From 1a2f01efa63036a5104f203a4789e682c0e0915d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 9 Jan 2018 01:23:08 +0000 Subject: [PATCH] libgo: update to Go1.10beta1 Update the Go library to the 1.10beta1 release. Requires a few changes to the compiler for modifications to the map runtime code, and to handle some nowritebarrier cases in the runtime. Reviewed-on: https://go-review.googlesource.com/86455 gotools/: * Makefile.am (go_cmd_vet_files): New variable. (go_cmd_buildid_files, go_cmd_test2json_files): New variables. (s-zdefaultcc): Change from constants to functions. (noinst_PROGRAMS): Add vet, buildid, and test2json. (cgo$(EXEEXT)): Link against $(LIBGOTOOL). (vet$(EXEEXT)): New target. (buildid$(EXEEXT)): New target. (test2json$(EXEEXT)): New target. (install-exec-local): Install all $(noinst_PROGRAMS). (uninstall-local): Uninstasll all $(noinst_PROGRAMS). (check-go-tool): Depend on $(noinst_PROGRAMS). Copy down objabi.go. (check-runtime): Depend on $(noinst_PROGRAMS). (check-cgo-test, check-carchive-test): Likewise. (check-vet): New target. (check): Depend on check-vet. Look at cmd_vet-testlog. (.PHONY): Add check-vet. * Makefile.in: Rebuild. From-SVN: r256365 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 43 +- gcc/go/gofrontend/runtime.def | 11 +- gcc/go/gofrontend/types.cc | 20 +- gcc/go/gofrontend/types.h | 4 +- gcc/go/gofrontend/wb.cc | 49 +- gotools/ChangeLog | 21 + gotools/Makefile.am | 97 +- gotools/Makefile.in | 120 +- libgo/MERGE | 2 +- libgo/Makefile.am | 59 +- libgo/Makefile.in | 56 +- libgo/VERSION | 2 +- libgo/configure | 24 +- libgo/configure.ac | 24 +- libgo/go/archive/tar/common.go | 608 ++- libgo/go/archive/tar/format.go | 174 +- libgo/go/archive/tar/reader.go | 825 ++-- libgo/go/archive/tar/reader_test.go | 1428 ++++-- .../tar/{stat_atim.go => stat_actime1.go} | 0 .../{stat_atimespec.go => stat_actime2.go} | 0 libgo/go/archive/tar/stat_unix.go | 72 +- libgo/go/archive/tar/strconv.go | 130 +- libgo/go/archive/tar/strconv_test.go | 139 +- libgo/go/archive/tar/tar_test.go | 541 +- .../go/archive/tar/testdata/gnu-long-nul.tar | Bin 0 -> 2560 bytes .../tar/testdata/gnu-nil-sparse-data.tar | Bin 0 -> 2560 bytes .../tar/testdata/gnu-nil-sparse-hole.tar | Bin 0 -> 1536 bytes .../go/archive/tar/testdata/gnu-not-utf8.tar | Bin 0 -> 1536 bytes .../archive/tar/testdata/gnu-sparse-big.tar | Bin 0 -> 5120 bytes libgo/go/archive/tar/testdata/gnu-utf8.tar | Bin 0 -> 2560 bytes .../go/archive/tar/testdata/invalid-go17.tar | Bin 0 -> 1536 bytes .../tar/testdata/pax-global-records.tar | Bin 0 -> 7168 bytes .../tar/testdata/pax-nil-sparse-data.tar | Bin 0 -> 4096 bytes ...issue12594.tar => pax-nil-sparse-hole.tar} | Bin 3072 -> 3072 bytes .../go/archive/tar/testdata/pax-nul-path.tar | Bin 0 -> 2560 bytes .../archive/tar/testdata/pax-nul-xattrs.tar | Bin 0 -> 2560 bytes .../tar/testdata/pax-pos-size-file.tar | Bin 2560 -> 2560 bytes libgo/go/archive/tar/testdata/pax-records.tar | Bin 0 -> 2560 bytes .../archive/tar/testdata/pax-sparse-big.tar | Bin 0 -> 6144 bytes .../archive/tar/testdata/trailing-slash.tar | Bin 0 -> 2560 bytes .../archive/tar/testdata/ustar-file-devs.tar | Bin 0 -> 1536 bytes .../archive/tar/testdata/writer-big-long.tar | Bin 4096 -> 1536 bytes libgo/go/archive/tar/testdata/writer-big.tar | Bin 4096 -> 512 bytes libgo/go/archive/tar/writer.go | 818 ++- libgo/go/archive/tar/writer_test.go | 995 +++- libgo/go/archive/zip/reader.go | 165 +- libgo/go/archive/zip/reader_test.go | 429 +- libgo/go/archive/zip/struct.go | 104 +- libgo/go/archive/zip/testdata/time-22738.zip | Bin 0 -> 140 bytes libgo/go/archive/zip/testdata/time-7zip.zip | Bin 0 -> 150 bytes libgo/go/archive/zip/testdata/time-go.zip | Bin 0 -> 148 bytes .../go/archive/zip/testdata/time-infozip.zip | Bin 0 -> 166 bytes libgo/go/archive/zip/testdata/time-osx.zip | Bin 0 -> 142 bytes libgo/go/archive/zip/testdata/time-win7.zip | Bin 0 -> 114 bytes libgo/go/archive/zip/testdata/time-winrar.zip | Bin 0 -> 150 bytes libgo/go/archive/zip/testdata/time-winzip.zip | Bin 0 -> 150 bytes libgo/go/archive/zip/testdata/utf8-7zip.zip | Bin 0 -> 146 bytes .../go/archive/zip/testdata/utf8-infozip.zip | Bin 0 -> 162 bytes libgo/go/archive/zip/testdata/utf8-osx.zip | Bin 0 -> 138 bytes libgo/go/archive/zip/testdata/utf8-winrar.zip | Bin 0 -> 146 bytes libgo/go/archive/zip/testdata/utf8-winzip.zip | Bin 0 -> 146 bytes libgo/go/archive/zip/writer.go | 137 +- libgo/go/archive/zip/writer_test.go | 124 +- libgo/go/archive/zip/zip_test.go | 42 +- libgo/go/bufio/bufio.go | 6 + libgo/go/bufio/bufio_test.go | 18 + libgo/go/bufio/export_test.go | 2 + libgo/go/bufio/scan.go | 9 +- libgo/go/builtin/builtin.go | 5 +- libgo/go/bytes/boundary_test.go | 84 + libgo/go/bytes/buffer.go | 94 +- libgo/go/bytes/buffer_test.go | 114 +- libgo/go/bytes/bytes.go | 292 +- libgo/go/bytes/bytes_amd64.go | 42 +- libgo/go/bytes/bytes_arm64.go | 70 + libgo/go/bytes/bytes_generic.go | 40 +- libgo/go/bytes/bytes_s390x.go | 42 +- libgo/go/bytes/bytes_test.go | 133 +- libgo/go/bytes/equal_test.go | 47 - libgo/go/bytes/example_test.go | 141 + libgo/go/bytes/reader.go | 6 + libgo/go/bytes/reader_test.go | 4 +- libgo/go/cmd/buildid/buildid.go | 73 + libgo/go/cmd/buildid/doc.go | 18 + libgo/go/cmd/cgo/ast.go | 272 +- libgo/go/cmd/cgo/doc.go | 285 +- libgo/go/cmd/cgo/gcc.go | 277 +- libgo/go/cmd/cgo/main.go | 23 +- libgo/go/cmd/cgo/out.go | 104 +- libgo/go/cmd/go/alldocs.go | 147 +- libgo/go/cmd/go/go_test.go | 1309 ++++- libgo/go/cmd/go/go_windows_test.go | 81 + libgo/go/cmd/go/internal/base/base.go | 4 +- libgo/go/cmd/go/internal/base/path.go | 22 - libgo/go/cmd/go/internal/base/tool.go | 11 +- libgo/go/cmd/go/internal/cache/cache.go | 453 ++ libgo/go/cmd/go/internal/cache/cache_test.go | 319 ++ libgo/go/cmd/go/internal/cache/default.go | 100 + libgo/go/cmd/go/internal/cache/hash.go | 174 + libgo/go/cmd/go/internal/cache/hash_test.go | 52 + libgo/go/cmd/go/internal/cfg/cfg.go | 50 +- libgo/go/cmd/go/internal/clean/clean.go | 68 +- libgo/go/cmd/go/internal/envcmd/env.go | 50 +- libgo/go/cmd/go/internal/fix/fix.go | 4 +- libgo/go/cmd/go/internal/fmtcmd/fmt.go | 36 +- libgo/go/cmd/go/internal/generate/generate.go | 4 +- libgo/go/cmd/go/internal/get/get.go | 18 +- libgo/go/cmd/go/internal/get/vcs.go | 116 +- libgo/go/cmd/go/internal/get/vcs_test.go | 18 + libgo/go/cmd/go/internal/help/helpdoc.go | 15 +- libgo/go/cmd/go/internal/list/list.go | 25 +- libgo/go/cmd/go/internal/load/flag.go | 121 + libgo/go/cmd/go/internal/load/flag_test.go | 135 + libgo/go/cmd/go/internal/load/icfg.go | 75 + libgo/go/cmd/go/internal/load/pkg.go | 975 +--- libgo/go/cmd/go/internal/load/search.go | 49 +- libgo/go/cmd/go/internal/load/testgo.go | 21 - libgo/go/cmd/go/internal/run/run.go | 9 +- libgo/go/cmd/go/internal/test/cover.go | 84 + libgo/go/cmd/go/internal/test/test.go | 758 ++- libgo/go/cmd/go/internal/test/testflag.go | 39 +- libgo/go/cmd/go/internal/tool/tool.go | 2 +- libgo/go/cmd/go/internal/vet/vet.go | 41 +- libgo/go/cmd/go/internal/vet/vetflag.go | 1 + libgo/go/cmd/go/internal/work/action.go | 752 +++ libgo/go/cmd/go/internal/work/build.go | 3596 +------------- libgo/go/cmd/go/internal/work/build_test.go | 7 +- libgo/go/cmd/go/internal/work/buildid.go | 614 +++ libgo/go/cmd/go/internal/work/exec.go | 2366 +++++++++ libgo/go/cmd/go/internal/work/gc.go | 500 ++ libgo/go/cmd/go/internal/work/gccgo.go | 554 +++ libgo/go/cmd/go/internal/work/init.go | 223 + libgo/go/cmd/go/main.go | 6 + libgo/go/cmd/go/note_test.go | 53 +- libgo/go/cmd/go/testdata/print_goroot.go | 11 + libgo/go/cmd/go/testdata/src/complex/main.go | 12 + .../testdata/src/complex/nest/sub/test12/p.go | 11 + .../testdata/src/complex/nest/sub/test23/p.go | 11 + .../src/complex/nest/sub/vendor/v2/v2.go | 3 + .../testdata/src/complex/nest/vendor/v1/v1.go | 3 + .../testdata/src/complex/nest/vendor/v2/v2.go | 3 + .../testdata/src/complex/nest/vendor/v3/v3.go | 3 + .../cmd/go/testdata/src/complex/vendor/v/v.go | 3 + libgo/go/cmd/go/testdata/src/complex/w/w.go | 3 + libgo/go/cmd/go/testdata/src/coverasm/p.go | 7 + libgo/go/cmd/go/testdata/src/coverasm/p.s | 2 + .../go/cmd/go/testdata/src/coverasm/p_test.go | 7 + libgo/go/cmd/go/testdata/src/coverbad/p.go | 5 + libgo/go/cmd/go/testdata/src/coverbad/p1.go | 7 + .../go/cmd/go/testdata/src/coverbad/p_test.go | 5 + libgo/go/cmd/go/testdata/src/coverdep/p.go | 6 + .../go/cmd/go/testdata/src/coverdep/p1/p1.go | 3 + .../go/cmd/go/testdata/src/coverdep/p_test.go | 7 + libgo/go/cmd/go/testdata/src/failfast_test.go | 54 + .../testdata/src/multimain/multimain_test.go | 16 + .../cmd/go/testdata/src/not_main/not_main.go | 3 + .../cmd/go/testdata/src/skipper/skip_test.go | 7 + .../go/cmd/go/testdata/src/sleepy1/p_test.go | 10 + .../go/cmd/go/testdata/src/sleepy2/p_test.go | 10 + libgo/go/cmd/go/testdata/src/sleepybad/p.go | 5 + .../testdata/src/testcache/testcache_test.go | 91 + .../cmd/go/testdata/src/testrace/race_test.go | 2 + libgo/go/cmd/go/testdata/src/vetcycle/p.go | 13 + libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go | 7 + libgo/go/cmd/go/testdata/src/vetfail/p2/p2.go | 6 + .../cmd/go/testdata/src/vetfail/p2/p2_test.go | 7 + .../testdata/standalone_main_normal_test.go | 10 + .../go/testdata/standalone_main_wrong_test.go | 10 + .../cmd/{go => }/internal/buildid/buildid.go | 139 +- libgo/go/cmd/internal/buildid/buildid_test.go | 137 + .../go/cmd/{go => }/internal/buildid/note.go | 41 +- libgo/go/cmd/internal/buildid/rewrite.go | 91 + libgo/go/cmd/internal/buildid/testdata/a.elf | Bin 0 -> 12768 bytes .../go/cmd/internal/buildid/testdata/a.macho | Bin 0 -> 13472 bytes libgo/go/cmd/internal/buildid/testdata/a.pe | Bin 0 -> 3584 bytes libgo/go/cmd/internal/edit/edit.go | 93 + libgo/go/cmd/internal/edit/edit_test.go | 28 + libgo/go/cmd/internal/objabi/autotype.go | 1 + libgo/go/cmd/internal/objabi/flag.go | 73 +- libgo/go/cmd/internal/objabi/line.go | 2 +- libgo/go/cmd/internal/objabi/reloctype.go | 14 +- .../cmd/internal/objabi/reloctype_string.go | 4 +- libgo/go/cmd/internal/objabi/symkind.go | 3 +- .../go/cmd/internal/objabi/symkind_string.go | 4 +- libgo/go/cmd/internal/objabi/util.go | 10 + libgo/go/cmd/internal/objabi/zbootstrap.go | 15 - libgo/go/cmd/internal/test2json/test2json.go | 413 ++ .../cmd/internal/test2json/test2json_test.go | 277 ++ .../internal/test2json/testdata/ascii.json | 10 + .../internal/test2json/testdata/ascii.test | 7 + .../internal/test2json/testdata/smiley.json | 182 + .../internal/test2json/testdata/smiley.test | 97 + .../internal/test2json/testdata/unicode.json | 10 + .../internal/test2json/testdata/unicode.test | 7 + .../cmd/internal/test2json/testdata/vet.json | 182 + .../cmd/internal/test2json/testdata/vet.test | 97 + libgo/go/cmd/test2json/main.go | 131 + libgo/go/cmd/vet/README | 33 + libgo/go/cmd/vet/all/main.go | 318 ++ libgo/go/cmd/vet/all/whitelist/386.txt | 27 + libgo/go/cmd/vet/all/whitelist/all.txt | 50 + libgo/go/cmd/vet/all/whitelist/amd64.txt | 34 + .../go/cmd/vet/all/whitelist/android_386.txt | 8 + .../cmd/vet/all/whitelist/android_amd64.txt | 3 + .../go/cmd/vet/all/whitelist/android_arm.txt | 5 + libgo/go/cmd/vet/all/whitelist/arm.txt | 21 + libgo/go/cmd/vet/all/whitelist/arm64.txt | 11 + libgo/go/cmd/vet/all/whitelist/darwin_386.txt | 9 + .../go/cmd/vet/all/whitelist/darwin_amd64.txt | 5 + libgo/go/cmd/vet/all/whitelist/darwin_arm.txt | 12 + .../go/cmd/vet/all/whitelist/darwin_arm64.txt | 8 + .../cmd/vet/all/whitelist/dragonfly_amd64.txt | 7 + .../go/cmd/vet/all/whitelist/freebsd_386.txt | 19 + .../cmd/vet/all/whitelist/freebsd_amd64.txt | 6 + .../go/cmd/vet/all/whitelist/freebsd_arm.txt | 4 + libgo/go/cmd/vet/all/whitelist/linux_386.txt | 13 + .../go/cmd/vet/all/whitelist/linux_amd64.txt | 8 + libgo/go/cmd/vet/all/whitelist/linux_arm.txt | 12 + .../go/cmd/vet/all/whitelist/linux_arm64.txt | 5 + .../go/cmd/vet/all/whitelist/linux_ppc64x.txt | 5 + libgo/go/cmd/vet/all/whitelist/mips.txt | 7 + libgo/go/cmd/vet/all/whitelist/mips64x.txt | 6 + libgo/go/cmd/vet/all/whitelist/mipsle.txt | 7 + libgo/go/cmd/vet/all/whitelist/mipsx.txt | 9 + libgo/go/cmd/vet/all/whitelist/nacl_386.txt | 13 + .../cmd/vet/all/whitelist/nacl_amd64p32.txt | 29 + libgo/go/cmd/vet/all/whitelist/nacl_arm.txt | 8 + libgo/go/cmd/vet/all/whitelist/netbsd.txt | 3 + libgo/go/cmd/vet/all/whitelist/netbsd_386.txt | 23 + .../go/cmd/vet/all/whitelist/netbsd_amd64.txt | 3 + libgo/go/cmd/vet/all/whitelist/netbsd_arm.txt | 5 + .../go/cmd/vet/all/whitelist/openbsd_386.txt | 17 + .../cmd/vet/all/whitelist/openbsd_amd64.txt | 3 + .../go/cmd/vet/all/whitelist/openbsd_arm.txt | 4 + libgo/go/cmd/vet/all/whitelist/plan9_386.txt | 3 + .../go/cmd/vet/all/whitelist/plan9_amd64.txt | 4 + libgo/go/cmd/vet/all/whitelist/plan9_arm.txt | 4 + libgo/go/cmd/vet/all/whitelist/ppc64x.txt | 12 + libgo/go/cmd/vet/all/whitelist/readme.txt | 4 + libgo/go/cmd/vet/all/whitelist/s390x.txt | 17 + .../cmd/vet/all/whitelist/solaris_amd64.txt | 6 + libgo/go/cmd/vet/all/whitelist/windows.txt | 7 + .../go/cmd/vet/all/whitelist/windows_386.txt | 10 + .../cmd/vet/all/whitelist/windows_amd64.txt | 9 + libgo/go/cmd/vet/asmdecl.go | 730 +++ libgo/go/cmd/vet/assign.go | 52 + libgo/go/cmd/vet/atomic.go | 69 + libgo/go/cmd/vet/bool.go | 186 + libgo/go/cmd/vet/buildtag.go | 91 + libgo/go/cmd/vet/cgo.go | 141 + libgo/go/cmd/vet/composite.go | 82 + libgo/go/cmd/vet/copylock.go | 256 + libgo/go/cmd/vet/dead.go | 108 + libgo/go/cmd/vet/deadcode.go | 298 ++ libgo/go/cmd/vet/doc.go | 224 + libgo/go/cmd/vet/httpresponse.go | 137 + libgo/go/cmd/vet/internal/cfg/builder.go | 512 ++ libgo/go/cmd/vet/internal/cfg/cfg.go | 142 + libgo/go/cmd/vet/internal/cfg/cfg_test.go | 190 + .../cmd/vet/internal/whitelist/whitelist.go | 28 + libgo/go/cmd/vet/lostcancel.go | 322 ++ libgo/go/cmd/vet/main.go | 619 +++ libgo/go/cmd/vet/method.go | 181 + libgo/go/cmd/vet/nilfunc.go | 67 + libgo/go/cmd/vet/print.go | 780 +++ libgo/go/cmd/vet/rangeloop.go | 105 + libgo/go/cmd/vet/shadow.go | 246 + libgo/go/cmd/vet/shift.go | 98 + libgo/go/cmd/vet/structtag.go | 226 + libgo/go/cmd/vet/testdata/asm/asm.go | 45 + libgo/go/cmd/vet/testdata/asm/asm1.s | 315 ++ libgo/go/cmd/vet/testdata/asm/asm2.s | 257 + libgo/go/cmd/vet/testdata/asm/asm3.s | 178 + libgo/go/cmd/vet/testdata/asm/asm4.s | 26 + libgo/go/cmd/vet/testdata/asm/asm5.s | 193 + libgo/go/cmd/vet/testdata/asm/asm6.s | 193 + libgo/go/cmd/vet/testdata/asm/asm7.s | 193 + libgo/go/cmd/vet/testdata/asm8.s | 165 + libgo/go/cmd/vet/testdata/assign.go | 31 + libgo/go/cmd/vet/testdata/atomic.go | 52 + libgo/go/cmd/vet/testdata/bool.go | 113 + .../go/cmd/vet/testdata/buildtag/buildtag.go | 14 + .../cmd/vet/testdata/buildtag/buildtag_bad.go | 15 + libgo/go/cmd/vet/testdata/cgo/cgo.go | 59 + libgo/go/cmd/vet/testdata/cgo/cgo2.go | 12 + libgo/go/cmd/vet/testdata/cgo/cgo3.go | 13 + libgo/go/cmd/vet/testdata/cgo/cgo4.go | 15 + libgo/go/cmd/vet/testdata/composite.go | 103 + libgo/go/cmd/vet/testdata/copylock.go | 188 + libgo/go/cmd/vet/testdata/copylock_func.go | 136 + libgo/go/cmd/vet/testdata/copylock_range.go | 67 + libgo/go/cmd/vet/testdata/deadcode.go | 2125 ++++++++ libgo/go/cmd/vet/testdata/divergent/buf.go | 17 + .../go/cmd/vet/testdata/divergent/buf_test.go | 35 + libgo/go/cmd/vet/testdata/httpresponse.go | 85 + .../vet/testdata/incomplete/examples_test.go | 33 + libgo/go/cmd/vet/testdata/lostcancel.go | 155 + libgo/go/cmd/vet/testdata/method.go | 22 + libgo/go/cmd/vet/testdata/nilfunc.go | 35 + libgo/go/cmd/vet/testdata/print.go | 535 ++ libgo/go/cmd/vet/testdata/rangeloop.go | 90 + libgo/go/cmd/vet/testdata/shadow.go | 59 + libgo/go/cmd/vet/testdata/shift.go | 162 + libgo/go/cmd/vet/testdata/structtag.go | 102 + libgo/go/cmd/vet/testdata/tagtest/file1.go | 10 + libgo/go/cmd/vet/testdata/tagtest/file2.go | 10 + libgo/go/cmd/vet/testdata/testingpkg/tests.go | 1 + .../cmd/vet/testdata/testingpkg/tests_test.go | 74 + libgo/go/cmd/vet/testdata/unsafeptr.go | 63 + libgo/go/cmd/vet/testdata/unused.go | 29 + libgo/go/cmd/vet/tests.go | 187 + libgo/go/cmd/vet/types.go | 312 ++ libgo/go/cmd/vet/unsafeptr.go | 97 + libgo/go/cmd/vet/unused.go | 93 + libgo/go/cmd/vet/vet_test.go | 249 + libgo/go/compress/bzip2/bzip2.go | 2 +- libgo/go/compress/bzip2/bzip2_test.go | 8 + libgo/go/compress/flate/huffman_bit_writer.go | 8 - libgo/go/compress/gzip/gunzip.go | 2 +- libgo/go/container/heap/heap_test.go | 1 + libgo/go/container/ring/example_test.go | 195 + libgo/go/context/benchmark_test.go | 56 +- libgo/go/context/context.go | 14 +- libgo/go/context/example_test.go | 2 +- libgo/go/crypto/aes/ctr_s390x.go | 4 + libgo/go/crypto/aes/gcm_s390x.go | 100 +- libgo/go/crypto/cipher/benchmark_test.go | 19 + libgo/go/crypto/cipher/cipher.go | 23 +- libgo/go/crypto/cipher/example_test.go | 76 +- libgo/go/crypto/cipher/gcm.go | 4 +- libgo/go/crypto/cipher/io.go | 6 +- libgo/go/crypto/cipher/ofb.go | 2 +- libgo/go/crypto/cipher/xor.go | 9 +- libgo/go/crypto/dsa/dsa.go | 2 +- libgo/go/crypto/ecdsa/ecdsa.go | 17 +- libgo/go/crypto/ecdsa/ecdsa_test.go | 58 +- libgo/go/crypto/elliptic/elliptic.go | 11 +- libgo/go/crypto/elliptic/elliptic_test.go | 129 +- libgo/go/crypto/elliptic/p256_amd64.go | 64 +- libgo/go/crypto/elliptic/p256_s390x.go | 49 +- libgo/go/crypto/hmac/hmac.go | 3 + libgo/go/crypto/issue21104_test.go | 61 + libgo/go/crypto/md5/md5.go | 78 +- libgo/go/crypto/md5/md5_test.go | 101 +- libgo/go/crypto/rand/rand_linux.go | 25 +- libgo/go/crypto/rand/rand_linux_test.go | 42 + libgo/go/crypto/rc4/rc4.go | 3 +- libgo/go/crypto/rc4/rc4_asm.go | 4 +- libgo/go/crypto/rc4/rc4_ref.go | 2 +- libgo/go/crypto/rsa/pss.go | 2 +- libgo/go/crypto/rsa/rsa.go | 19 +- libgo/go/crypto/sha1/sha1.go | 104 +- libgo/go/crypto/sha1/sha1_test.go | 105 +- libgo/go/crypto/sha1/sha1block_arm64.go | 30 + libgo/go/crypto/sha1/sha1block_generic.go | 2 +- libgo/go/crypto/sha256/sha256.go | 92 +- libgo/go/crypto/sha256/sha256_test.go | 191 +- libgo/go/crypto/sha256/sha256block_arm64.go | 25 + libgo/go/crypto/sha256/sha256block_generic.go | 2 +- libgo/go/crypto/sha512/sha512.go | 92 + libgo/go/crypto/sha512/sha512_test.go | 790 ++- libgo/go/crypto/subtle/constant_time.go | 16 +- libgo/go/crypto/subtle/constant_time_test.go | 32 + libgo/go/crypto/tls/common.go | 67 +- libgo/go/crypto/tls/conn.go | 28 +- libgo/go/crypto/tls/conn_test.go | 12 + libgo/go/crypto/tls/handshake_client.go | 177 +- libgo/go/crypto/tls/handshake_client_test.go | 37 +- libgo/go/crypto/tls/handshake_messages.go | 71 +- .../go/crypto/tls/handshake_messages_test.go | 12 +- libgo/go/crypto/tls/handshake_server.go | 32 +- libgo/go/crypto/tls/handshake_server_test.go | 87 + libgo/go/crypto/tls/handshake_test.go | 8 +- libgo/go/crypto/tls/key_agreement.go | 63 +- libgo/go/crypto/tls/prf.go | 46 +- .../Client-TLSv10-ClientCert-ECDSA-ECDSA | 94 +- .../Client-TLSv10-ClientCert-ECDSA-RSA | 90 +- .../Client-TLSv10-ClientCert-RSA-ECDSA | 92 +- .../testdata/Client-TLSv10-ClientCert-RSA-RSA | 90 +- .../testdata/Client-TLSv10-ECDHE-ECDSA-AES | 76 +- .../tls/testdata/Client-TLSv10-ECDHE-RSA-AES | 72 +- .../crypto/tls/testdata/Client-TLSv10-RSA-RC4 | 40 +- .../testdata/Client-TLSv11-ECDHE-ECDSA-AES | 74 +- .../tls/testdata/Client-TLSv11-ECDHE-RSA-AES | 72 +- .../crypto/tls/testdata/Client-TLSv11-RSA-RC4 | 40 +- .../testdata/Client-TLSv12-AES128-GCM-SHA256 | 44 +- .../tls/testdata/Client-TLSv12-AES128-SHA256 | 58 +- .../testdata/Client-TLSv12-AES256-GCM-SHA384 | 44 +- .../go/crypto/tls/testdata/Client-TLSv12-ALPN | 63 +- .../Client-TLSv12-ClientCert-ECDSA-ECDSA | 96 +- .../Client-TLSv12-ClientCert-ECDSA-RSA | 88 +- ...nt-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 | 84 +- .../Client-TLSv12-ClientCert-RSA-ECDSA | 100 +- .../testdata/Client-TLSv12-ClientCert-RSA-RSA | 84 +- .../testdata/Client-TLSv12-ECDHE-ECDSA-AES | 74 +- .../Client-TLSv12-ECDHE-ECDSA-AES-GCM | 68 +- .../Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 | 84 +- ...lient-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 | 68 +- ...lient-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 | 64 +- .../tls/testdata/Client-TLSv12-ECDHE-RSA-AES | 72 +- .../Client-TLSv12-ECDHE-RSA-AES128-SHA256 | 80 +- .../Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 | 60 +- .../crypto/tls/testdata/Client-TLSv12-RSA-RC4 | 40 +- .../testdata/Client-TLSv12-RenegotiateOnce | 292 +- .../testdata/Client-TLSv12-RenegotiateTwice | 522 +- .../Client-TLSv12-RenegotiateTwiceRejected | 298 +- .../Client-TLSv12-RenegotiationRejected | 68 +- .../go/crypto/tls/testdata/Client-TLSv12-SCT | 62 +- .../Client-TLSv12-X25519-ECDHE-RSA-AES-GCM | 65 +- .../go/crypto/tls/testdata/Server-TLSv12-ALPN | 64 +- .../tls/testdata/Server-TLSv12-ALPN-NoMatch | 64 +- ...rver-TLSv12-CipherSuiteCertPreferenceECDSA | 66 +- ...Server-TLSv12-CipherSuiteCertPreferenceRSA | 60 +- ...er-TLSv12-ClientAuthRequestedAndECDSAGiven | 76 +- .../Server-TLSv12-ClientAuthRequestedAndGiven | 78 +- .../Server-TLSv12-ClientAuthRequestedNotGiven | 60 +- .../testdata/Server-TLSv12-ECDHE-ECDSA-AES | 62 +- .../tls/testdata/Server-TLSv12-RSA-AES-GCM | 50 +- .../Server-TLSv12-RSA-AES256-GCM-SHA384 | 50 +- .../Server-TLSv12-X25519-ECDHE-RSA-AES-GCM | 50 +- libgo/go/crypto/tls/tls_test.go | 52 + libgo/go/crypto/x509/name_constraints_test.go | 2002 ++++++++ libgo/go/crypto/x509/pkcs1.go | 33 + libgo/go/crypto/x509/pkcs8.go | 47 + libgo/go/crypto/x509/pkcs8_test.go | 95 +- libgo/go/crypto/x509/pkix/pkix.go | 81 +- libgo/go/crypto/x509/root_cgo_darwin.go | 6 +- libgo/go/crypto/x509/root_windows.go | 4 +- libgo/go/crypto/x509/sec1.go | 6 + libgo/go/crypto/x509/sec1_test.go | 2 +- libgo/go/crypto/x509/verify.go | 695 ++- libgo/go/crypto/x509/verify_test.go | 131 +- libgo/go/crypto/x509/x509.go | 629 ++- libgo/go/crypto/x509/x509_test.go | 548 +- libgo/go/database/sql/convert.go | 32 +- libgo/go/database/sql/convert_test.go | 15 +- libgo/go/database/sql/ctxutil.go | 19 +- libgo/go/database/sql/driver/driver.go | 87 +- libgo/go/database/sql/fakedb_test.go | 73 + libgo/go/database/sql/sql.go | 305 +- libgo/go/database/sql/sql_test.go | 248 +- libgo/go/debug/dwarf/type.go | 77 +- libgo/go/debug/elf/elf.go | 756 ++- libgo/go/debug/elf/file.go | 19 +- libgo/go/debug/elf/reader.go | 6 +- libgo/go/debug/gosym/symtab.go | 9 +- libgo/go/debug/macho/file.go | 109 +- libgo/go/debug/macho/file_test.go | 303 +- libgo/go/debug/macho/macho.go | 233 +- libgo/go/debug/macho/reloctype.go | 72 + libgo/go/debug/macho/reloctype_string.go | 49 + .../testdata/clang-386-darwin-exec-with-rpath | Bin 0 -> 8416 bytes .../debug/macho/testdata/clang-386-darwin.obj | Bin 0 -> 464 bytes .../clang-amd64-darwin-exec-with-rpath | Bin 0 -> 8432 bytes .../macho/testdata/clang-amd64-darwin.obj | Bin 0 -> 768 bytes libgo/go/encoding/asn1/asn1.go | 109 +- libgo/go/encoding/asn1/asn1_test.go | 63 +- libgo/go/encoding/asn1/common.go | 33 +- libgo/go/encoding/asn1/marshal.go | 71 +- libgo/go/encoding/asn1/marshal_test.go | 46 + libgo/go/encoding/base32/base32.go | 15 +- libgo/go/encoding/base64/base64.go | 314 +- libgo/go/encoding/base64/base64_test.go | 5 +- libgo/go/encoding/binary/binary_test.go | 30 +- libgo/go/encoding/csv/reader.go | 437 +- libgo/go/encoding/csv/reader_test.go | 409 +- libgo/go/encoding/csv/writer.go | 6 +- libgo/go/encoding/gob/codec_test.go | 1 + libgo/go/encoding/gob/debug.go | 2 +- libgo/go/encoding/gob/decoder.go | 8 +- libgo/go/encoding/gob/doc.go | 2 +- libgo/go/encoding/hex/hex.go | 118 +- libgo/go/encoding/hex/hex_test.go | 96 +- libgo/go/encoding/json/bench_test.go | 15 + libgo/go/encoding/json/decode.go | 52 +- libgo/go/encoding/json/decode_test.go | 210 +- libgo/go/encoding/json/encode.go | 36 +- libgo/go/encoding/json/encode_test.go | 11 +- libgo/go/encoding/json/stream.go | 52 +- libgo/go/encoding/json/stream_test.go | 21 +- libgo/go/encoding/pem/example_test.go | 21 + libgo/go/encoding/pem/pem.go | 27 +- libgo/go/encoding/pem/pem_test.go | 14 + libgo/go/encoding/xml/atom_test.go | 6 +- libgo/go/encoding/xml/marshal.go | 9 +- libgo/go/encoding/xml/marshal_test.go | 23 +- libgo/go/encoding/xml/read.go | 85 +- libgo/go/encoding/xml/read_test.go | 183 +- libgo/go/encoding/xml/typeinfo.go | 12 +- libgo/go/encoding/xml/xml.go | 118 +- libgo/go/encoding/xml/xml_test.go | 93 +- libgo/go/expvar/expvar.go | 12 +- libgo/go/expvar/expvar_test.go | 22 + libgo/go/flag/export_test.go | 2 + libgo/go/flag/flag.go | 67 +- libgo/go/flag/flag_test.go | 56 + libgo/go/fmt/doc.go | 5 +- libgo/go/fmt/example_test.go | 31 + libgo/go/fmt/fmt_test.go | 30 +- libgo/go/fmt/print.go | 16 +- libgo/go/fmt/scan.go | 34 +- libgo/go/go/ast/ast.go | 4 +- libgo/go/go/ast/import.go | 48 +- libgo/go/go/build/build.go | 42 +- libgo/go/go/build/build_test.go | 13 + libgo/go/go/build/deps_test.go | 20 +- libgo/go/go/build/doc.go | 1 + libgo/go/go/constant/value.go | 2 +- libgo/go/go/doc/example.go | 11 +- libgo/go/go/doc/exports.go | 2 +- libgo/go/go/doc/reader.go | 25 +- libgo/go/go/doc/testdata/blank.0.golden | 15 +- libgo/go/go/doc/testdata/blank.1.golden | 24 +- libgo/go/go/doc/testdata/blank.2.golden | 15 +- libgo/go/go/doc/testdata/blank.go | 10 +- libgo/go/go/doc/testdata/issue16153.0.golden | 32 + libgo/go/go/doc/testdata/issue16153.1.golden | 34 + libgo/go/go/doc/testdata/issue16153.2.golden | 32 + libgo/go/go/doc/testdata/issue16153.go | 27 + libgo/go/go/doc/testdata/issue18063.0.golden | 45 + libgo/go/go/doc/testdata/issue18063.1.golden | 45 + libgo/go/go/doc/testdata/issue18063.2.golden | 45 + libgo/go/go/doc/testdata/issue18063.go | 33 + libgo/go/go/format/format.go | 8 +- libgo/go/go/importer/importer.go | 45 +- libgo/go/go/importer/importer_test.go | 68 + .../gccgoimporter/gccgoinstallation_test.go | 5 +- .../go/go/internal/gccgoimporter/importer.go | 50 +- .../internal/gccgoimporter/importer_test.go | 3 +- .../go/internal/gccgoimporter/parser_test.go | 5 + libgo/go/go/internal/gcimporter/bimport.go | 2 +- libgo/go/go/internal/gcimporter/gcimporter.go | 65 +- .../go/internal/gcimporter/gcimporter_test.go | 16 +- .../go/go/internal/srcimporter/srcimporter.go | 28 +- .../internal/srcimporter/srcimporter_test.go | 14 + .../testdata/issue20855/issue20855.go | 7 + libgo/go/go/printer/nodes.go | 72 +- libgo/go/go/printer/testdata/comments.golden | 28 + libgo/go/go/printer/testdata/comments.input | 28 + .../go/go/printer/testdata/expressions.golden | 49 +- .../go/go/printer/testdata/expressions.input | 40 +- libgo/go/go/printer/testdata/expressions.raw | 49 +- libgo/go/go/types/api.go | 30 +- libgo/go/go/types/api_test.go | 81 +- libgo/go/go/types/builtins.go | 7 +- libgo/go/go/types/call.go | 67 +- libgo/go/go/types/check_test.go | 1 + libgo/go/go/types/conversions.go | 17 +- libgo/go/go/types/expr.go | 37 +- libgo/go/go/types/exprstring.go | 12 +- libgo/go/go/types/hilbert_test.go | 2 + libgo/go/go/types/issues_test.go | 22 + libgo/go/go/types/methodset.go | 12 +- libgo/go/go/types/object.go | 38 +- libgo/go/go/types/object_test.go | 12 +- libgo/go/go/types/predicates.go | 6 +- libgo/go/go/types/resolver.go | 8 +- libgo/go/go/types/scope.go | 3 +- libgo/go/go/types/stdlib_test.go | 20 +- libgo/go/go/types/stmt.go | 37 +- libgo/go/go/types/testdata/cycles4.src | 12 + libgo/go/go/types/testdata/shifts.src | 9 + libgo/go/go/types/testdata/vardecl.src | 7 + libgo/go/go/types/type.go | 20 +- libgo/go/go/types/typestring.go | 10 + libgo/go/go/types/typestring_test.go | 20 + libgo/go/go/types/typexpr.go | 10 +- .../go/golang_org/x/crypto/cryptobyte/asn1.go | 732 +++ .../x/crypto/cryptobyte/asn1/asn1.go | 46 + .../x/crypto/cryptobyte/asn1_test.go | 300 ++ .../golang_org/x/crypto/cryptobyte/builder.go | 309 ++ .../x/crypto/cryptobyte/cryptobyte_test.go | 428 ++ .../x/crypto/cryptobyte/example_test.go | 156 + .../golang_org/x/crypto/cryptobyte/string.go | 167 + libgo/go/golang_org/x/net/idna/idna.go | 128 +- libgo/go/golang_org/x/net/idna/punycode.go | 2 +- libgo/go/golang_org/x/net/idna/tables.go | 4398 +++++++++-------- libgo/go/golang_org/x/net/idna/trie.go | 2 +- libgo/go/golang_org/x/net/idna/trieval.go | 19 +- .../x/net/internal/nettest/helper_bsd.go | 53 + .../x/net/internal/nettest/helper_nobsd.go | 15 + .../x/net/internal/nettest/helper_posix.go | 31 + .../x/net/internal/nettest/helper_stub.go | 32 + .../x/net/internal/nettest/helper_unix.go | 29 + .../x/net/internal/nettest/helper_windows.go | 42 + .../x/net/internal/nettest/interface.go | 94 + .../x/net/internal/nettest/rlimit.go | 11 + .../x/net/internal/nettest/stack.go | 152 + .../golang_org/x/net/nettest/conntest_test.go | 58 +- .../go/golang_org/x/net/route/defs_openbsd.go | 11 + .../golang_org/x/net/route/route_classic.go | 10 +- libgo/go/golang_org/x/net/route/route_test.go | 4 + libgo/go/golang_org/x/net/route/sys_darwin.go | 4 +- .../golang_org/x/net/route/sys_dragonfly.go | 4 +- .../go/golang_org/x/net/route/sys_freebsd.go | 4 +- libgo/go/golang_org/x/net/route/sys_netbsd.go | 4 +- .../go/golang_org/x/net/route/sys_openbsd.go | 5 +- .../go/golang_org/x/net/route/zsys_openbsd.go | 13 +- .../x/text/secure/bidirule/bidirule.go | 6 +- libgo/go/golang_org/x/text/secure/doc.go | 2 +- .../golang_org/x/text/transform/transform.go | 2 +- .../go/golang_org/x/text/unicode/bidi/bidi.go | 2 +- .../golang_org/x/text/unicode/bidi/bracket.go | 2 +- .../go/golang_org/x/text/unicode/bidi/core.go | 2 +- .../go/golang_org/x/text/unicode/bidi/prop.go | 2 +- .../golang_org/x/text/unicode/bidi/tables.go | 1358 ++--- .../golang_org/x/text/unicode/bidi/trieval.go | 2 +- libgo/go/golang_org/x/text/unicode/doc.go | 2 +- .../x/text/unicode/norm/composition.go | 20 +- .../x/text/unicode/norm/forminfo.go | 2 +- .../golang_org/x/text/unicode/norm/input.go | 10 +- .../go/golang_org/x/text/unicode/norm/iter.go | 33 +- .../x/text/unicode/norm/normalize.go | 18 +- .../x/text/unicode/norm/readwriter.go | 2 +- .../golang_org/x/text/unicode/norm/tables.go | 2844 +++++------ .../x/text/unicode/norm/transform.go | 4 +- .../go/golang_org/x/text/unicode/norm/trie.go | 2 +- libgo/go/hash/adler32/adler32.go | 50 +- libgo/go/hash/adler32/adler32_test.go | 125 +- libgo/go/hash/crc32/crc32.go | 71 +- libgo/go/hash/crc32/crc32_arm64.go | 5 +- libgo/go/hash/crc32/crc32_test.go | 150 +- libgo/go/hash/crc64/crc64.go | 72 +- libgo/go/hash/crc64/crc64_test.go | 154 +- libgo/go/hash/example_test.go | 53 + libgo/go/hash/fnv/fnv.go | 165 + libgo/go/hash/fnv/fnv_test.go | 113 +- libgo/go/hash/hash.go | 15 + libgo/go/hash/marshal_test.go | 107 + libgo/go/html/entity.go | 2 +- libgo/go/html/template/escape_test.go | 21 +- libgo/go/html/template/template.go | 5 + libgo/go/html/template/url.go | 22 +- libgo/go/image/color/color.go | 33 +- libgo/go/image/color/color_test.go | 47 + libgo/go/image/draw/draw.go | 24 +- libgo/go/image/draw/draw_test.go | 45 + libgo/go/image/gif/reader.go | 339 +- libgo/go/image/gif/reader_test.go | 58 + libgo/go/image/gif/writer.go | 144 +- libgo/go/image/gif/writer_test.go | 42 +- libgo/go/image/jpeg/reader_test.go | 4 +- libgo/go/image/jpeg/writer_test.go | 8 +- libgo/go/image/png/reader.go | 6 + libgo/go/image/png/reader_test.go | 29 +- libgo/go/image/png/writer_test.go | 28 +- libgo/go/internal/cpu/cpu.go | 47 +- libgo/go/internal/cpu/cpu_arm64.go | 40 +- libgo/go/internal/cpu/cpu_ppc64x.go | 54 + libgo/go/internal/cpu/cpu_test.go | 23 + libgo/go/internal/cpu/cpu_x86.go | 8 +- libgo/go/internal/poll/export_windows_test.go | 17 + libgo/go/internal/poll/fd.go | 4 + libgo/go/internal/poll/fd_poll_runtime.go | 4 +- libgo/go/internal/poll/fd_unix.go | 27 +- libgo/go/internal/poll/fd_windows.go | 185 +- libgo/go/internal/poll/fd_windows_test.go | 111 + libgo/go/internal/poll/sendfile_windows.go | 9 + libgo/go/internal/poll/sockoptip.go | 2 +- .../syscall/windows/exec_windows_test.go | 152 + .../go/internal/syscall/windows/mksyscall.go | 2 +- .../internal/syscall/windows/psapi_windows.go | 20 + .../syscall/windows/security_windows.go | 26 + .../syscall/windows/syscall_windows.go | 128 +- .../syscall/windows/zsyscall_windows.go | 99 +- libgo/go/internal/testenv/testenv.go | 59 +- libgo/go/internal/trace/parser.go | 88 +- libgo/go/io/example_test.go | 16 + libgo/go/io/io.go | 10 +- libgo/go/io/io_test.go | 39 + libgo/go/io/ioutil/ioutil.go | 23 +- libgo/go/io/multi.go | 16 +- libgo/go/io/multi_test.go | 49 + libgo/go/io/pipe.go | 177 +- libgo/go/io/pipe_test.go | 109 + libgo/go/log/log.go | 24 +- libgo/go/log/log_test.go | 11 + libgo/go/log/syslog/syslog_unix.go | 4 +- libgo/go/math/abs.go | 11 +- libgo/go/math/all_test.go | 240 +- libgo/go/math/big/calibrate_test.go | 86 +- libgo/go/math/big/decimal.go | 2 +- libgo/go/math/big/float.go | 12 +- libgo/go/math/big/int.go | 219 +- libgo/go/math/big/int_test.go | 164 +- libgo/go/math/big/intconv.go | 13 +- libgo/go/math/big/intconv_test.go | 16 +- libgo/go/math/big/intmarsh.go | 8 +- libgo/go/math/big/nat.go | 75 +- libgo/go/math/big/nat_test.go | 46 + libgo/go/math/big/natconv.go | 30 +- libgo/go/math/big/natconv_test.go | 14 +- libgo/go/math/big/prime.go | 10 +- libgo/go/math/big/rat.go | 9 +- libgo/go/math/big/ratconv.go | 7 +- libgo/go/math/big/ratmarsh.go | 6 +- libgo/go/math/big/sqrt.go | 151 + libgo/go/math/big/sqrt_test.go | 131 + libgo/go/math/bits.go | 3 + libgo/go/math/bits/example_test.go | 200 +- libgo/go/math/bits/make_examples.go | 112 + libgo/go/math/cmplx/asin.go | 19 +- libgo/go/math/cmplx/cmath_test.go | 63 + libgo/go/math/cmplx/sqrt.go | 7 +- libgo/go/math/const.go | 18 +- libgo/go/math/dim.go | 17 +- libgo/go/math/erfinv.go | 127 + libgo/go/math/example_test.go | 71 + libgo/go/math/exp.go | 4 +- libgo/go/math/exp_asm.go | 12 + libgo/go/math/expm1.go | 50 +- libgo/go/math/floor.go | 77 +- libgo/go/math/pow.go | 20 +- libgo/go/math/rand/rand.go | 54 + libgo/go/math/rand/rand_test.go | 137 +- libgo/go/mime/mediatype.go | 37 +- libgo/go/mime/mediatype_test.go | 183 +- libgo/go/mime/multipart/formdata.go | 3 +- libgo/go/mime/multipart/formdata_test.go | 26 + libgo/go/net/cgo_unix.go | 1 - libgo/go/net/dial_test.go | 2 + libgo/go/net/fd_windows.go | 22 +- libgo/go/net/hook_windows.go | 8 +- libgo/go/net/hosts_test.go | 2 +- libgo/go/net/http/client.go | 29 +- libgo/go/net/http/client_test.go | 80 +- libgo/go/net/http/clientserver_test.go | 58 +- libgo/go/net/http/cookie.go | 2 - libgo/go/net/http/example_test.go | 28 + libgo/go/net/http/export_test.go | 13 +- libgo/go/net/http/fs.go | 18 +- libgo/go/net/http/fs_test.go | 92 +- libgo/go/net/http/h2_bundle.go | 581 ++- libgo/go/net/http/header.go | 1 + libgo/go/net/http/httputil/dump_test.go | 2 - libgo/go/net/http/httputil/reverseproxy.go | 52 +- .../go/net/http/httputil/reverseproxy_test.go | 73 + libgo/go/net/http/pprof/pprof.go | 10 +- libgo/go/net/http/readrequest_test.go | 8 + libgo/go/net/http/request.go | 30 +- libgo/go/net/http/response.go | 7 + libgo/go/net/http/response_test.go | 36 +- libgo/go/net/http/serve_test.go | 163 +- libgo/go/net/http/server.go | 159 +- libgo/go/net/http/sniff.go | 15 + libgo/go/net/http/sniff_test.go | 24 +- libgo/go/net/http/transfer.go | 5 +- libgo/go/net/http/transport.go | 185 +- libgo/go/net/http/transport_test.go | 367 +- libgo/go/net/internal/socktest/sys_windows.go | 37 +- libgo/go/net/iprawsock.go | 2 +- libgo/go/net/listen_test.go | 33 + libgo/go/net/lookup_plan9.go | 2 +- libgo/go/net/lookup_test.go | 24 + libgo/go/net/lookup_windows.go | 5 +- libgo/go/net/mail/message.go | 177 +- libgo/go/net/mail/message_test.go | 191 +- libgo/go/net/main_windows_test.go | 3 + libgo/go/net/parse.go | 2 +- libgo/go/net/pipe.go | 232 +- libgo/go/net/pipe_test.go | 74 +- libgo/go/net/platform_test.go | 28 +- libgo/go/net/port.go | 4 +- libgo/go/net/protoconn_test.go | 10 +- libgo/go/net/rawconn.go | 16 + libgo/go/net/rawconn_unix_test.go | 50 + libgo/go/net/rawconn_windows_test.go | 53 + libgo/go/net/rpc/server.go | 14 +- libgo/go/net/rpc/server_test.go | 52 + libgo/go/net/smtp/auth.go | 33 +- libgo/go/net/smtp/smtp.go | 39 + libgo/go/net/smtp/smtp_test.go | 106 +- libgo/go/net/sock_bsd.go | 4 +- libgo/go/net/sock_windows.go | 13 +- .../{sockoptip_bsd.go => sockoptip_bsdvar.go} | 2 +- libgo/go/net/sockoptip_posix.go | 2 +- libgo/go/net/sockoptip_stub.go | 2 +- libgo/go/net/tcpsock.go | 12 + libgo/go/net/tcpsock_test.go | 72 + libgo/go/net/textproto/reader.go | 16 +- libgo/go/net/textproto/reader_test.go | 18 + libgo/go/net/udpsock.go | 2 +- libgo/go/net/udpsock_test.go | 4 +- libgo/go/net/unixsock.go | 12 + libgo/go/net/unixsock_linux_test.go | 104 + libgo/go/net/unixsock_test.go | 45 - libgo/go/net/url/url.go | 50 +- libgo/go/net/url/url_test.go | 52 + libgo/go/net/write_unix_test.go | 66 + libgo/go/os/env_test.go | 2 +- libgo/go/os/error.go | 25 + libgo/go/os/exec/exec.go | 78 +- libgo/go/os/exec_plan9.go | 7 +- libgo/go/os/exec_posix.go | 7 +- libgo/go/os/file.go | 49 +- libgo/go/os/file_plan9.go | 26 + libgo/go/os/file_posix.go | 24 + libgo/go/os/file_unix.go | 40 +- libgo/go/os/os_test.go | 66 +- libgo/go/os/os_unix_test.go | 13 - libgo/go/os/path.go | 6 + libgo/go/os/path_test.go | 31 + libgo/go/os/pipe_bsd.go | 2 +- libgo/go/os/pipe_freebsd.go | 18 +- libgo/go/os/pipe_linux.go | 2 +- libgo/go/os/signal/internal/pty/pty.go | 62 + libgo/go/os/signal/signal_cgo_test.go | 228 + libgo/go/os/signal/signal_test.go | 6 +- libgo/go/os/sys_freebsd.go | 17 +- libgo/go/os/timeout_test.go | 589 +++ libgo/go/os/user/cgo_lookup_unix.go | 15 +- libgo/go/os/user/cgo_unix_test.go | 24 + libgo/go/os/user/listgroups_unix.go | 3 +- libgo/go/os/wait_wait6.go | 5 - libgo/go/path/example_test.go | 4 + libgo/go/path/filepath/example_test.go | 22 + libgo/go/path/filepath/example_unix_test.go | 22 + libgo/go/path/filepath/path.go | 24 +- libgo/go/path/filepath/path_test.go | 216 +- libgo/go/path/filepath/path_windows.go | 4 +- libgo/go/path/filepath/symlink_windows.go | 97 +- libgo/go/plugin/plugin.go | 1 + libgo/go/plugin/plugin_dlopen.go | 90 +- libgo/go/reflect/all_test.go | 229 +- libgo/go/reflect/export_test.go | 4 +- libgo/go/reflect/swapper.go | 4 +- libgo/go/reflect/type.go | 38 +- libgo/go/reflect/value.go | 153 +- libgo/go/regexp/backtrack.go | 59 +- libgo/go/regexp/exec.go | 15 +- libgo/go/regexp/syntax/prog.go | 13 +- libgo/go/runtime/alg.go | 9 +- libgo/go/runtime/append_test.go | 78 +- libgo/go/runtime/cgo_gccgo.go | 16 +- libgo/go/runtime/cgocall.go | 6 +- libgo/go/runtime/cgocheck.go | 4 + libgo/go/runtime/chan.go | 74 +- libgo/go/runtime/chan_test.go | 110 + libgo/go/runtime/cpuprof.go | 1 + libgo/go/runtime/cputicks.go | 2 +- libgo/go/runtime/crash_cgo_test.go | 92 +- libgo/go/runtime/crash_test.go | 47 +- libgo/go/runtime/crash_unix_test.go | 11 +- libgo/go/runtime/debug.go | 3 - libgo/go/runtime/export_test.go | 43 +- libgo/go/runtime/extern.go | 4 +- libgo/go/runtime/gc_test.go | 143 +- libgo/go/runtime/hash32.go | 26 + libgo/go/runtime/hash64.go | 22 + libgo/go/runtime/hash_test.go | 34 + libgo/go/runtime/hashmap.go | 695 ++- libgo/go/runtime/hashmap_fast.go | 927 +++- libgo/go/runtime/heapdump.go | 11 - .../go/runtime/internal/atomic/atomic_test.go | 2 +- libgo/go/runtime/internal/sys/sys.go | 4 +- libgo/go/runtime/lock_sema.go | 8 +- libgo/go/runtime/malloc.go | 82 +- libgo/go/runtime/malloc_test.go | 5 +- libgo/go/runtime/map_test.go | 222 +- libgo/go/runtime/mbarrier.go | 58 +- libgo/go/runtime/mbitmap.go | 26 +- libgo/go/runtime/mcache.go | 3 +- libgo/go/runtime/mem_gccgo.go | 54 +- libgo/go/runtime/memmove_test.go | 9 + libgo/go/runtime/mfinal.go | 15 +- libgo/go/runtime/mfinal_test.go | 21 + libgo/go/runtime/mgc.go | 322 +- libgo/go/runtime/mgc_gccgo.go | 23 +- libgo/go/runtime/mgclarge.go | 4 +- libgo/go/runtime/mgcmark.go | 47 +- libgo/go/runtime/mgcwork.go | 56 +- libgo/go/runtime/mheap.go | 81 +- libgo/go/runtime/mksizeclasses.go | 13 +- libgo/go/runtime/mstats.go | 16 +- libgo/go/runtime/mwbbuf.go | 248 + libgo/go/runtime/netpoll_kqueue.go | 19 +- libgo/go/runtime/netpoll_windows.go | 2 +- libgo/go/runtime/os_freebsd.go | 11 + libgo/go/runtime/os_linux.go | 71 +- libgo/go/runtime/os_linux_ppc64x.go | 53 +- libgo/go/runtime/os_netbsd.go | 16 +- libgo/go/runtime/panic.go | 27 +- libgo/go/runtime/pprof/pprof.go | 94 +- libgo/go/runtime/pprof/pprof_test.go | 291 +- libgo/go/runtime/pprof/proto.go | 4 +- libgo/go/runtime/print.go | 18 +- libgo/go/runtime/proc.go | 641 ++- libgo/go/runtime/proc_runtime_test.go | 2 - libgo/go/runtime/proc_test.go | 153 +- libgo/go/runtime/runtime-lldb_test.go | 84 +- libgo/go/runtime/runtime.go | 6 + libgo/go/runtime/runtime1.go | 11 - libgo/go/runtime/runtime2.go | 141 +- libgo/go/runtime/runtime_mmap_test.go | 29 +- libgo/go/runtime/runtime_test.go | 9 +- libgo/go/runtime/rwmutex_test.go | 5 + libgo/go/runtime/select.go | 76 +- libgo/go/runtime/sema.go | 5 +- libgo/go/runtime/signal_gccgo.go | 5 - libgo/go/runtime/signal_sighandler.go | 6 +- libgo/go/runtime/signal_unix.go | 95 +- libgo/go/runtime/sigqueue.go | 35 +- libgo/go/runtime/sizeclasses.go | 134 +- libgo/go/runtime/slice.go | 42 +- libgo/go/runtime/string.go | 6 +- libgo/go/runtime/stubs.go | 29 +- libgo/go/runtime/stubs2.go | 7 + libgo/go/runtime/testdata/testprog/gc.go | 3 + libgo/go/runtime/testdata/testprog/gettid.go | 29 + .../runtime/testdata/testprog/gettid_none.go | 15 + .../runtime/testdata/testprog/lockosthread.go | 94 + .../testdata/testprog/syscall_windows.go | 45 +- .../runtime/testdata/testprogcgo/callback.go | 6 +- .../testdata/testprogcgo/catchpanic.go | 46 + libgo/go/runtime/testdata/testprogcgo/cgo.go | 6 +- .../testdata/testprogcgo/lockosthread.c | 13 + .../testdata/testprogcgo/lockosthread.go | 111 + .../runtime/testdata/testprogcgo/sigstack.go | 95 + .../testdata/testprogcgo/stack_windows.go | 54 + libgo/go/runtime/time.go | 256 +- libgo/go/runtime/trace.go | 112 +- libgo/go/runtime/trace/example_test.go | 41 + libgo/go/runtime/trace/trace.go | 37 +- libgo/go/runtime/trace/trace_test.go | 57 + libgo/go/runtime/traceback_gccgo.go | 4 +- libgo/go/sort/example_interface_test.go | 14 + libgo/go/sort/example_keys_test.go | 2 +- libgo/go/sort/example_multi_test.go | 9 +- libgo/go/sort/example_test.go | 44 + libgo/go/sort/slice.go | 46 + libgo/go/sort/sort.go | 39 - libgo/go/sort/sort_test.go | 60 +- libgo/go/strconv/atoi.go | 133 +- libgo/go/strconv/atoi_test.go | 363 +- libgo/go/strconv/export_test.go | 10 + libgo/go/strconv/extfloat.go | 2 +- libgo/go/strconv/isprint.go | 65 +- libgo/go/strconv/quote.go | 2 +- libgo/go/strings/builder.go | 120 + libgo/go/strings/builder_test.go | 282 ++ libgo/go/strings/example_test.go | 124 +- libgo/go/strings/strings.go | 255 +- libgo/go/strings/strings_amd64.go | 20 +- libgo/go/strings/strings_generic.go | 38 +- libgo/go/strings/strings_s390x.go | 20 +- libgo/go/strings/strings_test.go | 46 + libgo/go/sync/atomic/atomic_test.go | 6 +- libgo/go/sync/atomic/value.go | 12 - libgo/go/sync/cond.go | 2 +- libgo/go/sync/waitgroup.go | 12 +- libgo/go/syscall/creds_test.go | 183 +- libgo/go/syscall/exec_freebsd.go | 18 +- libgo/go/syscall/exec_linux.go | 18 +- libgo/go/syscall/exec_linux_test.go | 25 +- libgo/go/syscall/exec_windows.go | 7 +- libgo/go/syscall/libcall_posix.go | 3 - libgo/go/syscall/socket.go | 21 +- libgo/go/syscall/syscall.go | 9 +- libgo/go/syscall/syscall_unix_test.go | 3 + libgo/go/testing/benchmark.go | 84 +- libgo/go/testing/example.go | 2 +- libgo/go/testing/iotest/logger.go | 2 +- libgo/go/testing/testing.go | 134 +- libgo/go/text/tabwriter/tabwriter.go | 84 +- libgo/go/text/template/doc.go | 6 + libgo/go/text/template/exec.go | 128 +- libgo/go/text/template/exec_test.go | 21 + libgo/go/text/template/funcs.go | 20 +- libgo/go/text/template/multi_test.go | 3 + libgo/go/text/template/parse/lex.go | 22 +- libgo/go/text/template/parse/lex_test.go | 32 +- libgo/go/text/template/parse/node.go | 64 + libgo/go/text/template/parse/parse.go | 44 +- libgo/go/text/template/parse/parse_test.go | 12 + libgo/go/time/example_test.go | 335 +- libgo/go/time/export_android_test.go | 4 +- libgo/go/time/export_test.go | 1 + libgo/go/time/format.go | 19 +- libgo/go/time/format_test.go | 3 + libgo/go/time/genzabbrs.go | 16 +- libgo/go/time/internal_test.go | 24 + libgo/go/time/sleep.go | 4 +- libgo/go/time/sleep_test.go | 53 +- libgo/go/time/sys_plan9.go | 34 +- libgo/go/time/sys_unix.go | 36 +- libgo/go/time/sys_windows.go | 34 +- libgo/go/time/tick_test.go | 22 +- libgo/go/time/time.go | 16 +- libgo/go/time/time_test.go | 5 +- libgo/go/time/zoneinfo.go | 19 +- libgo/go/time/zoneinfo_android.go | 56 +- libgo/go/time/zoneinfo_ios.go | 32 +- libgo/go/time/zoneinfo_plan9.go | 26 +- libgo/go/time/zoneinfo_read.go | 113 +- libgo/go/time/zoneinfo_test.go | 27 + libgo/go/time/zoneinfo_unix.go | 44 +- libgo/go/time/zoneinfo_windows.go | 25 +- libgo/go/unicode/letter.go | 8 +- libgo/go/unicode/script_test.go | 12 +- libgo/go/unicode/tables.go | 372 +- libgo/go/unicode/utf8/utf8.go | 20 +- libgo/godeps.sh | 3 +- libgo/merge.sh | 8 +- libgo/misc/cgo/errors/errors_test.go | 161 + libgo/misc/cgo/errors/issue13635.go | 24 - libgo/misc/cgo/errors/{ptr.go => ptr_test.go} | 198 +- libgo/misc/cgo/errors/{ => src}/err1.go | 0 libgo/misc/cgo/errors/{ => src}/err2.go | 0 libgo/misc/cgo/errors/{ => src}/err3.go | 0 libgo/misc/cgo/errors/src/err4.go | 15 + .../misc/cgo/errors/{ => src}/issue11097a.go | 0 .../misc/cgo/errors/{ => src}/issue11097b.go | 0 libgo/misc/cgo/errors/{ => src}/issue13129.go | 2 +- libgo/misc/cgo/errors/{ => src}/issue13423.go | 0 libgo/misc/cgo/errors/src/issue13467.go | 15 + libgo/misc/cgo/errors/src/issue13635.go | 24 + libgo/misc/cgo/errors/{ => src}/issue13830.go | 0 libgo/misc/cgo/errors/{ => src}/issue14669.go | 0 libgo/misc/cgo/errors/{ => src}/issue16116.go | 0 libgo/misc/cgo/errors/{ => src}/issue16591.go | 0 libgo/misc/cgo/errors/{ => src}/issue18452.go | 4 +- libgo/misc/cgo/errors/{ => src}/issue18889.go | 0 libgo/misc/cgo/errors/{ => src}/issue7757.go | 0 libgo/misc/cgo/errors/{ => src}/issue8442.go | 0 libgo/misc/cgo/errors/src/long_double_size.go | 16 + libgo/misc/cgo/errors/{ => src}/malloc.go | 0 libgo/misc/cgo/errors/test.bash | 75 - libgo/misc/cgo/life/main.go | 5 +- libgo/misc/cgo/stdio/chain.go | 2 +- libgo/misc/cgo/stdio/fib.go | 2 +- libgo/misc/cgo/stdio/hello.go | 2 +- libgo/misc/cgo/test/cgo_test.go | 6 + libgo/misc/cgo/test/issue18720.go | 30 +- libgo/misc/cgo/test/issue19832.go | 16 + libgo/misc/cgo/test/issue20910.c | 19 + libgo/misc/cgo/test/issue20910.go | 19 + libgo/misc/cgo/test/issue21668.go | 13 + libgo/misc/cgo/test/issue21708.go | 16 + libgo/misc/cgo/test/issue21809.go | 45 + libgo/misc/cgo/test/issue21897.go | 56 + libgo/misc/cgo/test/issue21897b.go | 13 + libgo/misc/cgo/test/issue22958.go | 24 + libgo/misc/cgo/test/issue6907.go | 33 + libgo/misc/cgo/test/issue6907export.go | 30 + libgo/misc/cgo/test/issue6907export_c.c | 11 + libgo/misc/cgo/test/issue7978.go | 9 +- libgo/misc/cgo/testcarchive/carchive_test.go | 28 +- libgo/misc/cgo/testcshared/cshared_test.go | 479 ++ libgo/misc/cgo/testcshared/test.bash | 193 - libgo/misc/cgo/testplugin/src/host/host.go | 32 +- .../cgo/testplugin/src/issue18584/main.go | 23 + .../cgo/testplugin/src/issue18584/plugin.go | 19 + .../cgo/testplugin/src/issue19418/main.go | 29 + .../cgo/testplugin/src/issue19418/plugin.go} | 4 +- .../cgo/testplugin/src/issue19529/plugin.go | 15 + .../cgo/testplugin/src/issue22175/main.go | 28 + .../cgo/testplugin/src/issue22175/plugin1.go | 21 + .../cgo/testplugin/src/issue22175/plugin2.go} | 6 +- .../cgo/testplugin/src/issue22295.pkg/main.go | 28 + .../testplugin/src/issue22295.pkg/plugin.go | 16 + .../cgo/testplugin/src/plugin1/plugin1.go | 20 +- .../cgo/testplugin/src/plugin2/plugin2.go | 16 + libgo/misc/cgo/testplugin/test.bash | 69 +- .../{unnamed1.go => unnamed1/main.go} | 0 .../{unnamed2.go => unnamed2/main.go} | 0 libgo/misc/cgo/testsanitizers/cc_test.go | 441 ++ libgo/misc/cgo/testsanitizers/cshared_test.go | 74 + libgo/misc/cgo/testsanitizers/msan_test.go | 55 + .../misc/cgo/testsanitizers/{ => src}/msan.go | 0 .../cgo/testsanitizers/{ => src}/msan2.go | 0 .../cgo/testsanitizers/src/msan2_cmsan.go | 38 + .../cgo/testsanitizers/{ => src}/msan3.go | 0 .../cgo/testsanitizers/{ => src}/msan4.go | 0 .../cgo/testsanitizers/{ => src}/msan5.go | 0 .../cgo/testsanitizers/{ => src}/msan_fail.go | 0 .../testsanitizers/{ => src}/msan_shared.go | 0 .../misc/cgo/testsanitizers/{ => src}/tsan.go | 0 .../cgo/testsanitizers/{ => src}/tsan10.go | 0 .../cgo/testsanitizers/{ => src}/tsan11.go | 0 .../cgo/testsanitizers/{ => src}/tsan12.go | 0 .../cgo/testsanitizers/{ => src}/tsan2.go | 0 .../cgo/testsanitizers/{ => src}/tsan3.go | 0 .../cgo/testsanitizers/{ => src}/tsan4.go | 0 .../cgo/testsanitizers/{ => src}/tsan5.go | 0 .../cgo/testsanitizers/{ => src}/tsan6.go | 0 .../cgo/testsanitizers/{ => src}/tsan7.go | 0 .../cgo/testsanitizers/{ => src}/tsan8.go | 0 .../cgo/testsanitizers/{ => src}/tsan9.go | 0 .../testsanitizers/{ => src}/tsan_shared.go | 0 libgo/misc/cgo/testsanitizers/test.bash | 233 - libgo/misc/cgo/testsanitizers/tsan_test.go | 56 + libgo/misc/cgo/testshared/shared_test.go | 139 +- libgo/misc/cgo/testshared/src/depBase/dep.go | 2 +- libgo/misc/cgo/testshared/src/exe/exe.go | 2 +- libgo/misc/cgo/testshared/src/global/main.go | 71 + .../cgo/testshared/src/globallib/global.go | 17 + libgo/runtime/go-callers.c | 23 +- libgo/runtime/proc.c | 40 +- libgo/runtime/runtime.h | 3 +- libgo/runtime/runtime_c.c | 15 - libgo/testsuite/gotest | 2 +- 1102 files changed, 73194 insertions(+), 22803 deletions(-) rename libgo/go/archive/tar/{stat_atim.go => stat_actime1.go} (100%) rename libgo/go/archive/tar/{stat_atimespec.go => stat_actime2.go} (100%) create mode 100644 libgo/go/archive/tar/testdata/gnu-long-nul.tar create mode 100644 libgo/go/archive/tar/testdata/gnu-nil-sparse-data.tar create mode 100644 libgo/go/archive/tar/testdata/gnu-nil-sparse-hole.tar create mode 100644 libgo/go/archive/tar/testdata/gnu-not-utf8.tar create mode 100644 libgo/go/archive/tar/testdata/gnu-sparse-big.tar create mode 100644 libgo/go/archive/tar/testdata/gnu-utf8.tar create mode 100644 libgo/go/archive/tar/testdata/invalid-go17.tar create mode 100644 libgo/go/archive/tar/testdata/pax-global-records.tar create mode 100644 libgo/go/archive/tar/testdata/pax-nil-sparse-data.tar rename libgo/go/archive/tar/testdata/{ustar.issue12594.tar => pax-nil-sparse-hole.tar} (75%) create mode 100644 libgo/go/archive/tar/testdata/pax-nul-path.tar create mode 100644 libgo/go/archive/tar/testdata/pax-nul-xattrs.tar create mode 100644 libgo/go/archive/tar/testdata/pax-records.tar create mode 100644 libgo/go/archive/tar/testdata/pax-sparse-big.tar create mode 100644 libgo/go/archive/tar/testdata/trailing-slash.tar create mode 100644 libgo/go/archive/tar/testdata/ustar-file-devs.tar create mode 100644 libgo/go/archive/zip/testdata/time-22738.zip create mode 100644 libgo/go/archive/zip/testdata/time-7zip.zip create mode 100644 libgo/go/archive/zip/testdata/time-go.zip create mode 100644 libgo/go/archive/zip/testdata/time-infozip.zip create mode 100644 libgo/go/archive/zip/testdata/time-osx.zip create mode 100644 libgo/go/archive/zip/testdata/time-win7.zip create mode 100644 libgo/go/archive/zip/testdata/time-winrar.zip create mode 100644 libgo/go/archive/zip/testdata/time-winzip.zip create mode 100644 libgo/go/archive/zip/testdata/utf8-7zip.zip create mode 100644 libgo/go/archive/zip/testdata/utf8-infozip.zip create mode 100644 libgo/go/archive/zip/testdata/utf8-osx.zip create mode 100644 libgo/go/archive/zip/testdata/utf8-winrar.zip create mode 100644 libgo/go/archive/zip/testdata/utf8-winzip.zip create mode 100644 libgo/go/bytes/boundary_test.go create mode 100644 libgo/go/bytes/bytes_arm64.go delete mode 100644 libgo/go/bytes/equal_test.go create mode 100644 libgo/go/cmd/buildid/buildid.go create mode 100644 libgo/go/cmd/buildid/doc.go create mode 100644 libgo/go/cmd/go/internal/cache/cache.go create mode 100644 libgo/go/cmd/go/internal/cache/cache_test.go create mode 100644 libgo/go/cmd/go/internal/cache/default.go create mode 100644 libgo/go/cmd/go/internal/cache/hash.go create mode 100644 libgo/go/cmd/go/internal/cache/hash_test.go create mode 100644 libgo/go/cmd/go/internal/load/flag.go create mode 100644 libgo/go/cmd/go/internal/load/flag_test.go create mode 100644 libgo/go/cmd/go/internal/load/icfg.go delete mode 100644 libgo/go/cmd/go/internal/load/testgo.go create mode 100644 libgo/go/cmd/go/internal/test/cover.go create mode 100644 libgo/go/cmd/go/internal/work/action.go create mode 100644 libgo/go/cmd/go/internal/work/buildid.go create mode 100644 libgo/go/cmd/go/internal/work/exec.go create mode 100644 libgo/go/cmd/go/internal/work/gc.go create mode 100644 libgo/go/cmd/go/internal/work/gccgo.go create mode 100644 libgo/go/cmd/go/internal/work/init.go create mode 100644 libgo/go/cmd/go/testdata/print_goroot.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/main.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go create mode 100644 libgo/go/cmd/go/testdata/src/complex/w/w.go create mode 100644 libgo/go/cmd/go/testdata/src/coverasm/p.go create mode 100644 libgo/go/cmd/go/testdata/src/coverasm/p.s create mode 100644 libgo/go/cmd/go/testdata/src/coverasm/p_test.go create mode 100644 libgo/go/cmd/go/testdata/src/coverbad/p.go create mode 100644 libgo/go/cmd/go/testdata/src/coverbad/p1.go create mode 100644 libgo/go/cmd/go/testdata/src/coverbad/p_test.go create mode 100644 libgo/go/cmd/go/testdata/src/coverdep/p.go create mode 100644 libgo/go/cmd/go/testdata/src/coverdep/p1/p1.go create mode 100644 libgo/go/cmd/go/testdata/src/coverdep/p_test.go create mode 100644 libgo/go/cmd/go/testdata/src/failfast_test.go create mode 100644 libgo/go/cmd/go/testdata/src/multimain/multimain_test.go create mode 100644 libgo/go/cmd/go/testdata/src/not_main/not_main.go create mode 100644 libgo/go/cmd/go/testdata/src/skipper/skip_test.go create mode 100644 libgo/go/cmd/go/testdata/src/sleepy1/p_test.go create mode 100644 libgo/go/cmd/go/testdata/src/sleepy2/p_test.go create mode 100644 libgo/go/cmd/go/testdata/src/sleepybad/p.go create mode 100644 libgo/go/cmd/go/testdata/src/testcache/testcache_test.go create mode 100644 libgo/go/cmd/go/testdata/src/vetcycle/p.go create mode 100644 libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go create mode 100644 libgo/go/cmd/go/testdata/src/vetfail/p2/p2.go create mode 100644 libgo/go/cmd/go/testdata/src/vetfail/p2/p2_test.go create mode 100644 libgo/go/cmd/go/testdata/standalone_main_normal_test.go create mode 100644 libgo/go/cmd/go/testdata/standalone_main_wrong_test.go rename libgo/go/cmd/{go => }/internal/buildid/buildid.go (62%) create mode 100644 libgo/go/cmd/internal/buildid/buildid_test.go rename libgo/go/cmd/{go => }/internal/buildid/note.go (80%) create mode 100644 libgo/go/cmd/internal/buildid/rewrite.go create mode 100644 libgo/go/cmd/internal/buildid/testdata/a.elf create mode 100644 libgo/go/cmd/internal/buildid/testdata/a.macho create mode 100644 libgo/go/cmd/internal/buildid/testdata/a.pe create mode 100644 libgo/go/cmd/internal/edit/edit.go create mode 100644 libgo/go/cmd/internal/edit/edit_test.go delete mode 100644 libgo/go/cmd/internal/objabi/zbootstrap.go create mode 100644 libgo/go/cmd/internal/test2json/test2json.go create mode 100644 libgo/go/cmd/internal/test2json/test2json_test.go create mode 100644 libgo/go/cmd/internal/test2json/testdata/ascii.json create mode 100644 libgo/go/cmd/internal/test2json/testdata/ascii.test create mode 100644 libgo/go/cmd/internal/test2json/testdata/smiley.json create mode 100644 libgo/go/cmd/internal/test2json/testdata/smiley.test create mode 100644 libgo/go/cmd/internal/test2json/testdata/unicode.json create mode 100644 libgo/go/cmd/internal/test2json/testdata/unicode.test create mode 100644 libgo/go/cmd/internal/test2json/testdata/vet.json create mode 100644 libgo/go/cmd/internal/test2json/testdata/vet.test create mode 100644 libgo/go/cmd/test2json/main.go create mode 100644 libgo/go/cmd/vet/README create mode 100644 libgo/go/cmd/vet/all/main.go create mode 100644 libgo/go/cmd/vet/all/whitelist/386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/all.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/android_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/android_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/android_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/arm64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/darwin_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/darwin_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/dragonfly_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/freebsd_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/freebsd_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/freebsd_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/linux_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/linux_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/linux_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/linux_arm64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/mips.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/mips64x.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/mipsle.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/mipsx.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/nacl_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/nacl_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/netbsd.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/netbsd_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/netbsd_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/netbsd_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/openbsd_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/openbsd_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/openbsd_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/plan9_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/plan9_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/plan9_arm.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/ppc64x.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/readme.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/s390x.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/solaris_amd64.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/windows.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/windows_386.txt create mode 100644 libgo/go/cmd/vet/all/whitelist/windows_amd64.txt create mode 100644 libgo/go/cmd/vet/asmdecl.go create mode 100644 libgo/go/cmd/vet/assign.go create mode 100644 libgo/go/cmd/vet/atomic.go create mode 100644 libgo/go/cmd/vet/bool.go create mode 100644 libgo/go/cmd/vet/buildtag.go create mode 100644 libgo/go/cmd/vet/cgo.go create mode 100644 libgo/go/cmd/vet/composite.go create mode 100644 libgo/go/cmd/vet/copylock.go create mode 100644 libgo/go/cmd/vet/dead.go create mode 100644 libgo/go/cmd/vet/deadcode.go create mode 100644 libgo/go/cmd/vet/doc.go create mode 100644 libgo/go/cmd/vet/httpresponse.go create mode 100644 libgo/go/cmd/vet/internal/cfg/builder.go create mode 100644 libgo/go/cmd/vet/internal/cfg/cfg.go create mode 100644 libgo/go/cmd/vet/internal/cfg/cfg_test.go create mode 100644 libgo/go/cmd/vet/internal/whitelist/whitelist.go create mode 100644 libgo/go/cmd/vet/lostcancel.go create mode 100644 libgo/go/cmd/vet/main.go create mode 100644 libgo/go/cmd/vet/method.go create mode 100644 libgo/go/cmd/vet/nilfunc.go create mode 100644 libgo/go/cmd/vet/print.go create mode 100644 libgo/go/cmd/vet/rangeloop.go create mode 100644 libgo/go/cmd/vet/shadow.go create mode 100644 libgo/go/cmd/vet/shift.go create mode 100644 libgo/go/cmd/vet/structtag.go create mode 100644 libgo/go/cmd/vet/testdata/asm/asm.go create mode 100644 libgo/go/cmd/vet/testdata/asm/asm1.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm2.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm3.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm4.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm5.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm6.s create mode 100644 libgo/go/cmd/vet/testdata/asm/asm7.s create mode 100644 libgo/go/cmd/vet/testdata/asm8.s create mode 100644 libgo/go/cmd/vet/testdata/assign.go create mode 100644 libgo/go/cmd/vet/testdata/atomic.go create mode 100644 libgo/go/cmd/vet/testdata/bool.go create mode 100644 libgo/go/cmd/vet/testdata/buildtag/buildtag.go create mode 100644 libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go create mode 100644 libgo/go/cmd/vet/testdata/cgo/cgo.go create mode 100644 libgo/go/cmd/vet/testdata/cgo/cgo2.go create mode 100644 libgo/go/cmd/vet/testdata/cgo/cgo3.go create mode 100644 libgo/go/cmd/vet/testdata/cgo/cgo4.go create mode 100644 libgo/go/cmd/vet/testdata/composite.go create mode 100644 libgo/go/cmd/vet/testdata/copylock.go create mode 100644 libgo/go/cmd/vet/testdata/copylock_func.go create mode 100644 libgo/go/cmd/vet/testdata/copylock_range.go create mode 100644 libgo/go/cmd/vet/testdata/deadcode.go create mode 100644 libgo/go/cmd/vet/testdata/divergent/buf.go create mode 100644 libgo/go/cmd/vet/testdata/divergent/buf_test.go create mode 100644 libgo/go/cmd/vet/testdata/httpresponse.go create mode 100644 libgo/go/cmd/vet/testdata/incomplete/examples_test.go create mode 100644 libgo/go/cmd/vet/testdata/lostcancel.go create mode 100644 libgo/go/cmd/vet/testdata/method.go create mode 100644 libgo/go/cmd/vet/testdata/nilfunc.go create mode 100644 libgo/go/cmd/vet/testdata/print.go create mode 100644 libgo/go/cmd/vet/testdata/rangeloop.go create mode 100644 libgo/go/cmd/vet/testdata/shadow.go create mode 100644 libgo/go/cmd/vet/testdata/shift.go create mode 100644 libgo/go/cmd/vet/testdata/structtag.go create mode 100644 libgo/go/cmd/vet/testdata/tagtest/file1.go create mode 100644 libgo/go/cmd/vet/testdata/tagtest/file2.go create mode 100644 libgo/go/cmd/vet/testdata/testingpkg/tests.go create mode 100644 libgo/go/cmd/vet/testdata/testingpkg/tests_test.go create mode 100644 libgo/go/cmd/vet/testdata/unsafeptr.go create mode 100644 libgo/go/cmd/vet/testdata/unused.go create mode 100644 libgo/go/cmd/vet/tests.go create mode 100644 libgo/go/cmd/vet/types.go create mode 100644 libgo/go/cmd/vet/unsafeptr.go create mode 100644 libgo/go/cmd/vet/unused.go create mode 100644 libgo/go/cmd/vet/vet_test.go create mode 100644 libgo/go/container/ring/example_test.go create mode 100644 libgo/go/crypto/issue21104_test.go create mode 100644 libgo/go/crypto/rand/rand_linux_test.go create mode 100644 libgo/go/crypto/sha1/sha1block_arm64.go create mode 100644 libgo/go/crypto/sha256/sha256block_arm64.go create mode 100644 libgo/go/crypto/x509/name_constraints_test.go create mode 100644 libgo/go/debug/macho/reloctype.go create mode 100644 libgo/go/debug/macho/reloctype_string.go create mode 100644 libgo/go/debug/macho/testdata/clang-386-darwin-exec-with-rpath create mode 100644 libgo/go/debug/macho/testdata/clang-386-darwin.obj create mode 100644 libgo/go/debug/macho/testdata/clang-amd64-darwin-exec-with-rpath create mode 100644 libgo/go/debug/macho/testdata/clang-amd64-darwin.obj create mode 100644 libgo/go/fmt/example_test.go create mode 100644 libgo/go/go/doc/testdata/issue16153.0.golden create mode 100644 libgo/go/go/doc/testdata/issue16153.1.golden create mode 100644 libgo/go/go/doc/testdata/issue16153.2.golden create mode 100644 libgo/go/go/doc/testdata/issue16153.go create mode 100644 libgo/go/go/doc/testdata/issue18063.0.golden create mode 100644 libgo/go/go/doc/testdata/issue18063.1.golden create mode 100644 libgo/go/go/doc/testdata/issue18063.2.golden create mode 100644 libgo/go/go/doc/testdata/issue18063.go create mode 100644 libgo/go/go/importer/importer_test.go create mode 100644 libgo/go/go/internal/srcimporter/testdata/issue20855/issue20855.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/asn1.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/asn1/asn1.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/asn1_test.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/builder.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/cryptobyte_test.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/example_test.go create mode 100644 libgo/go/golang_org/x/crypto/cryptobyte/string.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_bsd.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_nobsd.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_posix.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_stub.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_unix.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/helper_windows.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/interface.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/rlimit.go create mode 100644 libgo/go/golang_org/x/net/internal/nettest/stack.go create mode 100644 libgo/go/hash/example_test.go create mode 100644 libgo/go/hash/marshal_test.go create mode 100644 libgo/go/image/color/color_test.go create mode 100644 libgo/go/internal/cpu/cpu_ppc64x.go create mode 100644 libgo/go/internal/poll/export_windows_test.go create mode 100644 libgo/go/internal/poll/fd_windows_test.go create mode 100644 libgo/go/internal/syscall/windows/exec_windows_test.go create mode 100644 libgo/go/internal/syscall/windows/psapi_windows.go create mode 100644 libgo/go/math/big/sqrt.go create mode 100644 libgo/go/math/big/sqrt_test.go create mode 100644 libgo/go/math/bits/make_examples.go create mode 100644 libgo/go/math/erfinv.go create mode 100644 libgo/go/math/exp_asm.go rename libgo/go/net/{sockoptip_bsd.go => sockoptip_bsdvar.go} (93%) create mode 100644 libgo/go/net/unixsock_linux_test.go create mode 100644 libgo/go/net/write_unix_test.go create mode 100644 libgo/go/os/signal/internal/pty/pty.go create mode 100644 libgo/go/os/signal/signal_cgo_test.go create mode 100644 libgo/go/os/timeout_test.go create mode 100644 libgo/go/os/user/cgo_unix_test.go create mode 100644 libgo/go/path/filepath/example_test.go create mode 100644 libgo/go/runtime/mwbbuf.go create mode 100644 libgo/go/runtime/testdata/testprog/gettid.go create mode 100644 libgo/go/runtime/testdata/testprog/gettid_none.go create mode 100644 libgo/go/runtime/testdata/testprog/lockosthread.go create mode 100644 libgo/go/runtime/testdata/testprogcgo/catchpanic.go create mode 100644 libgo/go/runtime/testdata/testprogcgo/lockosthread.c create mode 100644 libgo/go/runtime/testdata/testprogcgo/lockosthread.go create mode 100644 libgo/go/runtime/testdata/testprogcgo/sigstack.go create mode 100644 libgo/go/runtime/testdata/testprogcgo/stack_windows.go create mode 100644 libgo/go/runtime/trace/example_test.go create mode 100644 libgo/go/sort/slice.go create mode 100644 libgo/go/strconv/export_test.go create mode 100644 libgo/go/strings/builder.go create mode 100644 libgo/go/strings/builder_test.go create mode 100644 libgo/misc/cgo/errors/errors_test.go delete mode 100644 libgo/misc/cgo/errors/issue13635.go rename libgo/misc/cgo/errors/{ptr.go => ptr_test.go} (79%) rename libgo/misc/cgo/errors/{ => src}/err1.go (100%) rename libgo/misc/cgo/errors/{ => src}/err2.go (100%) rename libgo/misc/cgo/errors/{ => src}/err3.go (100%) create mode 100644 libgo/misc/cgo/errors/src/err4.go rename libgo/misc/cgo/errors/{ => src}/issue11097a.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue11097b.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue13129.go (88%) rename libgo/misc/cgo/errors/{ => src}/issue13423.go (100%) create mode 100644 libgo/misc/cgo/errors/src/issue13467.go create mode 100644 libgo/misc/cgo/errors/src/issue13635.go rename libgo/misc/cgo/errors/{ => src}/issue13830.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue14669.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue16116.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue16591.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue18452.go (75%) rename libgo/misc/cgo/errors/{ => src}/issue18889.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue7757.go (100%) rename libgo/misc/cgo/errors/{ => src}/issue8442.go (100%) create mode 100644 libgo/misc/cgo/errors/src/long_double_size.go rename libgo/misc/cgo/errors/{ => src}/malloc.go (100%) delete mode 100644 libgo/misc/cgo/errors/test.bash create mode 100644 libgo/misc/cgo/test/issue19832.go create mode 100644 libgo/misc/cgo/test/issue20910.c create mode 100644 libgo/misc/cgo/test/issue20910.go create mode 100644 libgo/misc/cgo/test/issue21668.go create mode 100644 libgo/misc/cgo/test/issue21708.go create mode 100644 libgo/misc/cgo/test/issue21809.go create mode 100644 libgo/misc/cgo/test/issue21897.go create mode 100644 libgo/misc/cgo/test/issue21897b.go create mode 100644 libgo/misc/cgo/test/issue22958.go create mode 100644 libgo/misc/cgo/test/issue6907.go create mode 100644 libgo/misc/cgo/test/issue6907export.go create mode 100644 libgo/misc/cgo/test/issue6907export_c.c create mode 100644 libgo/misc/cgo/testcshared/cshared_test.go delete mode 100644 libgo/misc/cgo/testcshared/test.bash create mode 100644 libgo/misc/cgo/testplugin/src/issue18584/main.go create mode 100644 libgo/misc/cgo/testplugin/src/issue18584/plugin.go create mode 100644 libgo/misc/cgo/testplugin/src/issue19418/main.go rename libgo/{go/internal/cpu/cpu_ppc64.go => misc/cgo/testplugin/src/issue19418/plugin.go} (80%) create mode 100644 libgo/misc/cgo/testplugin/src/issue19529/plugin.go create mode 100644 libgo/misc/cgo/testplugin/src/issue22175/main.go create mode 100644 libgo/misc/cgo/testplugin/src/issue22175/plugin1.go rename libgo/{go/internal/cpu/cpu_ppc64le.go => misc/cgo/testplugin/src/issue22175/plugin2.go} (73%) create mode 100644 libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go create mode 100644 libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go rename libgo/misc/cgo/testplugin/{unnamed1.go => unnamed1/main.go} (100%) rename libgo/misc/cgo/testplugin/{unnamed2.go => unnamed2/main.go} (100%) create mode 100644 libgo/misc/cgo/testsanitizers/cc_test.go create mode 100644 libgo/misc/cgo/testsanitizers/cshared_test.go create mode 100644 libgo/misc/cgo/testsanitizers/msan_test.go rename libgo/misc/cgo/testsanitizers/{ => src}/msan.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/msan2.go (100%) create mode 100644 libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go rename libgo/misc/cgo/testsanitizers/{ => src}/msan3.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/msan4.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/msan5.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/msan_fail.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/msan_shared.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan10.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan11.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan12.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan2.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan3.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan4.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan5.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan6.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan7.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan8.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan9.go (100%) rename libgo/misc/cgo/testsanitizers/{ => src}/tsan_shared.go (100%) delete mode 100644 libgo/misc/cgo/testsanitizers/test.bash create mode 100644 libgo/misc/cgo/testsanitizers/tsan_test.go create mode 100644 libgo/misc/cgo/testshared/src/global/main.go create mode 100644 libgo/misc/cgo/testshared/src/globallib/global.go diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b03c3fb3492..d836309e6a0 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -1319f36ccc65cf802b8e17ddd3d2da3ca6d82f4c +dbc0c7e4329aada2ae3554c20cfb8cfa48041213 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index f5adc18586d..c34a5b01b67 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -7483,6 +7483,7 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter) return Expression::make_error(this->location()); } len_arg = Expression::make_integer_ul(0, NULL, loc); + len_small = true; } else { @@ -7551,9 +7552,23 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter) else if (is_map) { Expression* type_arg = Expression::make_type_descriptor(type, type_loc); - call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg, - Expression::make_nil(loc), - Expression::make_nil(loc)); + if (!len_small) + call = Runtime::make_call(Runtime::MAKEMAP64, loc, 3, type_arg, + len_arg, + Expression::make_nil(loc)); + else + { + Numeric_constant nclen; + unsigned long vlen; + if (len_arg->numeric_constant_value(&nclen) + && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID + && vlen <= Map_type::bucket_size) + call = Runtime::make_call(Runtime::MAKEMAP_SMALL, loc, 0); + else + call = Runtime::make_call(Runtime::MAKEMAP, loc, 3, type_arg, + len_arg, + Expression::make_nil(loc)); + } } else if (is_chan) { @@ -9503,14 +9518,8 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, // could implement them in normal code, but then we would have to // explicitly unwind the stack. These functions are intended to be // efficient. Note that this technique obviously only works for - // direct calls, but that is the only way they are used. The actual - // argument to these functions is always the address of a parameter; - // we don't need that for the GCC builtin functions, so we just - // ignore it. - if (gogo->compiling_runtime() - && this->args_ != NULL - && this->args_->size() == 1 - && gogo->package_name() == "runtime") + // direct calls, but that is the only way they are used. + if (gogo->compiling_runtime() && gogo->package_name() == "runtime") { Func_expression* fe = this->fn_->func_expression(); if (fe != NULL @@ -9518,15 +9527,21 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, && fe->named_object()->package() == NULL) { std::string n = Gogo::unpack_hidden_name(fe->named_object()->name()); - if (n == "getcallerpc") + if ((this->args_ == NULL || this->args_->size() == 0) + && n == "getcallerpc") { static Named_object* builtin_return_address; return this->lower_to_builtin(&builtin_return_address, "__builtin_return_address", 0); } - else if (n == "getcallersp") + else if (this->args_ != NULL + && this->args_->size() == 1 + && n == "getcallersp") { + // The actual argument to getcallersp is always the + // address of a parameter; we don't need that for the + // GCC builtin function, so we just ignore it. static Named_object* builtin_frame_address; return this->lower_to_builtin(&builtin_frame_address, "__builtin_frame_address", @@ -10027,7 +10042,7 @@ Call_expression::do_check_types(Gogo*) } const Typed_identifier_list* parameters = fntype->parameters(); - if (this->args_ == NULL) + if (this->args_ == NULL || this->args_->size() == 0) { if (parameters != NULL && !parameters->empty()) this->report_error(_("not enough arguments")); diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index ef148eec9b0..605bcff4a0f 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -91,9 +91,14 @@ DEF_GO_RUNTIME(MAKESLICE64, "runtime.makeslice64", P3(TYPE, INT64, INT64), R1(SLICE)) -// Make a map. -DEF_GO_RUNTIME(MAKEMAP, "runtime.makemap", P4(TYPE, INT64, POINTER, POINTER), - R1(MAP)) +// Make a map with a hint and an (optional, unused) map structure. +DEF_GO_RUNTIME(MAKEMAP, "runtime.makemap", P3(TYPE, INT, POINTER), + R1(MAP)) +DEF_GO_RUNTIME(MAKEMAP64, "runtime.makemap64", P3(TYPE, INT64, POINTER), + R1(MAP)) + +// Make a map with no hint, or a small constant hint. +DEF_GO_RUNTIME(MAKEMAP_SMALL, "runtime.makemap_small", P0(), R1(MAP)) // Build a map from a composite literal. DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 2274c313467..85273bf55d2 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -7830,7 +7830,7 @@ Map_type::do_get_backend(Gogo* gogo) bfields[7].btype = uintptr_type->get_backend(gogo); bfields[7].location = bloc; - bfields[8].name = "overflow"; + bfields[8].name = "extra"; bfields[8].btype = bpvt; bfields[8].location = bloc; @@ -8144,21 +8144,23 @@ Map_type::hmap_type(Type* bucket_type) Type* int_type = Type::lookup_integer_type("int"); Type* uint8_type = Type::lookup_integer_type("uint8"); + Type* uint16_type = Type::lookup_integer_type("uint16"); Type* uint32_type = Type::lookup_integer_type("uint32"); Type* uintptr_type = Type::lookup_integer_type("uintptr"); Type* void_ptr_type = Type::make_pointer_type(Type::make_void_type()); Type* ptr_bucket_type = Type::make_pointer_type(bucket_type); - Struct_type* ret = make_builtin_struct_type(8, + Struct_type* ret = make_builtin_struct_type(9, "count", int_type, "flags", uint8_type, "B", uint8_type, + "noverflow", uint16_type, "hash0", uint32_type, "buckets", ptr_bucket_type, "oldbuckets", ptr_bucket_type, "nevacuate", uintptr_type, - "overflow", void_ptr_type); + "extra", void_ptr_type); ret->set_is_struct_incomparable(); this->hmap_type_ = ret; return ret; @@ -8191,18 +8193,22 @@ Map_type::hiter_type(Gogo* gogo) Type* hmap_type = this->hmap_type(bucket_type); Type* hmap_ptr_type = Type::make_pointer_type(hmap_type); Type* void_ptr_type = Type::make_pointer_type(Type::make_void_type()); + Type* bool_type = Type::lookup_bool_type(); - Struct_type* ret = make_builtin_struct_type(12, + Struct_type* ret = make_builtin_struct_type(15, "key", key_ptr_type, "val", val_ptr_type, "t", uint8_ptr_type, "h", hmap_ptr_type, "buckets", bucket_ptr_type, "bptr", bucket_ptr_type, - "overflow0", void_ptr_type, - "overflow1", void_ptr_type, + "overflow", void_ptr_type, + "oldoverflow", void_ptr_type, "startBucket", uintptr_type, - "stuff", uintptr_type, + "offset", uint8_type, + "wrapped", bool_type, + "B", uint8_type, + "i", uint8_type, "bucket", uintptr_type, "checkBucket", uintptr_type); ret->set_is_struct_incomparable(); diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index a1e388414c2..08e57019a6c 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -2826,6 +2826,9 @@ class Map_type : public Type static Type* make_map_type_descriptor_type(); + // This must be in sync with libgo/go/runtime/hashmap.go. + static const int bucket_size = 8; + protected: int do_traverse(Traverse*); @@ -2867,7 +2870,6 @@ class Map_type : public Type private: // These must be in sync with libgo/go/runtime/hashmap.go. - static const int bucket_size = 8; static const int max_key_size = 128; static const int max_val_size = 128; static const int max_zero_size = 1024; diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index 0085667ee04..5870661b66e 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -331,6 +331,25 @@ Gogo::assign_needs_write_barrier(Expression* lhs) if (!lhs->type()->has_pointer()) return false; + // An assignment to a field is handled like an assignment to the + // struct. + while (true) + { + // Nothing to do for a type that can not be in the heap, or a + // pointer to a type that can not be in the heap. We check this + // at each level of a struct. + if (!lhs->type()->in_heap()) + return false; + if (lhs->type()->points_to() != NULL + && !lhs->type()->points_to()->in_heap()) + return false; + + Field_reference_expression* fre = lhs->field_reference_expression(); + if (fre == NULL) + break; + lhs = fre->expr(); + } + // Nothing to do for an assignment to a temporary. if (lhs->temporary_reference_expression() != NULL) return false; @@ -359,12 +378,30 @@ Gogo::assign_needs_write_barrier(Expression* lhs) } } - // Nothing to do for a type that can not be in the heap, or a - // pointer to a type that can not be in the heap. - if (!lhs->type()->in_heap()) - return false; - if (lhs->type()->points_to() != NULL && !lhs->type()->points_to()->in_heap()) - return false; + // For a struct assignment, we don't need a write barrier if all the + // pointer types can not be in the heap. + Struct_type* st = lhs->type()->struct_type(); + if (st != NULL) + { + bool in_heap = false; + const Struct_field_list* fields = st->fields(); + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + p++) + { + Type* ft = p->type(); + if (!ft->has_pointer()) + continue; + if (!ft->in_heap()) + continue; + if (ft->points_to() != NULL && !ft->points_to()->in_heap()) + continue; + in_heap = true; + break; + } + if (!in_heap) + return false; + } // Write barrier needed in other cases. return true; diff --git a/gotools/ChangeLog b/gotools/ChangeLog index bd6e13f9ed5..70c61160faa 100644 --- a/gotools/ChangeLog +++ b/gotools/ChangeLog @@ -1,3 +1,24 @@ +2018-01-08 Ian Lance Taylor + + * Makefile.am (go_cmd_vet_files): New variable. + (go_cmd_buildid_files, go_cmd_test2json_files): New variables. + (s-zdefaultcc): Change from constants to functions. + (noinst_PROGRAMS): Add vet, buildid, and test2json. + (cgo$(EXEEXT)): Link against $(LIBGOTOOL). + (vet$(EXEEXT)): New target. + (buildid$(EXEEXT)): New target. + (test2json$(EXEEXT)): New target. + (install-exec-local): Install all $(noinst_PROGRAMS). + (uninstall-local): Uninstasll all $(noinst_PROGRAMS). + (check-go-tool): Depend on $(noinst_PROGRAMS). Copy down + objabi.go. + (check-runtime): Depend on $(noinst_PROGRAMS). + (check-cgo-test, check-carchive-test): Likewise. + (check-vet): New target. + (check): Depend on check-vet. Look at cmd_vet-testlog. + (.PHONY): Add check-vet. + * Makefile.in: Rebuild. + 2017-10-25 Ian Lance Taylor * Makefile.am (check-go-tool): Output colon after ${fl}. diff --git a/gotools/Makefile.am b/gotools/Makefile.am index cbb64ae85d6..3cecee681f3 100644 --- a/gotools/Makefile.am +++ b/gotools/Makefile.am @@ -69,6 +69,40 @@ go_cmd_cgo_files = \ $(cmdsrcdir)/cgo/out.go \ $(cmdsrcdir)/cgo/util.go +go_cmd_vet_files = \ + $(cmdsrcdir)/vet/asmdecl.go \ + $(cmdsrcdir)/vet/assign.go \ + $(cmdsrcdir)/vet/atomic.go \ + $(cmdsrcdir)/vet/bool.go \ + $(cmdsrcdir)/vet/buildtag.go \ + $(cmdsrcdir)/vet/cgo.go \ + $(cmdsrcdir)/vet/composite.go \ + $(cmdsrcdir)/vet/copylock.go \ + $(cmdsrcdir)/vet/deadcode.go \ + $(cmdsrcdir)/vet/dead.go \ + $(cmdsrcdir)/vet/doc.go \ + $(cmdsrcdir)/vet/httpresponse.go \ + $(cmdsrcdir)/vet/lostcancel.go \ + $(cmdsrcdir)/vet/main.go \ + $(cmdsrcdir)/vet/method.go \ + $(cmdsrcdir)/vet/nilfunc.go \ + $(cmdsrcdir)/vet/print.go \ + $(cmdsrcdir)/vet/rangeloop.go \ + $(cmdsrcdir)/vet/shadow.go \ + $(cmdsrcdir)/vet/shift.go \ + $(cmdsrcdir)/vet/structtag.go \ + $(cmdsrcdir)/vet/tests.go \ + $(cmdsrcdir)/vet/types.go \ + $(cmdsrcdir)/vet/unsafeptr.go \ + $(cmdsrcdir)/vet/unused.go + +go_cmd_buildid_files = \ + $(cmdsrcdir)/buildid/buildid.go \ + $(cmdsrcdir)/buildid/doc.go + +go_cmd_test2json_files = \ + $(cmdsrcdir)/test2json/main.go + GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)') GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)') GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)') @@ -76,9 +110,9 @@ GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)') zdefaultcc.go: s-zdefaultcc; @true s-zdefaultcc: Makefile echo 'package main' > zdefaultcc.go.tmp - echo 'const defaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const defaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const defaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp + echo 'func defaultGCCGO(goos, goarch string) string { return "$(bindir)/$(GCCGO_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func defaultCC(goos, goarch string) string { return "$(GCC_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func defaultCXX(goos, goarch string) string { return "$(GXX_INSTALL_NAME)" }' >> zdefaultcc.go.tmp echo 'const defaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp $(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go $(STAMP) $@ @@ -97,23 +131,33 @@ if NATIVE # and install them as regular programs. bin_PROGRAMS = go$(EXEEXT) gofmt$(EXEEXT) -noinst_PROGRAMS = cgo$(EXEEXT) +noinst_PROGRAMS = cgo$(EXEEXT) vet$(EXEEXT) buildid$(EXEEXT) test2json$(EXEEXT) man_MANS = go.1 gofmt.1 go$(EXEEXT): $(go_cmd_go_files) $(LIBGOTOOL) $(LIBGODEP) $(GOLINK) $(go_cmd_go_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) gofmt$(EXEEXT): $(go_cmd_gofmt_files) $(LIBGODEP) $(GOLINK) $(go_cmd_gofmt_files) $(LIBS) $(NET_LIBS) -cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGODEP) - $(GOLINK) $(go_cmd_cgo_files) zdefaultcc.go $(LIBS) $(NET_LIBS) - -install-exec-local: cgo$(EXEEXT) +cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGOTOOL) $(LIBGODEP) + $(GOLINK) $(go_cmd_cgo_files) zdefaultcc.go $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +vet$(EXEEXT): $(go_cmd_vet_files) $(LIBGOTOOL) $(LIBGODEP) + $(GOLINK) $(go_cmd_vet_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +buildid$(EXEEXT): $(go_cmd_buildid_files) $(LIBGOTOOL) $(LIBGODEP) + $(GOLINK) $(go_cmd_buildid_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +test2json$(EXEEXT): $(go_cmd_test2json_files) $(LIBGOTOOL) $(LIBGODEP) + $(GOLINK) $(go_cmd_test2json_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) + +install-exec-local: $(noinst_PROGRAMS) $(MKDIR_P) $(DESTDIR)$(libexecsubdir) - rm -f $(DESTDIR)$(libexecsubdir)/cgo$(exeext) - $(INSTALL_PROGRAM) cgo$(exeext) $(DESTDIR)$(libexecsubdir)/cgo$(exeext) + for f in $(noinst_PROGRAMS); do \ + rm -f $(DESTDIR)$(libexecsubdir)/$$f; \ + $(INSTALL_PROGRAM) $$f $(DESTDIR)$(libexecsubdir)/$$f; \ + done uninstall-local: - rm -f $(DESTDIR)$(libexecsubdir)/cgo$(exeext) + for f in $(noinst_PROGRAMS); do \ + rm -f $(DESTDIR)$(libexecsubdir)/$$f; \ + done GOTESTFLAGS = @@ -177,8 +221,8 @@ CHECK_ENV = \ # It assumes that abs_libgodir is set. ECHO_ENV = PATH=`echo $(abs_builddir):$${PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'` GCCGO='$(abs_builddir)/check-gccgo' CC='$(abs_builddir)/check-gcc' GCCGOTOOLDIR='$(abs_builddir)' GO_TESTING_GOTOOLS=yes LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'` GOROOT=`echo $${abs_libgodir}` -# check-go-tools runs `go test cmd/go` in our environment. -check-go-tool: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +# check-go-tool runs `go test cmd/go` in our environment. +check-go-tool: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc rm -rf check-go-dir cmd_go-testlog $(MKDIR_P) check-go-dir/src/cmd/go cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/ @@ -187,6 +231,7 @@ check-go-tool: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/ cp -r $(cmdsrcdir)/go/testdata check-go-dir/src/cmd/go/ cp -r $(cmdsrcdir)/internal check-go-dir/src/cmd/ + cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \ echo "cd check-go-dir/src/cmd/go && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_go-testlog @@ -200,7 +245,7 @@ check-go-tool: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc # The runtime package is also tested as part of libgo, # but the runtime tests use the go tool heavily, so testing # here too will catch more problems. -check-runtime: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc rm -rf check-runtime-dir runtime-testlog $(MKDIR_P) check-runtime-dir @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ @@ -219,7 +264,7 @@ check-runtime: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc grep '^--- ' runtime-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 # check-cgo-test runs `go test misc/cgo/test` in our environment. -check-cgo-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc rm -rf cgo-test-dir cgo-testlog $(MKDIR_P) cgo-test-dir/misc/cgo cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/ @@ -233,7 +278,7 @@ check-cgo-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc # check-carchive-test runs `go test misc/cgo/testcarchive/carchive_test.go` # in our environment. -check-carchive-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc rm -rf carchive-test-dir carchive-testlog $(MKDIR_P) carchive-test-dir/misc/cgo cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/ @@ -245,11 +290,25 @@ check-carchive-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc (cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || echo "--- $${fl}: go test misc/cgo/testcarchive (0.00s)" >> carchive-testlog grep '^--- ' carchive-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 +# check-vet runs `go test cmd/vet` in our environment. +check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc + rm -rf check-vet-dir cmd_vet-testlog + $(MKDIR_P) check-vet-dir/src/cmd + cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/ + @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ + abs_checkdir=`cd check-vet-dir && $(PWD_COMMAND)`; \ + echo "cd check-vet-dir/src/cmd/vet && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_vet-testlog + $(CHECK_ENV) \ + GOPATH=`cd check-vet-dir && $(PWD_COMMAND)`; \ + export GOPATH; \ + (cd check-vet-dir/src/cmd/vet && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cmd_vet-testlog 2>&1 || echo "--- $${fl}: go test cmd/vet (0.00s)" >> cmd_vet-testlog + grep '^--- ' cmd_vet-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 + # The check targets runs the tests and assembles the output files. -check: check-head check-go-tool check-runtime check-cgo-test check-carchive-test +check: check-head check-go-tool check-runtime check-cgo-test check-carchive-test check-vet @mv gotools.head gotools.sum @cp gotools.sum gotools.log - @for file in cmd_go-testlog runtime-testlog cgo-testlog carchive-testlog; do \ + @for file in cmd_go-testlog runtime-testlog cgo-testlog carchive-testlog cmd_vet-testlog; do \ testname=`echo $${file} | sed -e 's/-testlog//' -e 's|_|/|'`; \ echo "Running $${testname}" >> gotools.sum; \ echo "Running $${testname}" >> gotools.log; \ @@ -275,7 +334,7 @@ check: check-head check-go-tool check-runtime check-cgo-test check-carchive-test @echo "runtest completed at `date`" >> gotools.log @if grep '^FAIL' gotools.sum >/dev/null 2>&1; then exit 1; fi -.PHONY: check check-head check-go-tool check-runtime check-cgo-test check-carchive-test +.PHONY: check check-head check-go-tool check-runtime check-cgo-test check-carchive-test check-vet else diff --git a/gotools/Makefile.in b/gotools/Makefile.in index 4f2b1073986..77ebd158ea5 100644 --- a/gotools/Makefile.in +++ b/gotools/Makefile.in @@ -88,6 +88,9 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +buildid_SOURCES = buildid.c +buildid_OBJECTS = buildid.$(OBJEXT) +buildid_LDADD = $(LDADD) cgo_SOURCES = cgo.c cgo_OBJECTS = cgo.$(OBJEXT) cgo_LDADD = $(LDADD) @@ -97,6 +100,12 @@ go_LDADD = $(LDADD) gofmt_SOURCES = gofmt.c gofmt_OBJECTS = gofmt.$(OBJEXT) gofmt_LDADD = $(LDADD) +test2json_SOURCES = test2json.c +test2json_OBJECTS = test2json.$(OBJEXT) +test2json_LDADD = $(LDADD) +vet_SOURCES = vet.c +vet_OBJECTS = vet.$(OBJEXT) +vet_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles @@ -105,7 +114,7 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = cgo.c go.c gofmt.c +SOURCES = buildid.c cgo.c go.c gofmt.c test2json.c vet.c am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -288,6 +297,40 @@ go_cmd_cgo_files = \ $(cmdsrcdir)/cgo/out.go \ $(cmdsrcdir)/cgo/util.go +go_cmd_vet_files = \ + $(cmdsrcdir)/vet/asmdecl.go \ + $(cmdsrcdir)/vet/assign.go \ + $(cmdsrcdir)/vet/atomic.go \ + $(cmdsrcdir)/vet/bool.go \ + $(cmdsrcdir)/vet/buildtag.go \ + $(cmdsrcdir)/vet/cgo.go \ + $(cmdsrcdir)/vet/composite.go \ + $(cmdsrcdir)/vet/copylock.go \ + $(cmdsrcdir)/vet/deadcode.go \ + $(cmdsrcdir)/vet/dead.go \ + $(cmdsrcdir)/vet/doc.go \ + $(cmdsrcdir)/vet/httpresponse.go \ + $(cmdsrcdir)/vet/lostcancel.go \ + $(cmdsrcdir)/vet/main.go \ + $(cmdsrcdir)/vet/method.go \ + $(cmdsrcdir)/vet/nilfunc.go \ + $(cmdsrcdir)/vet/print.go \ + $(cmdsrcdir)/vet/rangeloop.go \ + $(cmdsrcdir)/vet/shadow.go \ + $(cmdsrcdir)/vet/shift.go \ + $(cmdsrcdir)/vet/structtag.go \ + $(cmdsrcdir)/vet/tests.go \ + $(cmdsrcdir)/vet/types.go \ + $(cmdsrcdir)/vet/unsafeptr.go \ + $(cmdsrcdir)/vet/unused.go + +go_cmd_buildid_files = \ + $(cmdsrcdir)/buildid/buildid.go \ + $(cmdsrcdir)/buildid/doc.go + +go_cmd_test2json_files = \ + $(cmdsrcdir)/test2json/main.go + GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)') GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)') GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)') @@ -300,7 +343,7 @@ MOSTLYCLEANFILES = \ # For a native build we build the programs using the newly built libgo # and install them as regular programs. @NATIVE_TRUE@bin_PROGRAMS = go$(EXEEXT) gofmt$(EXEEXT) -@NATIVE_TRUE@noinst_PROGRAMS = cgo$(EXEEXT) +@NATIVE_TRUE@noinst_PROGRAMS = cgo$(EXEEXT) vet$(EXEEXT) buildid$(EXEEXT) test2json$(EXEEXT) @NATIVE_TRUE@man_MANS = go.1 gofmt.1 @NATIVE_TRUE@GOTESTFLAGS = @@ -411,6 +454,9 @@ clean-binPROGRAMS: clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +@NATIVE_FALSE@buildid$(EXEEXT): $(buildid_OBJECTS) $(buildid_DEPENDENCIES) $(EXTRA_buildid_DEPENDENCIES) +@NATIVE_FALSE@ @rm -f buildid$(EXEEXT) +@NATIVE_FALSE@ $(LINK) $(buildid_OBJECTS) $(buildid_LDADD) $(LIBS) @NATIVE_FALSE@cgo$(EXEEXT): $(cgo_OBJECTS) $(cgo_DEPENDENCIES) $(EXTRA_cgo_DEPENDENCIES) @NATIVE_FALSE@ @rm -f cgo$(EXEEXT) @NATIVE_FALSE@ $(LINK) $(cgo_OBJECTS) $(cgo_LDADD) $(LIBS) @@ -420,6 +466,12 @@ clean-noinstPROGRAMS: @NATIVE_FALSE@gofmt$(EXEEXT): $(gofmt_OBJECTS) $(gofmt_DEPENDENCIES) $(EXTRA_gofmt_DEPENDENCIES) @NATIVE_FALSE@ @rm -f gofmt$(EXEEXT) @NATIVE_FALSE@ $(LINK) $(gofmt_OBJECTS) $(gofmt_LDADD) $(LIBS) +@NATIVE_FALSE@test2json$(EXEEXT): $(test2json_OBJECTS) $(test2json_DEPENDENCIES) $(EXTRA_test2json_DEPENDENCIES) +@NATIVE_FALSE@ @rm -f test2json$(EXEEXT) +@NATIVE_FALSE@ $(LINK) $(test2json_OBJECTS) $(test2json_LDADD) $(LIBS) +@NATIVE_FALSE@vet$(EXEEXT): $(vet_OBJECTS) $(vet_DEPENDENCIES) $(EXTRA_vet_DEPENDENCIES) +@NATIVE_FALSE@ @rm -f vet$(EXEEXT) +@NATIVE_FALSE@ $(LINK) $(vet_OBJECTS) $(vet_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -427,9 +479,12 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buildid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gofmt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test2json.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vet.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -676,9 +731,9 @@ uninstall-man: uninstall-man1 zdefaultcc.go: s-zdefaultcc; @true s-zdefaultcc: Makefile echo 'package main' > zdefaultcc.go.tmp - echo 'const defaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const defaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const defaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp + echo 'func defaultGCCGO(goos, goarch string) string { return "$(bindir)/$(GCCGO_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func defaultCC(goos, goarch string) string { return "$(GCC_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func defaultCXX(goos, goarch string) string { return "$(GXX_INSTALL_NAME)" }' >> zdefaultcc.go.tmp echo 'const defaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp $(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go $(STAMP) $@ @@ -690,16 +745,26 @@ mostlyclean-local: @NATIVE_TRUE@ $(GOLINK) $(go_cmd_go_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) @NATIVE_TRUE@gofmt$(EXEEXT): $(go_cmd_gofmt_files) $(LIBGODEP) @NATIVE_TRUE@ $(GOLINK) $(go_cmd_gofmt_files) $(LIBS) $(NET_LIBS) -@NATIVE_TRUE@cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGODEP) -@NATIVE_TRUE@ $(GOLINK) $(go_cmd_cgo_files) zdefaultcc.go $(LIBS) $(NET_LIBS) - -@NATIVE_TRUE@install-exec-local: cgo$(EXEEXT) +@NATIVE_TRUE@cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGOTOOL) $(LIBGODEP) +@NATIVE_TRUE@ $(GOLINK) $(go_cmd_cgo_files) zdefaultcc.go $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +@NATIVE_TRUE@vet$(EXEEXT): $(go_cmd_vet_files) $(LIBGOTOOL) $(LIBGODEP) +@NATIVE_TRUE@ $(GOLINK) $(go_cmd_vet_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +@NATIVE_TRUE@buildid$(EXEEXT): $(go_cmd_buildid_files) $(LIBGOTOOL) $(LIBGODEP) +@NATIVE_TRUE@ $(GOLINK) $(go_cmd_buildid_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) +@NATIVE_TRUE@test2json$(EXEEXT): $(go_cmd_test2json_files) $(LIBGOTOOL) $(LIBGODEP) +@NATIVE_TRUE@ $(GOLINK) $(go_cmd_test2json_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS) + +@NATIVE_TRUE@install-exec-local: $(noinst_PROGRAMS) @NATIVE_TRUE@ $(MKDIR_P) $(DESTDIR)$(libexecsubdir) -@NATIVE_TRUE@ rm -f $(DESTDIR)$(libexecsubdir)/cgo$(exeext) -@NATIVE_TRUE@ $(INSTALL_PROGRAM) cgo$(exeext) $(DESTDIR)$(libexecsubdir)/cgo$(exeext) +@NATIVE_TRUE@ for f in $(noinst_PROGRAMS); do \ +@NATIVE_TRUE@ rm -f $(DESTDIR)$(libexecsubdir)/$$f; \ +@NATIVE_TRUE@ $(INSTALL_PROGRAM) $$f $(DESTDIR)$(libexecsubdir)/$$f; \ +@NATIVE_TRUE@ done @NATIVE_TRUE@uninstall-local: -@NATIVE_TRUE@ rm -f $(DESTDIR)$(libexecsubdir)/cgo$(exeext) +@NATIVE_TRUE@ for f in $(noinst_PROGRAMS); do \ +@NATIVE_TRUE@ rm -f $(DESTDIR)$(libexecsubdir)/$$f; \ +@NATIVE_TRUE@ done # Run tests using the go tool, and frob the output to look like that # generated by DejaGNU. The main output of this is two files: @@ -735,8 +800,8 @@ mostlyclean-local: @NATIVE_TRUE@ chmod +x $@.tmp @NATIVE_TRUE@ mv -f $@.tmp $@ -# check-go-tools runs `go test cmd/go` in our environment. -@NATIVE_TRUE@check-go-tool: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +# check-go-tool runs `go test cmd/go` in our environment. +@NATIVE_TRUE@check-go-tool: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc @NATIVE_TRUE@ rm -rf check-go-dir cmd_go-testlog @NATIVE_TRUE@ $(MKDIR_P) check-go-dir/src/cmd/go @NATIVE_TRUE@ cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/ @@ -745,6 +810,7 @@ mostlyclean-local: @NATIVE_TRUE@ cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/ @NATIVE_TRUE@ cp -r $(cmdsrcdir)/go/testdata check-go-dir/src/cmd/go/ @NATIVE_TRUE@ cp -r $(cmdsrcdir)/internal check-go-dir/src/cmd/ +@NATIVE_TRUE@ cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/ @NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ @NATIVE_TRUE@ abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \ @NATIVE_TRUE@ echo "cd check-go-dir/src/cmd/go && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_go-testlog @@ -758,7 +824,7 @@ mostlyclean-local: # The runtime package is also tested as part of libgo, # but the runtime tests use the go tool heavily, so testing # here too will catch more problems. -@NATIVE_TRUE@check-runtime: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +@NATIVE_TRUE@check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc @NATIVE_TRUE@ rm -rf check-runtime-dir runtime-testlog @NATIVE_TRUE@ $(MKDIR_P) check-runtime-dir @NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ @@ -777,7 +843,7 @@ mostlyclean-local: @NATIVE_TRUE@ grep '^--- ' runtime-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 # check-cgo-test runs `go test misc/cgo/test` in our environment. -@NATIVE_TRUE@check-cgo-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +@NATIVE_TRUE@check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc @NATIVE_TRUE@ rm -rf cgo-test-dir cgo-testlog @NATIVE_TRUE@ $(MKDIR_P) cgo-test-dir/misc/cgo @NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/ @@ -791,7 +857,7 @@ mostlyclean-local: # check-carchive-test runs `go test misc/cgo/testcarchive/carchive_test.go` # in our environment. -@NATIVE_TRUE@check-carchive-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc +@NATIVE_TRUE@check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc @NATIVE_TRUE@ rm -rf carchive-test-dir carchive-testlog @NATIVE_TRUE@ $(MKDIR_P) carchive-test-dir/misc/cgo @NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/ @@ -803,11 +869,25 @@ mostlyclean-local: @NATIVE_TRUE@ (cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || echo "--- $${fl}: go test misc/cgo/testcarchive (0.00s)" >> carchive-testlog @NATIVE_TRUE@ grep '^--- ' carchive-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 +# check-vet runs `go test cmd/vet` in our environment. +@NATIVE_TRUE@check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc +@NATIVE_TRUE@ rm -rf check-vet-dir cmd_vet-testlog +@NATIVE_TRUE@ $(MKDIR_P) check-vet-dir/src/cmd +@NATIVE_TRUE@ cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/ +@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \ +@NATIVE_TRUE@ abs_checkdir=`cd check-vet-dir && $(PWD_COMMAND)`; \ +@NATIVE_TRUE@ echo "cd check-vet-dir/src/cmd/vet && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_vet-testlog +@NATIVE_TRUE@ $(CHECK_ENV) \ +@NATIVE_TRUE@ GOPATH=`cd check-vet-dir && $(PWD_COMMAND)`; \ +@NATIVE_TRUE@ export GOPATH; \ +@NATIVE_TRUE@ (cd check-vet-dir/src/cmd/vet && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cmd_vet-testlog 2>&1 || echo "--- $${fl}: go test cmd/vet (0.00s)" >> cmd_vet-testlog +@NATIVE_TRUE@ grep '^--- ' cmd_vet-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/' | sort -k 2 + # The check targets runs the tests and assembles the output files. -@NATIVE_TRUE@check: check-head check-go-tool check-runtime check-cgo-test check-carchive-test +@NATIVE_TRUE@check: check-head check-go-tool check-runtime check-cgo-test check-carchive-test check-vet @NATIVE_TRUE@ @mv gotools.head gotools.sum @NATIVE_TRUE@ @cp gotools.sum gotools.log -@NATIVE_TRUE@ @for file in cmd_go-testlog runtime-testlog cgo-testlog carchive-testlog; do \ +@NATIVE_TRUE@ @for file in cmd_go-testlog runtime-testlog cgo-testlog carchive-testlog cmd_vet-testlog; do \ @NATIVE_TRUE@ testname=`echo $${file} | sed -e 's/-testlog//' -e 's|_|/|'`; \ @NATIVE_TRUE@ echo "Running $${testname}" >> gotools.sum; \ @NATIVE_TRUE@ echo "Running $${testname}" >> gotools.log; \ @@ -833,7 +913,7 @@ mostlyclean-local: @NATIVE_TRUE@ @echo "runtest completed at `date`" >> gotools.log @NATIVE_TRUE@ @if grep '^FAIL' gotools.sum >/dev/null 2>&1; then exit 1; fi -@NATIVE_TRUE@.PHONY: check check-head check-go-tool check-runtime check-cgo-test check-carchive-test +@NATIVE_TRUE@.PHONY: check check-head check-go-tool check-runtime check-cgo-test check-carchive-test check-vet # For a non-native build we have to build the programs using a # previously built host (or build -> host) Go compiler. We should diff --git a/libgo/MERGE b/libgo/MERGE index 85703d6ec4f..29faa72cbad 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -c8aec4095e089ff6ac50d18e97c3f46561f14f48 +9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 85c5c774ff7..d5ea8f6e9ab 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -400,8 +400,11 @@ toolexeclibgounicode_DATA = \ # internal packages nothing will explicitly depend on them. # Force them to be built. noinst_DATA = \ + golang_org/x/net/internal/nettest.gox \ + golang_org/x/net/nettest.gox \ internal/testenv.gox \ - net/internal/socktest.gox + net/internal/socktest.gox \ + os/signal/internal/pty.gox if LIBGO_IS_RTEMS rtems_task_variable_add_file = runtime/rtems-task-variable-add.c @@ -533,6 +536,24 @@ s-version: Makefile $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(STAMP) $@ +objabi.go: s-objabi; @true +s-objabi: Makefile + rm -f objabi.go.tmp + echo "package objabi" > objabi.go.tmp + echo "import \"runtime\"" >> objabi.go.tmp + echo 'const defaultGOROOT = `$(prefix)`' >> objabi.go.tmp + echo 'const defaultGO386 = `sse2`' >> objabi.go.tmp + echo 'const defaultGOARM = `5`' >> objabi.go.tmp + echo 'const defaultGOMIPS = `hardfloat`' >> objabi.go.tmp + echo 'const defaultGOOS = runtime.GOOS' >> objabi.go.tmp + echo 'const defaultGOARCH = runtime.GOARCH' >> objabi.go.tmp + echo 'const defaultGO_EXTLINK_ENABLED = ``' >> objabi.go.tmp + echo 'const version = `'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'`' >> objabi.go.tmp + echo 'const stackGuardMultiplier = 1' >> objabi.go.tmp + echo 'const goexperiment = ``' >> objabi.go.tmp + $(SHELL) $(srcdir)/mvifdiff.sh objabi.go.tmp objabi.go + $(STAMP) $@ + runtime_sysinfo.go: s-runtime_sysinfo; @true s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go GOARCH=$(GOARCH) GOOS=$(GOOS) $(SHELL) $(srcdir)/mkrsysinfo.sh @@ -553,10 +574,11 @@ zdefaultcc.go: s-zdefaultcc; @true s-zdefaultcc: Makefile echo 'package cfg' > zdefaultcc.go.tmp echo >> zdefaultcc.go.tmp - echo 'const DefaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp + echo 'func DefaultGCCGO(goos, goarch string) string { return "$(bindir)/$(GCCGO_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCC(goos, goarch string) string { return "$(GCC_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCXX(goos, goarch string) string { return "$(GXX_INSTALL_NAME)" }' >> zdefaultcc.go.tmp echo 'const DefaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp + echo 'var OSArchSupportsCgo = map[string]bool{}' >> zdefaultcc.go.tmp $(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go $(STAMP) $@ @@ -758,11 +780,15 @@ PACKAGES = \ go/types \ golang_org/x/crypto/chacha20poly1305 \ golang_org/x/crypto/chacha20poly1305/internal/chacha20 \ + golang_org/x/crypto/cryptobyte \ + golang_org/x/crypto/cryptobyte/asn1 \ golang_org/x/crypto/curve25519 \ golang_org/x/crypto/poly1305 \ golang_org/x/net/http2/hpack \ golang_org/x/net/idna \ + golang_org/x/net/internal/nettest \ golang_org/x/net/lex/httplex \ + golang_org/x/net/nettest \ golang_org/x/net/proxy \ golang_org/x/text/secure/bidirule \ golang_org/x/text/transform \ @@ -824,6 +850,7 @@ PACKAGES = \ os \ os/exec \ os/signal \ + os/signal/internal/pty \ os/user \ path \ path/filepath \ @@ -905,7 +932,7 @@ libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC GOTOOL_PACKAGES = \ cmd/go/internal/base \ cmd/go/internal/bug \ - cmd/go/internal/buildid \ + cmd/go/internal/cache \ cmd/go/internal/cfg \ cmd/go/internal/clean \ cmd/go/internal/cmdflag \ @@ -927,7 +954,12 @@ GOTOOL_PACKAGES = \ cmd/go/internal/web \ cmd/go/internal/work \ cmd/internal/browser \ - cmd/internal/objabi + cmd/internal/buildid \ + cmd/internal/edit \ + cmd/internal/objabi \ + cmd/internal/test2json \ + cmd/vet/internal/cfg \ + cmd/vet/internal/whitelist libgotool_a_SOURCES = libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES)) @@ -1136,17 +1168,23 @@ runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline extra_go_files_runtime_internal_sys = version.go runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys) +extra_go_files_cmd_internal_objabi = objabi.go +cmd/internal/objabi.lo.dep: $(extra_go_files_cmd_internal_objabi) + extra_go_files_cmd_go_internal_cfg = zdefaultcc.go cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg) extra_go_files_cmd_go_internal_load = zstdpkglist.go cmd/go/internal/load.lo.dep: $(extra_go_files_cmd_go_internal_load) +extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a +extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a + # FIXME: The following C files may as well move to the runtime # directory and be treated like other C files. @@ -1233,10 +1271,12 @@ TEST_PACKAGES = \ bufio/check \ bytes/check \ context/check \ + crypto/check \ errors/check \ expvar/check \ flag/check \ fmt/check \ + hash/check \ html/check \ image/check \ io/check \ @@ -1258,11 +1298,16 @@ TEST_PACKAGES = \ unicode/check \ archive/tar/check \ archive/zip/check \ + cmd/go/internal/cache/check \ cmd/go/internal/generate/check \ cmd/go/internal/get/check \ cmd/go/internal/load/check \ cmd/go/internal/work/check \ + cmd/internal/buildid/check \ + cmd/internal/edit/check \ cmd/internal/objabi/check \ + cmd/internal/test2json/check \ + cmd/vet/internal/cfg/check \ compress/bzip2/check \ compress/flate/check \ compress/gzip/check \ @@ -1315,6 +1360,7 @@ TEST_PACKAGES = \ go/constant/check \ go/doc/check \ go/format/check \ + go/importer/check \ go/internal/gcimporter/check \ go/internal/gccgoimporter/check \ go/internal/srcimporter/check \ @@ -1325,6 +1371,7 @@ TEST_PACKAGES = \ go/types/check \ golang_org/x/crypto/chacha20poly1305/check \ golang_org/x/crypto/chacha20poly1305/internal/chacha20/check \ + golang_org/x/crypto/cryptobyte/check \ golang_org/x/crypto/curve25519/check \ golang_org/x/crypto/poly1305/check \ golang_org/x/net/http2/hpack/check \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 3cf1daae4b5..6e03b89e407 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -770,7 +770,9 @@ toolexeclibgounicode_DATA = \ # Some packages are only needed for tests, so unlike the other # internal packages nothing will explicitly depend on them. # Force them to be built. -noinst_DATA = internal/testenv.gox net/internal/socktest.gox \ +noinst_DATA = golang_org/x/net/internal/nettest.gox \ + golang_org/x/net/nettest.gox internal/testenv.gox \ + net/internal/socktest.gox os/signal/internal/pty.gox \ zstdpkglist.go zdefaultcc.go @LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file = @LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c @@ -909,11 +911,15 @@ PACKAGES = \ go/types \ golang_org/x/crypto/chacha20poly1305 \ golang_org/x/crypto/chacha20poly1305/internal/chacha20 \ + golang_org/x/crypto/cryptobyte \ + golang_org/x/crypto/cryptobyte/asn1 \ golang_org/x/crypto/curve25519 \ golang_org/x/crypto/poly1305 \ golang_org/x/net/http2/hpack \ golang_org/x/net/idna \ + golang_org/x/net/internal/nettest \ golang_org/x/net/lex/httplex \ + golang_org/x/net/nettest \ golang_org/x/net/proxy \ golang_org/x/text/secure/bidirule \ golang_org/x/text/transform \ @@ -975,6 +981,7 @@ PACKAGES = \ os \ os/exec \ os/signal \ + os/signal/internal/pty \ os/user \ path \ path/filepath \ @@ -1053,7 +1060,7 @@ libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC GOTOOL_PACKAGES = \ cmd/go/internal/base \ cmd/go/internal/bug \ - cmd/go/internal/buildid \ + cmd/go/internal/cache \ cmd/go/internal/cfg \ cmd/go/internal/clean \ cmd/go/internal/cmdflag \ @@ -1075,7 +1082,12 @@ GOTOOL_PACKAGES = \ cmd/go/internal/web \ cmd/go/internal/work \ cmd/internal/browser \ - cmd/internal/objabi + cmd/internal/buildid \ + cmd/internal/edit \ + cmd/internal/objabi \ + cmd/internal/test2json \ + cmd/vet/internal/cfg \ + cmd/vet/internal/whitelist libgotool_a_SOURCES = libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES)) @@ -1210,12 +1222,15 @@ runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime # Also use -fno-inline to get better results from the memory profiler. runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline extra_go_files_runtime_internal_sys = version.go +extra_go_files_cmd_internal_objabi = objabi.go extra_go_files_cmd_go_internal_cfg = zdefaultcc.go extra_go_files_cmd_go_internal_load = zstdpkglist.go +extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a +extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a @HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = # Solaris 11.4 changed the type of fields in struct stat. @@ -1238,10 +1253,12 @@ TEST_PACKAGES = \ bufio/check \ bytes/check \ context/check \ + crypto/check \ errors/check \ expvar/check \ flag/check \ fmt/check \ + hash/check \ html/check \ image/check \ io/check \ @@ -1263,11 +1280,16 @@ TEST_PACKAGES = \ unicode/check \ archive/tar/check \ archive/zip/check \ + cmd/go/internal/cache/check \ cmd/go/internal/generate/check \ cmd/go/internal/get/check \ cmd/go/internal/load/check \ cmd/go/internal/work/check \ + cmd/internal/buildid/check \ + cmd/internal/edit/check \ cmd/internal/objabi/check \ + cmd/internal/test2json/check \ + cmd/vet/internal/cfg/check \ compress/bzip2/check \ compress/flate/check \ compress/gzip/check \ @@ -1320,6 +1342,7 @@ TEST_PACKAGES = \ go/constant/check \ go/doc/check \ go/format/check \ + go/importer/check \ go/internal/gcimporter/check \ go/internal/gccgoimporter/check \ go/internal/srcimporter/check \ @@ -1330,6 +1353,7 @@ TEST_PACKAGES = \ go/types/check \ golang_org/x/crypto/chacha20poly1305/check \ golang_org/x/crypto/chacha20poly1305/internal/chacha20/check \ + golang_org/x/crypto/cryptobyte/check \ golang_org/x/crypto/curve25519/check \ golang_org/x/crypto/poly1305/check \ golang_org/x/net/http2/hpack/check \ @@ -3130,6 +3154,24 @@ s-version: Makefile $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(STAMP) $@ +objabi.go: s-objabi; @true +s-objabi: Makefile + rm -f objabi.go.tmp + echo "package objabi" > objabi.go.tmp + echo "import \"runtime\"" >> objabi.go.tmp + echo 'const defaultGOROOT = `$(prefix)`' >> objabi.go.tmp + echo 'const defaultGO386 = `sse2`' >> objabi.go.tmp + echo 'const defaultGOARM = `5`' >> objabi.go.tmp + echo 'const defaultGOMIPS = `hardfloat`' >> objabi.go.tmp + echo 'const defaultGOOS = runtime.GOOS' >> objabi.go.tmp + echo 'const defaultGOARCH = runtime.GOARCH' >> objabi.go.tmp + echo 'const defaultGO_EXTLINK_ENABLED = ``' >> objabi.go.tmp + echo 'const version = `'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'`' >> objabi.go.tmp + echo 'const stackGuardMultiplier = 1' >> objabi.go.tmp + echo 'const goexperiment = ``' >> objabi.go.tmp + $(SHELL) $(srcdir)/mvifdiff.sh objabi.go.tmp objabi.go + $(STAMP) $@ + runtime_sysinfo.go: s-runtime_sysinfo; @true s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go GOARCH=$(GOARCH) GOOS=$(GOOS) $(SHELL) $(srcdir)/mkrsysinfo.sh @@ -3146,10 +3188,11 @@ zdefaultcc.go: s-zdefaultcc; @true s-zdefaultcc: Makefile echo 'package cfg' > zdefaultcc.go.tmp echo >> zdefaultcc.go.tmp - echo 'const DefaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp + echo 'func DefaultGCCGO(goos, goarch string) string { return "$(bindir)/$(GCCGO_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCC(goos, goarch string) string { return "$(GCC_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCXX(goos, goarch string) string { return "$(GXX_INSTALL_NAME)" }' >> zdefaultcc.go.tmp echo 'const DefaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp + echo 'var OSArchSupportsCgo = map[string]bool{}' >> zdefaultcc.go.tmp $(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go $(STAMP) $@ @@ -3305,6 +3348,7 @@ $(foreach package,$(GOTOOL_PACKAGES),$(eval $(call PACKAGE_template,$(package))) runtime.lo.dep: $(extra_go_files_runtime) syscall.lo.dep: $(extra_go_files_syscall) runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys) +cmd/internal/objabi.lo.dep: $(extra_go_files_cmd_internal_objabi) cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg) cmd/go/internal/load.lo.dep: $(extra_go_files_cmd_go_internal_load) diff --git a/libgo/VERSION b/libgo/VERSION index 6d1d72fa431..eb8d74cd88b 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.9 +go1.10beta1 diff --git a/libgo/configure b/libgo/configure index 3f8b6a0887f..eeccf25bccc 100755 --- a/libgo/configure +++ b/libgo/configure @@ -2494,7 +2494,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" -libtool_VERSION=12:0:0 +libtool_VERSION=13:0:0 # Default to --enable-multilib @@ -13652,7 +13652,7 @@ ALLGOARCHFAMILY="I386 ALPHA AMD64 ARM ARM64 IA64 M68K MIPS MIPS64 PPC PPC64 S390 GOARCH=unknown GOARCH_FAMILY=unknown -GOARCH_BIGENDIAN=0 +GOARCH_BIGENDIAN=false GOARCH_CACHELINESIZE=64 GOARCH_PHYSPAGESIZE=4096 GOARCH_PCQUANTUM=1 @@ -13680,6 +13680,12 @@ case ${host} in GOARCH_CACHELINESIZE=32 GOARCH_PCQUANTUM=4 GOARCH_MINFRAMESIZE=4 + case ${host} in + arm*b*-*-*) + GOARCH=armbe + GOARCH_BIGENDIAN=true + ;; + esac ;; i[34567]86-*-* | x86_64-*-*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13712,7 +13718,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext m68k*-*-*) GOARCH=m68k GOARCH_FAMILY=M68K - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=16 GOARCH_PCQUANTUM=4 GOARCH_INT64ALIGN=2 @@ -13776,7 +13782,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext GOARCH="${GOARCH}le" ;; *) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true ;; esac GOARCH_CACHELINESIZE=32 @@ -13794,7 +13800,7 @@ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : GOARCH=ppc GOARCH_FAMILY=PPC -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true else @@ -13811,7 +13817,7 @@ if ac_fn_c_try_compile "$LINENO"; then : else GOARCH=ppc64 -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext @@ -13841,7 +13847,7 @@ GOARCH_MINFRAMESIZE=8 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=256 GOARCH_PCQUANTUM=2 ;; @@ -13863,7 +13869,7 @@ GOARCH_FAMILY=SPARC64 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_PHYSPAGESIZE=8192 GOARCH_PCQUANTUM=4 ;; @@ -15142,7 +15148,7 @@ fi $as_echo "$libgo_cv_c_fancymath" >&6; } MATH_FLAG= if test "$libgo_cv_c_fancymath" = yes; then - MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations" + MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations -fno-math-errno" else MATH_FLAG="-ffp-contract=off" fi diff --git a/libgo/configure.ac b/libgo/configure.ac index 297ddb1cacd..9a9da38d605 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, libgo) AC_CONFIG_SRCDIR(Makefile.am) AC_CONFIG_HEADER(config.h) -libtool_VERSION=12:0:0 +libtool_VERSION=13:0:0 AC_SUBST(libtool_VERSION) AM_ENABLE_MULTILIB(, ..) @@ -215,7 +215,7 @@ ALLGOARCHFAMILY="I386 ALPHA AMD64 ARM ARM64 IA64 M68K MIPS MIPS64 PPC PPC64 S390 GOARCH=unknown GOARCH_FAMILY=unknown -GOARCH_BIGENDIAN=0 +GOARCH_BIGENDIAN=false GOARCH_CACHELINESIZE=64 GOARCH_PHYSPAGESIZE=4096 GOARCH_PCQUANTUM=1 @@ -243,6 +243,12 @@ case ${host} in GOARCH_CACHELINESIZE=32 GOARCH_PCQUANTUM=4 GOARCH_MINFRAMESIZE=4 + case ${host} in + arm*b*-*-*) + GOARCH=armbe + GOARCH_BIGENDIAN=true + ;; + esac ;; changequote(,)dnl i[34567]86-*-* | x86_64-*-*) @@ -270,7 +276,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" m68k*-*-*) GOARCH=m68k GOARCH_FAMILY=M68K - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=16 GOARCH_PCQUANTUM=4 GOARCH_INT64ALIGN=2 @@ -313,7 +319,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" GOARCH="${GOARCH}le" ;; *) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true ;; esac GOARCH_CACHELINESIZE=32 @@ -327,7 +333,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" #endif], [GOARCH=ppc GOARCH_FAMILY=PPC -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true ], [ GOARCH_FAMILY=PPC64 @@ -338,7 +344,7 @@ AC_COMPILE_IFELSE([ [GOARCH=ppc64le ], [GOARCH=ppc64 -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true ])]) GOARCH_PHYSPAGESIZE=65536 GOARCH_PCQUANTUM=4 @@ -356,7 +362,7 @@ GOARCH_MINFRAMESIZE=4 GOARCH_FAMILY=S390X GOARCH_MINFRAMESIZE=8 ]) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=256 GOARCH_PCQUANTUM=2 ;; @@ -371,7 +377,7 @@ GOARCH_FAMILY=SPARC [GOARCH=sparc64 GOARCH_FAMILY=SPARC64 ]) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_PHYSPAGESIZE=8192 GOARCH_PCQUANTUM=4 ;; @@ -718,7 +724,7 @@ AC_COMPILE_IFELSE([int i;], CFLAGS=$CFLAGS_hold]) MATH_FLAG= if test "$libgo_cv_c_fancymath" = yes; then - MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations" + MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations -fno-math-errno" else MATH_FLAG="-ffp-contract=off" fi diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go index d49c5c3fd9e..4a2c173bf3a 100644 --- a/libgo/go/archive/tar/common.go +++ b/libgo/go/archive/tar/common.go @@ -3,20 +3,22 @@ // license that can be found in the LICENSE file. // Package tar implements access to tar archives. -// It aims to cover most of the variations, including those produced -// by GNU and BSD tars. // -// References: -// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5 -// http://www.gnu.org/software/tar/manual/html_node/Standard.html -// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html +// Tape archives (tar) are a file format for storing a sequence of files that +// can be read and written in a streaming manner. +// This package aims to cover most variations of the format, +// including those produced by GNU and BSD tar tools. package tar import ( "errors" "fmt" + "math" "os" "path" + "reflect" + "strconv" + "strings" "time" ) @@ -24,42 +26,500 @@ import ( // architectures. If a large value is encountered when decoding, the result // stored in Header will be the truncated version. -// Header type flags. +var ( + ErrHeader = errors.New("archive/tar: invalid tar header") + ErrWriteTooLong = errors.New("archive/tar: write too long") + ErrFieldTooLong = errors.New("archive/tar: header field too long") + ErrWriteAfterClose = errors.New("archive/tar: write after close") + errMissData = errors.New("archive/tar: sparse file references non-existent data") + errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data") + errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole") +) + +type headerError []string + +func (he headerError) Error() string { + const prefix = "archive/tar: cannot encode header" + var ss []string + for _, s := range he { + if s != "" { + ss = append(ss, s) + } + } + if len(ss) == 0 { + return prefix + } + return fmt.Sprintf("%s: %v", prefix, strings.Join(ss, "; and ")) +} + +// Type flags for Header.Typeflag. +const ( + // Type '0' indicates a regular file. + TypeReg = '0' + TypeRegA = '\x00' // For legacy support; use TypeReg instead + + // Type '1' to '6' are header-only flags and may not have a data body. + TypeLink = '1' // Hard link + TypeSymlink = '2' // Symbolic link + TypeChar = '3' // Character device node + TypeBlock = '4' // Block device node + TypeDir = '5' // Directory + TypeFifo = '6' // FIFO node + + // Type '7' is reserved. + TypeCont = '7' + + // Type 'x' is used by the PAX format to store key-value records that + // are only relevant to the next file. + // This package transparently handles these types. + TypeXHeader = 'x' + + // Type 'g' is used by the PAX format to store key-value records that + // are relevant to all subsequent files. + // This package only supports parsing and composing such headers, + // but does not currently support persisting the global state across files. + TypeXGlobalHeader = 'g' + + // Type 'S' indicates a sparse file in the GNU format. + TypeGNUSparse = 'S' + + // Types 'L' and 'K' are used by the GNU format for a meta file + // used to store the path or link name for the next file. + // This package transparently handles these types. + TypeGNULongName = 'L' + TypeGNULongLink = 'K' +) + +// Keywords for PAX extended header records. const ( - TypeReg = '0' // regular file - TypeRegA = '\x00' // regular file - TypeLink = '1' // hard link - TypeSymlink = '2' // symbolic link - TypeChar = '3' // character device node - TypeBlock = '4' // block device node - TypeDir = '5' // directory - TypeFifo = '6' // fifo node - TypeCont = '7' // reserved - TypeXHeader = 'x' // extended header - 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 + paxNone = "" // Indicates that no PAX key is suitable + paxPath = "path" + paxLinkpath = "linkpath" + paxSize = "size" + paxUid = "uid" + paxGid = "gid" + paxUname = "uname" + paxGname = "gname" + paxMtime = "mtime" + paxAtime = "atime" + paxCtime = "ctime" // Removed from later revision of PAX spec, but was valid + paxCharset = "charset" // Currently unused + paxComment = "comment" // Currently unused + + paxSchilyXattr = "SCHILY.xattr." + + // Keywords for GNU sparse files in a PAX extended header. + paxGNUSparse = "GNU.sparse." + 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" ) +// basicKeys is a set of the PAX keys for which we have built-in support. +// This does not contain "charset" or "comment", which are both PAX-specific, +// so adding them as first-class features of Header is unlikely. +// Users can use the PAXRecords field to set it themselves. +var basicKeys = map[string]bool{ + paxPath: true, paxLinkpath: true, paxSize: true, paxUid: true, paxGid: true, + paxUname: true, paxGname: true, paxMtime: true, paxAtime: true, paxCtime: true, +} + // A Header represents a single header in a tar archive. // Some fields may not be populated. +// +// For forward compatibility, users that retrieve a Header from Reader.Next, +// mutate it in some ways, and then pass it back to Writer.WriteHeader +// should do so by creating a new Header and copying the fields +// that they are interested in preserving. type Header struct { - Name string // name of header file entry - Mode int64 // permission and mode bits - Uid int // user id of owner - Gid int // group id of owner - Size int64 // length in bytes - ModTime time.Time // modified time - Typeflag byte // type of header entry - Linkname string // target name of link - Uname string // user name of owner - Gname string // group name of owner - Devmajor int64 // major number of character or block device - Devminor int64 // minor number of character or block device - AccessTime time.Time // access time - ChangeTime time.Time // status change time - Xattrs map[string]string + Typeflag byte // Type of header entry (should be TypeReg for most files) + + Name string // Name of file entry + Linkname string // Target name of link (valid for TypeLink or TypeSymlink) + + Size int64 // Logical file size in bytes + Mode int64 // Permission and mode bits + Uid int // User ID of owner + Gid int // Group ID of owner + Uname string // User name of owner + Gname string // Group name of owner + + // If the Format is unspecified, then Writer.WriteHeader rounds ModTime + // to the nearest second and ignores the AccessTime and ChangeTime fields. + // + // To use AccessTime or ChangeTime, specify the Format as PAX or GNU. + // To use sub-second resolution, specify the Format as PAX. + ModTime time.Time // Modification time + AccessTime time.Time // Access time (requires either PAX or GNU support) + ChangeTime time.Time // Change time (requires either PAX or GNU support) + + Devmajor int64 // Major device number (valid for TypeChar or TypeBlock) + Devminor int64 // Minor device number (valid for TypeChar or TypeBlock) + + // Xattrs stores extended attributes as PAX records under the + // "SCHILY.xattr." namespace. + // + // The following are semantically equivalent: + // h.Xattrs[key] = value + // h.PAXRecords["SCHILY.xattr."+key] = value + // + // When Writer.WriteHeader is called, the contents of Xattrs will take + // precedence over those in PAXRecords. + // + // Deprecated: Use PAXRecords instead. + Xattrs map[string]string + + // PAXRecords is a map of PAX extended header records. + // + // User-defined records should have keys of the following form: + // VENDOR.keyword + // Where VENDOR is some namespace in all uppercase, and keyword may + // not contain the '=' character (e.g., "GOLANG.pkg.version"). + // The key and value should be non-empty UTF-8 strings. + // + // When Writer.WriteHeader is called, PAX records derived from the + // the other fields in Header take precedence over PAXRecords. + PAXRecords map[string]string + + // Format specifies the format of the tar header. + // + // This is set by Reader.Next as a best-effort guess at the format. + // Since the Reader liberally reads some non-compliant files, + // it is possible for this to be FormatUnknown. + // + // If the format is unspecified when Writer.WriteHeader is called, + // then it uses the first format (in the order of USTAR, PAX, GNU) + // capable of encoding this Header (see Format). + Format Format +} + +// sparseEntry represents a Length-sized fragment at Offset in the file. +type sparseEntry struct{ Offset, Length int64 } + +func (s sparseEntry) endOffset() int64 { return s.Offset + s.Length } + +// A sparse file can be represented as either a sparseDatas or a sparseHoles. +// As long as the total size is known, they are equivalent and one can be +// converted to the other form and back. The various tar formats with sparse +// file support represent sparse files in the sparseDatas form. That is, they +// specify the fragments in the file that has data, and treat everything else as +// having zero bytes. As such, the encoding and decoding logic in this package +// deals with sparseDatas. +// +// However, the external API uses sparseHoles instead of sparseDatas because the +// zero value of sparseHoles logically represents a normal file (i.e., there are +// no holes in it). On the other hand, the zero value of sparseDatas implies +// that the file has no data in it, which is rather odd. +// +// As an example, if the underlying raw file contains the 10-byte data: +// var compactFile = "abcdefgh" +// +// And the sparse map has the following entries: +// var spd sparseDatas = []sparseEntry{ +// {Offset: 2, Length: 5}, // Data fragment for 2..6 +// {Offset: 18, Length: 3}, // Data fragment for 18..20 +// } +// var sph sparseHoles = []sparseEntry{ +// {Offset: 0, Length: 2}, // Hole fragment for 0..1 +// {Offset: 7, Length: 11}, // Hole fragment for 7..17 +// {Offset: 21, Length: 4}, // Hole fragment for 21..24 +// } +// +// Then the content of the resulting sparse file with a Header.Size of 25 is: +// var sparseFile = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4 +type ( + sparseDatas []sparseEntry + sparseHoles []sparseEntry +) + +// validateSparseEntries reports whether sp is a valid sparse map. +// It does not matter whether sp represents data fragments or hole fragments. +func validateSparseEntries(sp []sparseEntry, size int64) bool { + // Validate all sparse entries. These are the same checks as performed by + // the BSD tar utility. + if size < 0 { + return false + } + var pre sparseEntry + for _, cur := range sp { + switch { + case cur.Offset < 0 || cur.Length < 0: + return false // Negative values are never okay + case cur.Offset > math.MaxInt64-cur.Length: + return false // Integer overflow with large length + case cur.endOffset() > size: + return false // Region extends beyond the actual size + case pre.endOffset() > cur.Offset: + return false // Regions cannot overlap and must be in order + } + pre = cur + } + return true +} + +// alignSparseEntries mutates src and returns dst where each fragment's +// starting offset is aligned up to the nearest block edge, and each +// ending offset is aligned down to the nearest block edge. +// +// Even though the Go tar Reader and the BSD tar utility can handle entries +// with arbitrary offsets and lengths, the GNU tar utility can only handle +// offsets and lengths that are multiples of blockSize. +func alignSparseEntries(src []sparseEntry, size int64) []sparseEntry { + dst := src[:0] + for _, s := range src { + pos, end := s.Offset, s.endOffset() + pos += blockPadding(+pos) // Round-up to nearest blockSize + if end != size { + end -= blockPadding(-end) // Round-down to nearest blockSize + } + if pos < end { + dst = append(dst, sparseEntry{Offset: pos, Length: end - pos}) + } + } + return dst +} + +// invertSparseEntries converts a sparse map from one form to the other. +// If the input is sparseHoles, then it will output sparseDatas and vice-versa. +// The input must have been already validated. +// +// This function mutates src and returns a normalized map where: +// * adjacent fragments are coalesced together +// * only the last fragment may be empty +// * the endOffset of the last fragment is the total size +func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry { + dst := src[:0] + var pre sparseEntry + for _, cur := range src { + if cur.Length == 0 { + continue // Skip empty fragments + } + pre.Length = cur.Offset - pre.Offset + if pre.Length > 0 { + dst = append(dst, pre) // Only add non-empty fragments + } + pre.Offset = cur.endOffset() + } + pre.Length = size - pre.Offset // Possibly the only empty fragment + return append(dst, pre) +} + +// fileState tracks the number of logical (includes sparse holes) and physical +// (actual in tar archive) bytes remaining for the current file. +// +// Invariant: LogicalRemaining >= PhysicalRemaining +type fileState interface { + LogicalRemaining() int64 + PhysicalRemaining() int64 +} + +// allowedFormats determines which formats can be used. +// The value returned is the logical OR of multiple possible formats. +// If the value is FormatUnknown, then the input Header cannot be encoded +// and an error is returned explaining why. +// +// As a by-product of checking the fields, this function returns paxHdrs, which +// contain all fields that could not be directly encoded. +// A value receiver ensures that this method does not mutate the source Header. +func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err error) { + format = FormatUSTAR | FormatPAX | FormatGNU + paxHdrs = make(map[string]string) + + var whyNoUSTAR, whyNoPAX, whyNoGNU string + var preferPAX bool // Prefer PAX over USTAR + verifyString := func(s string, size int, name, paxKey string) { + // NUL-terminator is optional for path and linkpath. + // Technically, it is required for uname and gname, + // but neither GNU nor BSD tar checks for it. + tooLong := len(s) > size + allowLongGNU := paxKey == paxPath || paxKey == paxLinkpath + if hasNUL(s) || (tooLong && !allowLongGNU) { + whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%q", name, s) + format.mustNotBe(FormatGNU) + } + if !isASCII(s) || tooLong { + canSplitUSTAR := paxKey == paxPath + if _, _, ok := splitUSTARPath(s); !canSplitUSTAR || !ok { + whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%q", name, s) + format.mustNotBe(FormatUSTAR) + } + if paxKey == paxNone { + whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%q", name, s) + format.mustNotBe(FormatPAX) + } else { + paxHdrs[paxKey] = s + } + } + if v, ok := h.PAXRecords[paxKey]; ok && v == s { + paxHdrs[paxKey] = v + } + } + verifyNumeric := func(n int64, size int, name, paxKey string) { + if !fitsInBase256(size, n) { + whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%d", name, n) + format.mustNotBe(FormatGNU) + } + if !fitsInOctal(size, n) { + whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%d", name, n) + format.mustNotBe(FormatUSTAR) + if paxKey == paxNone { + whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%d", name, n) + format.mustNotBe(FormatPAX) + } else { + paxHdrs[paxKey] = strconv.FormatInt(n, 10) + } + } + if v, ok := h.PAXRecords[paxKey]; ok && v == strconv.FormatInt(n, 10) { + paxHdrs[paxKey] = v + } + } + verifyTime := func(ts time.Time, size int, name, paxKey string) { + if ts.IsZero() { + return // Always okay + } + if !fitsInBase256(size, ts.Unix()) { + whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%v", name, ts) + format.mustNotBe(FormatGNU) + } + isMtime := paxKey == paxMtime + fitsOctal := fitsInOctal(size, ts.Unix()) + if (isMtime && !fitsOctal) || !isMtime { + whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%v", name, ts) + format.mustNotBe(FormatUSTAR) + } + needsNano := ts.Nanosecond() != 0 + if !isMtime || !fitsOctal || needsNano { + preferPAX = true // USTAR may truncate sub-second measurements + if paxKey == paxNone { + whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%v", name, ts) + format.mustNotBe(FormatPAX) + } else { + paxHdrs[paxKey] = formatPAXTime(ts) + } + } + if v, ok := h.PAXRecords[paxKey]; ok && v == formatPAXTime(ts) { + paxHdrs[paxKey] = v + } + } + + // Check basic fields. + var blk block + v7 := blk.V7() + ustar := blk.USTAR() + gnu := blk.GNU() + verifyString(h.Name, len(v7.Name()), "Name", paxPath) + verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath) + verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname) + verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname) + verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone) + verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid) + verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid) + verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize) + verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone) + verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone) + verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime) + verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime) + verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime) + + // Check for header-only types. + var whyOnlyPAX, whyOnlyGNU string + switch h.Typeflag { + case TypeReg, TypeChar, TypeBlock, TypeFifo, TypeGNUSparse: + // Exclude TypeLink and TypeSymlink, since they may reference directories. + if strings.HasSuffix(h.Name, "/") { + return FormatUnknown, nil, headerError{"filename may not have trailing slash"} + } + case TypeXHeader, TypeGNULongName, TypeGNULongLink: + return FormatUnknown, nil, headerError{"cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers"} + case TypeXGlobalHeader: + h2 := Header{Name: h.Name, Typeflag: h.Typeflag, Xattrs: h.Xattrs, PAXRecords: h.PAXRecords, Format: h.Format} + if !reflect.DeepEqual(h, h2) { + return FormatUnknown, nil, headerError{"only PAXRecords should be set for TypeXGlobalHeader"} + } + whyOnlyPAX = "only PAX supports TypeXGlobalHeader" + format.mayOnlyBe(FormatPAX) + } + if !isHeaderOnlyType(h.Typeflag) && h.Size < 0 { + return FormatUnknown, nil, headerError{"negative size on header-only type"} + } + + // Check PAX records. + if len(h.Xattrs) > 0 { + for k, v := range h.Xattrs { + paxHdrs[paxSchilyXattr+k] = v + } + whyOnlyPAX = "only PAX supports Xattrs" + format.mayOnlyBe(FormatPAX) + } + if len(h.PAXRecords) > 0 { + for k, v := range h.PAXRecords { + switch _, exists := paxHdrs[k]; { + case exists: + continue // Do not overwrite existing records + case h.Typeflag == TypeXGlobalHeader: + paxHdrs[k] = v // Copy all records + case !basicKeys[k] && !strings.HasPrefix(k, paxGNUSparse): + paxHdrs[k] = v // Ignore local records that may conflict + } + } + whyOnlyPAX = "only PAX supports PAXRecords" + format.mayOnlyBe(FormatPAX) + } + for k, v := range paxHdrs { + if !validPAXRecord(k, v) { + return FormatUnknown, nil, headerError{fmt.Sprintf("invalid PAX record: %q", k+" = "+v)} + } + } + + // TODO(dsnet): Re-enable this when adding sparse support. + // See https://golang.org/issue/22735 + /* + // Check sparse files. + if len(h.SparseHoles) > 0 || h.Typeflag == TypeGNUSparse { + if isHeaderOnlyType(h.Typeflag) { + return FormatUnknown, nil, headerError{"header-only type cannot be sparse"} + } + if !validateSparseEntries(h.SparseHoles, h.Size) { + return FormatUnknown, nil, headerError{"invalid sparse holes"} + } + if h.Typeflag == TypeGNUSparse { + whyOnlyGNU = "only GNU supports TypeGNUSparse" + format.mayOnlyBe(FormatGNU) + } else { + whyNoGNU = "GNU supports sparse files only with TypeGNUSparse" + format.mustNotBe(FormatGNU) + } + whyNoUSTAR = "USTAR does not support sparse files" + format.mustNotBe(FormatUSTAR) + } + */ + + // Check desired format. + if wantFormat := h.Format; wantFormat != FormatUnknown { + if wantFormat.has(FormatPAX) && !preferPAX { + wantFormat.mayBe(FormatUSTAR) // PAX implies USTAR allowed too + } + format.mayOnlyBe(wantFormat) // Set union of formats allowed and format wanted + } + if format == FormatUnknown { + switch h.Format { + case FormatUSTAR: + err = headerError{"Format specifies USTAR", whyNoUSTAR, whyOnlyPAX, whyOnlyGNU} + case FormatPAX: + err = headerError{"Format specifies PAX", whyNoPAX, whyOnlyGNU} + case FormatGNU: + err = headerError{"Format specifies GNU", whyNoGNU, whyOnlyPAX} + default: + err = headerError{whyNoUSTAR, whyNoPAX, whyNoGNU, whyOnlyPAX, whyOnlyGNU} + } + } + return format, paxHdrs, err } // FileInfo returns an os.FileInfo for the Header. @@ -92,63 +552,43 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) { // Set setuid, setgid and sticky bits. if fi.h.Mode&c_ISUID != 0 { - // setuid mode |= os.ModeSetuid } if fi.h.Mode&c_ISGID != 0 { - // setgid mode |= os.ModeSetgid } if fi.h.Mode&c_ISVTX != 0 { - // sticky mode |= os.ModeSticky } - // Set file mode bits. - // clear perm, setuid, setgid and sticky bits. - m := os.FileMode(fi.h.Mode) &^ 07777 - if m == c_ISDIR { - // directory + // Set file mode bits; clear perm, setuid, setgid, and sticky bits. + switch m := os.FileMode(fi.h.Mode) &^ 07777; m { + case c_ISDIR: mode |= os.ModeDir - } - if m == c_ISFIFO { - // named pipe (FIFO) + case c_ISFIFO: mode |= os.ModeNamedPipe - } - if m == c_ISLNK { - // symbolic link + case c_ISLNK: mode |= os.ModeSymlink - } - if m == c_ISBLK { - // device file + case c_ISBLK: mode |= os.ModeDevice - } - if m == c_ISCHR { - // Unix character device + case c_ISCHR: mode |= os.ModeDevice mode |= os.ModeCharDevice - } - if m == c_ISSOCK { - // Unix domain socket + case c_ISSOCK: mode |= os.ModeSocket } switch fi.h.Typeflag { case TypeSymlink: - // symbolic link mode |= os.ModeSymlink case TypeChar: - // character device node mode |= os.ModeDevice mode |= os.ModeCharDevice case TypeBlock: - // block device node mode |= os.ModeDevice case TypeDir: - // directory mode |= os.ModeDir case TypeFifo: - // fifo node mode |= os.ModeNamedPipe } @@ -176,33 +616,16 @@ const ( c_ISSOCK = 0140000 // Socket ) -// Keywords for the PAX Extended Header -const ( - paxAtime = "atime" - paxCharset = "charset" - paxComment = "comment" - paxCtime = "ctime" // please note that ctime is not a valid pax header. - paxGid = "gid" - paxGname = "gname" - paxLinkpath = "linkpath" - paxMtime = "mtime" - paxPath = "path" - paxSize = "size" - paxUid = "uid" - paxUname = "uname" - paxXattr = "SCHILY.xattr." - paxNone = "" -) - // FileInfoHeader creates a partially-populated Header from fi. // If fi describes a symlink, FileInfoHeader records link as the link target. // If fi describes a directory, a slash is appended to the name. -// Because os.FileInfo's Name method returns only the base name of -// the file it describes, it may be necessary to modify the Name field -// of the returned header to provide the full path name of the file. +// +// Since os.FileInfo's Name method only returns the base name of +// the file it describes, it may be necessary to modify Header.Name +// to provide the full path name of the file. func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { if fi == nil { - return nil, errors.New("tar: FileInfo is nil") + return nil, errors.New("archive/tar: FileInfo is nil") } fm := fi.Mode() h := &Header{ @@ -265,6 +688,12 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { h.Size = 0 h.Linkname = sys.Linkname } + if sys.PAXRecords != nil { + h.PAXRecords = make(map[string]string) + for k, v := range sys.PAXRecords { + h.PAXRecords[k] = v + } + } } if sysStat != nil { return h, sysStat(fi, h) @@ -282,3 +711,10 @@ func isHeaderOnlyType(flag byte) bool { return false } } + +func min(a, b int64) int64 { + if a < b { + return a + } + return b +} diff --git a/libgo/go/archive/tar/format.go b/libgo/go/archive/tar/format.go index c2c9910d002..6e29698a14a 100644 --- a/libgo/go/archive/tar/format.go +++ b/libgo/go/archive/tar/format.go @@ -4,38 +4,133 @@ package tar +import "strings" + +// Format represents the tar archive format. +// +// The original tar format was introduced in Unix V7. +// Since then, there have been multiple competing formats attempting to +// standardize or extend the V7 format to overcome its limitations. +// The most common formats are the USTAR, PAX, and GNU formats, +// each with their own advantages and limitations. +// +// The following table captures the capabilities of each format: +// +// | USTAR | PAX | GNU +// ------------------+--------+-----------+---------- +// Name | 256B | unlimited | unlimited +// Linkname | 100B | unlimited | unlimited +// Size | uint33 | unlimited | uint89 +// Mode | uint21 | uint21 | uint57 +// Uid/Gid | uint21 | unlimited | uint57 +// Uname/Gname | 32B | unlimited | 32B +// ModTime | uint33 | unlimited | int89 +// AccessTime | n/a | unlimited | int89 +// ChangeTime | n/a | unlimited | int89 +// Devmajor/Devminor | uint21 | uint21 | uint57 +// ------------------+--------+-----------+---------- +// string encoding | ASCII | UTF-8 | binary +// sub-second times | no | yes | no +// sparse files | no | yes | yes +// +// The table's upper portion shows the Header fields, where each format reports +// the maximum number of bytes allowed for each string field and +// the integer type used to store each numeric field +// (where timestamps are stored as the number of seconds since the Unix epoch). +// +// The table's lower portion shows specialized features of each format, +// such as supported string encodings, support for sub-second timestamps, +// or support for sparse files. +// +// The Writer currently provides no support for sparse files. +type Format int + // Constants to identify various tar formats. const ( - // The format is unknown. - formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc... + // Deliberately hide the meaning of constants from public API. + _ Format = (1 << iota) / 4 // Sequence of 0, 0, 1, 2, 4, 8, etc... + + // FormatUnknown indicates that the format is unknown. + FormatUnknown // The format of the original Unix V7 tar tool prior to standardization. formatV7 - // The old and new GNU formats, which are incompatible with USTAR. - // This does cover the old GNU sparse extension. - // This does not cover the GNU sparse extensions using PAX headers, - // versions 0.0, 0.1, and 1.0; these fall under the PAX format. - formatGNU + // FormatUSTAR represents the USTAR header format defined in POSIX.1-1988. + // + // While this format is compatible with most tar readers, + // the format has several limitations making it unsuitable for some usages. + // Most notably, it cannot support sparse files, files larger than 8GiB, + // filenames larger than 256 characters, and non-ASCII filenames. + // + // Reference: + // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06 + FormatUSTAR + + // FormatPAX represents the PAX header format defined in POSIX.1-2001. + // + // PAX extends USTAR by writing a special file with Typeflag TypeXHeader + // preceding the original header. This file contains a set of key-value + // records, which are used to overcome USTAR's shortcomings, in addition to + // providing the ability to have sub-second resolution for timestamps. + // + // Some newer formats add their own extensions to PAX by defining their + // own keys and assigning certain semantic meaning to the associated values. + // For example, sparse file support in PAX is implemented using keys + // defined by the GNU manual (e.g., "GNU.sparse.map"). + // + // Reference: + // http://pubs.opengroup.org/onlinepubs/009695399/utilities/pax.html + FormatPAX + + // FormatGNU represents the GNU header format. + // + // The GNU header format is older than the USTAR and PAX standards and + // is not compatible with them. The GNU format supports + // arbitrary file sizes, filenames of arbitrary encoding and length, + // sparse files, and other features. + // + // It is recommended that PAX be chosen over GNU unless the target + // application can only parse GNU formatted archives. + // + // Reference: + // http://www.gnu.org/software/tar/manual/html_node/Standard.html + FormatGNU // Schily's tar format, which is incompatible with USTAR. // This does not cover STAR extensions to the PAX format; these fall under // the PAX format. formatSTAR - // USTAR is the former standardization of tar defined in POSIX.1-1988. - // This is incompatible with the GNU and STAR formats. - formatUSTAR - - // PAX is the latest standardization of tar defined in POSIX.1-2001. - // This is an extension of USTAR and is "backwards compatible" with it. - // - // Some newer formats add their own extensions to PAX, such as GNU sparse - // files and SCHILY extended attributes. Since they are backwards compatible - // with PAX, they will be labelled as "PAX". - formatPAX + formatMax ) +func (f Format) has(f2 Format) bool { return f&f2 != 0 } +func (f *Format) mayBe(f2 Format) { *f |= f2 } +func (f *Format) mayOnlyBe(f2 Format) { *f &= f2 } +func (f *Format) mustNotBe(f2 Format) { *f &^= f2 } + +var formatNames = map[Format]string{ + formatV7: "V7", FormatUSTAR: "USTAR", FormatPAX: "PAX", FormatGNU: "GNU", formatSTAR: "STAR", +} + +func (f Format) String() string { + var ss []string + for f2 := Format(1); f2 < formatMax; f2 <<= 1 { + if f.has(f2) { + ss = append(ss, formatNames[f2]) + } + } + switch len(ss) { + case 0: + return "" + case 1: + return ss[0] + default: + return "(" + strings.Join(ss, " | ") + ")" + } +} + // Magics used to identify various formats. const ( magicGNU, versionGNU = "ustar ", " \x00" @@ -50,6 +145,12 @@ const ( prefixSize = 155 // Max length of the prefix field in USTAR format ) +// blockPadding computes the number of bytes needed to pad offset up to the +// nearest block edge where 0 <= n < blockSize. +func blockPadding(offset int64) (n int64) { + return -offset & (blockSize - 1) +} + var zeroBlock block type block [blockSize]byte @@ -63,14 +164,14 @@ func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) } // GetFormat checks that the block is a valid tar header based on the checksum. // It then attempts to guess the specific format based on magic values. -// If the checksum fails, then formatUnknown is returned. -func (b *block) GetFormat() (format int) { +// If the checksum fails, then FormatUnknown is returned. +func (b *block) GetFormat() Format { // Verify checksum. var p parser value := p.parseOctal(b.V7().Chksum()) chksum1, chksum2 := b.ComputeChecksum() if p.err != nil || (value != chksum1 && value != chksum2) { - return formatUnknown + return FormatUnknown } // Guess the magic values. @@ -81,9 +182,9 @@ func (b *block) GetFormat() (format int) { case magic == magicUSTAR && trailer == trailerSTAR: return formatSTAR case magic == magicUSTAR: - return formatUSTAR + return FormatUSTAR | FormatPAX case magic == magicGNU && version == versionGNU: - return formatGNU + return FormatGNU default: return formatV7 } @@ -91,19 +192,19 @@ func (b *block) GetFormat() (format int) { // SetFormat writes the magic values necessary for specified format // and then updates the checksum accordingly. -func (b *block) SetFormat(format int) { +func (b *block) SetFormat(format Format) { // Set the magic values. - switch format { - case formatV7: + switch { + case format.has(formatV7): // Do nothing. - case formatGNU: + case format.has(FormatGNU): copy(b.GNU().Magic(), magicGNU) copy(b.GNU().Version(), versionGNU) - case formatSTAR: + case format.has(formatSTAR): copy(b.STAR().Magic(), magicUSTAR) copy(b.STAR().Version(), versionUSTAR) copy(b.STAR().Trailer(), trailerSTAR) - case formatUSTAR, formatPAX: + case format.has(FormatUSTAR | FormatPAX): copy(b.USTAR().Magic(), magicUSTAR) copy(b.USTAR().Version(), versionUSTAR) default: @@ -128,12 +229,17 @@ func (b *block) ComputeChecksum() (unsigned, signed int64) { if 148 <= i && i < 156 { c = ' ' // Treat the checksum field itself as all spaces. } - unsigned += int64(uint8(c)) + unsigned += int64(c) signed += int64(int8(c)) } return unsigned, signed } +// Reset clears the block with all zeros. +func (b *block) Reset() { + *b = block{} +} + type headerV7 [blockSize]byte func (h *headerV7) Name() []byte { return h[000:][:100] } @@ -187,11 +293,11 @@ func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] } type sparseArray []byte -func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) } +func (s sparseArray) Entry(i int) sparseElem { return (sparseElem)(s[i*24:]) } func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] } func (s sparseArray) MaxEntries() int { return len(s) / 24 } -type sparseNode []byte +type sparseElem []byte -func (s sparseNode) Offset() []byte { return s[00:][:12] } -func (s sparseNode) NumBytes() []byte { return s[12:][:12] } +func (s sparseElem) Offset() []byte { return s[00:][:12] } +func (s sparseElem) Length() []byte { return s[12:][:12] } diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index 9abe888218f..f4eeb557be9 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -4,33 +4,23 @@ package tar -// TODO(dsymonds): -// - pax extensions - import ( "bytes" - "errors" "io" "io/ioutil" - "math" "strconv" "strings" "time" ) -var ( - ErrHeader = errors.New("archive/tar: invalid tar header") -) - -// A Reader provides sequential access to the contents of a tar archive. -// A tar archive consists of a sequence of files. -// 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. +// Reader provides sequential access to the contents of a tar archive. +// Reader.Next advances to the next file in the archive (including the first), +// and then Reader can be treated as an io.Reader to access the file's data. type Reader struct { r io.Reader - pad int64 // amount of padding (ignored) after current file entry - curr numBytesReader // reader for current file entry - blk block // buffer to use as temporary local storage + pad int64 // Amount of padding (ignored) after current file entry + curr fileReader // Reader for current file entry + blk block // Buffer to use as temporary local storage // err is a persistent error. // It is only the responsibility of every exported method of Reader to @@ -38,68 +28,21 @@ type Reader struct { err error } -// A numBytesReader is an io.Reader with a numBytes method, returning the number -// of bytes remaining in the underlying encoded data. -type numBytesReader interface { +type fileReader interface { io.Reader - numBytes() int64 -} + fileState -// 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 numBytesReader // Reads the sparse-encoded file data - sp []sparseEntry // The sparse map for the file - pos int64 // Keeps track of file position - total int64 // Total size of the file -} - -// A sparseEntry holds a single entry in a sparse file's sparse map. -// -// Sparse files are represented using a series of sparseEntrys. -// Despite the name, a sparseEntry represents an actual data fragment that -// references data found in the underlying archive stream. All regions not -// covered by a sparseEntry are logically filled with zeros. -// -// For example, if the underlying raw file contains the 10-byte data: -// var compactData = "abcdefgh" -// -// And the sparse map has the following entries: -// var sp = []sparseEntry{ -// {offset: 2, numBytes: 5} // Data fragment for [2..7] -// {offset: 18, numBytes: 3} // Data fragment for [18..21] -// } -// -// Then the content of the resulting sparse file with a "real" size of 25 is: -// var sparseData = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4 -type sparseEntry struct { - offset int64 // Starting position of the fragment - numBytes int64 // Length of the fragment + WriteTo(io.Writer) (int64, error) } -// 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" -) - // NewReader creates a new Reader reading from r. -func NewReader(r io.Reader) *Reader { return &Reader{r: r} } +func NewReader(r io.Reader) *Reader { + return &Reader{r: r, curr: ®FileReader{r, 0}} +} // Next advances to the next entry in the tar archive. +// The Header.Size determines how many bytes can be read for the next file. +// Any remaining data in the current file is automatically discarded. // // io.EOF is returned at the end of the input. func (tr *Reader) Next() (*Header, error) { @@ -112,18 +55,26 @@ func (tr *Reader) Next() (*Header, error) { } func (tr *Reader) next() (*Header, error) { - var extHdrs map[string]string + var paxHdrs map[string]string + var gnuLongName, gnuLongLink string // Externally, Next iterates through the tar archive as if it is a series of // files. Internally, the tar format often uses fake "files" to add meta // data that describes the next file. These meta data "files" should not // normally be visible to the outside. As such, this loop iterates through // one or more "header files" until it finds a "normal file". + format := FormatUSTAR | FormatPAX | FormatGNU loop: for { - if err := tr.skipUnread(); err != nil { + // Discard the remainder of the file and any padding. + if err := discard(tr.r, tr.curr.PhysicalRemaining()); err != nil { return nil, err } + if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil { + return nil, err + } + tr.pad = 0 + hdr, rawHdr, err := tr.readHeader() if err != nil { return nil, err @@ -131,43 +82,58 @@ loop: if err := tr.handleRegularFile(hdr); err != nil { return nil, err } + format.mayOnlyBe(hdr.Format) // Check for PAX/GNU special headers and files. switch hdr.Typeflag { - case TypeXHeader: - extHdrs, err = parsePAX(tr) + case TypeXHeader, TypeXGlobalHeader: + format.mayOnlyBe(FormatPAX) + paxHdrs, err = parsePAX(tr) if err != nil { return nil, err } + if hdr.Typeflag == TypeXGlobalHeader { + mergePAX(hdr, paxHdrs) + return &Header{ + Name: hdr.Name, + Typeflag: hdr.Typeflag, + Xattrs: hdr.Xattrs, + PAXRecords: hdr.PAXRecords, + Format: format, + }, nil + } continue loop // This is a meta header affecting the next header case TypeGNULongName, TypeGNULongLink: + format.mayOnlyBe(FormatGNU) realname, err := ioutil.ReadAll(tr) if err != nil { return nil, err } - // Convert GNU extensions to use PAX headers. - if extHdrs == nil { - extHdrs = make(map[string]string) - } var p parser switch hdr.Typeflag { case TypeGNULongName: - extHdrs[paxPath] = p.parseString(realname) + gnuLongName = p.parseString(realname) case TypeGNULongLink: - extHdrs[paxLinkpath] = p.parseString(realname) - } - if p.err != nil { - return nil, p.err + gnuLongLink = p.parseString(realname) } continue loop // This is a meta header affecting the next header default: // The old GNU sparse format is handled here since it is technically // just a regular file with additional attributes. - if err := mergePAX(hdr, extHdrs); err != nil { + if err := mergePAX(hdr, paxHdrs); err != nil { return nil, err } + if gnuLongName != "" { + hdr.Name = gnuLongName + } + if gnuLongLink != "" { + hdr.Linkname = gnuLongLink + } + if hdr.Typeflag == TypeRegA && strings.HasSuffix(hdr.Name, "/") { + hdr.Typeflag = TypeDir // Legacy archives use trailing slash for directories + } // The extended headers may have updated the size. // Thus, setup the regFileReader again after merging PAX headers. @@ -177,9 +143,15 @@ loop: // Sparse formats rely on being able to read from the logical data // section; there must be a preceding call to handleRegularFile. - if err := tr.handleSparseFile(hdr, rawHdr, extHdrs); err != nil { + if err := tr.handleSparseFile(hdr, rawHdr); err != nil { return nil, err } + + // Set the final guess at the format. + if format.has(FormatUSTAR) && format.has(FormatPAX) { + format.mayOnlyBe(FormatUSTAR) + } + hdr.Format = format return hdr, nil // This is a file, so stop } } @@ -197,105 +169,86 @@ func (tr *Reader) handleRegularFile(hdr *Header) error { return ErrHeader } - tr.pad = -nb & (blockSize - 1) // blockSize is a power of two + tr.pad = blockPadding(nb) tr.curr = ®FileReader{r: tr.r, nb: nb} return nil } // handleSparseFile checks if the current file is a sparse format of any type // and sets the curr reader appropriately. -func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[string]string) error { - var sp []sparseEntry +func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block) error { + var spd sparseDatas var err error if hdr.Typeflag == TypeGNUSparse { - sp, err = tr.readOldGNUSparseMap(hdr, rawHdr) - if err != nil { - return err - } + spd, err = tr.readOldGNUSparseMap(hdr, rawHdr) } else { - sp, err = tr.checkForGNUSparsePAXHeaders(hdr, extHdrs) - if err != nil { - return err - } + spd, err = tr.readGNUSparsePAXHeaders(hdr) } // If sp is non-nil, then this is a sparse file. - // Note that it is possible for len(sp) to be zero. - if sp != nil { - tr.curr, err = newSparseFileReader(tr.curr, sp, hdr.Size) + // Note that it is possible for len(sp) == 0. + if err == nil && spd != nil { + if isHeaderOnlyType(hdr.Typeflag) || !validateSparseEntries(spd, hdr.Size) { + return ErrHeader + } + sph := invertSparseEntries(spd, hdr.Size) + tr.curr = &sparseFileReader{tr.curr, sph, 0} } return 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, 64) +// readGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. +// If they are found, then this function reads the sparse map and returns it. +// This assumes that 0.0 headers have already been converted to 0.1 headers +// by the the PAX header parsing logic. +func (tr *Reader) readGNUSparsePAXHeaders(hdr *Header) (sparseDatas, error) { + // Identify the version of GNU headers. + var is1x0 bool + major, minor := hdr.PAXRecords[paxGNUSparseMajor], hdr.PAXRecords[paxGNUSparseMinor] + switch { + case major == "0" && (minor == "0" || minor == "1"): + is1x0 = false + case major == "1" && minor == "0": + is1x0 = true + case major != "" || minor != "": + return nil, nil // Unknown GNU sparse PAX version + case hdr.PAXRecords[paxGNUSparseMap] != "": + is1x0 = false // 0.0 and 0.1 did not have explicit version records, so guess + default: + return nil, nil // Not a PAX format GNU sparse file. + } + hdr.Format.mayOnlyBe(FormatPAX) + + // Update hdr from GNU sparse PAX headers. + if name := hdr.PAXRecords[paxGNUSparseName]; name != "" { + hdr.Name = name + } + size := hdr.PAXRecords[paxGNUSparseSize] + if size == "" { + size = hdr.PAXRecords[paxGNUSparseRealSize] + } + if size != "" { + n, err := strconv.ParseInt(size, 10, 64) if err != nil { return nil, ErrHeader } - hdr.Size = realSize - } else if sparseRealSizeOk { - realSize, err := strconv.ParseInt(sparseRealSize, 10, 64) - if err != nil { - return nil, ErrHeader - } - hdr.Size = realSize + hdr.Size = n } - // 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) + // Read the sparse map according to the appropriate format. + if is1x0 { + return readGNUSparseMap1x0(tr.curr) } - return sp, err + return readGNUSparseMap0x1(hdr.PAXRecords) } -// 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 -// struct with higher precision or longer values. Esp. useful -// for name and linkname fields. -func mergePAX(hdr *Header, headers map[string]string) (err error) { - var id64 int64 - for k, v := range headers { +// mergePAX merges paxHdrs into hdr for all relevant fields of Header. +func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { + for k, v := range paxHdrs { + if v == "" { + continue // Keep the original USTAR value + } + var id64 int64 switch k { case paxPath: hdr.Name = v @@ -320,17 +273,18 @@ func mergePAX(hdr *Header, headers map[string]string) (err error) { case paxSize: hdr.Size, err = strconv.ParseInt(v, 10, 64) default: - if strings.HasPrefix(k, paxXattr) { + if strings.HasPrefix(k, paxSchilyXattr) { if hdr.Xattrs == nil { hdr.Xattrs = make(map[string]string) } - hdr.Xattrs[k[len(paxXattr):]] = v + hdr.Xattrs[k[len(paxSchilyXattr):]] = v } } if err != nil { return ErrHeader } } + hdr.PAXRecords = paxHdrs return nil } @@ -348,7 +302,7 @@ func parsePAX(r io.Reader) (map[string]string, error) { // headers since 0.0 headers were not PAX compliant. var sparseMap []string - extHdrs := make(map[string]string) + paxHdrs := make(map[string]string) for len(sbuf) > 0 { key, value, residual, err := parsePAXRecord(sbuf) if err != nil { @@ -366,58 +320,13 @@ func parsePAX(r io.Reader) (map[string]string, error) { } sparseMap = append(sparseMap, value) default: - // According to PAX specification, a value is stored only if it is - // non-empty. Otherwise, the key is deleted. - if len(value) > 0 { - extHdrs[key] = value - } else { - delete(extHdrs, key) - } + paxHdrs[key] = value } } if len(sparseMap) > 0 { - extHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",") + paxHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",") } - return extHdrs, nil -} - -// skipUnread skips any unread bytes in the existing file entry, as well as any -// alignment padding. It returns io.ErrUnexpectedEOF if any io.EOF is -// encountered in the data portion; it is okay to hit io.EOF in the padding. -// -// Note that this function still works properly even when sparse files are being -// used since numBytes returns the bytes remaining in the underlying io.Reader. -func (tr *Reader) skipUnread() error { - dataSkip := tr.numBytes() // Number of data bytes to skip - totalSkip := dataSkip + tr.pad // Total number of bytes to skip - tr.curr, tr.pad = nil, 0 - - // If possible, Seek to the last byte before the end of the data section. - // Do this because Seek is often lazy about reporting errors; this will mask - // the fact that the tar stream may be truncated. We can rely on the - // io.CopyN done shortly afterwards to trigger any IO errors. - var seekSkipped int64 // Number of bytes skipped via Seek - if sr, ok := tr.r.(io.Seeker); ok && dataSkip > 1 { - // Not all io.Seeker can actually Seek. For example, os.Stdin implements - // io.Seeker, but calling Seek always returns an error and performs - // no action. Thus, we try an innocent seek to the current position - // to see if Seek is really supported. - pos1, err := sr.Seek(0, io.SeekCurrent) - if err == nil { - // Seek seems supported, so perform the real Seek. - pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent) - if err != nil { - return err - } - seekSkipped = pos2 - pos1 - } - } - - copySkipped, err := io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped) - if err == io.EOF && seekSkipped+copySkipped < dataSkip { - err = io.ErrUnexpectedEOF - } - return err + return paxHdrs, nil } // readHeader reads the next block header and assumes that the underlying reader @@ -445,7 +354,7 @@ func (tr *Reader) readHeader() (*Header, *block, error) { // Verify the header matches a known format. format := tr.blk.GetFormat() - if format == formatUnknown { + if format == FormatUnknown { return nil, nil, ErrHeader } @@ -454,59 +363,86 @@ func (tr *Reader) readHeader() (*Header, *block, error) { // Unpack the V7 header. v7 := tr.blk.V7() + hdr.Typeflag = v7.TypeFlag()[0] hdr.Name = p.parseString(v7.Name()) + hdr.Linkname = p.parseString(v7.LinkName()) + hdr.Size = p.parseNumeric(v7.Size()) hdr.Mode = p.parseNumeric(v7.Mode()) hdr.Uid = int(p.parseNumeric(v7.UID())) hdr.Gid = int(p.parseNumeric(v7.GID())) - hdr.Size = p.parseNumeric(v7.Size()) hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0) - hdr.Typeflag = v7.TypeFlag()[0] - hdr.Linkname = p.parseString(v7.LinkName()) - - // The atime and ctime fields are often left unused. Some versions of Go - // had a bug in the tar.Writer where it would output an invalid tar file - // in certain rare situations because the logic incorrectly believed that - // the old GNU format had a prefix field. This is wrong and leads to - // an outputted file that actually mangles the atime and ctime fields. - // - // In order to continue reading tar files created by a buggy writer, we - // try to parse the atime and ctime fields, but just return the zero value - // of time.Time when we cannot parse them. - // - // See https://golang.org/issues/12594 - tryParseTime := func(b []byte) time.Time { - var p parser - n := p.parseNumeric(b) - if b[0] != 0x00 && p.err == nil { - return time.Unix(n, 0) - } - return time.Time{} - } // Unpack format specific fields. if format > formatV7 { ustar := tr.blk.USTAR() hdr.Uname = p.parseString(ustar.UserName()) hdr.Gname = p.parseString(ustar.GroupName()) - if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock { - hdr.Devmajor = p.parseNumeric(ustar.DevMajor()) - hdr.Devminor = p.parseNumeric(ustar.DevMinor()) - } + hdr.Devmajor = p.parseNumeric(ustar.DevMajor()) + hdr.Devminor = p.parseNumeric(ustar.DevMinor()) var prefix string - switch format { - case formatUSTAR: + switch { + case format.has(FormatUSTAR | FormatPAX): + hdr.Format = format ustar := tr.blk.USTAR() prefix = p.parseString(ustar.Prefix()) - case formatSTAR: + + // For Format detection, check if block is properly formatted since + // the parser is more liberal than what USTAR actually permits. + notASCII := func(r rune) bool { return r >= 0x80 } + if bytes.IndexFunc(tr.blk[:], notASCII) >= 0 { + hdr.Format = FormatUnknown // Non-ASCII characters in block. + } + nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 } + if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) && + nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) { + hdr.Format = FormatUnknown // Numeric fields must end in NUL + } + case format.has(formatSTAR): star := tr.blk.STAR() prefix = p.parseString(star.Prefix()) hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0) hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0) - case formatGNU: + case format.has(FormatGNU): + hdr.Format = format + var p2 parser gnu := tr.blk.GNU() - hdr.AccessTime = tryParseTime(gnu.AccessTime()) - hdr.ChangeTime = tryParseTime(gnu.ChangeTime()) + if b := gnu.AccessTime(); b[0] != 0 { + hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0) + } + if b := gnu.ChangeTime(); b[0] != 0 { + hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0) + } + + // Prior to Go1.8, the Writer had a bug where it would output + // an invalid tar file in certain rare situations because the logic + // incorrectly believed that the old GNU format had a prefix field. + // This is wrong and leads to an output file that mangles the + // atime and ctime fields, which are often left unused. + // + // In order to continue reading tar files created by former, buggy + // versions of Go, we skeptically parse the atime and ctime fields. + // If we are unable to parse them and the prefix field looks like + // an ASCII string, then we fallback on the pre-Go1.8 behavior + // of treating these fields as the USTAR prefix field. + // + // Note that this will not use the fallback logic for all possible + // files generated by a pre-Go1.8 toolchain. If the generated file + // happened to have a prefix field that parses as valid + // atime and ctime fields (e.g., when they are valid octal strings), + // then it is impossible to distinguish between an valid GNU file + // and an invalid pre-Go1.8 file. + // + // See https://golang.org/issues/12594 + // See https://golang.org/issues/21005 + if p2.err != nil { + hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{} + ustar := tr.blk.USTAR() + if s := p.parseString(ustar.Prefix()); isASCII(s) { + prefix = s + } + hdr.Format = FormatUnknown // Buggy file is not GNU + } } if len(prefix) > 0 { hdr.Name = prefix + "/" + hdr.Name @@ -523,21 +459,22 @@ func (tr *Reader) readHeader() (*Header, *block, error) { // The Header.Size does not reflect the size of any extended headers used. // Thus, this function will read from the raw io.Reader to fetch extra headers. // This method mutates blk in the process. -func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) { +func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, error) { // Make sure that the input format is GNU. // Unfortunately, the STAR format also has a sparse header format that uses // the same type flag but has a completely different layout. - if blk.GetFormat() != formatGNU { + if blk.GetFormat() != FormatGNU { return nil, ErrHeader } + hdr.Format.mayOnlyBe(FormatGNU) var p parser hdr.Size = p.parseNumeric(blk.GNU().RealSize()) if p.err != nil { return nil, p.err } - var s sparseArray = blk.GNU().Sparse() - var sp = make([]sparseEntry, 0, s.MaxEntries()) + s := blk.GNU().Sparse() + spd := make(sparseDatas, 0, s.MaxEntries()) for { for i := 0; i < s.MaxEntries(); i++ { // This termination condition is identical to GNU and BSD tar. @@ -545,25 +482,22 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, e break // Don't return, need to process extended headers (even if empty) } offset := p.parseNumeric(s.Entry(i).Offset()) - numBytes := p.parseNumeric(s.Entry(i).NumBytes()) + length := p.parseNumeric(s.Entry(i).Length()) if p.err != nil { return nil, p.err } - sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + spd = append(spd, sparseEntry{Offset: offset, Length: length}) } if s.IsExtended()[0] > 0 { // There are more entries. Read an extension header and parse its entries. - if _, err := io.ReadFull(tr.r, blk[:]); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } + if _, err := mustReadFull(tr.r, blk[:]); err != nil { return nil, err } s = blk.Sparse() continue } - return sp, nil // Done + return spd, nil // Done } } @@ -571,28 +505,27 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, e // version 1.0. The format of the sparse map consists of a series of // newline-terminated numeric fields. The first field is the number of entries // and is always present. Following this are the entries, consisting of two -// fields (offset, numBytes). This function must stop reading at the end +// fields (offset, length). This function must stop reading at the end // boundary of the block containing the last newline. // // Note that the GNU manual says that numeric values should be encoded in octal // format. However, the GNU tar utility itself outputs these values in decimal. // As such, this library treats values as being encoded in decimal. -func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { - var cntNewline int64 - var buf bytes.Buffer - var blk = make([]byte, blockSize) - - // feedTokens copies data in numBlock chunks from r into buf until there are +func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) { + var ( + cntNewline int64 + buf bytes.Buffer + blk block + ) + + // feedTokens copies data in blocks from r into buf until there are // at least cnt newlines in buf. It will not read more blocks than needed. - var feedTokens = func(cnt int64) error { - for cntNewline < cnt { - if _, err := io.ReadFull(r, blk); err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } + feedTokens := func(n int64) error { + for cntNewline < n { + if _, err := mustReadFull(r, blk[:]); err != nil { return err } - buf.Write(blk) + buf.Write(blk[:]) for _, c := range blk { if c == '\n' { cntNewline++ @@ -604,10 +537,10 @@ func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { // nextToken gets the next token delimited by a newline. This assumes that // at least one newline exists in the buffer. - var nextToken = func() string { + nextToken := func() string { cntNewline-- tok, _ := buf.ReadString('\n') - return tok[:len(tok)-1] // Cut off newline + return strings.TrimRight(tok, "\n") } // Parse for the number of entries. @@ -626,80 +559,67 @@ func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { if err := feedTokens(2 * numEntries); err != nil { return nil, err } - sp := make([]sparseEntry, 0, numEntries) + spd := make(sparseDatas, 0, numEntries) for i := int64(0); i < numEntries; i++ { - offset, err := strconv.ParseInt(nextToken(), 10, 64) - if err != nil { - return nil, ErrHeader - } - numBytes, err := strconv.ParseInt(nextToken(), 10, 64) - if err != nil { + offset, err1 := strconv.ParseInt(nextToken(), 10, 64) + length, err2 := strconv.ParseInt(nextToken(), 10, 64) + if err1 != nil || err2 != nil { return nil, ErrHeader } - sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + spd = append(spd, sparseEntry{Offset: offset, Length: length}) } - return sp, nil + return spd, 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(extHdrs map[string]string) ([]sparseEntry, error) { +func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) { // Get number of entries. // Use integer overflow resistant math to check this. - numEntriesStr := extHdrs[paxGNUSparseNumBlocks] + numEntriesStr := paxHdrs[paxGNUSparseNumBlocks] numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) { return nil, ErrHeader } // There should be two numbers in sparseMap for each entry. - sparseMap := strings.Split(extHdrs[paxGNUSparseMap], ",") + sparseMap := strings.Split(paxHdrs[paxGNUSparseMap], ",") + if len(sparseMap) == 1 && sparseMap[0] == "" { + sparseMap = sparseMap[:0] + } if int64(len(sparseMap)) != 2*numEntries { return nil, ErrHeader } // Loop through the entries in the sparse map. // numEntries is trusted now. - sp := make([]sparseEntry, 0, numEntries) - for i := int64(0); i < numEntries; i++ { - offset, err := strconv.ParseInt(sparseMap[2*i], 10, 64) - if err != nil { - return nil, ErrHeader - } - numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 64) - if err != nil { + spd := make(sparseDatas, 0, numEntries) + for len(sparseMap) >= 2 { + offset, err1 := strconv.ParseInt(sparseMap[0], 10, 64) + length, err2 := strconv.ParseInt(sparseMap[1], 10, 64) + if err1 != nil || err2 != nil { return nil, ErrHeader } - sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + spd = append(spd, sparseEntry{Offset: offset, Length: length}) + sparseMap = sparseMap[2:] } - return sp, nil + return spd, 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. +// Read reads from the current file in the tar archive. +// It returns (0, io.EOF) when it reaches the end of that file, +// until Next is called to advance to the next file. // -// Calling Read on special types like TypeLink, TypeSymLink, TypeChar, -// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what +// If the current file is sparse, then the regions marked as a hole +// are read back as NUL-bytes. +// +// Calling Read on special types like TypeLink, TypeSymlink, TypeChar, +// TypeBlock, TypeDir, and TypeFifo returns (0, io.EOF) regardless of what // the Header.Size claims. func (tr *Reader) Read(b []byte) (int, error) { if tr.err != nil { return 0, tr.err } - if tr.curr == nil { - return 0, io.EOF - } - n, err := tr.curr.Read(b) if err != nil && err != io.EOF { tr.err = err @@ -707,116 +627,229 @@ func (tr *Reader) Read(b []byte) (int, error) { return n, err } -func (rfr *regFileReader) Read(b []byte) (n int, err error) { - if rfr.nb == 0 { - // file consumed - return 0, io.EOF +// writeTo writes the content of the current file to w. +// The bytes written matches the number of remaining bytes in the current file. +// +// If the current file is sparse and w is an io.WriteSeeker, +// then writeTo uses Seek to skip past holes defined in Header.SparseHoles, +// assuming that skipped regions are filled with NULs. +// This always writes the last byte to ensure w is the right size. +// +// TODO(dsnet): Re-export this when adding sparse file support. +// See https://golang.org/issue/22735 +func (tr *Reader) writeTo(w io.Writer) (int64, error) { + if tr.err != nil { + return 0, tr.err } - if int64(len(b)) > rfr.nb { - b = b[0:rfr.nb] + n, err := tr.curr.WriteTo(w) + if err != nil { + tr.err = err } - n, err = rfr.r.Read(b) - rfr.nb -= int64(n) + return n, err +} - if err == io.EOF && rfr.nb > 0 { - err = io.ErrUnexpectedEOF +// regFileReader is a fileReader for reading data from a regular file entry. +type regFileReader struct { + r io.Reader // Underlying Reader + nb int64 // Number of remaining bytes to read +} + +func (fr *regFileReader) Read(b []byte) (n int, err error) { + if int64(len(b)) > fr.nb { + b = b[:fr.nb] + } + if len(b) > 0 { + n, err = fr.r.Read(b) + fr.nb -= int64(n) + } + switch { + case err == io.EOF && fr.nb > 0: + return n, io.ErrUnexpectedEOF + case err == nil && fr.nb == 0: + return n, io.EOF + default: + return n, 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 +func (fr *regFileReader) WriteTo(w io.Writer) (int64, error) { + return io.Copy(w, struct{ io.Reader }{fr}) } -// newSparseFileReader creates a new sparseFileReader, but validates all of the -// sparse entries before doing so. -func newSparseFileReader(rfr numBytesReader, sp []sparseEntry, total int64) (*sparseFileReader, error) { - if total < 0 { - return nil, ErrHeader // Total size cannot be negative - } +func (fr regFileReader) LogicalRemaining() int64 { + return fr.nb +} - // Validate all sparse entries. These are the same checks as performed by - // the BSD tar utility. - for i, s := range sp { - switch { - case s.offset < 0 || s.numBytes < 0: - return nil, ErrHeader // Negative values are never okay - case s.offset > math.MaxInt64-s.numBytes: - return nil, ErrHeader // Integer overflow with large length - case s.offset+s.numBytes > total: - return nil, ErrHeader // Region extends beyond the "real" size - case i > 0 && sp[i-1].offset+sp[i-1].numBytes > s.offset: - return nil, ErrHeader // Regions can't overlap and must be in order - } - } - return &sparseFileReader{rfr: rfr, sp: sp, total: total}, nil +func (fr regFileReader) PhysicalRemaining() int64 { + return fr.nb +} + +// sparseFileReader is a fileReader for reading data from a sparse file entry. +type sparseFileReader struct { + fr fileReader // Underlying fileReader + sp sparseHoles // Normalized list of sparse holes + pos int64 // Current position in sparse file } -// readHole reads a sparse hole ending at endOffset. -func (sfr *sparseFileReader) readHole(b []byte, endOffset int64) int { - n64 := endOffset - sfr.pos - if n64 > int64(len(b)) { - n64 = int64(len(b)) +func (sr *sparseFileReader) Read(b []byte) (n int, err error) { + finished := int64(len(b)) >= sr.LogicalRemaining() + if finished { + b = b[:sr.LogicalRemaining()] + } + + b0 := b + endPos := sr.pos + int64(len(b)) + for endPos > sr.pos && err == nil { + var nf int // Bytes read in fragment + holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset() + if sr.pos < holeStart { // In a data fragment + bf := b[:min(int64(len(b)), holeStart-sr.pos)] + nf, err = tryReadFull(sr.fr, bf) + } else { // In a hole fragment + bf := b[:min(int64(len(b)), holeEnd-sr.pos)] + nf, err = tryReadFull(zeroReader{}, bf) + } + b = b[nf:] + sr.pos += int64(nf) + if sr.pos >= holeEnd && len(sr.sp) > 1 { + sr.sp = sr.sp[1:] // Ensure last fragment always remains + } } - n := int(n64) - for i := 0; i < n; i++ { - b[i] = 0 + + n = len(b0) - len(b) + switch { + case err == io.EOF: + return n, errMissData // Less data in dense file than sparse file + case err != nil: + return n, err + case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0: + return n, errUnrefData // More data in dense file than sparse file + case finished: + return n, io.EOF + default: + return n, nil } - sfr.pos += n64 - return n } -// Read reads the sparse file data in expanded form. -func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { - // Skip past all empty fragments. - for len(sfr.sp) > 0 && sfr.sp[0].numBytes == 0 { - sfr.sp = sfr.sp[1:] +func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) { + ws, ok := w.(io.WriteSeeker) + if ok { + if _, err := ws.Seek(0, io.SeekCurrent); err != nil { + ok = false // Not all io.Seeker can really seek + } } - - // If there are no more fragments, then it is possible that there - // is one last sparse hole. - if len(sfr.sp) == 0 { - // This behavior matches the BSD tar utility. - // However, GNU tar stops returning data even if sfr.total is unmet. - if sfr.pos < sfr.total { - return sfr.readHole(b, sfr.total), nil + if !ok { + return io.Copy(w, struct{ io.Reader }{sr}) + } + + var writeLastByte bool + pos0 := sr.pos + for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil { + var nf int64 // Size of fragment + holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset() + if sr.pos < holeStart { // In a data fragment + nf = holeStart - sr.pos + nf, err = io.CopyN(ws, sr.fr, nf) + } else { // In a hole fragment + nf = holeEnd - sr.pos + if sr.PhysicalRemaining() == 0 { + writeLastByte = true + nf-- + } + _, err = ws.Seek(nf, io.SeekCurrent) } - return 0, io.EOF + sr.pos += nf + if sr.pos >= holeEnd && len(sr.sp) > 1 { + sr.sp = sr.sp[1:] // Ensure last fragment always remains + } + } + + // If the last fragment is a hole, then seek to 1-byte before EOF, and + // write a single byte to ensure the file is the right size. + if writeLastByte && err == nil { + _, err = ws.Write([]byte{0}) + sr.pos++ } - // In front of a data fragment, so read a hole. - if sfr.pos < sfr.sp[0].offset { - return sfr.readHole(b, sfr.sp[0].offset), nil + n = sr.pos - pos0 + switch { + case err == io.EOF: + return n, errMissData // Less data in dense file than sparse file + case err != nil: + return n, err + case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0: + return n, errUnrefData // More data in dense file than sparse file + default: + return n, nil } +} + +func (sr sparseFileReader) LogicalRemaining() int64 { + return sr.sp[len(sr.sp)-1].endOffset() - sr.pos +} +func (sr sparseFileReader) PhysicalRemaining() int64 { + return sr.fr.PhysicalRemaining() +} + +type zeroReader struct{} - // In a data fragment, so read from it. - // This math is overflow free since we verify that offset and numBytes can - // be safely added when creating the sparseFileReader. - endPos := sfr.sp[0].offset + sfr.sp[0].numBytes // End offset of fragment - bytesLeft := endPos - sfr.pos // Bytes left in fragment - if int64(len(b)) > bytesLeft { - b = b[:bytesLeft] +func (zeroReader) Read(b []byte) (int, error) { + for i := range b { + b[i] = 0 } + return len(b), nil +} - n, err = sfr.rfr.Read(b) - sfr.pos += int64(n) +// mustReadFull is like io.ReadFull except it returns +// io.ErrUnexpectedEOF when io.EOF is hit before len(b) bytes are read. +func mustReadFull(r io.Reader, b []byte) (int, error) { + n, err := tryReadFull(r, b) if err == io.EOF { - if sfr.pos < endPos { - err = io.ErrUnexpectedEOF // There was supposed to be more data - } else if sfr.pos < sfr.total { - err = nil // There is still an implicit sparse hole at the end - } + err = io.ErrUnexpectedEOF } + return n, err +} - if sfr.pos == endPos { - sfr.sp = sfr.sp[1:] // We are done with this fragment, so pop it +// tryReadFull is like io.ReadFull except it returns +// io.EOF when it is hit before len(b) bytes are read. +func tryReadFull(r io.Reader, b []byte) (n int, err error) { + for len(b) > n && err == nil { + var nn int + nn, err = r.Read(b[n:]) + n += nn + } + if len(b) == n && err == io.EOF { + err = nil } return n, err } -// 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.numBytes() +// discard skips n bytes in r, reporting an error if unable to do so. +func discard(r io.Reader, n int64) error { + // If possible, Seek to the last byte before the end of the data section. + // Do this because Seek is often lazy about reporting errors; this will mask + // the fact that the stream may be truncated. We can rely on the + // io.CopyN done shortly afterwards to trigger any IO errors. + var seekSkipped int64 // Number of bytes skipped via Seek + if sr, ok := r.(io.Seeker); ok && n > 1 { + // Not all io.Seeker can actually Seek. For example, os.Stdin implements + // io.Seeker, but calling Seek always returns an error and performs + // no action. Thus, we try an innocent seek to the current position + // to see if Seek is really supported. + pos1, err := sr.Seek(0, io.SeekCurrent) + if pos1 >= 0 && err == nil { + // Seek seems supported, so perform the real Seek. + pos2, err := sr.Seek(n-1, io.SeekCurrent) + if pos2 < 0 || err != nil { + return err + } + seekSkipped = pos2 - pos1 + } + } + + copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped) + if err == io.EOF && seekSkipped+copySkipped < n { + err = io.ErrUnexpectedEOF + } + return err } diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go index 338686836b6..a6832d33b1b 100644 --- a/libgo/go/archive/tar/reader_test.go +++ b/libgo/go/archive/tar/reader_test.go @@ -7,12 +7,15 @@ package tar import ( "bytes" "crypto/md5" + "errors" "fmt" "io" "io/ioutil" "math" "os" + "path" "reflect" + "strconv" "strings" "testing" "time" @@ -36,6 +39,7 @@ func TestReader(t *testing.T) { Typeflag: '0', Uname: "dsymonds", Gname: "eng", + Format: FormatGNU, }, { Name: "small2.txt", Mode: 0640, @@ -46,6 +50,7 @@ func TestReader(t *testing.T) { Typeflag: '0', Uname: "dsymonds", Gname: "eng", + Format: FormatGNU, }}, chksums: []string{ "e38b27eaccb4391bdec553a7f3ae6b2f", @@ -66,6 +71,7 @@ func TestReader(t *testing.T) { Gname: "david", Devmajor: 0, Devminor: 0, + Format: FormatGNU, }, { Name: "sparse-posix-0.0", Mode: 420, @@ -79,6 +85,12 @@ func TestReader(t *testing.T) { Gname: "david", Devmajor: 0, Devminor: 0, + PAXRecords: map[string]string{ + "GNU.sparse.size": "200", + "GNU.sparse.numblocks": "95", + "GNU.sparse.map": "1,1,3,1,5,1,7,1,9,1,11,1,13,1,15,1,17,1,19,1,21,1,23,1,25,1,27,1,29,1,31,1,33,1,35,1,37,1,39,1,41,1,43,1,45,1,47,1,49,1,51,1,53,1,55,1,57,1,59,1,61,1,63,1,65,1,67,1,69,1,71,1,73,1,75,1,77,1,79,1,81,1,83,1,85,1,87,1,89,1,91,1,93,1,95,1,97,1,99,1,101,1,103,1,105,1,107,1,109,1,111,1,113,1,115,1,117,1,119,1,121,1,123,1,125,1,127,1,129,1,131,1,133,1,135,1,137,1,139,1,141,1,143,1,145,1,147,1,149,1,151,1,153,1,155,1,157,1,159,1,161,1,163,1,165,1,167,1,169,1,171,1,173,1,175,1,177,1,179,1,181,1,183,1,185,1,187,1,189,1", + }, + Format: FormatPAX, }, { Name: "sparse-posix-0.1", Mode: 420, @@ -92,6 +104,13 @@ func TestReader(t *testing.T) { Gname: "david", Devmajor: 0, Devminor: 0, + PAXRecords: map[string]string{ + "GNU.sparse.size": "200", + "GNU.sparse.numblocks": "95", + "GNU.sparse.map": "1,1,3,1,5,1,7,1,9,1,11,1,13,1,15,1,17,1,19,1,21,1,23,1,25,1,27,1,29,1,31,1,33,1,35,1,37,1,39,1,41,1,43,1,45,1,47,1,49,1,51,1,53,1,55,1,57,1,59,1,61,1,63,1,65,1,67,1,69,1,71,1,73,1,75,1,77,1,79,1,81,1,83,1,85,1,87,1,89,1,91,1,93,1,95,1,97,1,99,1,101,1,103,1,105,1,107,1,109,1,111,1,113,1,115,1,117,1,119,1,121,1,123,1,125,1,127,1,129,1,131,1,133,1,135,1,137,1,139,1,141,1,143,1,145,1,147,1,149,1,151,1,153,1,155,1,157,1,159,1,161,1,163,1,165,1,167,1,169,1,171,1,173,1,175,1,177,1,179,1,181,1,183,1,185,1,187,1,189,1", + "GNU.sparse.name": "sparse-posix-0.1", + }, + Format: FormatPAX, }, { Name: "sparse-posix-1.0", Mode: 420, @@ -105,6 +124,13 @@ func TestReader(t *testing.T) { Gname: "david", Devmajor: 0, Devminor: 0, + PAXRecords: map[string]string{ + "GNU.sparse.major": "1", + "GNU.sparse.minor": "0", + "GNU.sparse.realsize": "200", + "GNU.sparse.name": "sparse-posix-1.0", + }, + Format: FormatPAX, }, { Name: "end", Mode: 420, @@ -118,6 +144,7 @@ func TestReader(t *testing.T) { Gname: "david", Devmajor: 0, Devminor: 0, + Format: FormatGNU, }}, chksums: []string{ "6f53234398c2449fe67c1812d993012f", @@ -186,6 +213,13 @@ func TestReader(t *testing.T) { ChangeTime: time.Unix(1350244992, 23960108), AccessTime: time.Unix(1350244992, 23960108), Typeflag: TypeReg, + PAXRecords: map[string]string{ + "path": "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", + "mtime": "1350244992.023960108", + "atime": "1350244992.023960108", + "ctime": "1350244992.023960108", + }, + Format: FormatPAX, }, { Name: "a/b", Mode: 0777, @@ -199,6 +233,13 @@ func TestReader(t *testing.T) { AccessTime: time.Unix(1350266320, 910238425), Typeflag: TypeSymlink, Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", + PAXRecords: map[string]string{ + "linkpath": "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", + "mtime": "1350266320.910238425", + "atime": "1350266320.910238425", + "ctime": "1350266320.910238425", + }, + Format: FormatPAX, }}, }, { file: "testdata/pax-bad-hdr-file.tar", @@ -218,10 +259,63 @@ func TestReader(t *testing.T) { Typeflag: '0', Uname: "joetsai", Gname: "eng", + PAXRecords: map[string]string{ + "size": "000000000000000000000999", + }, + Format: FormatPAX, }}, chksums: []string{ "0afb597b283fe61b5d4879669a350556", }, + }, { + file: "testdata/pax-records.tar", + headers: []*Header{{ + Typeflag: TypeReg, + Name: "file", + Uname: strings.Repeat("long", 10), + ModTime: time.Unix(0, 0), + PAXRecords: map[string]string{ + "GOLANG.pkg": "tar", + "comment": "Hello, 世界", + "uname": strings.Repeat("long", 10), + }, + Format: FormatPAX, + }}, + }, { + file: "testdata/pax-global-records.tar", + headers: []*Header{{ + Typeflag: TypeXGlobalHeader, + Name: "global1", + PAXRecords: map[string]string{"path": "global1", "mtime": "1500000000.0"}, + Format: FormatPAX, + }, { + Typeflag: TypeReg, + Name: "file1", + ModTime: time.Unix(0, 0), + Format: FormatUSTAR, + }, { + Typeflag: TypeReg, + Name: "file2", + PAXRecords: map[string]string{"path": "file2"}, + ModTime: time.Unix(0, 0), + Format: FormatPAX, + }, { + Typeflag: TypeXGlobalHeader, + Name: "GlobalHead.0.0", + PAXRecords: map[string]string{"path": ""}, + Format: FormatPAX, + }, { + Typeflag: TypeReg, + Name: "file3", + ModTime: time.Unix(0, 0), + Format: FormatUSTAR, + }, { + Typeflag: TypeReg, + Name: "file4", + ModTime: time.Unix(1400000000, 0), + PAXRecords: map[string]string{"mtime": "1400000000"}, + Format: FormatPAX, + }}, }, { file: "testdata/nil-uid.tar", // golang.org/issue/5290 headers: []*Header{{ @@ -237,6 +331,7 @@ func TestReader(t *testing.T) { Gname: "eyefi", Devmajor: 0, Devminor: 0, + Format: FormatGNU, }}, }, { file: "testdata/xattrs.tar", @@ -258,6 +353,15 @@ func TestReader(t *testing.T) { // Interestingly, selinux encodes the terminating null inside the xattr "security.selinux": "unconfined_u:object_r:default_t:s0\x00", }, + PAXRecords: map[string]string{ + "mtime": "1386065770.44825232", + "atime": "1389782991.41987522", + "ctime": "1389782956.794414986", + "SCHILY.xattr.user.key": "value", + "SCHILY.xattr.user.key2": "value2", + "SCHILY.xattr.security.selinux": "unconfined_u:object_r:default_t:s0\x00", + }, + Format: FormatPAX, }, { Name: "small2.txt", Mode: 0644, @@ -273,6 +377,13 @@ func TestReader(t *testing.T) { Xattrs: map[string]string{ "security.selinux": "unconfined_u:object_r:default_t:s0\x00", }, + PAXRecords: map[string]string{ + "mtime": "1386065770.449252304", + "atime": "1389782991.41987522", + "ctime": "1386065770.449252304", + "SCHILY.xattr.security.selinux": "unconfined_u:object_r:default_t:s0\x00", + }, + Format: FormatPAX, }}, }, { // Matches the behavior of GNU, BSD, and STAR tar utilities. @@ -282,6 +393,7 @@ func TestReader(t *testing.T) { Linkname: "GNU4/GNU4/long-linkpath-name", ModTime: time.Unix(0, 0), Typeflag: '2', + Format: FormatGNU, }}, }, { // GNU tar file with atime and ctime fields set. @@ -300,6 +412,7 @@ func TestReader(t *testing.T) { Gname: "dsnet", AccessTime: time.Unix(1441974501, 0), ChangeTime: time.Unix(1441973436, 0), + Format: FormatGNU, }, { Name: "test2/foo", Mode: 33188, @@ -312,6 +425,7 @@ func TestReader(t *testing.T) { Gname: "dsnet", AccessTime: time.Unix(1441974501, 0), ChangeTime: time.Unix(1441973436, 0), + Format: FormatGNU, }, { Name: "test2/sparse", Mode: 33188, @@ -324,6 +438,7 @@ func TestReader(t *testing.T) { Gname: "dsnet", AccessTime: time.Unix(1441991948, 0), ChangeTime: time.Unix(1441973436, 0), + Format: FormatGNU, }}, }, { // Matches the behavior of GNU and BSD tar utilities. @@ -333,7 +448,75 @@ func TestReader(t *testing.T) { Linkname: "PAX4/PAX4/long-linkpath-name", ModTime: time.Unix(0, 0), Typeflag: '2', + PAXRecords: map[string]string{ + "linkpath": "PAX4/PAX4/long-linkpath-name", + }, + Format: FormatPAX, + }}, + }, { + // Both BSD and GNU tar truncate long names at first NUL even + // if there is data following that NUL character. + // This is reasonable as GNU long names are C-strings. + file: "testdata/gnu-long-nul.tar", + headers: []*Header{{ + Name: "0123456789", + Mode: 0644, + Uid: 1000, + Gid: 1000, + ModTime: time.Unix(1486082191, 0), + Typeflag: '0', + Uname: "rawr", + Gname: "dsnet", + Format: FormatGNU, }}, + }, { + // This archive was generated by Writer but is readable by both + // GNU and BSD tar utilities. + // The archive generated by GNU is nearly byte-for-byte identical + // to the Go version except the Go version sets a negative Devminor + // just to force the GNU format. + file: "testdata/gnu-utf8.tar", + headers: []*Header{{ + Name: "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹", + Mode: 0644, + Uid: 1000, Gid: 1000, + ModTime: time.Unix(0, 0), + Typeflag: '0', + Uname: "☺", + Gname: "⚹", + Format: FormatGNU, + }}, + }, { + // This archive was generated by Writer but is readable by both + // GNU and BSD tar utilities. + // The archive generated by GNU is nearly byte-for-byte identical + // to the Go version except the Go version sets a negative Devminor + // just to force the GNU format. + file: "testdata/gnu-not-utf8.tar", + headers: []*Header{{ + Name: "hi\x80\x81\x82\x83bye", + Mode: 0644, + Uid: 1000, + Gid: 1000, + ModTime: time.Unix(0, 0), + Typeflag: '0', + Uname: "rawr", + Gname: "dsnet", + Format: FormatGNU, + }}, + }, { + // BSD tar v3.1.2 and GNU tar v1.27.1 both rejects PAX records + // with NULs in the key. + file: "testdata/pax-nul-xattrs.tar", + err: ErrHeader, + }, { + // BSD tar v3.1.2 rejects a PAX path with NUL in the value, while + // GNU tar v1.27.1 simply truncates at first NUL. + // We emulate the behavior of BSD since it is strange doing NUL + // truncations since PAX records are length-prefix strings instead + // of NUL-terminated C-strings. + file: "testdata/pax-nul-path.tar", + err: ErrHeader, }, { file: "testdata/neg-size.tar", err: ErrHeader, @@ -346,483 +529,214 @@ func TestReader(t *testing.T) { }, { file: "testdata/issue12435.tar", err: ErrHeader, - }} - - for i, v := range vectors { - f, err := os.Open(v.file) - if err != nil { - t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err) - continue - } - defer f.Close() - - // Capture all headers and checksums. - var ( - tr = NewReader(f) - hdrs []*Header - chksums []string - rdbuf = make([]byte, 8) - ) - for { - var hdr *Header - hdr, err = tr.Next() - if err != nil { - if err == io.EOF { - err = nil // Expected error - } - break - } - hdrs = append(hdrs, hdr) - - if v.chksums == nil { - continue - } - h := md5.New() - _, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read - if err != nil { - break - } - chksums = append(chksums, fmt.Sprintf("%x", h.Sum(nil))) - } - - for j, hdr := range hdrs { - if j >= len(v.headers) { - t.Errorf("file %s, test %d, entry %d: unexpected header:\ngot %+v", - v.file, i, j, *hdr) - continue - } - if !reflect.DeepEqual(*hdr, *v.headers[j]) { - t.Errorf("file %s, test %d, entry %d: incorrect header:\ngot %+v\nwant %+v", - v.file, i, j, *hdr, *v.headers[j]) - } - } - if len(hdrs) != len(v.headers) { - t.Errorf("file %s, test %d: got %d headers, want %d headers", - v.file, i, len(hdrs), len(v.headers)) - } - - for j, sum := range chksums { - if j >= len(v.chksums) { - t.Errorf("file %s, test %d, entry %d: unexpected sum: got %s", - v.file, i, j, sum) - continue - } - if sum != v.chksums[j] { - t.Errorf("file %s, test %d, entry %d: incorrect checksum: got %s, want %s", - v.file, i, j, sum, v.chksums[j]) - } - } - - if err != v.err { - t.Errorf("file %s, test %d: unexpected error: got %v, want %v", - v.file, i, err, v.err) - } - f.Close() - } -} - -func TestPartialRead(t *testing.T) { - f, err := os.Open("testdata/gnu.tar") - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - defer f.Close() - - tr := NewReader(f) - - // Read the first four bytes; Next() should skip the last byte. - hdr, err := tr.Next() - if err != nil || hdr == nil { - t.Fatalf("Didn't get first file: %v", err) - } - buf := make([]byte, 4) - if _, err := io.ReadFull(tr, buf); err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if expected := []byte("Kilt"); !bytes.Equal(buf, expected) { - t.Errorf("Contents = %v, want %v", buf, expected) - } - - // Second file - hdr, err = tr.Next() - if err != nil || hdr == nil { - t.Fatalf("Didn't get second file: %v", err) - } - buf = make([]byte, 6) - if _, err := io.ReadFull(tr, buf); err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if expected := []byte("Google"); !bytes.Equal(buf, expected) { - t.Errorf("Contents = %v, want %v", buf, expected) - } -} - -func TestSparseFileReader(t *testing.T) { - vectors := []struct { - realSize int64 // Real size of the output file - sparseMap []sparseEntry // Input sparse map - sparseData string // Input compact data - expected string // Expected output data - err error // Expected error outcome - }{{ - realSize: 8, - sparseMap: []sparseEntry{ - {offset: 0, numBytes: 2}, - {offset: 5, numBytes: 3}, - }, - sparseData: "abcde", - expected: "ab\x00\x00\x00cde", - }, { - realSize: 10, - sparseMap: []sparseEntry{ - {offset: 0, numBytes: 2}, - {offset: 5, numBytes: 3}, - }, - sparseData: "abcde", - expected: "ab\x00\x00\x00cde\x00\x00", }, { - realSize: 8, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 2}, - }, - sparseData: "abcde", - expected: "\x00abc\x00\x00de", - }, { - realSize: 8, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 0}, - {offset: 6, numBytes: 0}, - {offset: 6, numBytes: 2}, - }, - sparseData: "abcde", - expected: "\x00abc\x00\x00de", + // Ensure that we can read back the original Header as written with + // a buggy pre-Go1.8 tar.Writer. + file: "testdata/invalid-go17.tar", + headers: []*Header{{ + Name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", + Uid: 010000000, + ModTime: time.Unix(0, 0), + }}, }, { - realSize: 10, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 2}, - }, - sparseData: "abcde", - expected: "\x00abc\x00\x00de\x00\x00", - }, { - realSize: 10, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 2}, - {offset: 8, numBytes: 0}, - {offset: 8, numBytes: 0}, - {offset: 8, numBytes: 0}, - {offset: 8, numBytes: 0}, - }, - sparseData: "abcde", - expected: "\x00abc\x00\x00de\x00\x00", - }, { - realSize: 2, - sparseMap: []sparseEntry{}, - sparseData: "", - expected: "\x00\x00", - }, { - realSize: -2, - sparseMap: []sparseEntry{}, - err: ErrHeader, - }, { - realSize: -10, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 2}, - }, - sparseData: "abcde", - err: ErrHeader, + // USTAR archive with a regular entry with non-zero device numbers. + file: "testdata/ustar-file-devs.tar", + headers: []*Header{{ + Name: "file", + Mode: 0644, + Typeflag: '0', + ModTime: time.Unix(0, 0), + Devmajor: 1, + Devminor: 1, + Format: FormatUSTAR, + }}, }, { - realSize: 10, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 5}, - }, - sparseData: "abcde", - err: ErrHeader, + // Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1. + file: "testdata/gnu-nil-sparse-data.tar", + headers: []*Header{{ + Name: "sparse.db", + Typeflag: TypeGNUSparse, + Size: 1000, + ModTime: time.Unix(0, 0), + Format: FormatGNU, + }}, }, { - realSize: 35, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: 5}, - }, - sparseData: "abcde", - err: io.ErrUnexpectedEOF, + // Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1. + file: "testdata/gnu-nil-sparse-hole.tar", + headers: []*Header{{ + Name: "sparse.db", + Typeflag: TypeGNUSparse, + Size: 1000, + ModTime: time.Unix(0, 0), + Format: FormatGNU, + }}, }, { - realSize: 35, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 6, numBytes: -5}, - }, - sparseData: "abcde", - err: ErrHeader, + // Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1. + file: "testdata/pax-nil-sparse-data.tar", + headers: []*Header{{ + Name: "sparse.db", + Typeflag: TypeReg, + Size: 1000, + ModTime: time.Unix(0, 0), + PAXRecords: map[string]string{ + "size": "1512", + "GNU.sparse.major": "1", + "GNU.sparse.minor": "0", + "GNU.sparse.realsize": "1000", + "GNU.sparse.name": "sparse.db", + }, + Format: FormatPAX, + }}, }, { - realSize: 35, - sparseMap: []sparseEntry{ - {offset: math.MaxInt64, numBytes: 3}, - {offset: 6, numBytes: -5}, - }, - sparseData: "abcde", - err: ErrHeader, + // Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1. + file: "testdata/pax-nil-sparse-hole.tar", + headers: []*Header{{ + Name: "sparse.db", + Typeflag: TypeReg, + Size: 1000, + ModTime: time.Unix(0, 0), + PAXRecords: map[string]string{ + "size": "512", + "GNU.sparse.major": "1", + "GNU.sparse.minor": "0", + "GNU.sparse.realsize": "1000", + "GNU.sparse.name": "sparse.db", + }, + Format: FormatPAX, + }}, }, { - realSize: 10, - sparseMap: []sparseEntry{ - {offset: 1, numBytes: 3}, - {offset: 2, numBytes: 2}, - }, - sparseData: "abcde", - err: ErrHeader, + file: "testdata/trailing-slash.tar", + headers: []*Header{{ + Typeflag: TypeDir, + Name: strings.Repeat("123456789/", 30), + ModTime: time.Unix(0, 0), + PAXRecords: map[string]string{ + "path": strings.Repeat("123456789/", 30), + }, + Format: FormatPAX, + }}, }} - for i, v := range vectors { - r := bytes.NewReader([]byte(v.sparseData)) - rfr := ®FileReader{r: r, nb: int64(len(v.sparseData))} - - var ( - sfr *sparseFileReader - err error - buf []byte - ) - - sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize) - if err != nil { - goto fail - } - if sfr.numBytes() != int64(len(v.sparseData)) { - t.Errorf("test %d, numBytes() before reading: got %d, want %d", i, sfr.numBytes(), len(v.sparseData)) - } - buf, err = ioutil.ReadAll(sfr) - if err != nil { - goto fail - } - if string(buf) != v.expected { - t.Errorf("test %d, ReadAll(): got %q, want %q", i, string(buf), v.expected) - } - if sfr.numBytes() != 0 { - t.Errorf("test %d, numBytes() after reading: got %d, want %d", i, sfr.numBytes(), 0) - } + for _, v := range vectors { + t.Run(path.Base(v.file), func(t *testing.T) { + f, err := os.Open(v.file) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + defer f.Close() - fail: - if err != v.err { - t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err) - } - } -} + // Capture all headers and checksums. + var ( + tr = NewReader(f) + hdrs []*Header + chksums []string + rdbuf = make([]byte, 8) + ) + for { + var hdr *Header + hdr, err = tr.Next() + if err != nil { + if err == io.EOF { + err = nil // Expected error + } + break + } + hdrs = append(hdrs, hdr) -func TestReadOldGNUSparseMap(t *testing.T) { - const ( - t00 = "00000000000\x0000000000000\x00" - t11 = "00000000001\x0000000000001\x00" - t12 = "00000000001\x0000000000002\x00" - t21 = "00000000002\x0000000000001\x00" - ) + if v.chksums == nil { + continue + } + h := md5.New() + _, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read + if err != nil { + break + } + chksums = append(chksums, fmt.Sprintf("%x", h.Sum(nil))) + } - mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block { - var blk block - copy(blk.GNU().RealSize(), size) - copy(blk.GNU().Sparse().Entry(0), sp0) - copy(blk.GNU().Sparse().Entry(1), sp1) - copy(blk.GNU().Sparse().Entry(2), sp2) - copy(blk.GNU().Sparse().Entry(3), sp3) - copy(blk.GNU().Sparse().IsExtended(), ext) - if format != formatUnknown { - blk.SetFormat(format) - } - return &blk - } + for i, hdr := range hdrs { + if i >= len(v.headers) { + t.Fatalf("entry %d: unexpected header:\ngot %+v", i, *hdr) + continue + } + if !reflect.DeepEqual(*hdr, *v.headers[i]) { + t.Fatalf("entry %d: incorrect header:\ngot %+v\nwant %+v", i, *hdr, *v.headers[i]) + } + } + if len(hdrs) != len(v.headers) { + t.Fatalf("got %d headers, want %d headers", len(hdrs), len(v.headers)) + } - vectors := []struct { - data string // Input data - rawHdr *block // Input raw header - want []sparseEntry // Expected sparse entries to be outputted - err error // Expected error to be returned - }{ - {"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader}, - {"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader}, - {"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil}, - {"", mkBlk("1234", t00, t11, "", "", "", formatGNU), - []sparseEntry{{0, 0}, {1, 1}}, nil}, - {"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU), - []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil}, - {"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU), - []sparseEntry{}, io.ErrUnexpectedEOF}, - {t11 + t11, - mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU), - []sparseEntry{}, io.ErrUnexpectedEOF}, - {t11 + t21 + strings.Repeat("\x00", 512), - mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU), - []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil}, - } + for i, sum := range chksums { + if i >= len(v.chksums) { + t.Fatalf("entry %d: unexpected sum: got %s", i, sum) + continue + } + if sum != v.chksums[i] { + t.Fatalf("entry %d: incorrect checksum: got %s, want %s", i, sum, v.chksums[i]) + } + } - for i, v := range vectors { - tr := Reader{r: strings.NewReader(v.data)} - hdr := new(Header) - got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr) - if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) { - t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want) - } - if err != v.err { - t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err) - } + if err != v.err { + t.Fatalf("unexpected error: got %v, want %v", err, v.err) + } + f.Close() + }) } } -func TestReadGNUSparseMap0x1(t *testing.T) { - const ( - maxUint = ^uint(0) - maxInt = int(maxUint >> 1) - ) - var ( - big1 = fmt.Sprintf("%d", int64(maxInt)) - big2 = fmt.Sprintf("%d", (int64(maxInt)/2)+1) - big3 = fmt.Sprintf("%d", (int64(maxInt) / 3)) - ) - +func TestPartialRead(t *testing.T) { + type testCase struct { + cnt int // Number of bytes to read + output string // Expected value of string read + } vectors := []struct { - extHdrs map[string]string // Input data - sparseMap []sparseEntry // Expected sparse entries to be outputted - err error // Expected errors that may be raised + file string + cases []testCase }{{ - extHdrs: map[string]string{paxGNUSparseNumBlocks: "-4"}, - err: ErrHeader, - }, { - extHdrs: map[string]string{paxGNUSparseNumBlocks: "fee "}, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: big1, - paxGNUSparseMap: "0,5,10,5,20,5,30,5", - }, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: big2, - paxGNUSparseMap: "0,5,10,5,20,5,30,5", - }, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: big3, - paxGNUSparseMap: "0,5,10,5,20,5,30,5", - }, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: "4", - paxGNUSparseMap: "0.5,5,10,5,20,5,30,5", - }, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: "4", - paxGNUSparseMap: "0,5.5,10,5,20,5,30,5", - }, - err: ErrHeader, - }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: "4", - paxGNUSparseMap: "0,fewafewa.5,fewafw,5,20,5,30,5", + file: "testdata/gnu.tar", + cases: []testCase{ + {4, "Kilt"}, + {6, "Google"}, }, - err: ErrHeader, }, { - extHdrs: map[string]string{ - paxGNUSparseNumBlocks: "4", - paxGNUSparseMap: "0,5,10,5,20,5,30,5", + file: "testdata/sparse-formats.tar", + cases: []testCase{ + {2, "\x00G"}, + {4, "\x00G\x00o"}, + {6, "\x00G\x00o\x00G"}, + {8, "\x00G\x00o\x00G\x00o"}, + {4, "end\n"}, }, - sparseMap: []sparseEntry{{0, 5}, {10, 5}, {20, 5}, {30, 5}}, }} - for i, v := range vectors { - sp, err := readGNUSparseMap0x1(v.extHdrs) - if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) { - t.Errorf("test %d, readGNUSparseMap0x1(...): got %v, want %v", i, sp, v.sparseMap) - } - if err != v.err { - t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err) - } - } -} - -func TestReadGNUSparseMap1x0(t *testing.T) { - sp := []sparseEntry{{1, 2}, {3, 4}} - for i := 0; i < 98; i++ { - sp = append(sp, sparseEntry{54321, 12345}) - } + for _, v := range vectors { + t.Run(path.Base(v.file), func(t *testing.T) { + f, err := os.Open(v.file) + if err != nil { + t.Fatalf("Open() error: %v", err) + } + defer f.Close() - vectors := []struct { - input string // Input data - sparseMap []sparseEntry // Expected sparse entries to be outputted - cnt int // Expected number of bytes read - err error // Expected errors that may be raised - }{{ - input: "", - cnt: 0, - err: io.ErrUnexpectedEOF, - }, { - input: "ab", - cnt: 2, - err: io.ErrUnexpectedEOF, - }, { - input: strings.Repeat("\x00", 512), - cnt: 512, - err: io.ErrUnexpectedEOF, - }, { - input: strings.Repeat("\x00", 511) + "\n", - cnt: 512, - err: ErrHeader, - }, { - input: strings.Repeat("\n", 512), - cnt: 512, - err: ErrHeader, - }, { - input: "0\n" + strings.Repeat("\x00", 510) + strings.Repeat("a", 512), - sparseMap: []sparseEntry{}, - cnt: 512, - }, { - input: strings.Repeat("0", 512) + "0\n" + strings.Repeat("\x00", 510), - sparseMap: []sparseEntry{}, - cnt: 1024, - }, { - input: strings.Repeat("0", 1024) + "1\n2\n3\n" + strings.Repeat("\x00", 506), - sparseMap: []sparseEntry{{2, 3}}, - cnt: 1536, - }, { - input: strings.Repeat("0", 1024) + "1\n2\n\n" + strings.Repeat("\x00", 509), - cnt: 1536, - err: ErrHeader, - }, { - input: strings.Repeat("0", 1024) + "1\n2\n" + strings.Repeat("\x00", 508), - cnt: 1536, - err: io.ErrUnexpectedEOF, - }, { - input: "-1\n2\n\n" + strings.Repeat("\x00", 506), - cnt: 512, - err: ErrHeader, - }, { - input: "1\nk\n2\n" + strings.Repeat("\x00", 506), - cnt: 512, - err: ErrHeader, - }, { - input: "100\n1\n2\n3\n4\n" + strings.Repeat("54321\n0000000000000012345\n", 98) + strings.Repeat("\x00", 512), - cnt: 2560, - sparseMap: sp, - }} + tr := NewReader(f) + for i, tc := range v.cases { + hdr, err := tr.Next() + if err != nil || hdr == nil { + t.Fatalf("entry %d, Next(): got %v, want %v", i, err, nil) + } + buf := make([]byte, tc.cnt) + if _, err := io.ReadFull(tr, buf); err != nil { + t.Fatalf("entry %d, ReadFull(): got %v, want %v", i, err, nil) + } + if string(buf) != tc.output { + t.Fatalf("entry %d, ReadFull(): got %q, want %q", i, string(buf), tc.output) + } + } - for i, v := range vectors { - r := strings.NewReader(v.input) - sp, err := readGNUSparseMap1x0(r) - if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) { - t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap) - } - if numBytes := len(v.input) - r.Len(); numBytes != v.cnt { - t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt) - } - if err != v.err { - t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err) - } + if _, err := tr.Next(); err != io.EOF { + t.Fatalf("Next(): got %v, want EOF", err) + } + }) } } @@ -950,17 +864,17 @@ func TestReadTruncation(t *testing.T) { } cnt++ if s2 == "manual" { - if _, err = io.Copy(ioutil.Discard, tr); err != nil { + if _, err = tr.writeTo(ioutil.Discard); err != nil { break } } } if err != v.err { - t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %v, want %v", + t.Errorf("test %d, NewReader(%s) with %s discard: got %v, want %v", i, s1, s2, err, v.err) } if cnt != v.cnt { - t.Errorf("test %d, NewReader(%s(...)) with %s discard: got %d headers, want %d headers", + t.Errorf("test %d, NewReader(%s) with %s discard: got %d headers, want %d headers", i, s1, s2, cnt, v.cnt) } } @@ -1025,12 +939,18 @@ func TestMergePAX(t *testing.T) { Name: "a/b/c", Uid: 1000, ModTime: time.Unix(1350244992, 23960108), + PAXRecords: map[string]string{ + "path": "a/b/c", + "uid": "1000", + "mtime": "1350244992.023960108", + }, }, ok: true, }, { in: map[string]string{ "gid": "gtgergergersagersgers", }, + ok: false, }, { in: map[string]string{ "missing": "missing", @@ -1038,6 +958,10 @@ func TestMergePAX(t *testing.T) { }, want: &Header{ Xattrs: map[string]string{"key": "value"}, + PAXRecords: map[string]string{ + "missing": "missing", + "SCHILY.xattr.key": "value", + }, }, ok: true, }} @@ -1070,7 +994,7 @@ func TestParsePAX(t *testing.T) { {"13 key1=haha\n13 key2=nana\n13 key3=kaka\n", map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true}, {"13 key1=val1\n13 key2=val2\n8 key1=\n", - map[string]string{"key2": "val2"}, true}, + map[string]string{"key1": "", "key2": "val2"}, true}, {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" + "23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" + "23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n", @@ -1087,10 +1011,600 @@ func TestParsePAX(t *testing.T) { r := strings.NewReader(v.in) got, err := parsePAX(r) if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) { - t.Errorf("test %d, parsePAX(...):\ngot %v\nwant %v", i, got, v.want) + t.Errorf("test %d, parsePAX():\ngot %v\nwant %v", i, got, v.want) } if ok := err == nil; ok != v.ok { - t.Errorf("test %d, parsePAX(...): got %v, want %v", i, ok, v.ok) + t.Errorf("test %d, parsePAX(): got %v, want %v", i, ok, v.ok) + } + } +} + +func TestReadOldGNUSparseMap(t *testing.T) { + populateSparseMap := func(sa sparseArray, sps []string) []string { + for i := 0; len(sps) > 0 && i < sa.MaxEntries(); i++ { + copy(sa.Entry(i), sps[0]) + sps = sps[1:] + } + if len(sps) > 0 { + copy(sa.IsExtended(), "\x80") + } + return sps + } + + makeInput := func(format Format, size string, sps ...string) (out []byte) { + // Write the initial GNU header. + var blk block + gnu := blk.GNU() + sparse := gnu.Sparse() + copy(gnu.RealSize(), size) + sps = populateSparseMap(sparse, sps) + if format != FormatUnknown { + blk.SetFormat(format) + } + out = append(out, blk[:]...) + + // Write extended sparse blocks. + for len(sps) > 0 { + var blk block + sps = populateSparseMap(blk.Sparse(), sps) + out = append(out, blk[:]...) + } + return out + } + + makeSparseStrings := func(sp []sparseEntry) (out []string) { + var f formatter + for _, s := range sp { + var b [24]byte + f.formatNumeric(b[:12], s.Offset) + f.formatNumeric(b[12:], s.Length) + out = append(out, string(b[:])) + } + return out + } + + vectors := []struct { + input []byte + wantMap sparseDatas + wantSize int64 + wantErr error + }{{ + input: makeInput(FormatUnknown, ""), + wantErr: ErrHeader, + }, { + input: makeInput(FormatGNU, "1234", "fewa"), + wantSize: 01234, + wantErr: ErrHeader, + }, { + input: makeInput(FormatGNU, "0031"), + wantSize: 031, + }, { + input: makeInput(FormatGNU, "80"), + wantErr: ErrHeader, + }, { + input: makeInput(FormatGNU, "1234", + makeSparseStrings(sparseDatas{{0, 0}, {1, 1}})...), + wantMap: sparseDatas{{0, 0}, {1, 1}}, + wantSize: 01234, + }, { + input: makeInput(FormatGNU, "1234", + append(makeSparseStrings(sparseDatas{{0, 0}, {1, 1}}), []string{"", "blah"}...)...), + wantMap: sparseDatas{{0, 0}, {1, 1}}, + wantSize: 01234, + }, { + input: makeInput(FormatGNU, "3333", + makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}})...), + wantMap: sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}}, + wantSize: 03333, + }, { + input: makeInput(FormatGNU, "", + append(append( + makeSparseStrings(sparseDatas{{0, 1}, {2, 1}}), + []string{"", ""}...), + makeSparseStrings(sparseDatas{{4, 1}, {6, 1}})...)...), + wantMap: sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}}, + }, { + input: makeInput(FormatGNU, "", + makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...)[:blockSize], + wantErr: io.ErrUnexpectedEOF, + }, { + input: makeInput(FormatGNU, "", + makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...)[:3*blockSize/2], + wantErr: io.ErrUnexpectedEOF, + }, { + input: makeInput(FormatGNU, "", + makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...), + wantMap: sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}}, + }, { + input: makeInput(FormatGNU, "", + makeSparseStrings(sparseDatas{{10 << 30, 512}, {20 << 30, 512}})...), + wantMap: sparseDatas{{10 << 30, 512}, {20 << 30, 512}}, + }} + + for i, v := range vectors { + var blk block + var hdr Header + v.input = v.input[copy(blk[:], v.input):] + tr := Reader{r: bytes.NewReader(v.input)} + got, err := tr.readOldGNUSparseMap(&hdr, &blk) + if !equalSparseEntries(got, v.wantMap) { + t.Errorf("test %d, readOldGNUSparseMap(): got %v, want %v", i, got, v.wantMap) + } + if err != v.wantErr { + t.Errorf("test %d, readOldGNUSparseMap() = %v, want %v", i, err, v.wantErr) + } + if hdr.Size != v.wantSize { + t.Errorf("test %d, Header.Size = %d, want %d", i, hdr.Size, v.wantSize) + } + } +} + +func TestReadGNUSparsePAXHeaders(t *testing.T) { + padInput := func(s string) string { + return s + string(zeroBlock[:blockPadding(int64(len(s)))]) + } + + vectors := []struct { + inputData string + inputHdrs map[string]string + wantMap sparseDatas + wantSize int64 + wantName string + wantErr error + }{{ + inputHdrs: nil, + wantErr: nil, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: strconv.FormatInt(math.MaxInt64, 10), + paxGNUSparseMap: "0,1,2,3", + }, + wantErr: ErrHeader, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "4\x00", + paxGNUSparseMap: "0,1,2,3", + }, + wantErr: ErrHeader, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "4", + paxGNUSparseMap: "0,1,2,3", + }, + wantErr: ErrHeader, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "2", + paxGNUSparseMap: "0,1,2,3", + }, + wantMap: sparseDatas{{0, 1}, {2, 3}}, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "2", + paxGNUSparseMap: "0, 1,2,3", + }, + wantErr: ErrHeader, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "2", + paxGNUSparseMap: "0,1,02,3", + paxGNUSparseRealSize: "4321", + }, + wantMap: sparseDatas{{0, 1}, {2, 3}}, + wantSize: 4321, + }, { + inputHdrs: map[string]string{ + paxGNUSparseNumBlocks: "2", + paxGNUSparseMap: "0,one1,2,3", + }, + wantErr: ErrHeader, + }, { + inputHdrs: map[string]string{ + paxGNUSparseMajor: "0", + paxGNUSparseMinor: "0", + paxGNUSparseNumBlocks: "2", + paxGNUSparseMap: "0,1,2,3", + paxGNUSparseSize: "1234", + paxGNUSparseRealSize: "4321", + paxGNUSparseName: "realname", + }, + wantMap: sparseDatas{{0, 1}, {2, 3}}, + wantSize: 1234, + wantName: "realname", + }, { + inputHdrs: map[string]string{ + paxGNUSparseMajor: "0", + paxGNUSparseMinor: "0", + paxGNUSparseNumBlocks: "1", + paxGNUSparseMap: "10737418240,512", + paxGNUSparseSize: "10737418240", + paxGNUSparseName: "realname", + }, + wantMap: sparseDatas{{10737418240, 512}}, + wantSize: 10737418240, + wantName: "realname", + }, { + inputHdrs: map[string]string{ + paxGNUSparseMajor: "0", + paxGNUSparseMinor: "0", + paxGNUSparseNumBlocks: "0", + paxGNUSparseMap: "", + }, + wantMap: sparseDatas{}, + }, { + inputHdrs: map[string]string{ + paxGNUSparseMajor: "0", + paxGNUSparseMinor: "1", + paxGNUSparseNumBlocks: "4", + paxGNUSparseMap: "0,5,10,5,20,5,30,5", + }, + wantMap: sparseDatas{{0, 5}, {10, 5}, {20, 5}, {30, 5}}, + }, { + inputHdrs: map[string]string{ + paxGNUSparseMajor: "1", + paxGNUSparseMinor: "0", + paxGNUSparseNumBlocks: "4", + paxGNUSparseMap: "0,5,10,5,20,5,30,5", + }, + wantErr: io.ErrUnexpectedEOF, + }, { + inputData: padInput("0\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{}, + }, { + inputData: padInput("0\n")[:blockSize-1] + "#", + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{}, + }, { + inputData: padInput("0"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: io.ErrUnexpectedEOF, + }, { + inputData: padInput("ab\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: ErrHeader, + }, { + inputData: padInput("1\n2\n3\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{{2, 3}}, + }, { + inputData: padInput("1\n2\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: io.ErrUnexpectedEOF, + }, { + inputData: padInput("1\n2\n\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: ErrHeader, + }, { + inputData: string(zeroBlock[:]) + padInput("0\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: ErrHeader, + }, { + inputData: strings.Repeat("0", blockSize) + padInput("1\n5\n1\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{{5, 1}}, + }, { + inputData: padInput(fmt.Sprintf("%d\n", int64(math.MaxInt64))), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantErr: ErrHeader, + }, { + inputData: padInput(strings.Repeat("0", 300) + "1\n" + strings.Repeat("0", 1000) + "5\n" + strings.Repeat("0", 800) + "2\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{{5, 2}}, + }, { + inputData: padInput("2\n10737418240\n512\n21474836480\n512\n"), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: sparseDatas{{10737418240, 512}, {21474836480, 512}}, + }, { + inputData: padInput("100\n" + func() string { + var ss []string + for i := 0; i < 100; i++ { + ss = append(ss, fmt.Sprintf("%d\n%d\n", int64(i)<<30, 512)) + } + return strings.Join(ss, "") + }()), + inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"}, + wantMap: func() (spd sparseDatas) { + for i := 0; i < 100; i++ { + spd = append(spd, sparseEntry{int64(i) << 30, 512}) + } + return spd + }(), + }} + + for i, v := range vectors { + var hdr Header + hdr.PAXRecords = v.inputHdrs + r := strings.NewReader(v.inputData + "#") // Add canary byte + tr := Reader{curr: ®FileReader{r, int64(r.Len())}} + got, err := tr.readGNUSparsePAXHeaders(&hdr) + if !equalSparseEntries(got, v.wantMap) { + t.Errorf("test %d, readGNUSparsePAXHeaders(): got %v, want %v", i, got, v.wantMap) + } + if err != v.wantErr { + t.Errorf("test %d, readGNUSparsePAXHeaders() = %v, want %v", i, err, v.wantErr) + } + if hdr.Size != v.wantSize { + t.Errorf("test %d, Header.Size = %d, want %d", i, hdr.Size, v.wantSize) + } + if hdr.Name != v.wantName { + t.Errorf("test %d, Header.Name = %s, want %s", i, hdr.Name, v.wantName) + } + if v.wantErr == nil && r.Len() == 0 { + t.Errorf("test %d, canary byte unexpectedly consumed", i) + } + } +} + +// testNonEmptyReader wraps an io.Reader and ensures that +// Read is never called with an empty buffer. +type testNonEmptyReader struct{ io.Reader } + +func (r testNonEmptyReader) Read(b []byte) (int, error) { + if len(b) == 0 { + return 0, errors.New("unexpected empty Read call") + } + return r.Reader.Read(b) +} + +func TestFileReader(t *testing.T) { + type ( + testRead struct { // Read(cnt) == (wantStr, wantErr) + cnt int + wantStr string + wantErr error + } + testWriteTo struct { // WriteTo(testFile{ops}) == (wantCnt, wantErr) + ops fileOps + wantCnt int64 + wantErr error + } + testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt + wantLCnt int64 + wantPCnt int64 + } + testFnc interface{} // testRead | testWriteTo | testRemaining + ) + + type ( + makeReg struct { + str string + size int64 + } + makeSparse struct { + makeReg makeReg + spd sparseDatas + size int64 + } + fileMaker interface{} // makeReg | makeSparse + ) + + vectors := []struct { + maker fileMaker + tests []testFnc + }{{ + maker: makeReg{"", 0}, + tests: []testFnc{ + testRemaining{0, 0}, + testRead{0, "", io.EOF}, + testRead{1, "", io.EOF}, + testWriteTo{nil, 0, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{"", 1}, + tests: []testFnc{ + testRemaining{1, 1}, + testRead{5, "", io.ErrUnexpectedEOF}, + testWriteTo{nil, 0, io.ErrUnexpectedEOF}, + testRemaining{1, 1}, + }, + }, { + maker: makeReg{"hello", 5}, + tests: []testFnc{ + testRemaining{5, 5}, + testRead{5, "hello", io.EOF}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{"hello, world", 50}, + tests: []testFnc{ + testRemaining{50, 50}, + testRead{7, "hello, ", nil}, + testRemaining{43, 43}, + testRead{5, "world", nil}, + testRemaining{38, 38}, + testWriteTo{nil, 0, io.ErrUnexpectedEOF}, + testRead{1, "", io.ErrUnexpectedEOF}, + testRemaining{38, 38}, + }, + }, { + maker: makeReg{"hello, world", 5}, + tests: []testFnc{ + testRemaining{5, 5}, + testRead{0, "", nil}, + testRead{4, "hell", nil}, + testRemaining{1, 1}, + testWriteTo{fileOps{"o"}, 1, nil}, + testRemaining{0, 0}, + testWriteTo{nil, 0, nil}, + testRead{0, "", io.EOF}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testRead{3, "ab\x00", nil}, + testRead{10, "\x00\x00cde", io.EOF}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testWriteTo{fileOps{"ab", int64(3), "cde"}, 8, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 10}, + tests: []testFnc{ + testRemaining{10, 5}, + testRead{100, "ab\x00\x00\x00cde\x00\x00", io.EOF}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abc", 5}, sparseDatas{{0, 2}, {5, 3}}, 10}, + tests: []testFnc{ + testRemaining{10, 5}, + testRead{100, "ab\x00\x00\x00c", io.ErrUnexpectedEOF}, + testRemaining{4, 2}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testRead{8, "\x00abc\x00\x00de", io.EOF}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 0}, {6, 0}, {6, 2}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testRead{8, "\x00abc\x00\x00de", io.EOF}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 0}, {6, 0}, {6, 2}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testWriteTo{fileOps{int64(1), "abc", int64(2), "de"}, 8, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 10}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00de\x00\x00", io.EOF}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 10}, + tests: []testFnc{ + testWriteTo{fileOps{int64(1), "abc", int64(2), "de", int64(1), "\x00"}, 10, nil}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}, {8, 0}, {8, 0}, {8, 0}, {8, 0}}, 10}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00de\x00\x00", io.EOF}, + }, + }, { + maker: makeSparse{makeReg{"", 0}, sparseDatas{}, 2}, + tests: []testFnc{ + testRead{100, "\x00\x00", io.EOF}, + }, + }, { + maker: makeSparse{makeReg{"", 8}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00", io.ErrUnexpectedEOF}, + }, + }, { + maker: makeSparse{makeReg{"ab", 2}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00ab", errMissData}, + }, + }, { + maker: makeSparse{makeReg{"ab", 8}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00ab", io.ErrUnexpectedEOF}, + }, + }, { + maker: makeSparse{makeReg{"abc", 3}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00", errMissData}, + }, + }, { + maker: makeSparse{makeReg{"abc", 8}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00", io.ErrUnexpectedEOF}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00de", errMissData}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testWriteTo{fileOps{int64(1), "abc", int64(2), "de"}, 8, errMissData}, + }, + }, { + maker: makeSparse{makeReg{"abcde", 8}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRead{100, "\x00abc\x00\x00de", io.ErrUnexpectedEOF}, + }, + }, { + maker: makeSparse{makeReg{"abcdefghEXTRA", 13}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRemaining{15, 13}, + testRead{100, "\x00abc\x00\x00defgh\x00\x00\x00\x00", errUnrefData}, + testWriteTo{nil, 0, errUnrefData}, + testRemaining{0, 5}, + }, + }, { + maker: makeSparse{makeReg{"abcdefghEXTRA", 13}, sparseDatas{{1, 3}, {6, 5}}, 15}, + tests: []testFnc{ + testRemaining{15, 13}, + testWriteTo{fileOps{int64(1), "abc", int64(2), "defgh", int64(4)}, 15, errUnrefData}, + testRead{100, "", errUnrefData}, + testRemaining{0, 5}, + }, + }} + + for i, v := range vectors { + var fr fileReader + switch maker := v.maker.(type) { + case makeReg: + r := testNonEmptyReader{strings.NewReader(maker.str)} + fr = ®FileReader{r, maker.size} + case makeSparse: + if !validateSparseEntries(maker.spd, maker.size) { + t.Fatalf("invalid sparse map: %v", maker.spd) + } + sph := invertSparseEntries(maker.spd, maker.size) + r := testNonEmptyReader{strings.NewReader(maker.makeReg.str)} + fr = ®FileReader{r, maker.makeReg.size} + fr = &sparseFileReader{fr, sph, 0} + default: + t.Fatalf("test %d, unknown make operation: %T", i, maker) + } + + for j, tf := range v.tests { + switch tf := tf.(type) { + case testRead: + b := make([]byte, tf.cnt) + n, err := fr.Read(b) + if got := string(b[:n]); got != tf.wantStr || err != tf.wantErr { + t.Errorf("test %d.%d, Read(%d):\ngot (%q, %v)\nwant (%q, %v)", i, j, tf.cnt, got, err, tf.wantStr, tf.wantErr) + } + case testWriteTo: + f := &testFile{ops: tf.ops} + got, err := fr.WriteTo(f) + if _, ok := err.(testError); ok { + t.Errorf("test %d.%d, WriteTo(): %v", i, j, err) + } else if got != tf.wantCnt || err != tf.wantErr { + t.Errorf("test %d.%d, WriteTo() = (%d, %v), want (%d, %v)", i, j, got, err, tf.wantCnt, tf.wantErr) + } + if len(f.ops) > 0 { + t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops)) + } + case testRemaining: + if got := fr.LogicalRemaining(); got != tf.wantLCnt { + t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt) + } + if got := fr.PhysicalRemaining(); got != tf.wantPCnt { + t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt) + } + default: + t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf) + } } } } diff --git a/libgo/go/archive/tar/stat_atim.go b/libgo/go/archive/tar/stat_actime1.go similarity index 100% rename from libgo/go/archive/tar/stat_atim.go rename to libgo/go/archive/tar/stat_actime1.go diff --git a/libgo/go/archive/tar/stat_atimespec.go b/libgo/go/archive/tar/stat_actime2.go similarity index 100% rename from libgo/go/archive/tar/stat_atimespec.go rename to libgo/go/archive/tar/stat_actime2.go diff --git a/libgo/go/archive/tar/stat_unix.go b/libgo/go/archive/tar/stat_unix.go index cb843db4cfd..868105f338e 100644 --- a/libgo/go/archive/tar/stat_unix.go +++ b/libgo/go/archive/tar/stat_unix.go @@ -8,6 +8,10 @@ package tar import ( "os" + "os/user" + "runtime" + "strconv" + "sync" "syscall" ) @@ -15,6 +19,10 @@ func init() { sysStat = statUnix } +// userMap and groupMap caches UID and GID lookups for performance reasons. +// The downside is that renaming uname or gname by the OS never takes effect. +var userMap, groupMap sync.Map // map[int]string + func statUnix(fi os.FileInfo, h *Header) error { sys, ok := fi.Sys().(*syscall.Stat_t) if !ok { @@ -22,11 +30,67 @@ func statUnix(fi os.FileInfo, h *Header) error { } h.Uid = int(sys.Uid) h.Gid = int(sys.Gid) - // TODO(bradfitz): populate username & group. os/user - // doesn't cache LookupId lookups, and lacks group - // lookup functions. + + // Best effort at populating Uname and Gname. + // The os/user functions may fail for any number of reasons + // (not implemented on that platform, cgo not enabled, etc). + if u, ok := userMap.Load(h.Uid); ok { + h.Uname = u.(string) + } else if u, err := user.LookupId(strconv.Itoa(h.Uid)); err == nil { + h.Uname = u.Username + userMap.Store(h.Uid, h.Uname) + } + if g, ok := groupMap.Load(h.Gid); ok { + h.Gname = g.(string) + } else if g, err := user.LookupGroupId(strconv.Itoa(h.Gid)); err == nil { + h.Gname = g.Name + groupMap.Store(h.Gid, h.Gname) + } + h.AccessTime = statAtime(sys) h.ChangeTime = statCtime(sys) - // TODO(bradfitz): major/minor device numbers? + + // Best effort at populating Devmajor and Devminor. + if h.Typeflag == TypeChar || h.Typeflag == TypeBlock { + dev := uint64(sys.Rdev) // May be int32 or uint32 + switch runtime.GOOS { + case "linux": + // Copied from golang.org/x/sys/unix/dev_linux.go. + major := uint32((dev & 0x00000000000fff00) >> 8) + major |= uint32((dev & 0xfffff00000000000) >> 32) + minor := uint32((dev & 0x00000000000000ff) >> 0) + minor |= uint32((dev & 0x00000ffffff00000) >> 12) + h.Devmajor, h.Devminor = int64(major), int64(minor) + case "darwin": + // Copied from golang.org/x/sys/unix/dev_darwin.go. + major := uint32((dev >> 24) & 0xff) + minor := uint32(dev & 0xffffff) + h.Devmajor, h.Devminor = int64(major), int64(minor) + case "dragonfly": + // Copied from golang.org/x/sys/unix/dev_dragonfly.go. + major := uint32((dev >> 8) & 0xff) + minor := uint32(dev & 0xffff00ff) + h.Devmajor, h.Devminor = int64(major), int64(minor) + case "freebsd": + // Copied from golang.org/x/sys/unix/dev_freebsd.go. + major := uint32((dev >> 8) & 0xff) + minor := uint32(dev & 0xffff00ff) + h.Devmajor, h.Devminor = int64(major), int64(minor) + case "netbsd": + // Copied from golang.org/x/sys/unix/dev_netbsd.go. + major := uint32((dev & 0x000fff00) >> 8) + minor := uint32((dev & 0x000000ff) >> 0) + minor |= uint32((dev & 0xfff00000) >> 12) + h.Devmajor, h.Devminor = int64(major), int64(minor) + case "openbsd": + // Copied from golang.org/x/sys/unix/dev_openbsd.go. + major := uint32((dev & 0x0000ff00) >> 8) + minor := uint32((dev & 0x000000ff) >> 0) + minor |= uint32((dev & 0xffff0000) >> 8) + h.Devmajor, h.Devminor = int64(major), int64(minor) + default: + // TODO: Implement solaris (see https://golang.org/issue/8106) + } + } return nil } diff --git a/libgo/go/archive/tar/strconv.go b/libgo/go/archive/tar/strconv.go index bb5b51c02de..d144485a492 100644 --- a/libgo/go/archive/tar/strconv.go +++ b/libgo/go/archive/tar/strconv.go @@ -12,26 +12,34 @@ import ( "time" ) +// hasNUL reports whether the NUL character exists within s. +func hasNUL(s string) bool { + return strings.IndexByte(s, 0) >= 0 +} + +// isASCII reports whether the input is an ASCII C-style string. func isASCII(s string) bool { for _, c := range s { - if c >= 0x80 { + if c >= 0x80 || c == 0x00 { return false } } return true } +// toASCII converts the input to an ASCII C-style string. +// This a best effort conversion, so invalid characters are dropped. func toASCII(s string) string { if isASCII(s) { return s } - var buf bytes.Buffer + b := make([]byte, 0, len(s)) for _, c := range s { - if c < 0x80 { - buf.WriteByte(byte(c)) + if c < 0x80 && c != 0x00 { + b = append(b, byte(c)) } } - return buf.String() + return string(b) } type parser struct { @@ -45,23 +53,28 @@ type formatter struct { // parseString parses bytes as a NUL-terminated C-style string. // If a NUL byte is not found then the whole slice is returned as a string. func (*parser) parseString(b []byte) string { - n := 0 - for n < len(b) && b[n] != 0 { - n++ + if i := bytes.IndexByte(b, 0); i >= 0 { + return string(b[:i]) } - return string(b[0:n]) + return string(b) } -// Write s into b, terminating it with a NUL if there is room. +// formatString copies s into b, NUL-terminating if possible. func (f *formatter) formatString(b []byte, s string) { if len(s) > len(b) { f.err = ErrFieldTooLong - return } - ascii := toASCII(s) - copy(b, ascii) - if len(ascii) < len(b) { - b[len(ascii)] = 0 + copy(b, s) + if len(s) < len(b) { + b[len(s)] = 0 + } + + // Some buggy readers treat regular files with a trailing slash + // in the V7 path field as a directory even though the full path + // recorded elsewhere (e.g., via PAX record) contains no trailing slash. + if len(s) > len(b) && b[len(b)-1] == '/' { + n := len(strings.TrimRight(s[:len(b)], "/")) + b[n] = 0 // Replace trailing slash with NUL terminator } } @@ -73,7 +86,7 @@ func (f *formatter) formatString(b []byte, s string) { // that the first byte can only be either 0x80 or 0xff. Thus, the first byte is // equivalent to the sign bit in two's complement form. func fitsInBase256(n int, x int64) bool { - var binBits = uint(n-1) * 8 + binBits := uint(n-1) * 8 return n >= 9 || (x >= -1<= 0; i-- { b[i] = byte(x) @@ -155,6 +174,11 @@ func (p *parser) parseOctal(b []byte) int64 { } func (f *formatter) formatOctal(b []byte, x int64) { + if !fitsInOctal(len(b), x) { + x = 0 // Last resort, just write zero + f.err = ErrFieldTooLong + } + s := strconv.FormatInt(x, 8) // Add leading zeros, but leave room for a NUL. if n := len(b) - len(s) - 1; n > 0 { @@ -163,6 +187,13 @@ func (f *formatter) formatOctal(b []byte, x int64) { f.formatString(b, s) } +// fitsInOctal reports whether the integer x fits in a field n-bytes long +// using octal encoding with the appropriate NUL terminator. +func fitsInOctal(n int, x int64) bool { + octBits := uint(n-1) * 3 + return x >= 0 && (n >= 22 || x < 1< 0 && ss[0] == '-' { - return time.Unix(secs, -1*int64(nsecs)), nil // Negative correction + return time.Unix(secs, -1*nsecs), nil // Negative correction } - return time.Unix(secs, int64(nsecs)), nil + return time.Unix(secs, nsecs), nil } -// TODO(dsnet): Implement formatPAXTime. +// formatPAXTime converts ts into a time of the form %d.%d as described in the +// PAX specification. This function is capable of negative timestamps. +func formatPAXTime(ts time.Time) (s string) { + secs, nsecs := ts.Unix(), ts.Nanosecond() + if nsecs == 0 { + return strconv.FormatInt(secs, 10) + } + + // If seconds is negative, then perform correction. + sign := "" + if secs < 0 { + sign = "-" // Remember sign + secs = -(secs + 1) // Add a second to secs + nsecs = -(nsecs - 1E9) // Take that second away from nsecs + } + return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0") +} // parsePAXRecord parses the input PAX record string into a key-value pair. // If parsing is successful, it will slice off the currently read record and // return the remainder as r. -// -// A PAX record is of the following form: -// "%d %s=%s\n" % (size, key, value) func parsePAXRecord(s string) (k, v, r string, err error) { // The size field ends at the first space. sp := strings.IndexByte(s, ' ') @@ -232,21 +276,51 @@ func parsePAXRecord(s string) (k, v, r string, err error) { if eq == -1 { return "", "", s, ErrHeader } - return rec[:eq], rec[eq+1:], rem, nil + k, v = rec[:eq], rec[eq+1:] + + if !validPAXRecord(k, v) { + return "", "", s, ErrHeader + } + return k, v, rem, nil } // formatPAXRecord formats a single PAX record, prefixing it with the // appropriate length. -func formatPAXRecord(k, v string) string { +func formatPAXRecord(k, v string) (string, error) { + if !validPAXRecord(k, v) { + return "", ErrHeader + } + const padding = 3 // Extra padding for ' ', '=', and '\n' size := len(k) + len(v) + padding size += len(strconv.Itoa(size)) - record := fmt.Sprintf("%d %s=%s\n", size, k, v) + record := strconv.Itoa(size) + " " + k + "=" + v + "\n" // Final adjustment if adding size field increased the record size. if len(record) != size { size = len(record) - record = fmt.Sprintf("%d %s=%s\n", size, k, v) + record = strconv.Itoa(size) + " " + k + "=" + v + "\n" + } + return record, nil +} + +// validPAXRecord reports whether the key-value pair is valid where each +// record is formatted as: +// "%d %s=%s\n" % (size, key, value) +// +// Keys and values should be UTF-8, but the number of bad writers out there +// forces us to be a more liberal. +// Thus, we only reject all keys with NUL, and only reject NULs in values +// for the PAX version of the USTAR string fields. +// The key must not contain an '=' character. +func validPAXRecord(k, v string) bool { + if k == "" || strings.IndexByte(k, '=') >= 0 { + return false + } + switch k { + case paxPath, paxLinkpath, paxUname, paxGname: + return !hasNUL(v) + default: + return !hasNUL(k) } - return record } diff --git a/libgo/go/archive/tar/strconv_test.go b/libgo/go/archive/tar/strconv_test.go index beb70938bfd..4cc388cb0f2 100644 --- a/libgo/go/archive/tar/strconv_test.go +++ b/libgo/go/archive/tar/strconv_test.go @@ -110,6 +110,25 @@ func TestFormatNumeric(t *testing.T) { want string ok bool }{ + // Test base-8 (octal) encoded values. + {0, "0\x00", true}, + {7, "7\x00", true}, + {8, "\x80\x08", true}, + {077, "77\x00", true}, + {0100, "\x80\x00\x40", true}, + {0, "0000000\x00", true}, + {0123, "0000123\x00", true}, + {07654321, "7654321\x00", true}, + {07777777, "7777777\x00", true}, + {010000000, "\x80\x00\x00\x00\x00\x20\x00\x00", true}, + {0, "00000000000\x00", true}, + {000001234567, "00001234567\x00", true}, + {076543210321, "76543210321\x00", true}, + {012345670123, "12345670123\x00", true}, + {077777777777, "77777777777\x00", true}, + {0100000000000, "\x80\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00", true}, + {math.MaxInt64, "777777777777777777777\x00", true}, + // Test base-256 (binary) encoded values. {-1, "\xff", true}, {-1, "\xff\xff", true}, @@ -155,6 +174,45 @@ func TestFormatNumeric(t *testing.T) { } } +func TestFitsInOctal(t *testing.T) { + vectors := []struct { + input int64 + width int + ok bool + }{ + {-1, 1, false}, + {-1, 2, false}, + {-1, 3, false}, + {0, 1, true}, + {0 + 1, 1, false}, + {0, 2, true}, + {07, 2, true}, + {07 + 1, 2, false}, + {0, 4, true}, + {0777, 4, true}, + {0777 + 1, 4, false}, + {0, 8, true}, + {07777777, 8, true}, + {07777777 + 1, 8, false}, + {0, 12, true}, + {077777777777, 12, true}, + {077777777777 + 1, 12, false}, + {math.MaxInt64, 22, true}, + {012345670123, 12, true}, + {01564164, 12, true}, + {-012345670123, 12, false}, + {-01564164, 12, false}, + {-1564164, 30, false}, + } + + for _, v := range vectors { + ok := fitsInOctal(v.width, v.input) + if ok != v.ok { + t.Errorf("checkOctal(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok) + } + } +} + func TestParsePAXTime(t *testing.T) { vectors := []struct { in string @@ -236,6 +294,51 @@ func TestParsePAXTime(t *testing.T) { } } +func TestFormatPAXTime(t *testing.T) { + vectors := []struct { + sec, nsec int64 + want string + }{ + {1350244992, 0, "1350244992"}, + {1350244992, 300000000, "1350244992.3"}, + {1350244992, 23960100, "1350244992.0239601"}, + {1350244992, 23960108, "1350244992.023960108"}, + {+1, +1E9 - 1E0, "1.999999999"}, + {+1, +1E9 - 1E3, "1.999999"}, + {+1, +1E9 - 1E6, "1.999"}, + {+1, +0E0 - 0E0, "1"}, + {+1, +1E6 - 0E0, "1.001"}, + {+1, +1E3 - 0E0, "1.000001"}, + {+1, +1E0 - 0E0, "1.000000001"}, + {0, 1E9 - 1E0, "0.999999999"}, + {0, 1E9 - 1E3, "0.999999"}, + {0, 1E9 - 1E6, "0.999"}, + {0, 0E0, "0"}, + {0, 1E6 + 0E0, "0.001"}, + {0, 1E3 + 0E0, "0.000001"}, + {0, 1E0 + 0E0, "0.000000001"}, + {-1, -1E9 + 1E0, "-1.999999999"}, + {-1, -1E9 + 1E3, "-1.999999"}, + {-1, -1E9 + 1E6, "-1.999"}, + {-1, -0E0 + 0E0, "-1"}, + {-1, -1E6 + 0E0, "-1.001"}, + {-1, -1E3 + 0E0, "-1.000001"}, + {-1, -1E0 + 0E0, "-1.000000001"}, + {-1350244992, 0, "-1350244992"}, + {-1350244992, -300000000, "-1350244992.3"}, + {-1350244992, -23960100, "-1350244992.0239601"}, + {-1350244992, -23960108, "-1350244992.023960108"}, + } + + for _, v := range vectors { + got := formatPAXTime(time.Unix(v.sec, v.nsec)) + if got != v.want { + t.Errorf("formatPAXTime(%ds, %dns): got %q, want %q", + v.sec, v.nsec, got, v.want) + } + } +} + func TestParsePAXRecord(t *testing.T) { medName := strings.Repeat("CD", 50) longName := strings.Repeat("AB", 100) @@ -256,7 +359,7 @@ func TestParsePAXRecord(t *testing.T) { {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true}, {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true}, {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true}, - {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true}, + {"17 \x00hello=\x00world\n", "17 \x00hello=\x00world\n", "", "", false}, {"1 k=1\n", "1 k=1\n", "", "", false}, {"6 k~1\n", "6 k~1\n", "", "", false}, {"6_k=1\n", "6_k=1\n", "", "", false}, @@ -296,21 +399,33 @@ func TestFormatPAXRecord(t *testing.T) { inKey string inVal string want string + ok bool }{ - {"k", "v", "6 k=v\n"}, - {"path", "/etc/hosts", "19 path=/etc/hosts\n"}, - {"path", longName, "210 path=" + longName + "\n"}, - {"path", medName, "110 path=" + medName + "\n"}, - {"foo", "ba", "9 foo=ba\n"}, - {"foo", "bar", "11 foo=bar\n"}, - {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"}, - {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"}, - {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"}, - {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"}, + {"k", "v", "6 k=v\n", true}, + {"path", "/etc/hosts", "19 path=/etc/hosts\n", true}, + {"path", longName, "210 path=" + longName + "\n", true}, + {"path", medName, "110 path=" + medName + "\n", true}, + {"foo", "ba", "9 foo=ba\n", true}, + {"foo", "bar", "11 foo=bar\n", true}, + {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n", true}, + {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n", true}, + {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n", true}, + {"xhello", "\x00world", "17 xhello=\x00world\n", true}, + {"path", "null\x00", "", false}, + {"null\x00", "value", "", false}, + {paxSchilyXattr + "key", "null\x00", "26 SCHILY.xattr.key=null\x00\n", true}, } for _, v := range vectors { - got := formatPAXRecord(v.inKey, v.inVal) + got, err := formatPAXRecord(v.inKey, v.inVal) + ok := (err == nil) + if ok != v.ok { + if v.ok { + t.Errorf("formatPAXRecord(%q, %q): got format failure, want success", v.inKey, v.inVal) + } else { + t.Errorf("formatPAXRecord(%q, %q): got format success, want failure", v.inKey, v.inVal) + } + } if got != v.want { t.Errorf("formatPAXRecord(%q, %q): got %q, want %q", v.inKey, v.inVal, got, v.want) diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go index fb7a9dcfc47..af80d6e0c15 100644 --- a/libgo/go/archive/tar/tar_test.go +++ b/libgo/go/archive/tar/tar_test.go @@ -6,8 +6,12 @@ package tar import ( "bytes" + "errors" + "fmt" "internal/testenv" + "io" "io/ioutil" + "math" "os" "path" "path/filepath" @@ -17,6 +21,193 @@ import ( "time" ) +type testError struct{ error } + +type fileOps []interface{} // []T where T is (string | int64) + +// testFile is an io.ReadWriteSeeker where the IO operations performed +// on it must match the list of operations in ops. +type testFile struct { + ops fileOps + pos int64 +} + +func (f *testFile) Read(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } + if len(f.ops) == 0 { + return 0, io.EOF + } + s, ok := f.ops[0].(string) + if !ok { + return 0, errors.New("unexpected Read operation") + } + + n := copy(b, s) + if len(s) > n { + f.ops[0] = s[n:] + } else { + f.ops = f.ops[1:] + } + f.pos += int64(len(b)) + return n, nil +} + +func (f *testFile) Write(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } + if len(f.ops) == 0 { + return 0, errors.New("unexpected Write operation") + } + s, ok := f.ops[0].(string) + if !ok { + return 0, errors.New("unexpected Write operation") + } + + if !strings.HasPrefix(s, string(b)) { + return 0, testError{fmt.Errorf("got Write(%q), want Write(%q)", b, s)} + } + if len(s) > len(b) { + f.ops[0] = s[len(b):] + } else { + f.ops = f.ops[1:] + } + f.pos += int64(len(b)) + return len(b), nil +} + +func (f *testFile) Seek(pos int64, whence int) (int64, error) { + if pos == 0 && whence == io.SeekCurrent { + return f.pos, nil + } + if len(f.ops) == 0 { + return 0, errors.New("unexpected Seek operation") + } + s, ok := f.ops[0].(int64) + if !ok { + return 0, errors.New("unexpected Seek operation") + } + + if s != pos || whence != io.SeekCurrent { + return 0, testError{fmt.Errorf("got Seek(%d, %d), want Seek(%d, %d)", pos, whence, s, io.SeekCurrent)} + } + f.pos += s + f.ops = f.ops[1:] + return f.pos, nil +} + +func equalSparseEntries(x, y []sparseEntry) bool { + return (len(x) == 0 && len(y) == 0) || reflect.DeepEqual(x, y) +} + +func TestSparseEntries(t *testing.T) { + vectors := []struct { + in []sparseEntry + size int64 + + wantValid bool // Result of validateSparseEntries + wantAligned []sparseEntry // Result of alignSparseEntries + wantInverted []sparseEntry // Result of invertSparseEntries + }{{ + in: []sparseEntry{}, size: 0, + wantValid: true, + wantInverted: []sparseEntry{{0, 0}}, + }, { + in: []sparseEntry{}, size: 5000, + wantValid: true, + wantInverted: []sparseEntry{{0, 5000}}, + }, { + in: []sparseEntry{{0, 5000}}, size: 5000, + wantValid: true, + wantAligned: []sparseEntry{{0, 5000}}, + wantInverted: []sparseEntry{{5000, 0}}, + }, { + in: []sparseEntry{{1000, 4000}}, size: 5000, + wantValid: true, + wantAligned: []sparseEntry{{1024, 3976}}, + wantInverted: []sparseEntry{{0, 1000}, {5000, 0}}, + }, { + in: []sparseEntry{{0, 3000}}, size: 5000, + wantValid: true, + wantAligned: []sparseEntry{{0, 2560}}, + wantInverted: []sparseEntry{{3000, 2000}}, + }, { + in: []sparseEntry{{3000, 2000}}, size: 5000, + wantValid: true, + wantAligned: []sparseEntry{{3072, 1928}}, + wantInverted: []sparseEntry{{0, 3000}, {5000, 0}}, + }, { + in: []sparseEntry{{2000, 2000}}, size: 5000, + wantValid: true, + wantAligned: []sparseEntry{{2048, 1536}}, + wantInverted: []sparseEntry{{0, 2000}, {4000, 1000}}, + }, { + in: []sparseEntry{{0, 2000}, {8000, 2000}}, size: 10000, + wantValid: true, + wantAligned: []sparseEntry{{0, 1536}, {8192, 1808}}, + wantInverted: []sparseEntry{{2000, 6000}, {10000, 0}}, + }, { + in: []sparseEntry{{0, 2000}, {2000, 2000}, {4000, 0}, {4000, 3000}, {7000, 1000}, {8000, 0}, {8000, 2000}}, size: 10000, + wantValid: true, + wantAligned: []sparseEntry{{0, 1536}, {2048, 1536}, {4096, 2560}, {7168, 512}, {8192, 1808}}, + wantInverted: []sparseEntry{{10000, 0}}, + }, { + in: []sparseEntry{{0, 0}, {1000, 0}, {2000, 0}, {3000, 0}, {4000, 0}, {5000, 0}}, size: 5000, + wantValid: true, + wantInverted: []sparseEntry{{0, 5000}}, + }, { + in: []sparseEntry{{1, 0}}, size: 0, + wantValid: false, + }, { + in: []sparseEntry{{-1, 0}}, size: 100, + wantValid: false, + }, { + in: []sparseEntry{{0, -1}}, size: 100, + wantValid: false, + }, { + in: []sparseEntry{{0, 0}}, size: -100, + wantValid: false, + }, { + in: []sparseEntry{{math.MaxInt64, 3}, {6, -5}}, size: 35, + wantValid: false, + }, { + in: []sparseEntry{{1, 3}, {6, -5}}, size: 35, + wantValid: false, + }, { + in: []sparseEntry{{math.MaxInt64, math.MaxInt64}}, size: math.MaxInt64, + wantValid: false, + }, { + in: []sparseEntry{{3, 3}}, size: 5, + wantValid: false, + }, { + in: []sparseEntry{{2, 0}, {1, 0}, {0, 0}}, size: 3, + wantValid: false, + }, { + in: []sparseEntry{{1, 3}, {2, 2}}, size: 10, + wantValid: false, + }} + + for i, v := range vectors { + gotValid := validateSparseEntries(v.in, v.size) + if gotValid != v.wantValid { + t.Errorf("test %d, validateSparseEntries() = %v, want %v", i, gotValid, v.wantValid) + } + if !v.wantValid { + continue + } + gotAligned := alignSparseEntries(append([]sparseEntry{}, v.in...), v.size) + if !equalSparseEntries(gotAligned, v.wantAligned) { + t.Errorf("test %d, alignSparseEntries():\ngot %v\nwant %v", i, gotAligned, v.wantAligned) + } + gotInverted := invertSparseEntries(append([]sparseEntry{}, v.in...), v.size) + if !equalSparseEntries(gotInverted, v.wantInverted) { + t.Errorf("test %d, inverseSparseEntries():\ngot %v\nwant %v", i, gotInverted, v.wantInverted) + } + } +} + func TestFileInfoHeader(t *testing.T) { fi, err := os.Stat("testdata/small.txt") if err != nil { @@ -109,15 +300,12 @@ func TestRoundTrip(t *testing.T) { var b bytes.Buffer tw := NewWriter(&b) hdr := &Header{ - Name: "file.txt", - Uid: 1 << 21, // too big for 8 octal digits - Size: int64(len(data)), - // AddDate to strip monotonic clock reading, - // and Round to discard sub-second precision, - // both of which are not included in the tar header - // and would otherwise break the round-trip check - // below. - ModTime: time.Now().AddDate(0, 0, 0).Round(1 * time.Second), + Name: "file.txt", + Uid: 1 << 21, // Too big for 8 octal digits + Size: int64(len(data)), + ModTime: time.Now().Round(time.Second), + PAXRecords: map[string]string{"uid": "2097152"}, + Format: FormatPAX, } if err := tw.WriteHeader(hdr); err != nil { t.Fatalf("tw.WriteHeader: %v", err) @@ -329,3 +517,338 @@ func TestHeaderRoundTrip(t *testing.T) { } } } + +func TestHeaderAllowedFormats(t *testing.T) { + vectors := []struct { + header *Header // Input header + paxHdrs map[string]string // Expected PAX headers that may be needed + formats Format // Expected formats that can encode the header + }{{ + header: &Header{}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Size: 077777777777}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Size: 077777777777, Format: FormatUSTAR}, + formats: FormatUSTAR, + }, { + header: &Header{Size: 077777777777, Format: FormatPAX}, + formats: FormatUSTAR | FormatPAX, + }, { + header: &Header{Size: 077777777777, Format: FormatGNU}, + formats: FormatGNU, + }, { + header: &Header{Size: 077777777777 + 1}, + paxHdrs: map[string]string{paxSize: "8589934592"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{Size: 077777777777 + 1, Format: FormatPAX}, + paxHdrs: map[string]string{paxSize: "8589934592"}, + formats: FormatPAX, + }, { + header: &Header{Size: 077777777777 + 1, Format: FormatGNU}, + paxHdrs: map[string]string{paxSize: "8589934592"}, + formats: FormatGNU, + }, { + header: &Header{Mode: 07777777}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Mode: 07777777 + 1}, + formats: FormatGNU, + }, { + header: &Header{Devmajor: -123}, + formats: FormatGNU, + }, { + header: &Header{Devmajor: 1<<56 - 1}, + formats: FormatGNU, + }, { + header: &Header{Devmajor: 1 << 56}, + formats: FormatUnknown, + }, { + header: &Header{Devmajor: -1 << 56}, + formats: FormatGNU, + }, { + header: &Header{Devmajor: -1<<56 - 1}, + formats: FormatUnknown, + }, { + header: &Header{Name: "用戶名", Devmajor: -1 << 56}, + formats: FormatGNU, + }, { + header: &Header{Size: math.MaxInt64}, + paxHdrs: map[string]string{paxSize: "9223372036854775807"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{Size: math.MinInt64}, + paxHdrs: map[string]string{paxSize: "-9223372036854775808"}, + formats: FormatUnknown, + }, { + header: &Header{Uname: "0123456789abcdef0123456789abcdef"}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Uname: "0123456789abcdef0123456789abcdefx"}, + paxHdrs: map[string]string{paxUname: "0123456789abcdef0123456789abcdefx"}, + formats: FormatPAX, + }, { + header: &Header{Name: "foobar"}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Name: strings.Repeat("a", nameSize)}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Name: strings.Repeat("a", nameSize+1)}, + paxHdrs: map[string]string{paxPath: strings.Repeat("a", nameSize+1)}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{Linkname: "用戶名"}, + paxHdrs: map[string]string{paxLinkpath: "用戶名"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{Linkname: strings.Repeat("用戶名\x00", nameSize)}, + paxHdrs: map[string]string{paxLinkpath: strings.Repeat("用戶名\x00", nameSize)}, + formats: FormatUnknown, + }, { + header: &Header{Linkname: "\x00hello"}, + paxHdrs: map[string]string{paxLinkpath: "\x00hello"}, + formats: FormatUnknown, + }, { + header: &Header{Uid: 07777777}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Uid: 07777777 + 1}, + paxHdrs: map[string]string{paxUid: "2097152"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{Xattrs: nil}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Xattrs: map[string]string{"foo": "bar"}}, + paxHdrs: map[string]string{paxSchilyXattr + "foo": "bar"}, + formats: FormatPAX, + }, { + header: &Header{Xattrs: map[string]string{"foo": "bar"}, Format: FormatGNU}, + paxHdrs: map[string]string{paxSchilyXattr + "foo": "bar"}, + formats: FormatUnknown, + }, { + header: &Header{Xattrs: map[string]string{"用戶名": "\x00hello"}}, + paxHdrs: map[string]string{paxSchilyXattr + "用戶名": "\x00hello"}, + formats: FormatPAX, + }, { + header: &Header{Xattrs: map[string]string{"foo=bar": "baz"}}, + formats: FormatUnknown, + }, { + header: &Header{Xattrs: map[string]string{"foo": ""}}, + paxHdrs: map[string]string{paxSchilyXattr + "foo": ""}, + formats: FormatPAX, + }, { + header: &Header{ModTime: time.Unix(0, 0)}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(077777777777, 0)}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(077777777777+1, 0)}, + paxHdrs: map[string]string{paxMtime: "8589934592"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(math.MaxInt64, 0)}, + paxHdrs: map[string]string{paxMtime: "9223372036854775807"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(math.MaxInt64, 0), Format: FormatUSTAR}, + paxHdrs: map[string]string{paxMtime: "9223372036854775807"}, + formats: FormatUnknown, + }, { + header: &Header{ModTime: time.Unix(-1, 0)}, + paxHdrs: map[string]string{paxMtime: "-1"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(1, 500)}, + paxHdrs: map[string]string{paxMtime: "1.0000005"}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(1, 0)}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(1, 0), Format: FormatPAX}, + formats: FormatUSTAR | FormatPAX, + }, { + header: &Header{ModTime: time.Unix(1, 500), Format: FormatUSTAR}, + paxHdrs: map[string]string{paxMtime: "1.0000005"}, + formats: FormatUSTAR, + }, { + header: &Header{ModTime: time.Unix(1, 500), Format: FormatPAX}, + paxHdrs: map[string]string{paxMtime: "1.0000005"}, + formats: FormatPAX, + }, { + header: &Header{ModTime: time.Unix(1, 500), Format: FormatGNU}, + paxHdrs: map[string]string{paxMtime: "1.0000005"}, + formats: FormatGNU, + }, { + header: &Header{ModTime: time.Unix(-1, 500)}, + paxHdrs: map[string]string{paxMtime: "-0.9999995"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{ModTime: time.Unix(-1, 500), Format: FormatGNU}, + paxHdrs: map[string]string{paxMtime: "-0.9999995"}, + formats: FormatGNU, + }, { + header: &Header{AccessTime: time.Unix(0, 0)}, + paxHdrs: map[string]string{paxAtime: "0"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{AccessTime: time.Unix(0, 0), Format: FormatUSTAR}, + paxHdrs: map[string]string{paxAtime: "0"}, + formats: FormatUnknown, + }, { + header: &Header{AccessTime: time.Unix(0, 0), Format: FormatPAX}, + paxHdrs: map[string]string{paxAtime: "0"}, + formats: FormatPAX, + }, { + header: &Header{AccessTime: time.Unix(0, 0), Format: FormatGNU}, + paxHdrs: map[string]string{paxAtime: "0"}, + formats: FormatGNU, + }, { + header: &Header{AccessTime: time.Unix(-123, 0)}, + paxHdrs: map[string]string{paxAtime: "-123"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{AccessTime: time.Unix(-123, 0), Format: FormatPAX}, + paxHdrs: map[string]string{paxAtime: "-123"}, + formats: FormatPAX, + }, { + header: &Header{ChangeTime: time.Unix(123, 456)}, + paxHdrs: map[string]string{paxCtime: "123.000000456"}, + formats: FormatPAX | FormatGNU, + }, { + header: &Header{ChangeTime: time.Unix(123, 456), Format: FormatUSTAR}, + paxHdrs: map[string]string{paxCtime: "123.000000456"}, + formats: FormatUnknown, + }, { + header: &Header{ChangeTime: time.Unix(123, 456), Format: FormatGNU}, + paxHdrs: map[string]string{paxCtime: "123.000000456"}, + formats: FormatGNU, + }, { + header: &Header{ChangeTime: time.Unix(123, 456), Format: FormatPAX}, + paxHdrs: map[string]string{paxCtime: "123.000000456"}, + formats: FormatPAX, + }, { + header: &Header{Name: "foo/", Typeflag: TypeDir}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }, { + header: &Header{Name: "foo/", Typeflag: TypeReg}, + formats: FormatUnknown, + }, { + header: &Header{Name: "foo/", Typeflag: TypeSymlink}, + formats: FormatUSTAR | FormatPAX | FormatGNU, + }} + + for i, v := range vectors { + formats, paxHdrs, err := v.header.allowedFormats() + if formats != v.formats { + t.Errorf("test %d, allowedFormats(): got %v, want %v", i, formats, v.formats) + } + if formats&FormatPAX > 0 && !reflect.DeepEqual(paxHdrs, v.paxHdrs) && !(len(paxHdrs) == 0 && len(v.paxHdrs) == 0) { + t.Errorf("test %d, allowedFormats():\ngot %v\nwant %s", i, paxHdrs, v.paxHdrs) + } + if (formats != FormatUnknown) && (err != nil) { + t.Errorf("test %d, unexpected error: %v", i, err) + } + if (formats == FormatUnknown) && (err == nil) { + t.Errorf("test %d, got nil-error, want non-nil error", i) + } + } +} + +func Benchmark(b *testing.B) { + type file struct { + hdr *Header + body []byte + } + + vectors := []struct { + label string + files []file + }{{ + "USTAR", + []file{{ + &Header{Name: "bar", Mode: 0640, Size: int64(3)}, + []byte("foo"), + }, { + &Header{Name: "world", Mode: 0640, Size: int64(5)}, + []byte("hello"), + }}, + }, { + "GNU", + []file{{ + &Header{Name: "bar", Mode: 0640, Size: int64(3), Devmajor: -1}, + []byte("foo"), + }, { + &Header{Name: "world", Mode: 0640, Size: int64(5), Devmajor: -1}, + []byte("hello"), + }}, + }, { + "PAX", + []file{{ + &Header{Name: "bar", Mode: 0640, Size: int64(3), Xattrs: map[string]string{"foo": "bar"}}, + []byte("foo"), + }, { + &Header{Name: "world", Mode: 0640, Size: int64(5), Xattrs: map[string]string{"foo": "bar"}}, + []byte("hello"), + }}, + }} + + b.Run("Writer", func(b *testing.B) { + for _, v := range vectors { + b.Run(v.label, func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + // Writing to ioutil.Discard because we want to + // test purely the writer code and not bring in disk performance into this. + tw := NewWriter(ioutil.Discard) + for _, file := range v.files { + if err := tw.WriteHeader(file.hdr); err != nil { + b.Errorf("unexpected WriteHeader error: %v", err) + } + if _, err := tw.Write(file.body); err != nil { + b.Errorf("unexpected Write error: %v", err) + } + } + if err := tw.Close(); err != nil { + b.Errorf("unexpected Close error: %v", err) + } + } + }) + } + }) + + b.Run("Reader", func(b *testing.B) { + for _, v := range vectors { + var buf bytes.Buffer + var r bytes.Reader + + // Write the archive to a byte buffer. + tw := NewWriter(&buf) + for _, file := range v.files { + tw.WriteHeader(file.hdr) + tw.Write(file.body) + } + tw.Close() + b.Run(v.label, func(b *testing.B) { + b.ReportAllocs() + // Read from the byte buffer. + for i := 0; i < b.N; i++ { + r.Reset(buf.Bytes()) + tr := NewReader(&r) + if _, err := tr.Next(); err != nil { + b.Errorf("unexpected Next error: %v", err) + } + if _, err := io.Copy(ioutil.Discard, tr); err != nil { + b.Errorf("unexpected Copy error : %v", err) + } + } + }) + } + }) + +} diff --git a/libgo/go/archive/tar/testdata/gnu-long-nul.tar b/libgo/go/archive/tar/testdata/gnu-long-nul.tar new file mode 100644 index 0000000000000000000000000000000000000000..28bc812aa60e81ea324297c81c738486acffc09c GIT binary patch literal 2560 zcmdPX*VA|K$8wwCI?c&U|<9U<_rqKG;!KK9|iA4$uNFwAh z(LG1BDGd;nOd;HlV4+|L3I(V*%L?&h*u>fXD6hgM&KaQJha%1hHHi0zdj!NPWD+XL zy~Mf*MHfO-7>YQu-cj~w2#kgR?Lxr7(8$=t)Xdz%l6EZGxqj4SN<)Blv5qjAQa6t3 zr(FmjVu^Mv+PQwzWJ*JTcCn5ynNl~7>Ze@@AYzGjEZVt#)MQFSfOfHtFqu*}j_Mx` Lfzc2cx*-4no2;l4 literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/gnu-utf8.tar b/libgo/go/archive/tar/testdata/gnu-utf8.tar new file mode 100644 index 0000000000000000000000000000000000000000..2c9c8079cf651d4271ed78ac12bed01df5882f16 GIT binary patch literal 2560 zcmdPX*VA|K$>Jxw74X(NP%*@pq_zwgdvgE SfDU0ZYQ<;>jE2Cl4gmlQRWrx{ literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/pax-global-records.tar b/libgo/go/archive/tar/testdata/pax-global-records.tar new file mode 100644 index 0000000000000000000000000000000000000000..3d3d241e65c3a18feae324e8c40c9e5c76515dde GIT binary patch literal 7168 zcmeHL!D_=W4E4ER;V;M}*-LlnxjXI`JeGBZl#Mone*Wa9rr4nrhBeBfTpT&!#d^cpD(885)#?nu-$bl zd_2p;+hBpM{R+d!YIE8hxR?tY^UL#n+jl6O_LaKNYd-D1vHp<<`zJM7tNzO*g*mMS z{}PVT{JZ_3frq#ms21`Cr=+Hc0kHIcL{G*ZFA#Efwe*);p(rx?(dkdptIvyaeUIQm zC7-2Q)O+&%G{(pIJ#q(#>i-#uLc#hT`hT40Pta=rFC=*e`!w3WI)BE>e1hozPB`6P z`9Jr6+W!j+!|;>--`D@FR+%d@^62z z6WvCNQYsy?g}w--Wmq1GRb#yo!^n6FL+rVPFb)i25_DFxFl=_ySE2CthOp~yfMC5n zgzw5X;&fI8rxS10qL)!vj@P!Lk;SKDDCFaylA_ktT^1Y*N_iCY9|;HQx}x(s9~OWA zqJCA?@<&&If%}1Z$P#4!Ysi0;#K`|&n6$PSPx2 Y`kB|j_kpV{SiUy=c3uImfCCCV00+Y!FaQ7m literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/ustar.issue12594.tar b/libgo/go/archive/tar/testdata/pax-nil-sparse-hole.tar similarity index 75% rename from libgo/go/archive/tar/testdata/ustar.issue12594.tar rename to libgo/go/archive/tar/testdata/pax-nil-sparse-hole.tar index c7910ae9f43b54e32b9facf34c9e96a03626adea..b44327bdbfb343658e5142f2129d7688f3044021 100644 GIT binary patch literal 3072 zcmeHH%?iRW4DPv4(I=Qq#{4<#s-8p;AE2@vCi{_AVfgfR)5#e0R)vk`(l!Zg@_qSw zRL!1LM%qMjVQxwrin0syYVvK&u}WA%A8S*X1e6#v(Ri)GaoNM%mA212!gF^cirwKH zeV8xRwbm){kvFfbS9078b1PL+`kfe#>tRrnDop;Q6fB_}P;`d`kk1{^iS=j6KXt0# z<^}!e3vlSZ*L*u7{k~1L`i~P_G4U5o`qKZn$%)JX@J^vJ=yD>2g)##I0fB&kCj?&3 CI8e<1 literal 3072 zcmeH{OAZ1d42D^I3QnMu*Q`7Y3lI}zjDyJ>-x-MuO(YruiKg8EX-er|zJ@U#qB+@J zXt!b6$eWdM0R%WODH+#F6DIfojL?~Mu00J0r&<4gv#xOaM5(Wb!BV%(j289X+ zI)KvRlEfmQ^^{tL?m0@$qmzCkLqmmv#F7kKs>V3AQxFN}F>ui-ycfm?#?I`Jb2|8dWnI0;3@?JVO8g0FZP& literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/pax-nul-xattrs.tar b/libgo/go/archive/tar/testdata/pax-nul-xattrs.tar new file mode 100644 index 0000000000000000000000000000000000000000..881f51768f9872f8d9bfcd2cbb637a64c88b59fb GIT binary patch literal 2560 zcmWGYtnf%pOi3*&)-%vgN=(tsE6vH#E2$`9pdK)Q00tbifq}6(Ob(=k!NAbi+{l1I zp@Mo&z->}#aYE@j+a){BLMtXu_aCah^nR1rE*#&;K|=WmI@H1V%$( H1cU$p$tyMF literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/pax-pos-size-file.tar b/libgo/go/archive/tar/testdata/pax-pos-size-file.tar index aed9a8aa48f7ab346d4f1bd7588a8060f5c2d6d2..ea5ccf916426a5b6300dd341dffeeb349e51ad90 100644 GIT binary patch delta 41 xcmZn=X%N{kgN4<^fI-1vaw202e`#?^ViALZK~{chNpWK4#D$WZHCeB-0001>4I2Oe delta 41 xcmZn=X%N{kgN4<=fI-1vaw202e`#?^Vv&LZLsoujNpWK4#D$WZHCeB-0090y4EF#4 diff --git a/libgo/go/archive/tar/testdata/pax-records.tar b/libgo/go/archive/tar/testdata/pax-records.tar new file mode 100644 index 0000000000000000000000000000000000000000..276c211baa388cd4857f60be3355dc710c079adf GIT binary patch literal 2560 zcmWGYtnf%pOi3*&)-%vg%gjk-pgu5w00tbifuXS}Ob(=k!NAbaz|4q2p@RBO!8Eb7 zxFoR%Xg#LPh!8QfP;mG6arAT7E67f_1qKC|k*Pv*er|4RUWu(oYEDkRj>3~2)1FW5 z;W9N)D9uaEO|{L*&r2r;bB%})9NM0wQI(8HJV7=Ju?a?-j1kv{3qm&5xc=w?9rhykjgnT@;M()2-EV}6ypIW4 zm*mBPoymBf{O?}zAMMUW`UKowz+L0vu6oVGGx7QtN_hQ0MUzwMKOAx<{8wZ(tg^0& zWSp?T=YcN*zYKgC_%p!)+e8FXL%{zBiBeXoUd6Lgn;H871mdv{nV}k5sUZL?#j{eI p8T$bQ;;{~yp&DALApk7Jvr?NG`vC;vu@0G`8d`_|BJgeqTmi{^;4uII literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/trailing-slash.tar b/libgo/go/archive/tar/testdata/trailing-slash.tar new file mode 100644 index 0000000000000000000000000000000000000000..bf1b2ec426b4999b111c7f0914fb1f2d52b91728 GIT binary patch literal 2560 zcmXpsGBz4Gd!2kkq(FP`FW-vLBN(KWX14Anam zFj`@3XrNG#Sdw8&v*@Q?!WuA>xdvlQlIJEmL^~{RXSF)#oEGZPaA5Df(AG_n|kZD?R%Y|fxyKx21-jV~=ONh|_7iBh{jE;leR XgnG`9QsYMTkA}c#2#kgRtwR6+ua*#N literal 0 HcmV?d00001 diff --git a/libgo/go/archive/tar/testdata/writer-big-long.tar b/libgo/go/archive/tar/testdata/writer-big-long.tar index 52bd748f3b286745455e815c63b6801c3fe06e91..09fc5dd3dd7fc5de3b6d22461fa23152fd499a41 100644 GIT binary patch delta 155 zcmZorXyBR9Dq(8IV1NJ&2F8XaMg|ND6_XPgQ#eYCOA?EK@{<=beV@cMOT@@Pp*XWD z)z;A5(A?6(%+k=pglqFcrXa@2flT%j?KMr!OiVz=8Je3KAk#1l7z~Y!jg8FB4NMKp TfmWHBm>DrB7@%6k$@(1tuVp1| delta 177 zcmZqRX;7HZDq(EIU}$7)Y-Db3U}|8_U|?)yW@^r$P%&AMF@?RfxFoSiL1E%T$H|_o z+b1#2+Psm;pK-DRW3{CL5SW>mFaRk-b5jF2-M|0_EFcoaU_&D#pj`?EAcHxe1~W|N OWc|MR0FwhF5d;9q&@8L~ diff --git a/libgo/go/archive/tar/testdata/writer-big.tar b/libgo/go/archive/tar/testdata/writer-big.tar index 753e883cebf52ac1291f1b7bf1b7a37ae517b2d9..435dcbce6abc74dc5efa1f4dd34129eb7701c697 100644 GIT binary patch delta 6 NcmZorXkb~u1ONu~0mlFU delta 106 UcmZo*X;4_eG`WCr0*!G40EZqaD*ylh diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go index c51c243a8b8..97d23f80388 100644 --- a/libgo/go/archive/tar/writer.go +++ b/libgo/go/archive/tar/writer.go @@ -4,255 +4,391 @@ package tar -// TODO(dsymonds): -// - catch more errors (no first header, etc.) - import ( "bytes" - "errors" "fmt" "io" "path" "sort" - "strconv" "strings" "time" ) -var ( - ErrWriteTooLong = errors.New("archive/tar: write too long") - ErrFieldTooLong = errors.New("archive/tar: header field too long") - ErrWriteAfterClose = errors.New("archive/tar: write after close") - errInvalidHeader = errors.New("archive/tar: header field too long or contains invalid values") -) - -// A Writer provides sequential writing of a tar archive in POSIX.1 format. -// A tar archive consists of a sequence of files. -// Call WriteHeader to begin a new file, and then call Write to supply that file's data, -// writing at most hdr.Size bytes in total. +// Writer provides sequential writing of a tar archive. +// Write.WriteHeader begins a new file with the provided Header, +// and then Writer can be treated as an io.Writer to supply that file's data. type Writer struct { - w io.Writer - err error - nb int64 // number of unwritten bytes for current file entry - pad int64 // amount of padding to write after current file entry - closed bool - usedBinary bool // whether the binary numeric field extension was used - preferPax bool // use PAX header instead of binary numeric header - hdrBuff block // buffer to use in writeHeader when writing a regular header - paxHdrBuff block // buffer to use in writeHeader when writing a PAX header + w io.Writer + pad int64 // Amount of padding to write after current file entry + curr fileWriter // Writer for current file entry + hdr Header // Shallow copy of Header that is safe for mutations + blk block // Buffer to use as temporary local storage + + // err is a persistent error. + // It is only the responsibility of every exported method of Writer to + // ensure that this error is sticky. + err error } // NewWriter creates a new Writer writing to w. -func NewWriter(w io.Writer) *Writer { return &Writer{w: w} } +func NewWriter(w io.Writer) *Writer { + return &Writer{w: w, curr: ®FileWriter{w, 0}} +} + +type fileWriter interface { + io.Writer + fileState -// Flush finishes writing the current file (optional). + ReadFrom(io.Reader) (int64, error) +} + +// Flush finishes writing the current file's block padding. +// The current file must be fully written before Flush can be called. +// +// This is unnecessary as the next call to WriteHeader or Close +// will implicitly flush out the file's padding. func (tw *Writer) Flush() error { - if tw.nb > 0 { - tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb) + if tw.err != nil { return tw.err } - - n := tw.nb + tw.pad - for n > 0 && tw.err == nil { - nr := n - if nr > blockSize { - nr = blockSize - } - var nw int - nw, tw.err = tw.w.Write(zeroBlock[0:nr]) - n -= int64(nw) + if nb := tw.curr.LogicalRemaining(); nb > 0 { + return fmt.Errorf("archive/tar: missed writing %d bytes", nb) + } + if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil { + return tw.err } - tw.nb = 0 tw.pad = 0 - return tw.err + return nil } -var ( - minTime = time.Unix(0, 0) - // There is room for 11 octal digits (33 bits) of mtime. - maxTime = minTime.Add((1<<33 - 1) * time.Second) -) - // WriteHeader writes hdr and prepares to accept the file's contents. -// WriteHeader calls Flush if it is not the first header. -// Calling after a Close will return ErrWriteAfterClose. +// The Header.Size determines how many bytes can be written for the next file. +// If the current file is not fully written, then this returns an error. +// This implicitly flushes any padding necessary before writing the header. func (tw *Writer) WriteHeader(hdr *Header) error { - return tw.writeHeader(hdr, true) -} - -// WriteHeader writes hdr and prepares to accept the file's contents. -// WriteHeader calls Flush if it is not the first header. -// Calling after a Close will return ErrWriteAfterClose. -// As this method is called internally by writePax header to allow it to -// suppress writing the pax header. -func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { - if tw.closed { - return ErrWriteAfterClose + if err := tw.Flush(); err != nil { + return err } - if tw.err == nil { - tw.Flush() + tw.hdr = *hdr // Shallow copy of Header + + // Round ModTime and ignore AccessTime and ChangeTime unless + // the format is explicitly chosen. + // This ensures nominal usage of WriteHeader (without specifying the format) + // does not always result in the PAX format being chosen, which + // causes a 1KiB increase to every header. + if tw.hdr.Format == FormatUnknown { + tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second) + tw.hdr.AccessTime = time.Time{} + tw.hdr.ChangeTime = time.Time{} } - if tw.err != nil { + + allowedFormats, paxHdrs, err := tw.hdr.allowedFormats() + switch { + case allowedFormats.has(FormatUSTAR): + tw.err = tw.writeUSTARHeader(&tw.hdr) return tw.err + case allowedFormats.has(FormatPAX): + tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs) + return tw.err + case allowedFormats.has(FormatGNU): + tw.err = tw.writeGNUHeader(&tw.hdr) + return tw.err + default: + return err // Non-fatal error } +} - // a map to hold pax header records, if any are needed - paxHeaders := make(map[string]string) - - // TODO(dsnet): we might want to use PAX headers for - // subsecond time resolution, but for now let's just capture - // too long fields or non ascii characters - - // We need to select which scratch buffer to use carefully, - // since this method is called recursively to write PAX headers. - // If allowPax is true, this is the non-recursive call, and we will use hdrBuff. - // If allowPax is false, we are being called by writePAXHeader, and hdrBuff is - // already being used by the non-recursive call, so we must use paxHdrBuff. - header := &tw.hdrBuff - if !allowPax { - header = &tw.paxHdrBuff +func (tw *Writer) writeUSTARHeader(hdr *Header) error { + // Check if we can use USTAR prefix/suffix splitting. + var namePrefix string + if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok { + namePrefix, hdr.Name = prefix, suffix } - copy(header[:], zeroBlock[:]) - // Wrappers around formatter that automatically sets paxHeaders if the - // argument extends beyond the capacity of the input byte slice. + // Pack the main header. var f formatter - var formatString = func(b []byte, s string, paxKeyword string) { - needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s) - if needsPaxHeader { - paxHeaders[paxKeyword] = s + blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal) + f.formatString(blk.USTAR().Prefix(), namePrefix) + blk.SetFormat(FormatUSTAR) + if f.err != nil { + return f.err // Should never happen since header is validated + } + return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag) +} + +func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { + realName, realSize := hdr.Name, hdr.Size + + // TODO(dsnet): Re-enable this when adding sparse support. + // See https://golang.org/issue/22735 + /* + // Handle sparse files. + var spd sparseDatas + var spb []byte + if len(hdr.SparseHoles) > 0 { + sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map + sph = alignSparseEntries(sph, hdr.Size) + spd = invertSparseEntries(sph, hdr.Size) + + // Format the sparse map. + hdr.Size = 0 // Replace with encoded size + spb = append(strconv.AppendInt(spb, int64(len(spd)), 10), '\n') + for _, s := range spd { + hdr.Size += s.Length + spb = append(strconv.AppendInt(spb, s.Offset, 10), '\n') + spb = append(strconv.AppendInt(spb, s.Length, 10), '\n') + } + pad := blockPadding(int64(len(spb))) + spb = append(spb, zeroBlock[:pad]...) + hdr.Size += int64(len(spb)) // Accounts for encoded sparse map + + // Add and modify appropriate PAX records. + dir, file := path.Split(realName) + hdr.Name = path.Join(dir, "GNUSparseFile.0", file) + paxHdrs[paxGNUSparseMajor] = "1" + paxHdrs[paxGNUSparseMinor] = "0" + paxHdrs[paxGNUSparseName] = realName + paxHdrs[paxGNUSparseRealSize] = strconv.FormatInt(realSize, 10) + paxHdrs[paxSize] = strconv.FormatInt(hdr.Size, 10) + delete(paxHdrs, paxPath) // Recorded by paxGNUSparseName + } + */ + _ = realSize + + // Write PAX records to the output. + isGlobal := hdr.Typeflag == TypeXGlobalHeader + if len(paxHdrs) > 0 || isGlobal { + // Sort keys for deterministic ordering. + var keys []string + for k := range paxHdrs { + keys = append(keys, k) + } + sort.Strings(keys) + + // Write each record to a buffer. + var buf bytes.Buffer + for _, k := range keys { + rec, err := formatPAXRecord(k, paxHdrs[k]) + if err != nil { + return err + } + buf.WriteString(rec) } - // Write string in a best-effort manner to satisfy readers that expect - // the field to be non-empty. - s = toASCII(s) - if len(s) > len(b) { - s = s[:len(b)] + // Write the extended header file. + var name string + var flag byte + if isGlobal { + name = realName + if name == "" { + name = "GlobalHead.0.0" + } + flag = TypeXGlobalHeader + } else { + dir, file := path.Split(realName) + name = path.Join(dir, "PaxHeaders.0", file) + flag = TypeXHeader } - f.formatString(b, s) // Should never error - } - var formatNumeric = func(b []byte, x int64, paxKeyword string) { - // Try octal first. - s := strconv.FormatInt(x, 8) - if len(s) < len(b) { - f.formatOctal(b, x) - return + data := buf.String() + if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { + return err // Global headers return here } + } - // If it is too long for octal, and PAX is preferred, use a PAX header. - if paxKeyword != paxNone && tw.preferPax { - f.formatOctal(b, 0) - s := strconv.FormatInt(x, 10) - paxHeaders[paxKeyword] = s - return + // Pack the main header. + var f formatter // Ignore errors since they are expected + fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) } + blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal) + blk.SetFormat(FormatPAX) + if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil { + return err + } + + // TODO(dsnet): Re-enable this when adding sparse support. + // See https://golang.org/issue/22735 + /* + // Write the sparse map and setup the sparse writer if necessary. + if len(spd) > 0 { + // Use tw.curr since the sparse map is accounted for in hdr.Size. + if _, err := tw.curr.Write(spb); err != nil { + return err + } + tw.curr = &sparseFileWriter{tw.curr, spd, 0} } + */ + return nil +} - tw.usedBinary = true - f.formatNumeric(b, x) +func (tw *Writer) writeGNUHeader(hdr *Header) error { + // Use long-link files if Name or Linkname exceeds the field size. + const longName = "././@LongLink" + if len(hdr.Name) > nameSize { + data := hdr.Name + "\x00" + if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil { + return err + } + } + if len(hdr.Linkname) > nameSize { + data := hdr.Linkname + "\x00" + if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil { + return err + } } - // Handle out of range ModTime carefully. - var modTime int64 - if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { - modTime = hdr.ModTime.Unix() + // Pack the main header. + var f formatter // Ignore errors since they are expected + var spd sparseDatas + var spb []byte + blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric) + if !hdr.AccessTime.IsZero() { + f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix()) + } + if !hdr.ChangeTime.IsZero() { + f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix()) + } + // TODO(dsnet): Re-enable this when adding sparse support. + // See https://golang.org/issue/22735 + /* + if hdr.Typeflag == TypeGNUSparse { + sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map + sph = alignSparseEntries(sph, hdr.Size) + spd = invertSparseEntries(sph, hdr.Size) + + // Format the sparse map. + formatSPD := func(sp sparseDatas, sa sparseArray) sparseDatas { + for i := 0; len(sp) > 0 && i < sa.MaxEntries(); i++ { + f.formatNumeric(sa.Entry(i).Offset(), sp[0].Offset) + f.formatNumeric(sa.Entry(i).Length(), sp[0].Length) + sp = sp[1:] + } + if len(sp) > 0 { + sa.IsExtended()[0] = 1 + } + return sp + } + sp2 := formatSPD(spd, blk.GNU().Sparse()) + for len(sp2) > 0 { + var spHdr block + sp2 = formatSPD(sp2, spHdr.Sparse()) + spb = append(spb, spHdr[:]...) + } + + // Update size fields in the header block. + realSize := hdr.Size + hdr.Size = 0 // Encoded size; does not account for encoded sparse map + for _, s := range spd { + hdr.Size += s.Length + } + copy(blk.V7().Size(), zeroBlock[:]) // Reset field + f.formatNumeric(blk.V7().Size(), hdr.Size) + f.formatNumeric(blk.GNU().RealSize(), realSize) + } + */ + blk.SetFormat(FormatGNU) + if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil { + return err } - v7 := header.V7() - formatString(v7.Name(), hdr.Name, paxPath) - // TODO(dsnet): The GNU format permits the mode field to be encoded in - // base-256 format. Thus, we can use formatNumeric instead of formatOctal. - f.formatOctal(v7.Mode(), hdr.Mode) - formatNumeric(v7.UID(), int64(hdr.Uid), paxUid) - formatNumeric(v7.GID(), int64(hdr.Gid), paxGid) - formatNumeric(v7.Size(), hdr.Size, paxSize) - // TODO(dsnet): Consider using PAX for finer time granularity. - formatNumeric(v7.ModTime(), modTime, paxNone) - v7.TypeFlag()[0] = hdr.Typeflag - formatString(v7.LinkName(), hdr.Linkname, paxLinkpath) - - ustar := header.USTAR() - formatString(ustar.UserName(), hdr.Uname, paxUname) - formatString(ustar.GroupName(), hdr.Gname, paxGname) - formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone) - formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone) - - // TODO(dsnet): The logic surrounding the prefix field is broken when trying - // to encode the header as GNU format. The challenge with the current logic - // is that we are unsure what format we are using at any given moment until - // we have processed *all* of the fields. The problem is that by the time - // all fields have been processed, some work has already been done to handle - // each field under the assumption that it is for one given format or - // another. In some situations, this causes the Writer to be confused and - // encode a prefix field when the format being used is GNU. Thus, producing - // an invalid tar file. - // - // As a short-term fix, we disable the logic to use the prefix field, which - // will force the badly generated GNU files to become encoded as being - // the PAX format. - // - // As an alternative fix, we could hard-code preferPax to be true. However, - // this is problematic for the following reasons: - // * The preferPax functionality is not tested at all. - // * This can result in headers that try to use both the GNU and PAX - // features at the same time, which is also wrong. - // - // The proper fix for this is to use a two-pass method: - // * The first pass simply determines what set of formats can possibly - // encode the given header. - // * The second pass actually encodes the header as that given format - // without worrying about violating the format. - // - // See the following: - // https://golang.org/issue/12594 - // https://golang.org/issue/17630 - // https://golang.org/issue/9683 - const usePrefix = false - - // try to use a ustar header when only the name is too long - _, paxPathUsed := paxHeaders[paxPath] - if usePrefix && !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed { - prefix, suffix, ok := splitUSTARPath(hdr.Name) - if ok { - // Since we can encode in USTAR format, disable PAX header. - delete(paxHeaders, paxPath) - - // Update the path fields - formatString(v7.Name(), suffix, paxNone) - formatString(ustar.Prefix(), prefix, paxNone) + // Write the extended sparse map and setup the sparse writer if necessary. + if len(spd) > 0 { + // Use tw.w since the sparse map is not accounted for in hdr.Size. + if _, err := tw.w.Write(spb); err != nil { + return err } + tw.curr = &sparseFileWriter{tw.curr, spd, 0} } + return nil +} + +type ( + stringFormatter func([]byte, string) + numberFormatter func([]byte, int64) +) - if tw.usedBinary { - header.SetFormat(formatGNU) - } else { - header.SetFormat(formatUSTAR) +// templateV7Plus fills out the V7 fields of a block using values from hdr. +// It also fills out fields (uname, gname, devmajor, devminor) that are +// shared in the USTAR, PAX, and GNU formats using the provided formatters. +// +// The block returned is only valid until the next call to +// templateV7Plus or writeRawFile. +func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block { + tw.blk.Reset() + + modTime := hdr.ModTime + if modTime.IsZero() { + modTime = time.Unix(0, 0) } - // Check if there were any formatting errors. - if f.err != nil { - tw.err = f.err - return tw.err + v7 := tw.blk.V7() + v7.TypeFlag()[0] = hdr.Typeflag + fmtStr(v7.Name(), hdr.Name) + fmtStr(v7.LinkName(), hdr.Linkname) + fmtNum(v7.Mode(), hdr.Mode) + fmtNum(v7.UID(), int64(hdr.Uid)) + fmtNum(v7.GID(), int64(hdr.Gid)) + fmtNum(v7.Size(), hdr.Size) + fmtNum(v7.ModTime(), modTime.Unix()) + + ustar := tw.blk.USTAR() + fmtStr(ustar.UserName(), hdr.Uname) + fmtStr(ustar.GroupName(), hdr.Gname) + fmtNum(ustar.DevMajor(), hdr.Devmajor) + fmtNum(ustar.DevMinor(), hdr.Devminor) + + return &tw.blk +} + +// writeRawFile writes a minimal file with the given name and flag type. +// It uses format to encode the header format and will write data as the body. +// It uses default values for all of the other fields (as BSD and GNU tar does). +func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error { + tw.blk.Reset() + + // Best effort for the filename. + name = toASCII(name) + if len(name) > nameSize { + name = name[:nameSize] } + name = strings.TrimRight(name, "/") - if allowPax { - for k, v := range hdr.Xattrs { - paxHeaders[paxXattr+k] = v - } + var f formatter + v7 := tw.blk.V7() + v7.TypeFlag()[0] = flag + f.formatString(v7.Name(), name) + f.formatOctal(v7.Mode(), 0) + f.formatOctal(v7.UID(), 0) + f.formatOctal(v7.GID(), 0) + f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB + f.formatOctal(v7.ModTime(), 0) + tw.blk.SetFormat(format) + if f.err != nil { + return f.err // Only occurs if size condition is violated } - if len(paxHeaders) > 0 { - if !allowPax { - return errInvalidHeader - } - if err := tw.writePAXHeader(hdr, paxHeaders); err != nil { - return err - } + // Write the header and data. + if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil { + return err } - tw.nb = hdr.Size - tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize + _, err := io.WriteString(tw, data) + return err +} - _, tw.err = tw.w.Write(header[:]) - return tw.err +// writeRawHeader writes the value of blk, regardless of its value. +// It sets up the Writer such that it can accept a file of the given size. +// If the flag is a special header-only flag, then the size is treated as zero. +func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error { + if err := tw.Flush(); err != nil { + return err + } + if _, err := tw.w.Write(blk[:]); err != nil { + return err + } + if isHeaderOnlyType(flag) { + size = 0 + } + tw.curr = ®FileWriter{tw.w, size} + tw.pad = blockPadding(size) + return nil } // splitUSTARPath splits a path according to USTAR prefix and suffix rules. @@ -276,95 +412,233 @@ func splitUSTARPath(name string) (prefix, suffix string, ok bool) { return name[:i], name[i+1:], true } -// writePaxHeader writes an extended pax header to the -// archive. -func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error { - // Prepare extended header - ext := new(Header) - ext.Typeflag = TypeXHeader - // Setting ModTime is required for reader parsing to - // succeed, and seems harmless enough. - ext.ModTime = hdr.ModTime - // The spec asks that we namespace our pseudo files - // with the current pid. However, this results in differing outputs - // for identical inputs. As such, the constant 0 is now used instead. - // golang.org/issue/12358 - dir, file := path.Split(hdr.Name) - fullName := path.Join(dir, "PaxHeaders.0", file) - - ascii := toASCII(fullName) - if len(ascii) > nameSize { - ascii = ascii[:nameSize] - } - ext.Name = ascii - // Construct the body - var buf bytes.Buffer - - // Keys are sorted before writing to body to allow deterministic output. - keys := make([]string, 0, len(paxHeaders)) - for k := range paxHeaders { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k])) - } - - ext.Size = int64(len(buf.Bytes())) - if err := tw.writeHeader(ext, false); err != nil { - return err - } - if _, err := tw.Write(buf.Bytes()); err != nil { - return err +// Write writes to the current file in the tar archive. +// Write returns the error ErrWriteTooLong if more than +// Header.Size bytes are written after WriteHeader. +// +// Calling Write on special types like TypeLink, TypeSymlink, TypeChar, +// TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless +// of what the Header.Size claims. +func (tw *Writer) Write(b []byte) (int, error) { + if tw.err != nil { + return 0, tw.err } - if err := tw.Flush(); err != nil { - return err + n, err := tw.curr.Write(b) + if err != nil && err != ErrWriteTooLong { + tw.err = err } - return nil + return n, err } -// Write writes to the current entry in the tar archive. -// Write returns the error ErrWriteTooLong if more than -// hdr.Size bytes are written after WriteHeader. -func (tw *Writer) Write(b []byte) (n int, err error) { - if tw.closed { - err = ErrWriteAfterClose - return - } - overwrite := false - if int64(len(b)) > tw.nb { - b = b[0:tw.nb] - overwrite = true - } - n, err = tw.w.Write(b) - tw.nb -= int64(n) - if err == nil && overwrite { - err = ErrWriteTooLong - return - } - tw.err = err - return +// readFrom populates the content of the current file by reading from r. +// The bytes read must match the number of remaining bytes in the current file. +// +// If the current file is sparse and r is an io.ReadSeeker, +// then readFrom uses Seek to skip past holes defined in Header.SparseHoles, +// assuming that skipped regions are all NULs. +// This always reads the last byte to ensure r is the right size. +// +// TODO(dsnet): Re-export this when adding sparse file support. +// See https://golang.org/issue/22735 +func (tw *Writer) readFrom(r io.Reader) (int64, error) { + if tw.err != nil { + return 0, tw.err + } + n, err := tw.curr.ReadFrom(r) + if err != nil && err != ErrWriteTooLong { + tw.err = err + } + return n, err } -// Close closes the tar archive, flushing any unwritten -// data to the underlying writer. +// Close closes the tar archive by flushing the padding, and writing the footer. +// If the current file (from a prior call to WriteHeader) is not fully written, +// then this returns an error. func (tw *Writer) Close() error { - if tw.err != nil || tw.closed { - return tw.err + if tw.err == ErrWriteAfterClose { + return nil } - tw.Flush() - tw.closed = true if tw.err != nil { return tw.err } - // trailer: two zero blocks - for i := 0; i < 2; i++ { - _, tw.err = tw.w.Write(zeroBlock[:]) - if tw.err != nil { - break + // Trailer: two zero blocks. + err := tw.Flush() + for i := 0; i < 2 && err == nil; i++ { + _, err = tw.w.Write(zeroBlock[:]) + } + + // Ensure all future actions are invalid. + tw.err = ErrWriteAfterClose + return err // Report IO errors +} + +// regFileWriter is a fileWriter for writing data to a regular file entry. +type regFileWriter struct { + w io.Writer // Underlying Writer + nb int64 // Number of remaining bytes to write +} + +func (fw *regFileWriter) Write(b []byte) (n int, err error) { + overwrite := int64(len(b)) > fw.nb + if overwrite { + b = b[:fw.nb] + } + if len(b) > 0 { + n, err = fw.w.Write(b) + fw.nb -= int64(n) + } + switch { + case err != nil: + return n, err + case overwrite: + return n, ErrWriteTooLong + default: + return n, nil + } +} + +func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) { + return io.Copy(struct{ io.Writer }{fw}, r) +} + +func (fw regFileWriter) LogicalRemaining() int64 { + return fw.nb +} +func (fw regFileWriter) PhysicalRemaining() int64 { + return fw.nb +} + +// sparseFileWriter is a fileWriter for writing data to a sparse file entry. +type sparseFileWriter struct { + fw fileWriter // Underlying fileWriter + sp sparseDatas // Normalized list of data fragments + pos int64 // Current position in sparse file +} + +func (sw *sparseFileWriter) Write(b []byte) (n int, err error) { + overwrite := int64(len(b)) > sw.LogicalRemaining() + if overwrite { + b = b[:sw.LogicalRemaining()] + } + + b0 := b + endPos := sw.pos + int64(len(b)) + for endPos > sw.pos && err == nil { + var nf int // Bytes written in fragment + dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset() + if sw.pos < dataStart { // In a hole fragment + bf := b[:min(int64(len(b)), dataStart-sw.pos)] + nf, err = zeroWriter{}.Write(bf) + } else { // In a data fragment + bf := b[:min(int64(len(b)), dataEnd-sw.pos)] + nf, err = sw.fw.Write(bf) + } + b = b[nf:] + sw.pos += int64(nf) + if sw.pos >= dataEnd && len(sw.sp) > 1 { + sw.sp = sw.sp[1:] // Ensure last fragment always remains + } + } + + n = len(b0) - len(b) + switch { + case err == ErrWriteTooLong: + return n, errMissData // Not possible; implies bug in validation logic + case err != nil: + return n, err + case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0: + return n, errUnrefData // Not possible; implies bug in validation logic + case overwrite: + return n, ErrWriteTooLong + default: + return n, nil + } +} + +func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) { + rs, ok := r.(io.ReadSeeker) + if ok { + if _, err := rs.Seek(0, io.SeekCurrent); err != nil { + ok = false // Not all io.Seeker can really seek + } + } + if !ok { + return io.Copy(struct{ io.Writer }{sw}, r) + } + + var readLastByte bool + pos0 := sw.pos + for sw.LogicalRemaining() > 0 && !readLastByte && err == nil { + var nf int64 // Size of fragment + dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset() + if sw.pos < dataStart { // In a hole fragment + nf = dataStart - sw.pos + if sw.PhysicalRemaining() == 0 { + readLastByte = true + nf-- + } + _, err = rs.Seek(nf, io.SeekCurrent) + } else { // In a data fragment + nf = dataEnd - sw.pos + nf, err = io.CopyN(sw.fw, rs, nf) } + sw.pos += nf + if sw.pos >= dataEnd && len(sw.sp) > 1 { + sw.sp = sw.sp[1:] // Ensure last fragment always remains + } + } + + // If the last fragment is a hole, then seek to 1-byte before EOF, and + // read a single byte to ensure the file is the right size. + if readLastByte && err == nil { + _, err = mustReadFull(rs, []byte{0}) + sw.pos++ + } + + n = sw.pos - pos0 + switch { + case err == io.EOF: + return n, io.ErrUnexpectedEOF + case err == ErrWriteTooLong: + return n, errMissData // Not possible; implies bug in validation logic + case err != nil: + return n, err + case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0: + return n, errUnrefData // Not possible; implies bug in validation logic + default: + return n, ensureEOF(rs) + } +} + +func (sw sparseFileWriter) LogicalRemaining() int64 { + return sw.sp[len(sw.sp)-1].endOffset() - sw.pos +} +func (sw sparseFileWriter) PhysicalRemaining() int64 { + return sw.fw.PhysicalRemaining() +} + +// zeroWriter may only be written with NULs, otherwise it returns errWriteHole. +type zeroWriter struct{} + +func (zeroWriter) Write(b []byte) (int, error) { + for i, c := range b { + if c != 0 { + return i, errWriteHole + } + } + return len(b), nil +} + +// ensureEOF checks whether r is at EOF, reporting ErrWriteTooLong if not so. +func ensureEOF(r io.Reader) error { + n, err := tryReadFull(r, []byte{0}) + switch { + case n > 0: + return ErrWriteTooLong + case err == io.EOF: + return nil + default: + return err } - return tw.err } diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go index d88b8f41ca8..24e8da271c2 100644 --- a/libgo/go/archive/tar/writer_test.go +++ b/libgo/go/archive/tar/writer_test.go @@ -6,10 +6,12 @@ package tar import ( "bytes" - "fmt" + "encoding/hex" + "errors" "io" "io/ioutil" "os" + "path" "reflect" "sort" "strings" @@ -18,120 +20,127 @@ import ( "time" ) -// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection. -func bytestr(offset int, b []byte) string { - const rowLen = 32 - s := fmt.Sprintf("%04x ", offset) - for _, ch := range b { - switch { - case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z': - s += fmt.Sprintf(" %c", ch) - default: - s += fmt.Sprintf(" %02x", ch) +func bytediff(a, b []byte) string { + const ( + uniqueA = "- " + uniqueB = "+ " + identity = " " + ) + var ss []string + sa := strings.Split(strings.TrimSpace(hex.Dump(a)), "\n") + sb := strings.Split(strings.TrimSpace(hex.Dump(b)), "\n") + for len(sa) > 0 && len(sb) > 0 { + if sa[0] == sb[0] { + ss = append(ss, identity+sa[0]) + } else { + ss = append(ss, uniqueA+sa[0]) + ss = append(ss, uniqueB+sb[0]) } + sa, sb = sa[1:], sb[1:] + } + for len(sa) > 0 { + ss = append(ss, uniqueA+sa[0]) + sa = sa[1:] + } + for len(sb) > 0 { + ss = append(ss, uniqueB+sb[0]) + sb = sb[1:] } - return s + return strings.Join(ss, "\n") } -// Render a pseudo-diff between two blocks of bytes. -func bytediff(a []byte, b []byte) string { - const rowLen = 32 - s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b)) - for offset := 0; len(a)+len(b) > 0; offset += rowLen { - na, nb := rowLen, rowLen - if na > len(a) { - na = len(a) +func TestWriter(t *testing.T) { + type ( + testHeader struct { // WriteHeader(hdr) == wantErr + hdr Header + wantErr error } - if nb > len(b) { - nb = len(b) + testWrite struct { // Write(str) == (wantCnt, wantErr) + str string + wantCnt int + wantErr error } - sa := bytestr(offset, a[0:na]) - sb := bytestr(offset, b[0:nb]) - if sa != sb { - s += fmt.Sprintf("-%v\n+%v\n", sa, sb) + testReadFrom struct { // ReadFrom(testFile{ops}) == (wantCnt, wantErr) + ops fileOps + wantCnt int64 + wantErr error } - a = a[na:] - b = b[nb:] - } - return s -} - -func TestWriter(t *testing.T) { - type entry struct { - header *Header - contents string - } + testClose struct { // Close() == wantErr + wantErr error + } + testFnc interface{} // testHeader | testWrite | testReadFrom | testClose + ) vectors := []struct { - file string // filename of expected output - entries []*entry + file string // Optional filename of expected output + tests []testFnc }{{ // The writer test file was produced with this command: // tar (GNU tar) 1.26 // ln -s small.txt link.txt // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt file: "testdata/writer.tar", - entries: []*entry{{ - header: &Header{ + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, Name: "small.txt", + Size: 5, Mode: 0640, Uid: 73025, Gid: 5000, - Size: 5, - ModTime: time.Unix(1246508266, 0), - Typeflag: '0', Uname: "dsymonds", Gname: "eng", - }, - contents: "Kilts", - }, { - header: &Header{ + ModTime: time.Unix(1246508266, 0), + }, nil}, + testWrite{"Kilts", 5, nil}, + + testHeader{Header{ + Typeflag: TypeReg, Name: "small2.txt", + Size: 11, Mode: 0640, Uid: 73025, - Gid: 5000, - Size: 11, - ModTime: time.Unix(1245217492, 0), - Typeflag: '0', Uname: "dsymonds", Gname: "eng", - }, - contents: "Google.com\n", - }, { - header: &Header{ + Gid: 5000, + ModTime: time.Unix(1245217492, 0), + }, nil}, + testWrite{"Google.com\n", 11, nil}, + + testHeader{Header{ + Typeflag: TypeSymlink, Name: "link.txt", + Linkname: "small.txt", Mode: 0777, Uid: 1000, Gid: 1000, - Size: 0, - ModTime: time.Unix(1314603082, 0), - Typeflag: '2', - Linkname: "small.txt", Uname: "strings", Gname: "strings", - }, - // no contents - }}, + ModTime: time.Unix(1314603082, 0), + }, nil}, + testWrite{"", 0, nil}, + + testClose{nil}, + }, }, { // The truncated test file was produced using these commands: // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar file: "testdata/writer-big.tar", - entries: []*entry{{ - header: &Header{ + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, Name: "tmp/16gig.txt", + Size: 16 << 30, Mode: 0640, Uid: 73025, Gid: 5000, - Size: 16 << 30, - ModTime: time.Unix(1254699560, 0), - Typeflag: '0', Uname: "dsymonds", Gname: "eng", - }, - // fake contents - contents: strings.Repeat("\x00", 4<<10), - }}, + ModTime: time.Unix(1254699560, 0), + Format: FormatGNU, + }, nil}, + }, }, { // This truncated file was produced using this library. // It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2. @@ -141,117 +150,377 @@ func TestWriter(t *testing.T) { // // This file is in PAX format. file: "testdata/writer-big-long.tar", - entries: []*entry{{ - header: &Header{ + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, Name: strings.Repeat("longname/", 15) + "16gig.txt", + Size: 16 << 30, 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), - }}, - }, { - // TODO(dsnet): The Writer output should match the following file. - // To fix an issue (see https://golang.org/issue/12594), we disabled - // prefix support, which alters the generated output. - /* - // This file was produced using gnu tar 1.17 - // gnutar -b 4 --format=ustar (longname/)*15 + file.txt - file: "testdata/ustar.tar" - */ - file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected - entries: []*entry{{ - header: &Header{ + ModTime: time.Unix(1399583047, 0), + }, nil}, + }, + }, { + // This file was produced using GNU tar v1.17. + // gnutar -b 4 --format=ustar (longname/)*15 + file.txt + file: "testdata/ustar.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, Name: strings.Repeat("longname/", 15) + "file.txt", + Size: 6, Mode: 0644, - Uid: 0765, - Gid: 024, - Size: 06, - ModTime: time.Unix(1360135598, 0), - Typeflag: '0', + Uid: 501, + Gid: 20, Uname: "shane", Gname: "staff", - }, - contents: "hello\n", - }}, - }, { - // This file was produced using gnu tar 1.26 - // echo "Slartibartfast" > file.txt - // ln file.txt hard.txt - // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt + ModTime: time.Unix(1360135598, 0), + }, nil}, + testWrite{"hello\n", 6, nil}, + testClose{nil}, + }, + }, { + // This file was produced using GNU tar v1.26: + // echo "Slartibartfast" > file.txt + // ln file.txt hard.txt + // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt file: "testdata/hardlink.tar", - entries: []*entry{{ - header: &Header{ + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, Name: "file.txt", + Size: 15, Mode: 0644, Uid: 1000, Gid: 100, - Size: 15, - ModTime: time.Unix(1425484303, 0), - Typeflag: '0', Uname: "vbatts", Gname: "users", - }, - contents: "Slartibartfast\n", - }, { - header: &Header{ + ModTime: time.Unix(1425484303, 0), + }, nil}, + testWrite{"Slartibartfast\n", 15, nil}, + + testHeader{Header{ + Typeflag: TypeLink, Name: "hard.txt", + Linkname: "file.txt", Mode: 0644, Uid: 1000, Gid: 100, - Size: 0, - ModTime: time.Unix(1425484303, 0), - Typeflag: '1', - Linkname: "file.txt", Uname: "vbatts", Gname: "users", - }, - // no contents - }}, + ModTime: time.Unix(1425484303, 0), + }, nil}, + testWrite{"", 0, nil}, + + testClose{nil}, + }, + }, { + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "bad-null.txt", + Xattrs: map[string]string{"null\x00null\x00": "fizzbuzz"}, + }, headerError{}}, + }, + }, { + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "null\x00.txt", + }, headerError{}}, + }, + }, { + file: "testdata/pax-records.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "file", + Uname: strings.Repeat("long", 10), + PAXRecords: map[string]string{ + "path": "FILE", // Should be ignored + "GNU.sparse.map": "0,0", // Should be ignored + "comment": "Hello, 世界", + "GOLANG.pkg": "tar", + }, + }, nil}, + testClose{nil}, + }, + }, { + // Craft a theoretically valid PAX archive with global headers. + // The GNU and BSD tar tools do not parse these the same way. + // + // BSD tar v3.1.2 parses and ignores all global headers; + // the behavior is verified by researching the source code. + // + // $ bsdtar -tvf pax-global-records.tar + // ---------- 0 0 0 0 Dec 31 1969 file1 + // ---------- 0 0 0 0 Dec 31 1969 file2 + // ---------- 0 0 0 0 Dec 31 1969 file3 + // ---------- 0 0 0 0 May 13 2014 file4 + // + // GNU tar v1.27.1 applies global headers to subsequent records, + // but does not do the following properly: + // * It does not treat an empty record as deletion. + // * It does not use subsequent global headers to update previous ones. + // + // $ gnutar -tvf pax-global-records.tar + // ---------- 0/0 0 2017-07-13 19:40 global1 + // ---------- 0/0 0 2017-07-13 19:40 file2 + // gnutar: Substituting `.' for empty member name + // ---------- 0/0 0 1969-12-31 16:00 + // gnutar: Substituting `.' for empty member name + // ---------- 0/0 0 2014-05-13 09:53 + // + // According to the PAX specification, this should have been the result: + // ---------- 0/0 0 2017-07-13 19:40 global1 + // ---------- 0/0 0 2017-07-13 19:40 file2 + // ---------- 0/0 0 2017-07-13 19:40 file3 + // ---------- 0/0 0 2014-05-13 09:53 file4 + file: "testdata/pax-global-records.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeXGlobalHeader, + PAXRecords: map[string]string{"path": "global1", "mtime": "1500000000.0"}, + }, nil}, + testHeader{Header{ + Typeflag: TypeReg, Name: "file1", + }, nil}, + testHeader{Header{ + Typeflag: TypeReg, + Name: "file2", + PAXRecords: map[string]string{"path": "file2"}, + }, nil}, + testHeader{Header{ + Typeflag: TypeXGlobalHeader, + PAXRecords: map[string]string{"path": ""}, // Should delete "path", but keep "mtime" + }, nil}, + testHeader{Header{ + Typeflag: TypeReg, Name: "file3", + }, nil}, + testHeader{Header{ + Typeflag: TypeReg, + Name: "file4", + ModTime: time.Unix(1400000000, 0), + PAXRecords: map[string]string{"mtime": "1400000000"}, + }, nil}, + testClose{nil}, + }, + }, { + file: "testdata/gnu-utf8.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹", + Mode: 0644, + Uid: 1000, Gid: 1000, + Uname: "☺", + Gname: "⚹", + ModTime: time.Unix(0, 0), + Format: FormatGNU, + }, nil}, + testClose{nil}, + }, + }, { + file: "testdata/gnu-not-utf8.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "hi\x80\x81\x82\x83bye", + Mode: 0644, + Uid: 1000, + Gid: 1000, + Uname: "rawr", + Gname: "dsnet", + ModTime: time.Unix(0, 0), + Format: FormatGNU, + }, nil}, + testClose{nil}, + }, + // TODO(dsnet): Re-enable this test when adding sparse support. + // See https://golang.org/issue/22735 + /* + }, { + file: "testdata/gnu-nil-sparse-data.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeGNUSparse, + Name: "sparse.db", + Size: 1000, + SparseHoles: []sparseEntry{{Offset: 1000, Length: 0}}, + }, nil}, + testWrite{strings.Repeat("0123456789", 100), 1000, nil}, + testClose{}, + }, + }, { + file: "testdata/gnu-nil-sparse-hole.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeGNUSparse, + Name: "sparse.db", + Size: 1000, + SparseHoles: []sparseEntry{{Offset: 0, Length: 1000}}, + }, nil}, + testWrite{strings.Repeat("\x00", 1000), 1000, nil}, + testClose{}, + }, + }, { + file: "testdata/pax-nil-sparse-data.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "sparse.db", + Size: 1000, + SparseHoles: []sparseEntry{{Offset: 1000, Length: 0}}, + }, nil}, + testWrite{strings.Repeat("0123456789", 100), 1000, nil}, + testClose{}, + }, + }, { + file: "testdata/pax-nil-sparse-hole.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "sparse.db", + Size: 1000, + SparseHoles: []sparseEntry{{Offset: 0, Length: 1000}}, + }, nil}, + testWrite{strings.Repeat("\x00", 1000), 1000, nil}, + testClose{}, + }, + }, { + file: "testdata/gnu-sparse-big.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeGNUSparse, + Name: "gnu-sparse", + Size: 6e10, + SparseHoles: []sparseEntry{ + {Offset: 0e10, Length: 1e10 - 100}, + {Offset: 1e10, Length: 1e10 - 100}, + {Offset: 2e10, Length: 1e10 - 100}, + {Offset: 3e10, Length: 1e10 - 100}, + {Offset: 4e10, Length: 1e10 - 100}, + {Offset: 5e10, Length: 1e10 - 100}, + }, + }, nil}, + testReadFrom{fileOps{ + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + }, 6e10, nil}, + testClose{nil}, + }, + }, { + file: "testdata/pax-sparse-big.tar", + tests: []testFnc{ + testHeader{Header{ + Typeflag: TypeReg, + Name: "pax-sparse", + Size: 6e10, + SparseHoles: []sparseEntry{ + {Offset: 0e10, Length: 1e10 - 100}, + {Offset: 1e10, Length: 1e10 - 100}, + {Offset: 2e10, Length: 1e10 - 100}, + {Offset: 3e10, Length: 1e10 - 100}, + {Offset: 4e10, Length: 1e10 - 100}, + {Offset: 5e10, Length: 1e10 - 100}, + }, + }, nil}, + testReadFrom{fileOps{ + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + int64(1e10 - blockSize), + strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10), + }, 6e10, nil}, + testClose{nil}, + }, + */ + }, { + file: "testdata/trailing-slash.tar", + tests: []testFnc{ + testHeader{Header{Name: strings.Repeat("123456789/", 30)}, nil}, + testClose{nil}, + }, }} -testLoop: - for i, v := range vectors { - expected, err := ioutil.ReadFile(v.file) - if err != nil { - t.Errorf("test %d: Unexpected error: %v", i, err) - continue - } - - buf := new(bytes.Buffer) - tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB - big := false - for j, entry := range v.entries { - big = big || entry.header.Size > 1<<10 - if err := tw.WriteHeader(entry.header); err != nil { - t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err) - continue testLoop - } - if _, err := io.WriteString(tw, entry.contents); err != nil { - t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err) - continue testLoop - } - } - // Only interested in Close failures for the small tests. - if err := tw.Close(); err != nil && !big { - t.Errorf("test %d: Failed closing archive: %v", i, err) - continue testLoop + equalError := func(x, y error) bool { + _, ok1 := x.(headerError) + _, ok2 := y.(headerError) + if ok1 || ok2 { + return ok1 && ok2 } + return x == y + } + for _, v := range vectors { + t.Run(path.Base(v.file), func(t *testing.T) { + const maxSize = 10 << 10 // 10KiB + buf := new(bytes.Buffer) + tw := NewWriter(iotest.TruncateWriter(buf, maxSize)) - actual := buf.Bytes() - if !bytes.Equal(expected, actual) { - t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v", - i, bytediff(expected, actual)) - } - if testing.Short() { // The second test is expensive. - break - } + for i, tf := range v.tests { + switch tf := tf.(type) { + case testHeader: + err := tw.WriteHeader(&tf.hdr) + if !equalError(err, tf.wantErr) { + t.Fatalf("test %d, WriteHeader() = %v, want %v", i, err, tf.wantErr) + } + case testWrite: + got, err := tw.Write([]byte(tf.str)) + if got != tf.wantCnt || !equalError(err, tf.wantErr) { + t.Fatalf("test %d, Write() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr) + } + case testReadFrom: + f := &testFile{ops: tf.ops} + got, err := tw.readFrom(f) + if _, ok := err.(testError); ok { + t.Errorf("test %d, ReadFrom(): %v", i, err) + } else if got != tf.wantCnt || !equalError(err, tf.wantErr) { + t.Errorf("test %d, ReadFrom() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr) + } + if len(f.ops) > 0 { + t.Errorf("test %d, expected %d more operations", i, len(f.ops)) + } + case testClose: + err := tw.Close() + if !equalError(err, tf.wantErr) { + t.Fatalf("test %d, Close() = %v, want %v", i, err, tf.wantErr) + } + default: + t.Fatalf("test %d, unknown test operation: %T", i, tf) + } + } + + if v.file != "" { + want, err := ioutil.ReadFile(v.file) + if err != nil { + t.Fatalf("ReadFile() = %v, want nil", err) + } + got := buf.Bytes() + if !bytes.Equal(want, got) { + t.Fatalf("incorrect result: (-got +want)\n%v", bytediff(got, want)) + } + } + }) } } @@ -546,21 +815,104 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) { } } -func TestWriteAfterClose(t *testing.T) { - var buffer bytes.Buffer - tw := NewWriter(&buffer) +// failOnceWriter fails exactly once and then always reports success. +type failOnceWriter bool - hdr := &Header{ - Name: "small.txt", - Size: 5, - } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatalf("Failed to write header: %s", err) - } - tw.Close() - if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose { - t.Fatalf("Write: got %v; want ErrWriteAfterClose", err) +func (w *failOnceWriter) Write(b []byte) (int, error) { + if !*w { + return 0, io.ErrShortWrite } + *w = true + return len(b), nil +} + +func TestWriterErrors(t *testing.T) { + t.Run("HeaderOnly", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + hdr := &Header{Name: "dir/", Typeflag: TypeDir} + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("WriteHeader() = %v, want nil", err) + } + if _, err := tw.Write([]byte{0x00}); err != ErrWriteTooLong { + t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong) + } + }) + + t.Run("NegativeSize", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + hdr := &Header{Name: "small.txt", Size: -1} + if err := tw.WriteHeader(hdr); err == nil { + t.Fatalf("WriteHeader() = nil, want non-nil error") + } + }) + + t.Run("BeforeHeader", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + if _, err := tw.Write([]byte("Kilts")); err != ErrWriteTooLong { + t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong) + } + }) + + t.Run("AfterClose", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + hdr := &Header{Name: "small.txt"} + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("WriteHeader() = %v, want nil", err) + } + if err := tw.Close(); err != nil { + t.Fatalf("Close() = %v, want nil", err) + } + if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose { + t.Fatalf("Write() = %v, want %v", err, ErrWriteAfterClose) + } + if err := tw.Flush(); err != ErrWriteAfterClose { + t.Fatalf("Flush() = %v, want %v", err, ErrWriteAfterClose) + } + if err := tw.Close(); err != nil { + t.Fatalf("Close() = %v, want nil", err) + } + }) + + t.Run("PrematureFlush", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + hdr := &Header{Name: "small.txt", Size: 5} + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("WriteHeader() = %v, want nil", err) + } + if err := tw.Flush(); err == nil { + t.Fatalf("Flush() = %v, want non-nil error", err) + } + }) + + t.Run("PrematureClose", func(t *testing.T) { + tw := NewWriter(new(bytes.Buffer)) + hdr := &Header{Name: "small.txt", Size: 5} + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("WriteHeader() = %v, want nil", err) + } + if err := tw.Close(); err == nil { + t.Fatalf("Close() = %v, want non-nil error", err) + } + }) + + t.Run("Persistence", func(t *testing.T) { + tw := NewWriter(new(failOnceWriter)) + if err := tw.WriteHeader(&Header{}); err != io.ErrShortWrite { + t.Fatalf("WriteHeader() = %v, want %v", err, io.ErrShortWrite) + } + if err := tw.WriteHeader(&Header{Name: "small.txt"}); err == nil { + t.Errorf("WriteHeader() = got %v, want non-nil error", err) + } + if _, err := tw.Write(nil); err == nil { + t.Errorf("Write() = %v, want non-nil error", err) + } + if err := tw.Flush(); err == nil { + t.Errorf("Flush() = %v, want non-nil error", err) + } + if err := tw.Close(); err == nil { + t.Errorf("Close() = %v, want non-nil error", err) + } + }) } func TestSplitUSTARPath(t *testing.T) { @@ -631,7 +983,7 @@ func TestIssue12594(t *testing.T) { if i := strings.IndexByte(prefix, 0); i >= 0 { prefix = prefix[:i] // Truncate at the NUL terminator } - if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) { + if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) { t.Errorf("test %d, found prefix in GNU format: %s", i, prefix) } @@ -645,3 +997,306 @@ func TestIssue12594(t *testing.T) { } } } + +// testNonEmptyWriter wraps an io.Writer and ensures that +// Write is never called with an empty buffer. +type testNonEmptyWriter struct{ io.Writer } + +func (w testNonEmptyWriter) Write(b []byte) (int, error) { + if len(b) == 0 { + return 0, errors.New("unexpected empty Write call") + } + return w.Writer.Write(b) +} + +func TestFileWriter(t *testing.T) { + type ( + testWrite struct { // Write(str) == (wantCnt, wantErr) + str string + wantCnt int + wantErr error + } + testReadFrom struct { // ReadFrom(testFile{ops}) == (wantCnt, wantErr) + ops fileOps + wantCnt int64 + wantErr error + } + testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt + wantLCnt int64 + wantPCnt int64 + } + testFnc interface{} // testWrite | testReadFrom | testRemaining + ) + + type ( + makeReg struct { + size int64 + wantStr string + } + makeSparse struct { + makeReg makeReg + sph sparseHoles + size int64 + } + fileMaker interface{} // makeReg | makeSparse + ) + + vectors := []struct { + maker fileMaker + tests []testFnc + }{{ + maker: makeReg{0, ""}, + tests: []testFnc{ + testRemaining{0, 0}, + testWrite{"", 0, nil}, + testWrite{"a", 0, ErrWriteTooLong}, + testReadFrom{fileOps{""}, 0, nil}, + testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{1, "a"}, + tests: []testFnc{ + testRemaining{1, 1}, + testWrite{"", 0, nil}, + testWrite{"a", 1, nil}, + testWrite{"bcde", 0, ErrWriteTooLong}, + testWrite{"", 0, nil}, + testReadFrom{fileOps{""}, 0, nil}, + testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{5, "hello"}, + tests: []testFnc{ + testRemaining{5, 5}, + testWrite{"hello", 5, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{5, "\x00\x00\x00\x00\x00"}, + tests: []testFnc{ + testRemaining{5, 5}, + testReadFrom{fileOps{"\x00\x00\x00\x00\x00"}, 5, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{5, "\x00\x00\x00\x00\x00"}, + tests: []testFnc{ + testRemaining{5, 5}, + testReadFrom{fileOps{"\x00\x00\x00\x00\x00extra"}, 5, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{5, "abc\x00\x00"}, + tests: []testFnc{ + testRemaining{5, 5}, + testWrite{"abc", 3, nil}, + testRemaining{2, 2}, + testReadFrom{fileOps{"\x00\x00"}, 2, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeReg{5, "\x00\x00abc"}, + tests: []testFnc{ + testRemaining{5, 5}, + testWrite{"\x00\x00", 2, nil}, + testRemaining{3, 3}, + testWrite{"abc", 3, nil}, + testReadFrom{fileOps{"z"}, 0, ErrWriteTooLong}, + testWrite{"z", 0, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testRemaining{8, 5}, + testWrite{"ab\x00\x00\x00cde", 8, nil}, + testWrite{"a", 0, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testWrite{"ab\x00\x00\x00cdez", 8, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testWrite{"ab\x00", 3, nil}, + testRemaining{5, 3}, + testWrite{"\x00\x00cde", 5, nil}, + testWrite{"a", 0, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testWrite{"ab", 2, nil}, + testRemaining{6, 3}, + testReadFrom{fileOps{int64(3), "cde"}, 6, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testReadFrom{fileOps{"ab", int64(3), "cdeX"}, 8, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testReadFrom{fileOps{"ab", int64(3), "cd"}, 7, io.ErrUnexpectedEOF}, + testRemaining{1, 0}, + }, + }, { + maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testReadFrom{fileOps{"ab", int64(3), "cde"}, 7, errMissData}, + testRemaining{1, 0}, + }, + }, { + maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, errUnrefData}, + testRemaining{0, 1}, + }, + }, { + maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testWrite{"ab", 2, nil}, + testRemaining{6, 2}, + testWrite{"\x00\x00\x00", 3, nil}, + testRemaining{3, 2}, + testWrite{"cde", 2, errMissData}, + testRemaining{1, 0}, + }, + }, { + maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8}, + tests: []testFnc{ + testWrite{"ab", 2, nil}, + testRemaining{6, 4}, + testWrite{"\x00\x00\x00", 3, nil}, + testRemaining{3, 4}, + testWrite{"cde", 3, errUnrefData}, + testRemaining{0, 1}, + }, + }, { + maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testRemaining{7, 3}, + testWrite{"\x00\x00abc\x00\x00", 7, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testRemaining{7, 3}, + testReadFrom{fileOps{int64(2), "abc", int64(1), "\x00"}, 7, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{3, ""}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"abcdefg", 0, errWriteHole}, + }, + }, { + maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"\x00\x00abcde", 5, errWriteHole}, + }, + }, { + maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"\x00\x00abc\x00\x00z", 7, ErrWriteTooLong}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"\x00\x00", 2, nil}, + testRemaining{5, 3}, + testWrite{"abc", 3, nil}, + testRemaining{2, 0}, + testWrite{"\x00\x00", 2, nil}, + testRemaining{0, 0}, + }, + }, { + maker: makeSparse{makeReg{2, "ab"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"\x00\x00", 2, nil}, + testWrite{"abc", 2, errMissData}, + testWrite{"\x00\x00", 0, errMissData}, + }, + }, { + maker: makeSparse{makeReg{4, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7}, + tests: []testFnc{ + testWrite{"\x00\x00", 2, nil}, + testWrite{"abc", 3, nil}, + testWrite{"\x00\x00", 2, errUnrefData}, + }, + }} + + for i, v := range vectors { + var wantStr string + bb := new(bytes.Buffer) + w := testNonEmptyWriter{bb} + var fw fileWriter + switch maker := v.maker.(type) { + case makeReg: + fw = ®FileWriter{w, maker.size} + wantStr = maker.wantStr + case makeSparse: + if !validateSparseEntries(maker.sph, maker.size) { + t.Fatalf("invalid sparse map: %v", maker.sph) + } + spd := invertSparseEntries(maker.sph, maker.size) + fw = ®FileWriter{w, maker.makeReg.size} + fw = &sparseFileWriter{fw, spd, 0} + wantStr = maker.makeReg.wantStr + default: + t.Fatalf("test %d, unknown make operation: %T", i, maker) + } + + for j, tf := range v.tests { + switch tf := tf.(type) { + case testWrite: + got, err := fw.Write([]byte(tf.str)) + if got != tf.wantCnt || err != tf.wantErr { + t.Errorf("test %d.%d, Write(%s):\ngot (%d, %v)\nwant (%d, %v)", i, j, tf.str, got, err, tf.wantCnt, tf.wantErr) + } + case testReadFrom: + f := &testFile{ops: tf.ops} + got, err := fw.ReadFrom(f) + if _, ok := err.(testError); ok { + t.Errorf("test %d.%d, ReadFrom(): %v", i, j, err) + } else if got != tf.wantCnt || err != tf.wantErr { + t.Errorf("test %d.%d, ReadFrom() = (%d, %v), want (%d, %v)", i, j, got, err, tf.wantCnt, tf.wantErr) + } + if len(f.ops) > 0 { + t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops)) + } + case testRemaining: + if got := fw.LogicalRemaining(); got != tf.wantLCnt { + t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt) + } + if got := fw.PhysicalRemaining(); got != tf.wantPCnt { + t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt) + } + default: + t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf) + } + } + + if got := bb.String(); got != wantStr { + t.Fatalf("test %d, String() = %q, want %q", i, got, wantStr) + } + } +} diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index f6c3ead3bea..1563e74dfce 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -13,6 +13,7 @@ import ( "hash/crc32" "io" "os" + "time" ) var ( @@ -94,7 +95,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error { // The count of files inside a zip is truncated to fit in a uint16. // Gloss over this by reading headers until we encounter - // a bad one, and then only report a ErrFormat or UnexpectedEOF if + // a bad one, and then only report an ErrFormat or UnexpectedEOF if // the file count modulo 65536 is incorrect. for { f := &File{zip: z, zipr: r, zipsize: size} @@ -280,52 +281,128 @@ func readDirectoryHeader(f *File, r io.Reader) error { f.Extra = d[filenameLen : filenameLen+extraLen] f.Comment = string(d[filenameLen+extraLen:]) + // Determine the character encoding. + utf8Valid1, utf8Require1 := detectUTF8(f.Name) + utf8Valid2, utf8Require2 := detectUTF8(f.Comment) + switch { + case !utf8Valid1 || !utf8Valid2: + // Name and Comment definitely not UTF-8. + f.NonUTF8 = true + case !utf8Require1 && !utf8Require2: + // Name and Comment use only single-byte runes that overlap with UTF-8. + f.NonUTF8 = false + default: + // Might be UTF-8, might be some other encoding; preserve existing flag. + // Some ZIP writers use UTF-8 encoding without setting the UTF-8 flag. + // Since it is impossible to always distinguish valid UTF-8 from some + // other encoding (e.g., GBK or Shift-JIS), we trust the flag. + f.NonUTF8 = f.Flags&0x800 == 0 + } + needUSize := f.UncompressedSize == ^uint32(0) needCSize := f.CompressedSize == ^uint32(0) needHeaderOffset := f.headerOffset == int64(^uint32(0)) - if len(f.Extra) > 0 { - // Best effort to find what we need. - // Other zip authors might not even follow the basic format, - // and we'll just ignore the Extra content in that case. - b := readBuf(f.Extra) - for len(b) >= 4 { // need at least tag and size - tag := b.uint16() - size := b.uint16() - if int(size) > len(b) { - break + // Best effort to find what we need. + // Other zip authors might not even follow the basic format, + // and we'll just ignore the Extra content in that case. + var modified time.Time +parseExtras: + for extra := readBuf(f.Extra); len(extra) >= 4; { // need at least tag and size + fieldTag := extra.uint16() + fieldSize := int(extra.uint16()) + if len(extra) < fieldSize { + break + } + fieldBuf := extra.sub(fieldSize) + + switch fieldTag { + case zip64ExtraID: + // update directory values from the zip64 extra block. + // They should only be consulted if the sizes read earlier + // are maxed out. + // See golang.org/issue/13367. + if needUSize { + needUSize = false + if len(fieldBuf) < 8 { + return ErrFormat + } + f.UncompressedSize64 = fieldBuf.uint64() } - if tag == zip64ExtraId { - // update directory values from the zip64 extra block. - // They should only be consulted if the sizes read earlier - // are maxed out. - // See golang.org/issue/13367. - eb := readBuf(b[:size]) - - if needUSize { - needUSize = false - if len(eb) < 8 { - return ErrFormat - } - f.UncompressedSize64 = eb.uint64() + if needCSize { + needCSize = false + if len(fieldBuf) < 8 { + return ErrFormat } - if needCSize { - needCSize = false - if len(eb) < 8 { - return ErrFormat - } - f.CompressedSize64 = eb.uint64() + f.CompressedSize64 = fieldBuf.uint64() + } + if needHeaderOffset { + needHeaderOffset = false + if len(fieldBuf) < 8 { + return ErrFormat } - if needHeaderOffset { - needHeaderOffset = false - if len(eb) < 8 { - return ErrFormat - } - f.headerOffset = int64(eb.uint64()) + f.headerOffset = int64(fieldBuf.uint64()) + } + case ntfsExtraID: + if len(fieldBuf) < 4 { + continue parseExtras + } + fieldBuf.uint32() // reserved (ignored) + for len(fieldBuf) >= 4 { // need at least tag and size + attrTag := fieldBuf.uint16() + attrSize := int(fieldBuf.uint16()) + if len(fieldBuf) < attrSize { + continue parseExtras + } + attrBuf := fieldBuf.sub(attrSize) + if attrTag != 1 || attrSize != 24 { + continue // Ignore irrelevant attributes } - break + + const ticksPerSecond = 1e7 // Windows timestamp resolution + ts := int64(attrBuf.uint64()) // ModTime since Windows epoch + secs := int64(ts / ticksPerSecond) + nsecs := (1e9 / ticksPerSecond) * int64(ts%ticksPerSecond) + epoch := time.Date(1601, time.January, 1, 0, 0, 0, 0, time.UTC) + modified = time.Unix(epoch.Unix()+secs, nsecs) + } + case unixExtraID: + if len(fieldBuf) < 8 { + continue parseExtras } - b = b[size:] + fieldBuf.uint32() // AcTime (ignored) + ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch + modified = time.Unix(ts, 0) + case extTimeExtraID: + if len(fieldBuf) < 5 || fieldBuf.uint8()&1 == 0 { + continue parseExtras + } + ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch + modified = time.Unix(ts, 0) + case infoZipUnixExtraID: + if len(fieldBuf) < 4 { + continue parseExtras + } + ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch + modified = time.Unix(ts, 0) + } + } + + msdosModified := msDosTimeToTime(f.ModifiedDate, f.ModifiedTime) + f.Modified = msdosModified + if !modified.IsZero() { + f.Modified = modified.UTC() + + // If legacy MS-DOS timestamps are set, we can use the delta between + // the legacy and extended versions to estimate timezone offset. + // + // A non-UTC timezone is always used (even if offset is zero). + // Thus, FileHeader.Modified.Location() == time.UTC is useful for + // determining whether extended timestamps are present. + // This is necessary for users that need to do additional time + // calculations when dealing with legacy ZIP formats. + if f.ModifiedTime != 0 || f.ModifiedDate != 0 { + f.Modified = modified.In(timeZone(msdosModified.Sub(modified))) } } @@ -508,6 +585,12 @@ func findSignatureInBlock(b []byte) int { type readBuf []byte +func (b *readBuf) uint8() uint8 { + v := (*b)[0] + *b = (*b)[1:] + return v +} + func (b *readBuf) uint16() uint16 { v := binary.LittleEndian.Uint16(*b) *b = (*b)[2:] @@ -525,3 +608,9 @@ func (b *readBuf) uint64() uint64 { *b = (*b)[8:] return v } + +func (b *readBuf) sub(n int) readBuf { + b2 := (*b)[:n] + *b = (*b)[n:] + return b2 +} diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index dfaae784361..0d9040f7674 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -27,9 +27,11 @@ type ZipTest struct { } type ZipTestFile struct { - Name string - Mode os.FileMode - Mtime string // optional, modified time in format "mm-dd-yy hh:mm:ss" + Name string + Mode os.FileMode + NonUTF8 bool + ModTime time.Time + Modified time.Time // Information describing expected zip file content. // First, reading the entire content should produce the error ContentErr. @@ -47,32 +49,22 @@ type ZipTestFile struct { Size uint64 } -// Caution: The Mtime values found for the test files should correspond to -// the values listed with unzip -l . However, the values -// listed by unzip appear to be off by some hours. When creating -// fresh test files and testing them, this issue is not present. -// The test files were created in Sydney, so there might be a time -// zone issue. The time zone information does have to be encoded -// somewhere, because otherwise unzip -l could not provide a different -// time from what the archive/zip package provides, but there appears -// to be no documentation about this. - var tests = []ZipTest{ { Name: "test.zip", Comment: "This is a zipfile comment.", File: []ZipTestFile{ { - Name: "test.txt", - Content: []byte("This is a test text file.\n"), - Mtime: "09-05-10 12:12:02", - Mode: 0644, + Name: "test.txt", + Content: []byte("This is a test text file.\n"), + Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), + Mode: 0644, }, { - Name: "gophercolor16x16.png", - File: "gophercolor16x16.png", - Mtime: "09-05-10 15:52:58", - Mode: 0644, + Name: "gophercolor16x16.png", + File: "gophercolor16x16.png", + Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), + Mode: 0644, }, }, }, @@ -81,16 +73,16 @@ var tests = []ZipTest{ Comment: "This is a zipfile comment.", File: []ZipTestFile{ { - Name: "test.txt", - Content: []byte("This is a test text file.\n"), - Mtime: "09-05-10 12:12:02", - Mode: 0644, + Name: "test.txt", + Content: []byte("This is a test text file.\n"), + Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)), + Mode: 0644, }, { - Name: "gophercolor16x16.png", - File: "gophercolor16x16.png", - Mtime: "09-05-10 15:52:58", - Mode: 0644, + Name: "gophercolor16x16.png", + File: "gophercolor16x16.png", + Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)), + Mode: 0644, }, }, }, @@ -99,10 +91,10 @@ var tests = []ZipTest{ Source: returnRecursiveZip, File: []ZipTestFile{ { - Name: "r/r.zip", - Content: rZipBytes(), - Mtime: "03-04-10 00:24:16", - Mode: 0666, + Name: "r/r.zip", + Content: rZipBytes(), + Modified: time.Date(2010, 3, 4, 0, 24, 16, 0, time.UTC), + Mode: 0666, }, }, }, @@ -110,9 +102,10 @@ var tests = []ZipTest{ Name: "symlink.zip", File: []ZipTestFile{ { - Name: "symlink", - Content: []byte("../target"), - Mode: 0777 | os.ModeSymlink, + Name: "symlink", + Content: []byte("../target"), + Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)), + Mode: 0777 | os.ModeSymlink, }, }, }, @@ -127,22 +120,72 @@ var tests = []ZipTest{ Name: "dd.zip", File: []ZipTestFile{ { - Name: "filename", - Content: []byte("This is a test textfile.\n"), - Mtime: "02-02-11 13:06:20", - Mode: 0666, + Name: "filename", + Content: []byte("This is a test textfile.\n"), + Modified: time.Date(2011, 2, 2, 13, 6, 20, 0, time.UTC), + Mode: 0666, }, }, }, { // created in windows XP file manager. Name: "winxp.zip", - File: crossPlatform, + File: []ZipTestFile{ + { + Name: "hello", + Content: []byte("world \r\n"), + Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, time.UTC), + Mode: 0666, + }, + { + Name: "dir/bar", + Content: []byte("foo \r\n"), + Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, time.UTC), + Mode: 0666, + }, + { + Name: "dir/empty/", + Content: []byte{}, + Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC), + Mode: os.ModeDir | 0777, + }, + { + Name: "readonly", + Content: []byte("important \r\n"), + Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, time.UTC), + Mode: 0444, + }, + }, }, { // created by Zip 3.0 under Linux Name: "unix.zip", - File: crossPlatform, + File: []ZipTestFile{ + { + Name: "hello", + Content: []byte("world \r\n"), + Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, timeZone(0)), + Mode: 0666, + }, + { + Name: "dir/bar", + Content: []byte("foo \r\n"), + Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, timeZone(0)), + Mode: 0666, + }, + { + Name: "dir/empty/", + Content: []byte{}, + Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)), + Mode: os.ModeDir | 0777, + }, + { + Name: "readonly", + Content: []byte("important \r\n"), + Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, timeZone(0)), + Mode: 0444, + }, + }, }, { // created by Go, before we wrote the "optional" data @@ -150,16 +193,16 @@ var tests = []ZipTest{ Name: "go-no-datadesc-sig.zip", File: []ZipTestFile{ { - Name: "foo.txt", - Content: []byte("foo\n"), - Mtime: "03-08-12 16:59:10", - Mode: 0644, + Name: "foo.txt", + Content: []byte("foo\n"), + Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), + Mode: 0644, }, { - Name: "bar.txt", - Content: []byte("bar\n"), - Mtime: "03-08-12 16:59:12", - Mode: 0644, + Name: "bar.txt", + Content: []byte("bar\n"), + Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), + Mode: 0644, }, }, }, @@ -169,14 +212,16 @@ var tests = []ZipTest{ Name: "go-with-datadesc-sig.zip", File: []ZipTestFile{ { - Name: "foo.txt", - Content: []byte("foo\n"), - Mode: 0666, + Name: "foo.txt", + Content: []byte("foo\n"), + Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), + Mode: 0666, }, { - Name: "bar.txt", - Content: []byte("bar\n"), - Mode: 0666, + Name: "bar.txt", + Content: []byte("bar\n"), + Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), + Mode: 0666, }, }, }, @@ -187,13 +232,15 @@ var tests = []ZipTest{ { Name: "foo.txt", Content: []byte("foo\n"), + Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), Mode: 0666, ContentErr: ErrChecksum, }, { - Name: "bar.txt", - Content: []byte("bar\n"), - Mode: 0666, + Name: "bar.txt", + Content: []byte("bar\n"), + Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), + Mode: 0666, }, }, }, @@ -203,16 +250,16 @@ var tests = []ZipTest{ Name: "crc32-not-streamed.zip", File: []ZipTestFile{ { - Name: "foo.txt", - Content: []byte("foo\n"), - Mtime: "03-08-12 16:59:10", - Mode: 0644, + Name: "foo.txt", + Content: []byte("foo\n"), + Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), + Mode: 0644, }, { - Name: "bar.txt", - Content: []byte("bar\n"), - Mtime: "03-08-12 16:59:12", - Mode: 0644, + Name: "bar.txt", + Content: []byte("bar\n"), + Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), + Mode: 0644, }, }, }, @@ -225,15 +272,15 @@ var tests = []ZipTest{ { Name: "foo.txt", Content: []byte("foo\n"), - Mtime: "03-08-12 16:59:10", + Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)), Mode: 0644, ContentErr: ErrChecksum, }, { - Name: "bar.txt", - Content: []byte("bar\n"), - Mtime: "03-08-12 16:59:12", - Mode: 0644, + Name: "bar.txt", + Content: []byte("bar\n"), + Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)), + Mode: 0644, }, }, }, @@ -241,10 +288,10 @@ var tests = []ZipTest{ Name: "zip64.zip", File: []ZipTestFile{ { - Name: "README", - Content: []byte("This small file is in ZIP64 format.\n"), - Mtime: "08-10-12 14:33:32", - Mode: 0644, + Name: "README", + Content: []byte("This small file is in ZIP64 format.\n"), + Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, time.UTC), + Mode: 0644, }, }, }, @@ -253,10 +300,10 @@ var tests = []ZipTest{ 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, + Name: "README", + Content: []byte("This small file is in ZIP64 format.\n"), + Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, timeZone(-4*time.Hour)), + Mode: 0644, }, }, }, @@ -266,41 +313,179 @@ var tests = []ZipTest{ Source: returnBigZipBytes, File: []ZipTestFile{ { - Name: "big.file", - Content: nil, - Size: 1<<32 - 1, - Mode: 0666, + Name: "big.file", + Content: nil, + Size: 1<<32 - 1, + Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC), + Mode: 0666, + }, + }, + }, + { + Name: "utf8-7zip.zip", + File: []ZipTestFile{ + { + Name: "世界", + Content: []byte{}, + Mode: 0666, + Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)), + }, + }, + }, + { + Name: "utf8-infozip.zip", + File: []ZipTestFile{ + { + Name: "世界", + Content: []byte{}, + Mode: 0644, + // Name is valid UTF-8, but format does not have UTF-8 flag set. + // We don't do UTF-8 detection for multi-byte runes due to + // false-positives with other encodings (e.g., Shift-JIS). + // Format says encoding is not UTF-8, so we trust it. + NonUTF8: true, + Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)), + }, + }, + }, + { + Name: "utf8-osx.zip", + File: []ZipTestFile{ + { + Name: "世界", + Content: []byte{}, + Mode: 0644, + // Name is valid UTF-8, but format does not have UTF-8 set. + NonUTF8: true, + Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)), + }, + }, + }, + { + Name: "utf8-winrar.zip", + File: []ZipTestFile{ + { + Name: "世界", + Content: []byte{}, + Mode: 0666, + Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)), }, }, }, -} - -var crossPlatform = []ZipTestFile{ { - Name: "hello", - Content: []byte("world \r\n"), - Mode: 0666, + Name: "utf8-winzip.zip", + File: []ZipTestFile{ + { + Name: "世界", + Content: []byte{}, + Mode: 0666, + Modified: time.Date(2017, 11, 6, 13, 9, 27, 867000000, timeZone(-8*time.Hour)), + }, + }, }, { - Name: "dir/bar", - Content: []byte("foo \r\n"), - Mode: 0666, + Name: "time-7zip.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)), + Mode: 0666, + }, + }, }, { - Name: "dir/empty/", - Content: []byte{}, - Mode: os.ModeDir | 0777, + Name: "time-infozip.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), + Mode: 0644, + }, + }, }, { - Name: "readonly", - Content: []byte("important \r\n"), - Mode: 0444, + Name: "time-osx.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 17, 27, 0, timeZone(-7*time.Hour)), + Mode: 0644, + }, + }, + }, + { + Name: "time-win7.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 58, 0, time.UTC), + Mode: 0666, + }, + }, + }, + { + Name: "time-winrar.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)), + Mode: 0666, + }, + }, + }, + { + Name: "time-winzip.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 57, 244000000, timeZone(-7*time.Hour)), + Mode: 0666, + }, + }, + }, + { + Name: "time-go.zip", + File: []ZipTestFile{ + { + Name: "test.txt", + Content: []byte{}, + Size: 1<<32 - 1, + Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), + Mode: 0666, + }, + }, + }, + { + Name: "time-22738.zip", + File: []ZipTestFile{ + { + Name: "file", + Content: []byte{}, + Mode: 0666, + Modified: time.Date(1999, 12, 31, 19, 0, 0, 0, timeZone(-5*time.Hour)), + ModTime: time.Date(1999, 12, 31, 19, 0, 0, 0, time.UTC), + }, + }, }, } func TestReader(t *testing.T) { for _, zt := range tests { - readTestZip(t, zt) + t.Run(zt.Name, func(t *testing.T) { + readTestZip(t, zt) + }) } } @@ -319,7 +504,7 @@ func readTestZip(t *testing.T, zt ZipTest) { } } if err != zt.Error { - t.Errorf("%s: error=%v, want %v", zt.Name, err, zt.Error) + t.Errorf("error=%v, want %v", err, zt.Error) return } @@ -335,16 +520,19 @@ func readTestZip(t *testing.T, zt ZipTest) { } if z.Comment != zt.Comment { - t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment) + t.Errorf("comment=%q, want %q", z.Comment, zt.Comment) } if len(z.File) != len(zt.File) { - t.Fatalf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File)) + t.Fatalf("file count=%d, want %d", len(z.File), len(zt.File)) } // test read of each file for i, ft := range zt.File { readTestFile(t, zt, ft, z.File[i]) } + if t.Failed() { + return + } // test simultaneous reads n := 0 @@ -363,23 +551,24 @@ func readTestZip(t *testing.T, zt ZipTest) { } } +func equalTimeAndZone(t1, t2 time.Time) bool { + name1, offset1 := t1.Zone() + name2, offset2 := t2.Zone() + return t1.Equal(t2) && name1 == name2 && offset1 == offset2 +} + func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { if f.Name != ft.Name { - t.Errorf("%s: name=%q, want %q", zt.Name, f.Name, ft.Name) + t.Errorf("name=%q, want %q", f.Name, ft.Name) } - - if ft.Mtime != "" { - mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime) - if err != nil { - t.Error(err) - return - } - if ft := f.ModTime(); !ft.Equal(mtime) { - t.Errorf("%s: %s: mtime=%s, want %s", zt.Name, f.Name, ft, mtime) - } + if !ft.Modified.IsZero() && !equalTimeAndZone(f.Modified, ft.Modified) { + t.Errorf("%s: Modified=%s, want %s", f.Name, f.Modified, ft.Modified) + } + if !ft.ModTime.IsZero() && !equalTimeAndZone(f.ModTime(), ft.ModTime) { + t.Errorf("%s: ModTime=%s, want %s", f.Name, f.ModTime(), ft.ModTime) } - testFileMode(t, zt.Name, f, ft.Mode) + testFileMode(t, f, ft.Mode) size := uint64(f.UncompressedSize) if size == uint32max { @@ -390,7 +579,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { r, err := f.Open() if err != nil { - t.Errorf("%s: %v", zt.Name, err) + t.Errorf("%v", err) return } @@ -408,7 +597,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { var b bytes.Buffer _, err = io.Copy(&b, r) if err != ft.ContentErr { - t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr) + t.Errorf("copying contents: %v (want %v)", err, ft.ContentErr) } if err != nil { return @@ -440,12 +629,12 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { } } -func testFileMode(t *testing.T, zipName string, f *File, want os.FileMode) { +func testFileMode(t *testing.T, f *File, want os.FileMode) { mode := f.Mode() if want == 0 { - t.Errorf("%s: %s mode: got %v, want none", zipName, f.Name, mode) + t.Errorf("%s mode: got %v, want none", f.Name, mode) } else if mode != want { - t.Errorf("%s: %s mode: want %v, got %v", zipName, f.Name, want, mode) + t.Errorf("%s mode: want %v, got %v", f.Name, want, mode) } } diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go index 0be210e8e73..f613ebdc344 100644 --- a/libgo/go/archive/zip/struct.go +++ b/libgo/go/archive/zip/struct.go @@ -27,8 +27,8 @@ import ( // Compression methods. const ( - Store uint16 = 0 - Deflate uint16 = 8 + Store uint16 = 0 // no compression + Deflate uint16 = 8 // DEFLATE compressed ) const ( @@ -46,40 +46,79 @@ const ( directory64LocLen = 20 // directory64EndLen = 56 // + extra - // Constants for the first byte in CreatorVersion + // Constants for the first byte in CreatorVersion. creatorFAT = 0 creatorUnix = 3 creatorNTFS = 11 creatorVFAT = 14 creatorMacOSX = 19 - // version numbers + // Version numbers. zipVersion20 = 20 // 2.0 zipVersion45 = 45 // 4.5 (reads and writes zip64 archives) - // limits for non zip64 files + // Limits for non zip64 files. uint16max = (1 << 16) - 1 uint32max = (1 << 32) - 1 - // extra header id's - zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field + // Extra header IDs. + // + // IDs 0..31 are reserved for official use by PKWARE. + // IDs above that range are defined by third-party vendors. + // Since ZIP lacked high precision timestamps (nor a official specification + // of the timezone used for the date fields), many competing extra fields + // have been invented. Pervasive use effectively makes them "official". + // + // See http://mdfs.net/Docs/Comp/Archiving/Zip/ExtraField + zip64ExtraID = 0x0001 // Zip64 extended information + ntfsExtraID = 0x000a // NTFS + unixExtraID = 0x000d // UNIX + extTimeExtraID = 0x5455 // Extended timestamp + infoZipUnixExtraID = 0x5855 // Info-ZIP Unix extension ) // FileHeader describes a file within a zip file. // See the zip spec for details. type FileHeader struct { // Name is the name of the file. - // It must be a relative path: it must not start with a drive - // letter (e.g. C:) or leading slash, and only forward slashes - // are allowed. + // It must be a relative path, not start with a drive letter (e.g. C:), + // and must use forward slashes instead of back slashes. Name string - CreatorVersion uint16 - ReaderVersion uint16 - Flags uint16 - Method uint16 - ModifiedTime uint16 // MS-DOS time - ModifiedDate uint16 // MS-DOS date + // Comment is any arbitrary user-defined string shorter than 64KiB. + Comment string + + // NonUTF8 indicates that Name and Comment are not encoded in UTF-8. + // + // By specification, the only other encoding permitted should be CP-437, + // but historically many ZIP readers interpret Name and Comment as whatever + // the system's local character encoding happens to be. + // + // This flag should only be set if the user intends to encode a non-portable + // ZIP file for a specific localized region. Otherwise, the Writer + // automatically sets the ZIP format's UTF-8 flag for valid UTF-8 strings. + NonUTF8 bool + + CreatorVersion uint16 + ReaderVersion uint16 + Flags uint16 + + // Method is the compression method. If zero, Store is used. + Method uint16 + + // Modified is the modified time of the file. + // + // When reading, an extended timestamp is preferred over the legacy MS-DOS + // date field, and the offset between the times is used as the timezone. + // If only the MS-DOS date is present, the timezone is assumed to be UTC. + // + // When writing, an extended timestamp (which is timezone-agnostic) is + // always emitted. The legacy MS-DOS date field is encoded according to the + // location of the Modified time. + Modified time.Time + ModifiedTime uint16 // Deprecated: Legacy MS-DOS date; use Modified instead. + ModifiedDate uint16 // Deprecated: Legacy MS-DOS time; use Modified instead. + CRC32 uint32 CompressedSize uint32 // Deprecated: Use CompressedSize64 instead. UncompressedSize uint32 // Deprecated: Use UncompressedSize64 instead. @@ -87,7 +126,6 @@ type FileHeader struct { UncompressedSize64 uint64 Extra []byte ExternalAttrs uint32 // Meaning depends on CreatorVersion - Comment string } // FileInfo returns an os.FileInfo for the FileHeader. @@ -117,6 +155,8 @@ func (fi headerFileInfo) Sys() interface{} { return fi.fh } // Because os.FileInfo's Name method returns only the base name of // the file it describes, it may be necessary to modify the Name field // of the returned header to provide the full path name of the file. +// If compression is desired, callers should set the FileHeader.Method +// field; it is unset by default. func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) { size := fi.Size() fh := &FileHeader{ @@ -144,6 +184,21 @@ type directoryEnd struct { comment string } +// timeZone returns a *time.Location based on the provided offset. +// If the offset is non-sensible, then this uses an offset of zero. +func timeZone(offset time.Duration) *time.Location { + const ( + minOffset = -12 * time.Hour // E.g., Baker island at -12:00 + maxOffset = +14 * time.Hour // E.g., Line island at +14:00 + offsetAlias = 15 * time.Minute // E.g., Nepal at +5:45 + ) + offset = offset.Round(offsetAlias) + if offset < minOffset || maxOffset < offset { + offset = 0 + } + return time.FixedZone("", int(offset/time.Second)) +} + // msDosTimeToTime converts an MS-DOS date and time into a time.Time. // The resolution is 2s. // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx @@ -168,21 +223,26 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time { // The resolution is 2s. // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { - t = t.In(time.UTC) fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) return } -// ModTime returns the modification time in UTC. -// The resolution is 2s. +// ModTime returns the modification time in UTC using the legacy +// ModifiedDate and ModifiedTime fields. +// +// Deprecated: Use Modified instead. func (h *FileHeader) ModTime() time.Time { return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) } -// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC. -// The resolution is 2s. +// SetModTime sets the Modified, ModifiedTime, and ModifiedDate fields +// to the given time in UTC. +// +// Deprecated: Use Modified instead. func (h *FileHeader) SetModTime(t time.Time) { + t = t.UTC() // Convert to UTC for compatibility + h.Modified = t h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t) } diff --git a/libgo/go/archive/zip/testdata/time-22738.zip b/libgo/go/archive/zip/testdata/time-22738.zip new file mode 100644 index 0000000000000000000000000000000000000000..eb85b57103e11a48eb210439f5d81f691c0cedc0 GIT binary patch literal 140 zcmWIWW@Zs#;9vlP8S~Xa6b!I1a5AK2=A?#(ure?F9Ko|w2)xbIc^X400 literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/time-go.zip b/libgo/go/archive/zip/testdata/time-go.zip new file mode 100644 index 0000000000000000000000000000000000000000..f008805fa42c982a0e28e5abe025425dbc1a9ad9 GIT binary patch literal 148 zcmWIWW@Zs#;9y{2s972B4W!_JgMpKwB(=CiucV?RG=!CbvDfowWPmq2NG%)$cr!AI bFyJ--t`N+?VjL?QNQMyz?SV81GcW)E?OYRQ literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/time-infozip.zip b/libgo/go/archive/zip/testdata/time-infozip.zip new file mode 100644 index 0000000000000000000000000000000000000000..8e6394891f0f1000d5aff4c14fff25659a00ac7c GIT binary patch literal 166 zcmWIWW@h1H0D;<-@!nttl;B{HVJJy0F3~HgCpPx6NtkA0Hc^2-v9sr literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/time-osx.zip b/libgo/go/archive/zip/testdata/time-osx.zip new file mode 100644 index 0000000000000000000000000000000000000000..e82c5c229e0917b8e33029e7666e755961ab9e48 GIT binary patch literal 142 zcmWIWW@h1H0D;<-@!nttl;B_xU?@o~F3~HgC<%?=VYu$~GqTt7XXIB#5rzP7MkY~a iT>5xm#yBi#1Thh&aKKFo@MdKL$uR<<6Oc9oaTowu0U8JZ literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/time-win7.zip b/libgo/go/archive/zip/testdata/time-win7.zip new file mode 100644 index 0000000000000000000000000000000000000000..8ba222b224674153fb65b5be87ca89f434fcb110 GIT binary patch literal 114 zcmWIWW@Zs#0D;<-@!nttl;8l;C8@F9Ko|w2)xbIc<#roA literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/time-winzip.zip b/libgo/go/archive/zip/testdata/time-winzip.zip new file mode 100644 index 0000000000000000000000000000000000000000..f6e8f8ba067e462fe7a9727159390919571b8270 GIT binary patch literal 150 zcmWIWW@h1H0D;<-@!nttl;8l;C8@jkM&B_K+#0Z2@Kw1r~0|1@$8R7r{ literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/utf8-7zip.zip b/libgo/go/archive/zip/testdata/utf8-7zip.zip new file mode 100644 index 0000000000000000000000000000000000000000..0e97884559fa599f7376daf2478cf6cf516dc817 GIT binary patch literal 146 zcmWIWW@h1HVBlb2(92BoW+w>yVlX3XFH;U0*F@dLbBL6$Hu0$~J@hL{8Z;-VWn literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/utf8-infozip.zip b/libgo/go/archive/zip/testdata/utf8-infozip.zip new file mode 100644 index 0000000000000000000000000000000000000000..25a892646cec2a10d19add86db7acb516556bea6 GIT binary patch literal 162 zcmWIWW@h1HVBlb2(92BoWK#03@RuM*si- literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/utf8-osx.zip b/libgo/go/archive/zip/testdata/utf8-osx.zip new file mode 100644 index 0000000000000000000000000000000000000000..9b0c058b5b5744d389e73e8afd9f6963426aaebf GIT binary patch literal 138 zcmWIWW@h1H00F(sG;c5iO0Y2qFg)2Y?fKN6&+w>yVlX3XFH;U0*F@dLbBL6$Hu0$~J@hL{8Z)OZ^i literal 0 HcmV?d00001 diff --git a/libgo/go/archive/zip/testdata/utf8-winzip.zip b/libgo/go/archive/zip/testdata/utf8-winzip.zip new file mode 100644 index 0000000000000000000000000000000000000000..909d52ed2d9a6db86fdc7669bb355e7da2338a6e GIT binary patch literal 146 zcmWIWW@h1HVBlb2(92BoW uint16max { + return errors.New("zip: Writer.Comment too long") + } + w.comment = comment + return nil +} + // Close finishes writing the zip file by writing the central directory. // It does not (and cannot) close the underlying writer. func (w *Writer) Close() error { @@ -91,7 +107,7 @@ func (w *Writer) Close() error { // append a zip64 extra block to Extra var buf [28]byte // 2x uint16 + 3x uint64 eb := writeBuf(buf[:]) - eb.uint16(zip64ExtraId) + eb.uint16(zip64ExtraID) eb.uint16(24) // size = 3x uint64 eb.uint64(h.UncompressedSize64) eb.uint64(h.CompressedSize64) @@ -172,21 +188,25 @@ func (w *Writer) Close() error { var buf [directoryEndLen]byte b := writeBuf(buf[:]) b.uint32(uint32(directoryEndSignature)) - b = b[4:] // skip over disk number and first disk number (2x uint16) - b.uint16(uint16(records)) // number of entries this disk - b.uint16(uint16(records)) // number of entries total - b.uint32(uint32(size)) // size of directory - b.uint32(uint32(offset)) // start of directory - // skipped size of comment (always zero) + b = b[4:] // skip over disk number and first disk number (2x uint16) + b.uint16(uint16(records)) // number of entries this disk + b.uint16(uint16(records)) // number of entries total + b.uint32(uint32(size)) // size of directory + b.uint32(uint32(offset)) // start of directory + b.uint16(uint16(len(w.comment))) // byte size of EOCD comment if _, err := w.cw.Write(buf[:]); err != nil { return err } + if _, err := io.WriteString(w.cw, w.comment); err != nil { + return err + } return w.cw.w.(*bufio.Writer).Flush() } // Create adds a file to the zip file using the provided name. // It returns a Writer to which the file contents should be written. +// The file contents will be compressed using the Deflate method. // The name must be a relative path: it must not start with a drive // letter (e.g. C:) or leading slash, and only forward slashes are // allowed. @@ -200,27 +220,36 @@ func (w *Writer) Create(name string) (io.Writer, error) { return w.CreateHeader(header) } -func hasValidUTF8(s string) bool { - n := 0 - for _, r := range s { - // By default, ZIP uses CP437, which is only identical to ASCII for the printable characters. - if r < 0x20 || r >= 0x7f { - if !utf8.ValidRune(r) { - return false +// detectUTF8 reports whether s is a valid UTF-8 string, and whether the string +// must be considered UTF-8 encoding (i.e., not compatible with CP-437, ASCII, +// or any other common encoding). +func detectUTF8(s string) (valid, require bool) { + for i := 0; i < len(s); { + r, size := utf8.DecodeRuneInString(s[i:]) + i += size + // Officially, ZIP uses CP-437, but many readers use the system's + // local character encoding. Most encoding are compatible with a large + // subset of CP-437, which itself is ASCII-like. + // + // Forbid 0x7e and 0x5c since EUC-KR and Shift-JIS replace those + // characters with localized currency and overline characters. + if r < 0x20 || r > 0x7d || r == 0x5c { + if !utf8.ValidRune(r) || (r == utf8.RuneError && size == 1) { + return false, false } - n++ + require = true } } - return n > 0 + return true, require } -// CreateHeader adds a file to the zip file using the provided FileHeader -// for the file metadata. -// It returns a Writer to which the file contents should be written. +// CreateHeader adds a file to the zip archive using the provided FileHeader +// for the file metadata. Writer takes ownership of fh and may mutate +// its fields. The caller must not modify fh after calling CreateHeader. // +// This returns a Writer to which the file contents should be written. // The file's contents must be written to the io.Writer before the next -// call to Create, CreateHeader, or Close. The provided FileHeader fh -// must not be modified after a call to CreateHeader. +// call to Create, CreateHeader, or Close. func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { if w.last != nil && !w.last.closed { if err := w.last.close(); err != nil { @@ -234,13 +263,62 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { fh.Flags |= 0x8 // we will write a data descriptor - if hasValidUTF8(fh.Name) || hasValidUTF8(fh.Comment) { - fh.Flags |= 0x800 // filename or comment have valid utf-8 string + // The ZIP format has a sad state of affairs regarding character encoding. + // Officially, the name and comment fields are supposed to be encoded + // in CP-437 (which is mostly compatible with ASCII), unless the UTF-8 + // flag bit is set. However, there are several problems: + // + // * Many ZIP readers still do not support UTF-8. + // * If the UTF-8 flag is cleared, several readers simply interpret the + // name and comment fields as whatever the local system encoding is. + // + // In order to avoid breaking readers without UTF-8 support, + // we avoid setting the UTF-8 flag if the strings are CP-437 compatible. + // However, if the strings require multibyte UTF-8 encoding and is a + // valid UTF-8 string, then we set the UTF-8 bit. + // + // For the case, where the user explicitly wants to specify the encoding + // as UTF-8, they will need to set the flag bit themselves. + utf8Valid1, utf8Require1 := detectUTF8(fh.Name) + utf8Valid2, utf8Require2 := detectUTF8(fh.Comment) + switch { + case fh.NonUTF8: + fh.Flags &^= 0x800 + case (utf8Require1 || utf8Require2) && (utf8Valid1 && utf8Valid2): + fh.Flags |= 0x800 } fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte fh.ReaderVersion = zipVersion20 + // If Modified is set, this takes precedence over MS-DOS timestamp fields. + if !fh.Modified.IsZero() { + // Contrary to the FileHeader.SetModTime method, we intentionally + // do not convert to UTC, because we assume the user intends to encode + // the date using the specified timezone. A user may want this control + // because many legacy ZIP readers interpret the timestamp according + // to the local timezone. + // + // The timezone is only non-UTC if a user directly sets the Modified + // field directly themselves. All other approaches sets UTC. + fh.ModifiedDate, fh.ModifiedTime = timeToMsDosTime(fh.Modified) + + // Use "extended timestamp" format since this is what Info-ZIP uses. + // Nearly every major ZIP implementation uses a different format, + // but at least most seem to be able to understand the other formats. + // + // This format happens to be identical for both local and central header + // if modification time is the only timestamp being encoded. + var mbuf [9]byte // 2*SizeOf(uint16) + SizeOf(uint8) + SizeOf(uint32) + mt := uint32(fh.Modified.Unix()) + eb := writeBuf(mbuf[:]) + eb.uint16(extTimeExtraID) + eb.uint16(5) // Size: SizeOf(uint8) + SizeOf(uint32) + eb.uint8(1) // Flags: ModTime + eb.uint32(mt) // ModTime + fh.Extra = append(fh.Extra, mbuf[:]...) + } + fw := &fileWriter{ zipw: w.cw, compCount: &countWriter{w: w.cw}, @@ -273,6 +351,14 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { } func writeHeader(w io.Writer, h *FileHeader) error { + const maxUint16 = 1<<16 - 1 + if len(h.Name) > maxUint16 { + return errLongName + } + if len(h.Extra) > maxUint16 { + return errLongExtra + } + var buf [fileHeaderLen]byte b := writeBuf(buf[:]) b.uint32(uint32(fileHeaderSignature)) @@ -402,6 +488,11 @@ func (w nopCloser) Close() error { type writeBuf []byte +func (b *writeBuf) uint8(v uint8) { + (*b)[0] = v + *b = (*b)[1:] +} + func (b *writeBuf) uint16(v uint16) { binary.LittleEndian.PutUint16(*b, v) *b = (*b)[2:] diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go index 92fb6ecf0ed..38f32296fa8 100644 --- a/libgo/go/archive/zip/writer_test.go +++ b/libgo/go/archive/zip/writer_test.go @@ -6,11 +6,14 @@ package zip import ( "bytes" + "fmt" "io" "io/ioutil" "math/rand" "os" + "strings" "testing" + "time" ) // TODO(adg): a more sophisticated test suite @@ -57,8 +60,8 @@ var writeTests = []WriteTest{ func TestWriter(t *testing.T) { largeData := make([]byte, 1<<17) - for i := range largeData { - largeData[i] = byte(rand.Int()) + if _, err := rand.Read(largeData); err != nil { + t.Fatal("rand.Read failed:", err) } writeTests[1].Data = largeData defer func() { @@ -87,31 +90,100 @@ func TestWriter(t *testing.T) { } } +// TestWriterComment is test for EOCD comment read/write. +func TestWriterComment(t *testing.T) { + var tests = []struct { + comment string + ok bool + }{ + {"hi, hello", true}, + {"hi, こんにちわ", true}, + {strings.Repeat("a", uint16max), true}, + {strings.Repeat("a", uint16max+1), false}, + } + + for _, test := range tests { + // write a zip file + buf := new(bytes.Buffer) + w := NewWriter(buf) + if err := w.SetComment(test.comment); err != nil { + if test.ok { + t.Fatalf("SetComment: unexpected error %v", err) + } + continue + } else { + if !test.ok { + t.Fatalf("SetComment: unexpected success, want error") + } + } + + if err := w.Close(); test.ok == (err != nil) { + t.Fatal(err) + } + + if w.closed != test.ok { + t.Fatalf("Writer.closed: got %v, want %v", w.closed, test.ok) + } + + // skip read test in failure cases + if !test.ok { + continue + } + + // read it back + r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) + if err != nil { + t.Fatal(err) + } + if r.Comment != test.comment { + t.Fatalf("Reader.Comment: got %v, want %v", r.Comment, test.comment) + } + } +} + func TestWriterUTF8(t *testing.T) { var utf8Tests = []struct { name string comment string - expect uint16 + nonUTF8 bool + flags uint16 }{ { name: "hi, hello", comment: "in the world", - expect: 0x8, + flags: 0x8, }, { name: "hi, こんにちわ", comment: "in the world", - expect: 0x808, + flags: 0x808, + }, + { + name: "hi, こんにちわ", + comment: "in the world", + nonUTF8: true, + flags: 0x8, }, { name: "hi, hello", comment: "in the 世界", - expect: 0x808, + flags: 0x808, }, { name: "hi, こんにちわ", comment: "in the 世界", - expect: 0x808, + flags: 0x808, + }, + { + name: "the replacement rune is �", + comment: "the replacement rune is �", + flags: 0x808, + }, + { + // Name is Japanese encoded in Shift JIS. + name: "\x93\xfa\x96{\x8c\xea.txt", + comment: "in the 世界", + flags: 0x008, // UTF-8 must not be set }, } @@ -123,6 +195,7 @@ func TestWriterUTF8(t *testing.T) { h := &FileHeader{ Name: test.name, Comment: test.comment, + NonUTF8: test.nonUTF8, Method: Deflate, } w, err := w.CreateHeader(h) @@ -142,18 +215,41 @@ func TestWriterUTF8(t *testing.T) { t.Fatal(err) } for i, test := range utf8Tests { - got := r.File[i].Flags - t.Logf("name %v, comment %v", test.name, test.comment) - if got != test.expect { - t.Fatalf("Flags: got %v, want %v", got, test.expect) + flags := r.File[i].Flags + if flags != test.flags { + t.Errorf("CreateHeader(name=%q comment=%q nonUTF8=%v): flags=%#x, want %#x", test.name, test.comment, test.nonUTF8, flags, test.flags) } } } +func TestWriterTime(t *testing.T) { + var buf bytes.Buffer + h := &FileHeader{ + Name: "test.txt", + Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), + } + w := NewWriter(&buf) + if _, err := w.CreateHeader(h); err != nil { + t.Fatalf("unexpected CreateHeader error: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("unexpected Close error: %v", err) + } + + want, err := ioutil.ReadFile("testdata/time-go.zip") + if err != nil { + t.Fatalf("unexpected ReadFile error: %v", err) + } + if got := buf.Bytes(); !bytes.Equal(got, want) { + fmt.Printf("%x\n%x\n", got, want) + t.Error("contents of time-go.zip differ") + } +} + func TestWriterOffset(t *testing.T) { largeData := make([]byte, 1<<17) - for i := range largeData { - largeData[i] = byte(rand.Int()) + if _, err := rand.Read(largeData); err != nil { + t.Fatal("rand.Read failed:", err) } writeTests[1].Data = largeData defer func() { @@ -225,7 +321,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) { if f.Name != wt.Name { t.Fatalf("File name: got %q, want %q", f.Name, wt.Name) } - testFileMode(t, wt.Name, f, wt.Mode) + testFileMode(t, f, wt.Mode) rc, err := f.Open() if err != nil { t.Fatal("opening:", err) diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go index 18c2171ba6c..7e02cb0eeaa 100644 --- a/libgo/go/archive/zip/zip_test.go +++ b/libgo/go/archive/zip/zip_test.go @@ -645,16 +645,54 @@ func TestHeaderTooShort(t *testing.T) { h := FileHeader{ Name: "foo.txt", Method: Deflate, - Extra: []byte{zip64ExtraId}, // missing size and second half of tag, but Extra is best-effort parsing + Extra: []byte{zip64ExtraID}, // missing size and second half of tag, but Extra is best-effort parsing } testValidHeader(&h, t) } +func TestHeaderTooLongErr(t *testing.T) { + var headerTests = []struct { + name string + extra []byte + wanterr error + }{ + { + name: strings.Repeat("x", 1<<16), + extra: []byte{}, + wanterr: errLongName, + }, + { + name: "long_extra", + extra: bytes.Repeat([]byte{0xff}, 1<<16), + wanterr: errLongExtra, + }, + } + + // write a zip file + buf := new(bytes.Buffer) + w := NewWriter(buf) + + for _, test := range headerTests { + h := &FileHeader{ + Name: test.name, + Extra: test.extra, + } + _, err := w.CreateHeader(h) + if err != test.wanterr { + t.Errorf("error=%v, want %v", err, test.wanterr) + } + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } +} + func TestHeaderIgnoredSize(t *testing.T) { h := FileHeader{ Name: "foo.txt", Method: Deflate, - Extra: []byte{zip64ExtraId & 0xFF, zip64ExtraId >> 8, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, // bad size but shouldn't be consulted + Extra: []byte{zip64ExtraID & 0xFF, zip64ExtraID >> 8, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, // bad size but shouldn't be consulted } testValidHeader(&h, t) } diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go index da94a2503f0..ad9c9f5ddf7 100644 --- a/libgo/go/bufio/bufio.go +++ b/libgo/go/bufio/bufio.go @@ -62,6 +62,9 @@ func NewReader(rd io.Reader) *Reader { return NewReaderSize(rd, defaultBufSize) } +// Size returns the size of the underlying buffer in bytes. +func (r *Reader) Size() int { return len(r.buf) } + // Reset discards any buffered data, resets all state, and switches // the buffered reader to read from r. func (b *Reader) Reset(r io.Reader) { @@ -548,6 +551,9 @@ func NewWriter(w io.Writer) *Writer { return NewWriterSize(w, defaultBufSize) } +// Size returns the size of the underlying buffer in bytes. +func (b *Writer) Size() int { return len(b.buf) } + // Reset discards any unflushed buffered data, clears any error, and // resets b to write its output to w. func (b *Writer) Reset(w io.Writer) { diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go index ef0f6c834e8..c829d2b0648 100644 --- a/libgo/go/bufio/bufio_test.go +++ b/libgo/go/bufio/bufio_test.go @@ -1418,6 +1418,24 @@ func TestReaderDiscard(t *testing.T) { } +func TestReaderSize(t *testing.T) { + if got, want := NewReader(nil).Size(), DefaultBufSize; got != want { + t.Errorf("NewReader's Reader.Size = %d; want %d", got, want) + } + if got, want := NewReaderSize(nil, 1234).Size(), 1234; got != want { + t.Errorf("NewReaderSize's Reader.Size = %d; want %d", got, want) + } +} + +func TestWriterSize(t *testing.T) { + if got, want := NewWriter(nil).Size(), DefaultBufSize; got != want { + t.Errorf("NewWriter's Writer.Size = %d; want %d", got, want) + } + if got, want := NewWriterSize(nil, 1234).Size(), 1234; got != want { + t.Errorf("NewWriterSize's Writer.Size = %d; want %d", got, want) + } +} + // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have. type onlyReader struct { io.Reader diff --git a/libgo/go/bufio/export_test.go b/libgo/go/bufio/export_test.go index 3d3bb27d8da..1667f01a841 100644 --- a/libgo/go/bufio/export_test.go +++ b/libgo/go/bufio/export_test.go @@ -11,6 +11,8 @@ import ( var IsSpace = isSpace +const DefaultBufSize = defaultBufSize + func (s *Scanner) MaxTokenSize(n int) { if n < utf8.UTFMax || n > 1e9 { panic("bad max token size") diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go index 9f741c98307..40aaa4ab817 100644 --- a/libgo/go/bufio/scan.go +++ b/libgo/go/bufio/scan.go @@ -123,8 +123,9 @@ var ErrFinalToken = errors.New("final token") // After Scan returns false, the Err method will return any error that // occurred during scanning, except that if it was io.EOF, Err // will return nil. -// Scan panics if the split function returns 100 empty tokens without -// advancing the input. This is a common error mode for scanners. +// Scan panics if the split function returns too many empty +// tokens without advancing the input. This is a common error mode for +// scanners. func (s *Scanner) Scan() bool { if s.done { return false @@ -156,8 +157,8 @@ func (s *Scanner) Scan() bool { } else { // Returning tokens not advancing input at EOF. s.empties++ - if s.empties > 100 { - panic("bufio.Scan: 100 empty tokens without progressing") + if s.empties > maxConsecutiveEmptyReads { + panic("bufio.Scan: too many empty tokens without progressing") } } return true diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go index 1c7c041d680..4578c855a9e 100644 --- a/libgo/go/builtin/builtin.go +++ b/libgo/go/builtin/builtin.go @@ -171,8 +171,9 @@ func cap(v Type) int // Slice: The size specifies the length. The capacity of the slice is // equal to its length. A second integer argument may be provided to // specify a different capacity; it must be no smaller than the -// length, so make([]int, 0, 10) allocates a slice of length 0 and -// capacity 10. +// length. For example, make([]int, 0, 10) allocates an underlying array +// of size 10 and returns a slice of length 0 and capacity 10 that is +// backed by this underlying array. // Map: An empty map is allocated with enough space to hold the // specified number of elements. The size may be omitted, in which case // a small starting size is allocated. diff --git a/libgo/go/bytes/boundary_test.go b/libgo/go/bytes/boundary_test.go new file mode 100644 index 00000000000..ea84f1e40fd --- /dev/null +++ b/libgo/go/bytes/boundary_test.go @@ -0,0 +1,84 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// +build linux + +package bytes_test + +import ( + . "bytes" + "syscall" + "testing" +) + +// This file tests the situation where byte operations are checking +// data very near to a page boundary. We want to make sure those +// operations do not read across the boundary and cause a page +// fault where they shouldn't. + +// These tests run only on linux. The code being tested is +// not OS-specific, so it does not need to be tested on all +// operating systems. + +// dangerousSlice returns a slice which is immediately +// preceded and followed by a faulting page. +func dangerousSlice(t *testing.T) []byte { + pagesize := syscall.Getpagesize() + b, err := syscall.Mmap(0, 0, 3*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANONYMOUS|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("mmap failed %s", err) + } + err = syscall.Mprotect(b[:pagesize], syscall.PROT_NONE) + if err != nil { + t.Fatalf("mprotect low failed %s\n", err) + } + err = syscall.Mprotect(b[2*pagesize:], syscall.PROT_NONE) + if err != nil { + t.Fatalf("mprotect high failed %s\n", err) + } + return b[pagesize : 2*pagesize] +} + +func TestEqualNearPageBoundary(t *testing.T) { + t.Parallel() + b := dangerousSlice(t) + for i := range b { + b[i] = 'A' + } + for i := 0; i <= len(b); i++ { + Equal(b[:i], b[len(b)-i:]) + Equal(b[len(b)-i:], b[:i]) + } +} + +func TestIndexByteNearPageBoundary(t *testing.T) { + t.Parallel() + b := dangerousSlice(t) + for i := range b { + idx := IndexByte(b[i:], 1) + if idx != -1 { + t.Fatalf("IndexByte(b[%d:])=%d, want -1\n", i, idx) + } + } +} + +func TestIndexNearPageBoundary(t *testing.T) { + t.Parallel() + var q [64]byte + b := dangerousSlice(t) + if len(b) > 256 { + // Only worry about when we're near the end of a page. + b = b[len(b)-256:] + } + for j := 1; j < len(q); j++ { + q[j-1] = 1 // difference is only found on the last byte + for i := range b { + idx := Index(b[i:], q[:j]) + if idx != -1 { + t.Fatalf("Index(b[%d:], q[:%d])=%d, want -1\n", i, j, idx) + } + } + q[j-1] = 0 + } +} diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go index 20e42bbbbca..dc9d5e95d32 100644 --- a/libgo/go/bytes/buffer.go +++ b/libgo/go/bytes/buffer.go @@ -15,34 +15,37 @@ import ( // A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { - buf []byte // contents are the bytes buf[off : len(buf)] - off int // read at &buf[off], write at &buf[len(buf)] - lastRead readOp // last read operation, so that Unread* can work correctly. - // FIXME: lastRead can fit in a single byte + buf []byte // contents are the bytes buf[off : len(buf)] + off int // read at &buf[off], write at &buf[len(buf)] + bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. + lastRead readOp // last read operation, so that Unread* can work correctly. - // memory to hold first slice; helps small buffers avoid allocation. // FIXME: it would be advisable to align Buffer to cachelines to avoid false // sharing. - bootstrap [64]byte } // The readOp constants describe the last action performed on // the buffer, so that UnreadRune and UnreadByte can check for // invalid usage. opReadRuneX constants are chosen such that // converted to int they correspond to the rune size that was read. -type readOp int +type readOp int8 +// Don't use iota for these, as the values need to correspond with the +// names and comments, which is easier to see when being explicit. const ( opRead readOp = -1 // Any other read operation. - opInvalid = 0 // Non-read operation. - opReadRune1 = 1 // Read rune of size 1. - opReadRune2 = 2 // Read rune of size 2. - opReadRune3 = 3 // Read rune of size 3. - opReadRune4 = 4 // Read rune of size 4. + opInvalid readOp = 0 // Non-read operation. + opReadRune1 readOp = 1 // Read rune of size 1. + opReadRune2 readOp = 2 // Read rune of size 2. + opReadRune3 readOp = 3 // Read rune of size 3. + opReadRune4 readOp = 4 // Read rune of size 4. ) // ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer. var ErrTooLarge = errors.New("bytes.Buffer: too large") +var errNegativeRead = errors.New("bytes.Buffer: reader returned negative count from Read") + +const maxInt = int(^uint(0) >> 1) // Bytes returns a slice of length b.Len() holding the unread portion of the buffer. // The slice is valid for use only until the next buffer modification (that is, @@ -53,6 +56,8 @@ func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } // String returns the contents of the unread portion of the buffer // as a string. If the Buffer is a nil pointer, it returns "". +// +// To build strings more efficiently, see the strings.Builder type. func (b *Buffer) String() string { if b == nil { // Special case, useful in debugging. @@ -61,6 +66,9 @@ func (b *Buffer) String() string { return string(b.buf[b.off:]) } +// empty returns whether the unread portion of the buffer is empty. +func (b *Buffer) empty() bool { return len(b.buf) <= b.off } + // Len returns the number of bytes of the unread portion of the buffer; // b.Len() == len(b.Bytes()). func (b *Buffer) Len() int { return len(b.buf) - b.off } @@ -81,7 +89,7 @@ func (b *Buffer) Truncate(n int) { if n < 0 || n > b.Len() { panic("bytes.Buffer: truncation out of range") } - b.buf = b.buf[0 : b.off+n] + b.buf = b.buf[:b.off+n] } // Reset resets the buffer to be empty, @@ -97,7 +105,7 @@ func (b *Buffer) Reset() { // internal buffer only needs to be resliced. // It returns the index where bytes should be written and whether it succeeded. func (b *Buffer) tryGrowByReslice(n int) (int, bool) { - if l := len(b.buf); l+n <= cap(b.buf) { + if l := len(b.buf); n <= cap(b.buf)-l { b.buf = b.buf[:l+n] return l, true } @@ -122,15 +130,18 @@ func (b *Buffer) grow(n int) int { b.buf = b.bootstrap[:n] return 0 } - if m+n <= cap(b.buf)/2 { + c := cap(b.buf) + if n <= c/2-m { // We can slide things down instead of allocating a new - // slice. We only need m+n <= cap(b.buf) to slide, but + // slice. We only need m+n <= c to slide, but // we instead let capacity get twice as large so we // don't spend all our time copying. - copy(b.buf[:], b.buf[b.off:]) + copy(b.buf, b.buf[b.off:]) + } else if c > maxInt-c-n { + panic(ErrTooLarge) } else { // Not enough space anywhere, we need to allocate. - buf := makeSlice(2*cap(b.buf) + n) + buf := makeSlice(2*c + n) copy(buf, b.buf[b.off:]) b.buf = buf } @@ -150,7 +161,7 @@ func (b *Buffer) Grow(n int) { panic("bytes.Buffer.Grow: negative count") } m := b.grow(n) - b.buf = b.buf[0:m] + b.buf = b.buf[:m] } // Write appends the contents of p to the buffer, growing the buffer as @@ -189,34 +200,22 @@ const MinRead = 512 // buffer becomes too large, ReadFrom will panic with ErrTooLarge. func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { b.lastRead = opInvalid - // If buffer is empty, reset to recover space. - if b.off >= len(b.buf) { - b.Reset() - } for { - if free := cap(b.buf) - len(b.buf); free < MinRead { - // not enough space at end - newBuf := b.buf - if b.off+free < MinRead { - // not enough space using beginning of buffer; - // double buffer capacity - newBuf = makeSlice(2*cap(b.buf) + MinRead) - } - copy(newBuf, b.buf[b.off:]) - b.buf = newBuf[:len(b.buf)-b.off] - b.off = 0 + i := b.grow(MinRead) + m, e := r.Read(b.buf[i:cap(b.buf)]) + if m < 0 { + panic(errNegativeRead) } - m, e := r.Read(b.buf[len(b.buf):cap(b.buf)]) - b.buf = b.buf[0 : len(b.buf)+m] + + b.buf = b.buf[:i+m] n += int64(m) if e == io.EOF { - break + return n, nil // e is EOF, so return nil explicitly } if e != nil { return n, e } } - return n, nil // err is EOF, so return nil explicitly } // makeSlice allocates a slice of size n. If the allocation fails, it panics @@ -237,8 +236,7 @@ func makeSlice(n int) []byte { // encountered during the write is also returned. func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { b.lastRead = opInvalid - if b.off < len(b.buf) { - nBytes := b.Len() + if nBytes := b.Len(); nBytes > 0 { m, e := w.Write(b.buf[b.off:]) if m > nBytes { panic("bytes.Buffer.WriteTo: invalid Write count") @@ -256,7 +254,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { } // Buffer is now empty; reset. b.Reset() - return + return n, nil } // WriteByte appends the byte c to the buffer, growing the buffer as needed. @@ -298,11 +296,11 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) { // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid - if b.off >= len(b.buf) { + if b.empty() { // Buffer is empty, reset to recover space. b.Reset() if len(p) == 0 { - return + return 0, nil } return 0, io.EOF } @@ -311,7 +309,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) { if n > 0 { b.lastRead = opRead } - return + return n, nil } // Next returns a slice containing the next n bytes from the buffer, @@ -335,8 +333,7 @@ func (b *Buffer) Next(n int) []byte { // ReadByte reads and returns the next byte from the buffer. // If no byte is available, it returns error io.EOF. func (b *Buffer) ReadByte() (byte, error) { - b.lastRead = opInvalid - if b.off >= len(b.buf) { + if b.empty() { // Buffer is empty, reset to recover space. b.Reset() return 0, io.EOF @@ -353,8 +350,7 @@ func (b *Buffer) ReadByte() (byte, error) { // If the bytes are an erroneous UTF-8 encoding, it // consumes one byte and returns U+FFFD, 1. func (b *Buffer) ReadRune() (r rune, size int, err error) { - b.lastRead = opInvalid - if b.off >= len(b.buf) { + if b.empty() { // Buffer is empty, reset to recover space. b.Reset() return 0, 0, io.EOF @@ -413,7 +409,7 @@ func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { // return a copy of slice. The buffer's backing array may // be overwritten by later calls. line = append(line, slice...) - return + return line, err } // readSlice is like ReadBytes but returns a reference to internal buffer data. diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go index ce2f01a0ad3..e4bbc12f6a1 100644 --- a/libgo/go/bytes/buffer_test.go +++ b/libgo/go/bytes/buffer_test.go @@ -6,25 +6,27 @@ package bytes_test import ( . "bytes" - "internal/testenv" "io" "math/rand" - "os/exec" "runtime" "testing" "unicode/utf8" ) -const N = 10000 // make this bigger for a larger (and slower) test -var data string // test data for write tests -var testBytes []byte // test data; same as data but as a slice. +const N = 10000 // make this bigger for a larger (and slower) test +var testString string // test data for write tests +var testBytes []byte // test data; same as testString but as a slice. + +type negativeReader struct{} + +func (r *negativeReader) Read([]byte) (int, error) { return -1, nil } func init() { testBytes = make([]byte, N) for i := 0; i < N; i++ { testBytes[i] = 'a' + byte(i%26) } - data = string(testBytes) + testString = string(testBytes) } // Verify that contents of buf match the string s. @@ -88,12 +90,12 @@ func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub func TestNewBuffer(t *testing.T) { buf := NewBuffer(testBytes) - check(t, "NewBuffer", buf, data) + check(t, "NewBuffer", buf, testString) } func TestNewBufferString(t *testing.T) { - buf := NewBufferString(data) - check(t, "NewBufferString", buf, data) + buf := NewBufferString(testString) + check(t, "NewBufferString", buf, testString) } // Empty buf through repeated reads into fub. @@ -128,7 +130,7 @@ func TestBasicOperations(t *testing.T) { buf.Truncate(0) check(t, "TestBasicOperations (3)", &buf, "") - n, err := buf.Write([]byte(data[0:1])) + n, err := buf.Write(testBytes[0:1]) if n != 1 { t.Errorf("wrote 1 byte, but n == %d", n) } @@ -137,30 +139,30 @@ func TestBasicOperations(t *testing.T) { } check(t, "TestBasicOperations (4)", &buf, "a") - buf.WriteByte(data[1]) + buf.WriteByte(testString[1]) check(t, "TestBasicOperations (5)", &buf, "ab") - n, err = buf.Write([]byte(data[2:26])) + n, err = buf.Write(testBytes[2:26]) if n != 24 { - t.Errorf("wrote 25 bytes, but n == %d", n) + t.Errorf("wrote 24 bytes, but n == %d", n) } - check(t, "TestBasicOperations (6)", &buf, string(data[0:26])) + check(t, "TestBasicOperations (6)", &buf, testString[0:26]) buf.Truncate(26) - check(t, "TestBasicOperations (7)", &buf, string(data[0:26])) + check(t, "TestBasicOperations (7)", &buf, testString[0:26]) buf.Truncate(20) - check(t, "TestBasicOperations (8)", &buf, string(data[0:20])) + check(t, "TestBasicOperations (8)", &buf, testString[0:20]) - empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5)) + empty(t, "TestBasicOperations (9)", &buf, testString[0:20], make([]byte, 5)) empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100)) - buf.WriteByte(data[1]) + buf.WriteByte(testString[1]) c, err := buf.ReadByte() if err != nil { t.Error("ReadByte unexpected eof") } - if c != data[1] { + if c != testString[1] { t.Errorf("ReadByte wrong value c=%v", c) } c, err = buf.ReadByte() @@ -177,8 +179,8 @@ func TestLargeStringWrites(t *testing.T) { limit = 9 } for i := 3; i < limit; i += 3 { - s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data) - empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i)) + s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, testString) + empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(testString)/i)) } check(t, "TestLargeStringWrites (3)", &buf, "") } @@ -191,7 +193,7 @@ func TestLargeByteWrites(t *testing.T) { } for i := 3; i < limit; i += 3 { s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, testBytes) - empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i)) + empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(testString)/i)) } check(t, "TestLargeByteWrites (3)", &buf, "") } @@ -199,8 +201,8 @@ func TestLargeByteWrites(t *testing.T) { func TestLargeStringReads(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { - s := fillString(t, "TestLargeReads (1)", &buf, "", 5, data[0:len(data)/i]) - empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))) + s := fillString(t, "TestLargeReads (1)", &buf, "", 5, testString[0:len(testString)/i]) + empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(testString))) } check(t, "TestLargeStringReads (3)", &buf, "") } @@ -209,7 +211,7 @@ func TestLargeByteReads(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) - empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))) + empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(testString))) } check(t, "TestLargeByteReads (3)", &buf, "") } @@ -218,14 +220,14 @@ func TestMixedReadsAndWrites(t *testing.T) { var buf Buffer s := "" for i := 0; i < 50; i++ { - wlen := rand.Intn(len(data)) + wlen := rand.Intn(len(testString)) if i%2 == 0 { - s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0:wlen]) + s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testString[0:wlen]) } else { s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testBytes[0:wlen]) } - rlen := rand.Intn(len(data)) + rlen := rand.Intn(len(testString)) fub := make([]byte, rlen) n, _ := buf.Read(fub) s = s[n:] @@ -263,17 +265,37 @@ func TestReadFrom(t *testing.T) { s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) var b Buffer b.ReadFrom(&buf) - empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data))) + empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(testString))) } } +func TestReadFromNegativeReader(t *testing.T) { + var b Buffer + defer func() { + switch err := recover().(type) { + case nil: + t.Fatal("bytes.Buffer.ReadFrom didn't panic") + case error: + // this is the error string of errNegativeRead + wantError := "bytes.Buffer: reader returned negative count from Read" + if err.Error() != wantError { + t.Fatalf("recovered panic: got %v, want %v", err.Error(), wantError) + } + default: + t.Fatalf("unexpected panic value: %#v", err) + } + }() + + b.ReadFrom(new(negativeReader)) +} + func TestWriteTo(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i]) var b Buffer buf.WriteTo(&b) - empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(data))) + empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(testString))) } } @@ -473,6 +495,18 @@ func TestGrow(t *testing.T) { } } +func TestGrowOverflow(t *testing.T) { + defer func() { + if err := recover(); err != ErrTooLarge { + t.Errorf("after too-large Grow, recover() = %v; want %v", err, ErrTooLarge) + } + }() + + buf := NewBuffer(make([]byte, 1)) + const maxInt = int(^uint(0) >> 1) + buf.Grow(maxInt) +} + // Was a bug: used to give EOF reading empty slice at EOF. func TestReadEmptyAtEOF(t *testing.T) { b := new(Buffer) @@ -548,26 +582,6 @@ func TestBufferGrowth(t *testing.T) { } } -// Test that tryGrowByReslice is inlined. -// Only execute on "linux-amd64" builder in order to avoid breakage. -func TestTryGrowByResliceInlined(t *testing.T) { - targetBuilder := "linux-amd64" - if testenv.Builder() != targetBuilder { - t.Skipf("%q gets executed on %q builder only", t.Name(), targetBuilder) - } - t.Parallel() - goBin := testenv.GoToolPath(t) - out, err := exec.Command(goBin, "tool", "nm", goBin).CombinedOutput() - if err != nil { - t.Fatalf("go tool nm: %v: %s", err, out) - } - // Verify this doesn't exist: - sym := "bytes.(*Buffer).tryGrowByReslice" - if Contains(out, []byte(sym)) { - t.Errorf("found symbol %q in cmd/go, but should be inlined", sym) - } -} - func BenchmarkWriteByte(b *testing.B) { const n = 4 << 10 b.SetBytes(n) diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index 7c878af688c..9af177fa882 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -39,7 +39,7 @@ func explode(s []byte, n int) [][]byte { break } _, size = utf8.DecodeRune(s) - a[na] = s[0:size] + a[na] = s[0:size:size] s = s[size:] na++ } @@ -68,12 +68,12 @@ func Contains(b, subslice []byte) bool { return Index(b, subslice) != -1 } -// ContainsAny reports whether any of the UTF-8-encoded Unicode code points in chars are within b. +// ContainsAny reports whether any of the UTF-8-encoded code points in chars are within b. func ContainsAny(b []byte, chars string) bool { return IndexAny(b, chars) >= 0 } -// ContainsRune reports whether the Unicode code point r is within b. +// ContainsRune reports whether the rune is contained in the UTF-8-encoded byte slice b. func ContainsRune(b []byte, r rune) bool { return IndexRune(b, r) >= 0 } @@ -112,7 +112,7 @@ func LastIndexByte(s []byte, c byte) int { return -1 } -// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points. +// IndexRune interprets s as a sequence of UTF-8-encoded code points. // It returns the byte index of the first occurrence in s of the given rune. // It returns -1 if rune is not present in s. // If r is utf8.RuneError, it returns the first instance of any @@ -144,29 +144,31 @@ func IndexRune(s []byte, r rune) int { // code points in chars. It returns -1 if chars is empty or if there is no code // point in common. func IndexAny(s []byte, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i, c := range s { - if as.contains(c) { - return i - } + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i, c := range s { + if as.contains(c) { + return i } - return -1 } + return -1 } - var width int - for i := 0; i < len(s); i += width { - r := rune(s[i]) - if r < utf8.RuneSelf { - width = 1 - } else { - r, width = utf8.DecodeRune(s[i:]) - } - for _, ch := range chars { - if r == ch { - return i - } + } + var width int + for i := 0; i < len(s); i += width { + r := rune(s[i]) + if r < utf8.RuneSelf { + width = 1 + } else { + r, width = utf8.DecodeRune(s[i:]) + } + for _, ch := range chars { + if r == ch { + return i } } } @@ -178,24 +180,26 @@ func IndexAny(s []byte, chars string) int { // the Unicode code points in chars. It returns -1 if chars is empty or if // there is no code point in common. func LastIndexAny(s []byte, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := len(s) - 1; i >= 0; i-- { - if as.contains(s[i]) { - return i - } + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i := len(s) - 1; i >= 0; i-- { + if as.contains(s[i]) { + return i } - return -1 } + return -1 } - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRune(s[:i]) - i -= size - for _, c := range chars { - if r == c { - return i - } + } + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRune(s[:i]) + i -= size + for _, c := range chars { + if r == c { + return i } } } @@ -223,7 +227,7 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte { if m < 0 { break } - a[i] = s[:m+sepSave] + a[i] = s[: m+sepSave : m+sepSave] s = s[m+len(sep):] i++ } @@ -265,52 +269,112 @@ func SplitAfter(s, sep []byte) [][]byte { return genSplit(s, sep, len(sep), -1) } -// Fields splits the slice s around each instance of one or more consecutive white space -// characters, returning a slice of subslices of s or an empty list if s contains only white space. +var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} + +// Fields interprets s as a sequence of UTF-8-encoded code points. +// It splits the slice s around each instance of one or more consecutive white space +// characters, as defined by unicode.IsSpace, returning a slice of subslices of s or an +// empty slice if s contains only white space. func Fields(s []byte) [][]byte { - return FieldsFunc(s, unicode.IsSpace) + // First count the fields. + // This is an exact count if s is ASCII, otherwise it is an approximation. + n := 0 + wasSpace := 1 + // setBits is used to track which bits are set in the bytes of s. + setBits := uint8(0) + for i := 0; i < len(s); i++ { + r := s[i] + setBits |= r + isSpace := int(asciiSpace[r]) + n += wasSpace & ^isSpace + wasSpace = isSpace + } + + if setBits >= utf8.RuneSelf { + // Some runes in the input slice are not ASCII. + return FieldsFunc(s, unicode.IsSpace) + } + + // ASCII fast path + a := make([][]byte, n) + na := 0 + fieldStart := 0 + i := 0 + // Skip spaces in the front of the input. + for i < len(s) && asciiSpace[s[i]] != 0 { + i++ + } + fieldStart = i + for i < len(s) { + if asciiSpace[s[i]] == 0 { + i++ + continue + } + a[na] = s[fieldStart:i:i] + na++ + i++ + // Skip spaces in between fields. + for i < len(s) && asciiSpace[s[i]] != 0 { + i++ + } + fieldStart = i + } + if fieldStart < len(s) { // Last field might end at EOF. + a[na] = s[fieldStart:len(s):len(s)] + } + return a } -// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points. +// FieldsFunc interprets s as a sequence of UTF-8-encoded 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 all code points in s satisfy f(c), or // len(s) == 0, an empty slice is returned. // FieldsFunc makes no guarantees about the order in which it calls f(c). // If f does not return consistent results for a given c, FieldsFunc may crash. func FieldsFunc(s []byte, f func(rune) bool) [][]byte { - n := 0 - inField := false - for i := 0; i < len(s); { - r, size := utf8.DecodeRune(s[i:]) - wasInField := inField - inField = !f(r) - if inField && !wasInField { - n++ - } - i += size + // A span is used to record a slice of s of the form s[start:end]. + // The start index is inclusive and the end index is exclusive. + type span struct { + start int + end int } + spans := make([]span, 0, 32) - a := make([][]byte, n) - na := 0 - fieldStart := -1 - for i := 0; i <= len(s) && na < n; { - r, size := utf8.DecodeRune(s[i:]) - if fieldStart < 0 && size > 0 && !f(r) { - fieldStart = i - i += size - continue - } - if fieldStart >= 0 && (size == 0 || f(r)) { - a[na] = s[fieldStart:i] - na++ - fieldStart = -1 + // Find the field start and end indices. + wasField := false + fromIndex := 0 + for i := 0; i < len(s); { + size := 1 + r := rune(s[i]) + if r >= utf8.RuneSelf { + r, size = utf8.DecodeRune(s[i:]) } - if size == 0 { - break + if f(r) { + if wasField { + spans = append(spans, span{start: fromIndex, end: i}) + wasField = false + } + } else { + if !wasField { + fromIndex = i + wasField = true + } } i += size } - return a[0:na] + + // Last field might end at EOF. + if wasField { + spans = append(spans, span{fromIndex, len(s)}) + } + + // Create subslices from recorded field indices. + a := make([][]byte, len(spans)) + for i, span := range spans { + a[i] = s[span.start:span.end:span.end] + } + + return a } // Join concatenates the elements of s to create a new byte slice. The separator @@ -349,8 +413,8 @@ func HasSuffix(s, suffix []byte) bool { // Map returns a copy of the byte slice s with all its characters modified // according to the mapping function. If mapping returns a negative value, the character is -// dropped from the string with no replacement. The characters in s and the -// output are interpreted as UTF-8-encoded Unicode code points. +// dropped from the byte slice with no replacement. The characters in s and the +// output are interpreted as UTF-8-encoded code points. func Map(mapping func(r rune) rune, s []byte) []byte { // In the worst case, the slice can grow when mapped, making // things unpleasant. But it's so rare we barge in assuming it's @@ -408,28 +472,28 @@ func Repeat(b []byte, count int) []byte { return nb } -// ToUpper returns a copy of the byte slice s with all Unicode letters mapped to their upper case. +// ToUpper treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters within it mapped to their upper case. func ToUpper(s []byte) []byte { return Map(unicode.ToUpper, s) } -// ToLower returns a copy of the byte slice s with all Unicode letters mapped to their lower case. +// ToLower treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their lower case. func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) } -// ToTitle returns a copy of the byte slice s with all Unicode letters mapped to their title case. +// ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case. func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) } -// ToUpperSpecial returns a copy of the byte slice s with all Unicode letters mapped to their +// ToUpperSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // upper case, giving priority to the special casing rules. func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte { return Map(func(r rune) rune { return c.ToUpper(r) }, s) } -// ToLowerSpecial returns a copy of the byte slice s with all Unicode letters mapped to their +// ToLowerSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // lower case, giving priority to the special casing rules. func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte { return Map(func(r rune) rune { return c.ToLower(r) }, s) } -// ToTitleSpecial returns a copy of the byte slice s with all Unicode letters mapped to their +// ToTitleSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // title case, giving priority to the special casing rules. func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte { return Map(func(r rune) rune { return c.ToTitle(r) }, s) @@ -460,8 +524,8 @@ func isSeparator(r rune) bool { return unicode.IsSpace(r) } -// Title returns a copy of s with all Unicode letters that begin words -// mapped to their title case. +// Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin +// words mapped to their title case. // // BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly. func Title(s []byte) []byte { @@ -481,8 +545,8 @@ func Title(s []byte) []byte { s) } -// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded -// Unicode code points c that satisfy f(c). +// TrimLeftFunc treats s as UTF-8-encoded bytes and returns a subslice of s by slicing off +// all leading UTF-8-encoded code points c that satisfy f(c). func TrimLeftFunc(s []byte, f func(r rune) bool) []byte { i := indexFunc(s, f, false) if i == -1 { @@ -491,8 +555,8 @@ func TrimLeftFunc(s []byte, f func(r rune) bool) []byte { return s[i:] } -// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8 -// encoded Unicode code points c that satisfy f(c). +// TrimRightFunc returns a subslice of s by slicing off all trailing +// UTF-8-encoded code points c that satisfy f(c). func TrimRightFunc(s []byte, f func(r rune) bool) []byte { i := lastIndexFunc(s, f, false) if i >= 0 && s[i] >= utf8.RuneSelf { @@ -505,7 +569,7 @@ func TrimRightFunc(s []byte, f func(r rune) bool) []byte { } // TrimFunc returns a subslice of s by slicing off all leading and trailing -// UTF-8-encoded Unicode code points c that satisfy f(c). +// UTF-8-encoded code points c that satisfy f(c). func TrimFunc(s []byte, f func(r rune) bool) []byte { return TrimRightFunc(TrimLeftFunc(s, f), f) } @@ -528,14 +592,14 @@ func TrimSuffix(s, suffix []byte) []byte { return s } -// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points. +// IndexFunc interprets s as a sequence of UTF-8-encoded code points. // It returns the byte index in s of the first Unicode // code point satisfying f(c), or -1 if none do. func IndexFunc(s []byte, f func(r rune) bool) int { return indexFunc(s, f, true) } -// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points. +// LastIndexFunc interprets s as a sequence of UTF-8-encoded code points. // It returns the byte index in s of the last Unicode // code point satisfying f(c), or -1 if none do. func LastIndexFunc(s []byte, f func(r rune) bool) int { @@ -626,19 +690,19 @@ func makeCutsetFunc(cutset string) func(r rune) bool { } // Trim returns a subslice of s by slicing off all leading and -// trailing UTF-8-encoded Unicode code points contained in cutset. +// trailing UTF-8-encoded code points contained in cutset. func Trim(s []byte, cutset string) []byte { return TrimFunc(s, makeCutsetFunc(cutset)) } // TrimLeft returns a subslice of s by slicing off all leading -// UTF-8-encoded Unicode code points contained in cutset. +// UTF-8-encoded code points contained in cutset. func TrimLeft(s []byte, cutset string) []byte { return TrimLeftFunc(s, makeCutsetFunc(cutset)) } // TrimRight returns a subslice of s by slicing off all trailing -// UTF-8-encoded Unicode code points that are contained in cutset. +// UTF-8-encoded code points that are contained in cutset. func TrimRight(s []byte, cutset string) []byte { return TrimRightFunc(s, makeCutsetFunc(cutset)) } @@ -649,7 +713,8 @@ func TrimSpace(s []byte) []byte { return TrimFunc(s, unicode.IsSpace) } -// Runes returns a slice of runes (Unicode code points) equivalent to s. +// Runes interprets s as a sequence of UTF-8-encoded code points. +// It returns a slice of runes (Unicode code points) equivalent to s. func Runes(s []byte) []rune { t := make([]rune, utf8.RuneCount(s)) i := 0 @@ -758,3 +823,46 @@ func EqualFold(s, t []byte) bool { // One string is empty. Are both? return len(s) == len(t) } + +func indexRabinKarp(s, sep []byte) int { + // Rabin-Karp search + hashsep, pow := hashStr(sep) + n := len(sep) + var h uint32 + for i := 0; i < n; i++ { + h = h*primeRK + uint32(s[i]) + } + if h == hashsep && Equal(s[:n], sep) { + return 0 + } + for i := n; i < len(s); { + h *= primeRK + h += uint32(s[i]) + h -= pow * uint32(s[i-n]) + i++ + if h == hashsep && Equal(s[i-n:i], sep) { + return i - n + } + } + return -1 +} + +// primeRK is the prime base used in Rabin-Karp algorithm. +const primeRK = 16777619 + +// hashStr returns the hash and the appropriate multiplicative +// factor for use in Rabin-Karp algorithm. +func hashStr(sep []byte) (uint32, uint32) { + hash := uint32(0) + for i := 0; i < len(sep); i++ { + hash = hash*primeRK + uint32(sep[i]) + } + var pow, sq uint32 = 1, primeRK + for i := len(sep); i > 0; i >>= 1 { + if i&1 != 0 { + pow *= sq + } + sq *= sq + } + return hash, pow +} diff --git a/libgo/go/bytes/bytes_amd64.go b/libgo/go/bytes/bytes_amd64.go index d40c7441e94..2fbbbb0d877 100644 --- a/libgo/go/bytes/bytes_amd64.go +++ b/libgo/go/bytes/bytes_amd64.go @@ -77,52 +77,14 @@ func Index(s, sep []byte) int { } return -1 } - // Rabin-Karp search - hashsep, pow := hashStr(sep) - var h uint32 - for i := 0; i < n; i++ { - h = h*primeRK + uint32(s[i]) - } - if h == hashsep && Equal(s[:n], sep) { - return 0 - } - for i := n; i < len(s); { - h *= primeRK - h += uint32(s[i]) - h -= pow * uint32(s[i-n]) - i++ - if h == hashsep && Equal(s[i-n:i], sep) { - return i - n - } - } - return -1 + return indexRabinKarp(s, sep) } // Count counts the number of non-overlapping instances of sep in s. -// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s. +// If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. func Count(s, sep []byte) int { if len(sep) == 1 && cpu.X86.HasPOPCNT { return countByte(s, sep[0]) } return countGeneric(s, sep) } - -// primeRK is the prime base used in Rabin-Karp algorithm. -const primeRK = 16777619 - -// hashStr returns the hash and the appropriate multiplicative -// factor for use in Rabin-Karp algorithm. -func hashStr(sep []byte) (uint32, uint32) { - hash := uint32(0) - for i := 0; i < len(sep); i++ { - hash = hash*primeRK + uint32(sep[i]) - } - var pow, sq uint32 = 1, primeRK - for i := len(sep); i > 0; i >>= 1 { - if i&1 != 0 { - pow *= sq - } - sq *= sq - } - return hash, pow -} diff --git a/libgo/go/bytes/bytes_arm64.go b/libgo/go/bytes/bytes_arm64.go new file mode 100644 index 00000000000..1213b067a9d --- /dev/null +++ b/libgo/go/bytes/bytes_arm64.go @@ -0,0 +1,70 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package bytes + +func countByte(s []byte, c byte) int // bytes_arm64.s + +// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. +func Index(s, sep []byte) int { + n := len(sep) + switch { + case n == 0: + return 0 + case n == 1: + return IndexByte(s, sep[0]) + case n == len(s): + if Equal(sep, s) { + return 0 + } + return -1 + case n > len(s): + return -1 + } + c := sep[0] + i := 0 + fails := 0 + t := s[:len(s)-n+1] + for i < len(t) { + if t[i] != c { + o := IndexByte(t[i:], c) + if o < 0 { + break + } + i += o + } + if Equal(s[i:i+n], sep) { + return i + } + i++ + fails++ + if fails >= 4+i>>4 && i < len(t) { + // Give up on IndexByte, it isn't skipping ahead + // far enough to be better than Rabin-Karp. + // Experiments (using IndexPeriodic) suggest + // the cutover is about 16 byte skips. + // TODO: if large prefixes of sep are matching + // we should cutover at even larger average skips, + // because Equal becomes that much more expensive. + // This code does not take that effect into account. + j := indexRabinKarp(s[i:], sep) + if j < 0 { + return -1 + } + return i + j + } + } + return -1 +} + +// Count counts the number of non-overlapping instances of sep in s. +// If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. +func Count(s, sep []byte) int { + if len(sep) == 1 { + return countByte(s, sep[0]) + } + return countGeneric(s, sep) +} diff --git a/libgo/go/bytes/bytes_generic.go b/libgo/go/bytes/bytes_generic.go index 75a9c36dc42..b52d9396520 100644 --- a/libgo/go/bytes/bytes_generic.go +++ b/libgo/go/bytes/bytes_generic.go @@ -2,27 +2,29 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -build !amd64,!s390x +// -build !amd64,!s390x,!arm64 package bytes -// TODO: implements short string optimization on non amd64 platforms -// and get rid of bytes_amd64.go - // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. func Index(s, sep []byte) int { n := len(sep) - if n == 0 { + switch { + case n == 0: return 0 - } - if n > len(s) { + case n == 1: + return IndexByte(s, sep[0]) + case n == len(s): + if Equal(sep, s) { + return 0 + } + return -1 + case n > len(s): return -1 } c := sep[0] - if n == 1 { - return IndexByte(s, c) - } i := 0 + fails := 0 t := s[:len(s)-n+1] for i < len(t) { if t[i] != c { @@ -36,12 +38,28 @@ func Index(s, sep []byte) int { return i } i++ + fails++ + if fails >= 4+i>>4 && i < len(t) { + // Give up on IndexByte, it isn't skipping ahead + // far enough to be better than Rabin-Karp. + // Experiments (using IndexPeriodic) suggest + // the cutover is about 16 byte skips. + // TODO: if large prefixes of sep are matching + // we should cutover at even larger average skips, + // because Equal becomes that much more expensive. + // This code does not take that effect into account. + j := indexRabinKarp(s[i:], sep) + if j < 0 { + return -1 + } + return i + j + } } return -1 } // Count counts the number of non-overlapping instances of sep in s. -// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s. +// If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. func Count(s, sep []byte) int { return countGeneric(s, sep) } diff --git a/libgo/go/bytes/bytes_s390x.go b/libgo/go/bytes/bytes_s390x.go index 54e013e9ada..0c228486fc3 100644 --- a/libgo/go/bytes/bytes_s390x.go +++ b/libgo/go/bytes/bytes_s390x.go @@ -78,49 +78,11 @@ func Index(s, sep []byte) int { } return -1 } - // Rabin-Karp search - hashsep, pow := hashStr(sep) - var h uint32 - for i := 0; i < n; i++ { - h = h*primeRK + uint32(s[i]) - } - if h == hashsep && Equal(s[:n], sep) { - return 0 - } - for i := n; i < len(s); { - h *= primeRK - h += uint32(s[i]) - h -= pow * uint32(s[i-n]) - i++ - if h == hashsep && Equal(s[i-n:i], sep) { - return i - n - } - } - return -1 + return indexRabinKarp(s, sep) } // Count counts the number of non-overlapping instances of sep in s. -// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s. +// If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. func Count(s, sep []byte) int { return countGeneric(s, sep) } - -// primeRK is the prime base used in Rabin-Karp algorithm. -const primeRK = 16777619 - -// hashStr returns the hash and the appropriate multiplicative -// factor for use in Rabin-Karp algorithm. -func hashStr(sep []byte) (uint32, uint32) { - hash := uint32(0) - for i := 0; i < len(sep); i++ { - hash = hash*primeRK + uint32(sep[i]) - } - var pow, sq uint32 = 1, primeRK - for i := len(sep); i > 0; i >>= 1 { - if i&1 != 0 { - pow *= sq - } - sq *= sq - } - return hash, pow -} diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index d571eb3ab49..23fce29e319 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -140,6 +140,9 @@ var indexTests = []BinOpTest{ {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33}, {"foofyfoobarfoobar", "y", 4}, {"oooooooooooooooooooooo", "r", -1}, + // test fallback to Rabin-Karp. + {"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22}, + {"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1}, } var lastIndexTests = []BinOpTest{ @@ -741,6 +744,13 @@ var splittests = []SplitTest{ func TestSplit(t *testing.T) { for _, tt := range splittests { a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) + + // Appending to the results should not change future results. + var x []byte + for _, v := range a { + x = append(v, 'z') + } + result := sliceOfString(a) if !eq(result, tt.a) { t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) @@ -749,6 +759,11 @@ func TestSplit(t *testing.T) { if tt.n == 0 { continue } + + if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { + t.Errorf("last appended result was %s; want %s", x, want) + } + s := Join(a, []byte(tt.sep)) if string(s) != tt.s { t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) @@ -787,11 +802,23 @@ var splitaftertests = []SplitTest{ func TestSplitAfter(t *testing.T) { for _, tt := range splitaftertests { a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) + + // Appending to the results should not change future results. + var x []byte + for _, v := range a { + x = append(v, 'z') + } + result := sliceOfString(a) if !eq(result, tt.a) { t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) continue } + + if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { + t.Errorf("last appended result was %s; want %s", x, want) + } + s := Join(a, nil) if string(s) != tt.s { t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) @@ -826,12 +853,29 @@ var fieldstests = []FieldsTest{ func TestFields(t *testing.T) { for _, tt := range fieldstests { - a := Fields([]byte(tt.s)) + b := []byte(tt.s) + a := Fields(b) + + // Appending to the results should not change future results. + var x []byte + for _, v := range a { + x = append(v, 'z') + } + result := sliceOfString(a) if !eq(result, tt.a) { t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) continue } + + if string(b) != tt.s { + t.Errorf("slice changed to %s; want %s", string(b), tt.s) + } + if len(tt.a) > 0 { + if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { + t.Errorf("last appended result was %s; want %s", x, want) + } + } } } @@ -852,11 +896,28 @@ func TestFieldsFunc(t *testing.T) { {"aXXbXXXcX", []string{"a", "b", "c"}}, } for _, tt := range fieldsFuncTests { - a := FieldsFunc([]byte(tt.s), pred) + b := []byte(tt.s) + a := FieldsFunc(b, pred) + + // Appending to the results should not change future results. + var x []byte + for _, v := range a { + x = append(v, 'z') + } + result := sliceOfString(a) if !eq(result, tt.a) { t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) } + + if string(b) != tt.s { + t.Errorf("slice changed to %s; want %s", b, tt.s) + } + if len(tt.a) > 0 { + if want := tt.a[len(tt.a)-1] + "z"; string(x) != want { + t.Errorf("last appended result was %s; want %s", x, want) + } + } } } @@ -1507,19 +1568,58 @@ var makeFieldsInput = func() []byte { return x } -var fieldsInput = makeFieldsInput() +var makeFieldsInputASCII = func() []byte { + x := make([]byte, 1<<20) + // Input is ~10% space, rest ASCII non-space. + for i := range x { + if rand.Intn(10) == 0 { + x[i] = ' ' + } else { + x[i] = 'x' + } + } + return x +} + +var bytesdata = []struct { + name string + data []byte +}{ + {"ASCII", makeFieldsInputASCII()}, + {"Mixed", makeFieldsInput()}, +} func BenchmarkFields(b *testing.B) { - b.SetBytes(int64(len(fieldsInput))) - for i := 0; i < b.N; i++ { - Fields(fieldsInput) + for _, sd := range bytesdata { + b.Run(sd.name, func(b *testing.B) { + for j := 1 << 4; j <= 1<<20; j <<= 4 { + b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { + b.ReportAllocs() + b.SetBytes(int64(j)) + data := sd.data[:j] + for i := 0; i < b.N; i++ { + Fields(data) + } + }) + } + }) } } func BenchmarkFieldsFunc(b *testing.B) { - b.SetBytes(int64(len(fieldsInput))) - for i := 0; i < b.N; i++ { - FieldsFunc(fieldsInput, unicode.IsSpace) + for _, sd := range bytesdata { + b.Run(sd.name, func(b *testing.B) { + for j := 1 << 4; j <= 1<<20; j <<= 4 { + b.Run(fmt.Sprintf("%d", j), func(b *testing.B) { + b.ReportAllocs() + b.SetBytes(int64(j)) + data := sd.data[:j] + for i := 0; i < b.N; i++ { + FieldsFunc(data, unicode.IsSpace) + } + }) + } + }) } } @@ -1638,3 +1738,18 @@ func BenchmarkTrimASCII(b *testing.B) { } } } + +func BenchmarkIndexPeriodic(b *testing.B) { + key := []byte{1, 1} + for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { + b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) { + buf := make([]byte, 1<<16) + for i := 0; i < len(buf); i += skip { + buf[i] = 1 + } + for i := 0; i < b.N; i++ { + Index(buf, key) + } + }) + } +} diff --git a/libgo/go/bytes/equal_test.go b/libgo/go/bytes/equal_test.go deleted file mode 100644 index 9fdead8a604..00000000000 --- a/libgo/go/bytes/equal_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -// +build linux - -package bytes_test - -import ( - . "bytes" - "syscall" - "testing" - "unsafe" -) - -// This file tests the situation where memeq is checking -// data very near to a page boundary. We want to make sure -// equal does not read across the boundary and cause a page -// fault where it shouldn't. - -// This test runs only on linux. The code being tested is -// not OS-specific, so it does not need to be tested on all -// operating systems. - -func TestEqualNearPageBoundary(t *testing.T) { - pagesize := syscall.Getpagesize() - b := make([]byte, 4*pagesize) - i := pagesize - for ; uintptr(unsafe.Pointer(&b[i]))%uintptr(pagesize) != 0; i++ { - } - syscall.Mprotect(b[i-pagesize:i], 0) - syscall.Mprotect(b[i+pagesize:i+2*pagesize], 0) - defer syscall.Mprotect(b[i-pagesize:i], syscall.PROT_READ|syscall.PROT_WRITE) - defer syscall.Mprotect(b[i+pagesize:i+2*pagesize], syscall.PROT_READ|syscall.PROT_WRITE) - - // both of these should fault - //pagesize += int(b[i-1]) - //pagesize += int(b[i+pagesize]) - - for j := 0; j < pagesize; j++ { - b[i+j] = 'A' - } - for j := 0; j <= pagesize; j++ { - Equal(b[i:i+j], b[i+pagesize-j:i+pagesize]) - Equal(b[i+pagesize-j:i+pagesize], b[i:i+j]) - } -} diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go index 93972770ab2..5b7a46058f5 100644 --- a/libgo/go/bytes/example_test.go +++ b/libgo/go/bytes/example_test.go @@ -119,6 +119,32 @@ func ExampleContains() { // true } +func ExampleContainsAny() { + fmt.Println(bytes.ContainsAny([]byte("I like seafood."), "fÄo!")) + fmt.Println(bytes.ContainsAny([]byte("I like seafood."), "去是伟大的.")) + fmt.Println(bytes.ContainsAny([]byte("I like seafood."), "")) + fmt.Println(bytes.ContainsAny([]byte(""), "")) + // Output: + // true + // true + // false + // false +} + +func ExampleContainsRune() { + fmt.Println(bytes.ContainsRune([]byte("I like seafood."), 'f')) + fmt.Println(bytes.ContainsRune([]byte("I like seafood."), 'ö')) + fmt.Println(bytes.ContainsRune([]byte("去是伟大的!"), '大')) + fmt.Println(bytes.ContainsRune([]byte("去是伟大的!"), '!')) + fmt.Println(bytes.ContainsRune([]byte(""), '@')) + // Output: + // true + // false + // true + // true + // false +} + func ExampleCount() { fmt.Println(bytes.Count([]byte("cheese"), []byte("e"))) fmt.Println(bytes.Count([]byte("five"), []byte(""))) // before & after each rune @@ -127,6 +153,14 @@ func ExampleCount() { // 5 } +func ExampleEqual() { + fmt.Println(bytes.Equal([]byte("Go"), []byte("Go"))) + fmt.Println(bytes.Equal([]byte("Go"), []byte("C++"))) + // Output: + // true + // false +} + func ExampleEqualFold() { fmt.Println(bytes.EqualFold([]byte("Go"), []byte("go"))) // Output: true @@ -162,6 +196,14 @@ func ExampleIndex() { // -1 } +func ExampleIndexByte() { + fmt.Println(bytes.IndexByte([]byte("chicken"), byte('k'))) + fmt.Println(bytes.IndexByte([]byte("chicken"), byte('g'))) + // Output: + // 4 + // -1 +} + func ExampleIndexFunc() { f := func(c rune) bool { return unicode.Is(unicode.Han, c) @@ -199,6 +241,36 @@ func ExampleLastIndex() { // -1 } +func ExampleLastIndexAny() { + fmt.Println(bytes.LastIndexAny([]byte("go gopher"), "MüQp")) + fmt.Println(bytes.LastIndexAny([]byte("go 地鼠"), "地大")) + fmt.Println(bytes.LastIndexAny([]byte("go gopher"), "z,!.")) + // Output: + // 5 + // 3 + // -1 +} + +func ExampleLastIndexByte() { + fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('g'))) + fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('r'))) + fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('z'))) + // Output: + // 3 + // 8 + // -1 +} + +func ExampleLastIndexFunc() { + fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsLetter)) + fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsPunct)) + fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsNumber)) + // Output: + // 8 + // 9 + // -1 +} + func ExampleJoin() { s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")} fmt.Printf("%s", bytes.Join(s, []byte(", "))) @@ -218,6 +290,23 @@ func ExampleReplace() { // moo moo moo } +func ExampleRunes() { + rs := bytes.Runes([]byte("go gopher")) + for _, r := range rs { + fmt.Printf("%#U\n", r) + } + // Output: + // U+0067 'g' + // U+006F 'o' + // U+0020 ' ' + // U+0067 'g' + // U+006F 'o' + // U+0070 'p' + // U+0068 'h' + // U+0065 'e' + // U+0072 'r' +} + func ExampleSplit() { fmt.Printf("%q\n", bytes.Split([]byte("a,b,c"), []byte(","))) fmt.Printf("%q\n", bytes.Split([]byte("a man a plan a canal panama"), []byte("a "))) @@ -267,6 +356,18 @@ func ExampleTrim() { // Output: ["Achtung! Achtung"] } +func ExampleTrimFunc() { + fmt.Println(string(bytes.TrimFunc([]byte("go-gopher!"), unicode.IsLetter))) + fmt.Println(string(bytes.TrimFunc([]byte("\"go-gopher!\""), unicode.IsLetter))) + fmt.Println(string(bytes.TrimFunc([]byte("go-gopher!"), unicode.IsPunct))) + fmt.Println(string(bytes.TrimFunc([]byte("1234go-gopher!567"), unicode.IsNumber))) + // Output: + // -gopher! + // "go-gopher!" + // go-gopher + // go-gopher! +} + func ExampleMap() { rot13 := func(r rune) rune { switch { @@ -281,11 +382,43 @@ func ExampleMap() { // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure... } +func ExampleTrimLeft() { + fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789"))) + // Output: + // gopher8257 +} + +func ExampleTrimLeftFunc() { + fmt.Println(string(bytes.TrimLeftFunc([]byte("go-gopher"), unicode.IsLetter))) + fmt.Println(string(bytes.TrimLeftFunc([]byte("go-gopher!"), unicode.IsPunct))) + fmt.Println(string(bytes.TrimLeftFunc([]byte("1234go-gopher!567"), unicode.IsNumber))) + // Output: + // -gopher + // go-gopher! + // go-gopher!567 +} + func ExampleTrimSpace() { fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n"))) // Output: a lone gopher } +func ExampleTrimRight() { + fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789"))) + // Output: + // 453gopher +} + +func ExampleTrimRightFunc() { + fmt.Println(string(bytes.TrimRightFunc([]byte("go-gopher"), unicode.IsLetter))) + fmt.Println(string(bytes.TrimRightFunc([]byte("go-gopher!"), unicode.IsPunct))) + fmt.Println(string(bytes.TrimRightFunc([]byte("1234go-gopher!567"), unicode.IsNumber))) + // Output: + // go- + // go-gopher + // 1234go-gopher! +} + func ExampleToUpper() { fmt.Printf("%s", bytes.ToUpper([]byte("Gopher"))) // Output: GOPHER @@ -295,3 +428,11 @@ func ExampleToLower() { fmt.Printf("%s", bytes.ToLower([]byte("Gopher"))) // Output: gopher } + +func ExampleReader_Len() { + fmt.Println(bytes.NewReader([]byte("Hi!")).Len()) + fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len()) + // Output: + // 3 + // 16 +} diff --git a/libgo/go/bytes/reader.go b/libgo/go/bytes/reader.go index 28cfc7a9788..08464c2402d 100644 --- a/libgo/go/bytes/reader.go +++ b/libgo/go/bytes/reader.go @@ -35,6 +35,7 @@ func (r *Reader) Len() int { // to any other method. func (r *Reader) Size() int64 { return int64(len(r.s)) } +// Read implements the io.Reader interface. func (r *Reader) Read(b []byte) (n int, err error) { if r.i >= int64(len(r.s)) { return 0, io.EOF @@ -45,6 +46,7 @@ func (r *Reader) Read(b []byte) (n int, err error) { return } +// ReadAt implements the io.ReaderAt interface. func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { // cannot modify state - see io.ReaderAt if off < 0 { @@ -60,6 +62,7 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { return } +// ReadByte implements the io.ByteReader interface. func (r *Reader) ReadByte() (byte, error) { r.prevRune = -1 if r.i >= int64(len(r.s)) { @@ -70,6 +73,7 @@ func (r *Reader) ReadByte() (byte, error) { return b, nil } +// UnreadByte complements ReadByte in implementing the io.ByteScanner interface. func (r *Reader) UnreadByte() error { r.prevRune = -1 if r.i <= 0 { @@ -79,6 +83,7 @@ func (r *Reader) UnreadByte() error { return nil } +// ReadRune implements the io.RuneReader interface. func (r *Reader) ReadRune() (ch rune, size int, err error) { if r.i >= int64(len(r.s)) { r.prevRune = -1 @@ -94,6 +99,7 @@ func (r *Reader) ReadRune() (ch rune, size int, err error) { return } +// UnreadRune complements ReadRune in implementing the io.RuneScanner interface. func (r *Reader) UnreadRune() error { if r.prevRune < 0 { return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune") diff --git a/libgo/go/bytes/reader_test.go b/libgo/go/bytes/reader_test.go index 7b3034d4e0d..8806876ff13 100644 --- a/libgo/go/bytes/reader_test.go +++ b/libgo/go/bytes/reader_test.go @@ -140,9 +140,9 @@ func TestReaderWriteTo(t *testing.T) { for i := 0; i < 30; i += 3 { var l int if i > 0 { - l = len(data) / i + l = len(testString) / i } - s := data[:l] + s := testString[:l] r := NewReader(testBytes[:l]) var b Buffer n, err := r.WriteTo(&b) diff --git a/libgo/go/cmd/buildid/buildid.go b/libgo/go/cmd/buildid/buildid.go new file mode 100644 index 00000000000..8d810ffdd99 --- /dev/null +++ b/libgo/go/cmd/buildid/buildid.go @@ -0,0 +1,73 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "strings" + + "cmd/internal/buildid" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go tool buildid [-w] file\n") + flag.PrintDefaults() + os.Exit(2) +} + +var wflag = flag.Bool("w", false, "write build ID") + +func main() { + log.SetPrefix("buildid: ") + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + if flag.NArg() != 1 { + usage() + } + + file := flag.Arg(0) + id, err := buildid.ReadFile(file) + if err != nil { + log.Fatal(err) + } + if !*wflag { + fmt.Printf("%s\n", id) + return + } + + f, err := os.Open(file) + if err != nil { + log.Fatal(err) + } + matches, hash, err := buildid.FindAndHash(f, id, 0) + if err != nil { + log.Fatal(err) + } + f.Close() + + tail := id + if i := strings.LastIndex(id, "."); i >= 0 { + tail = tail[i+1:] + } + if len(tail) != len(hash)*2 { + log.Fatalf("%s: cannot find %d-byte hash in id %s", file, len(hash), id) + } + newID := id[:len(id)-len(tail)] + fmt.Sprintf("%x", hash) + + f, err = os.OpenFile(file, os.O_WRONLY, 0) + if err != nil { + log.Fatal(err) + } + if err := buildid.Rewrite(f, matches, newID); err != nil { + log.Fatal(err) + } + if err := f.Close(); err != nil { + log.Fatal(err) + } +} diff --git a/libgo/go/cmd/buildid/doc.go b/libgo/go/cmd/buildid/doc.go new file mode 100644 index 00000000000..d1ec155c976 --- /dev/null +++ b/libgo/go/cmd/buildid/doc.go @@ -0,0 +1,18 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Buildid displays or updates the build ID stored in a Go package or binary. + +Usage: + go tool buildid [-w] file + +By default, buildid prints the build ID found in the named file. +If the -w option is given, buildid rewrites the build ID found in +the file to accurately record a content hash of the file. + +This tool is only intended for use by the go command or +other build systems. +*/ +package main diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go index 7122a9dbbeb..58e0ee78cb7 100644 --- a/libgo/go/cmd/cgo/ast.go +++ b/libgo/go/cmd/cgo/ast.go @@ -58,11 +58,14 @@ func (f *File) ParseGo(name string, src []byte) { // so we use ast1 to look for the doc comments on import "C" // and on exported functions, and we use ast2 for translating // and reprinting. + // In cgo mode, we ignore ast2 and just apply edits directly + // the text behind ast1. In godefs mode we modify and print ast2. ast1 := parse(name, src, parser.ParseComments) ast2 := parse(name, src, 0) f.Package = ast1.Name.Name f.Name = make(map[string]*Name) + f.NamePos = make(map[*Name]token.Pos) // In ast1, find the import "C" line and get any extra C preamble. sawC := false @@ -96,36 +99,53 @@ func (f *File) ParseGo(name string, src []byte) { } // In ast2, strip the import "C" line. - w := 0 - for _, decl := range ast2.Decls { - d, ok := decl.(*ast.GenDecl) - if !ok { - ast2.Decls[w] = decl + if *godefs { + w := 0 + for _, decl := range ast2.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + ast2.Decls[w] = decl + w++ + continue + } + ws := 0 + for _, spec := range d.Specs { + s, ok := spec.(*ast.ImportSpec) + if !ok || s.Path.Value != `"C"` { + d.Specs[ws] = spec + ws++ + } + } + if ws == 0 { + continue + } + d.Specs = d.Specs[0:ws] + ast2.Decls[w] = d w++ - continue } - ws := 0 - for _, spec := range d.Specs { - s, ok := spec.(*ast.ImportSpec) - if !ok || s.Path.Value != `"C"` { - d.Specs[ws] = spec - ws++ + ast2.Decls = ast2.Decls[0:w] + } else { + for _, decl := range ast2.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + for _, spec := range d.Specs { + if s, ok := spec.(*ast.ImportSpec); ok && s.Path.Value == `"C"` { + // Replace "C" with _ "unsafe", to keep program valid. + // (Deleting import statement or clause is not safe if it is followed + // in the source by an explicit semicolon.) + f.Edit.Replace(f.offset(s.Path.Pos()), f.offset(s.Path.End()), `_ "unsafe"`) + } } } - if ws == 0 { - continue - } - d.Specs = d.Specs[0:ws] - ast2.Decls[w] = d - w++ } - ast2.Decls = ast2.Decls[0:w] // Accumulate pointers to uses of C.x. if f.Ref == nil { f.Ref = make([]*Ref, 0, 8) } - f.walk(ast2, "prog", (*File).saveExprs) + f.walk(ast2, ctxProg, (*File).saveExprs) // Accumulate exported functions. // The comments are only on ast1 but we need to @@ -133,8 +153,8 @@ func (f *File) ParseGo(name string, src []byte) { // The first walk fills in ExpFunc, and the // second walk changes the entries to // refer to ast2 instead. - f.walk(ast1, "prog", (*File).saveExport) - f.walk(ast2, "prog", (*File).saveExport2) + f.walk(ast1, ctxProg, (*File).saveExport) + f.walk(ast2, ctxProg, (*File).saveExport2) f.Comments = ast1.Comments f.AST = ast2 @@ -143,9 +163,6 @@ func (f *File) ParseGo(name string, src []byte) { // Like ast.CommentGroup's Text method but preserves // leading blank lines, so that line numbers line up. func commentText(g *ast.CommentGroup) string { - if g == nil { - return "" - } var pieces []string for _, com := range g.List { c := com.Text @@ -165,7 +182,7 @@ func commentText(g *ast.CommentGroup) string { } // Save various references we are going to need later. -func (f *File) saveExprs(x interface{}, context string) { +func (f *File) saveExprs(x interface{}, context astContext) { switch x := x.(type) { case *ast.Expr: switch (*x).(type) { @@ -178,7 +195,7 @@ func (f *File) saveExprs(x interface{}, context string) { } // Save references to C.xxx for later processing. -func (f *File) saveRef(n *ast.Expr, context string) { +func (f *File) saveRef(n *ast.Expr, context astContext) { sel := (*n).(*ast.SelectorExpr) // For now, assume that the only instance of capital C is when // used as the imported package identifier. @@ -188,10 +205,10 @@ func (f *File) saveRef(n *ast.Expr, context string) { if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" { return } - if context == "as2" { - context = "expr" + if context == ctxAssign2 { + context = ctxExpr } - if context == "embed-type" { + if context == ctxEmbedType { error_(sel.Pos(), "cannot embed C type") } goname := sel.Sel.Name @@ -212,6 +229,7 @@ func (f *File) saveRef(n *ast.Expr, context string) { Go: goname, } f.Name[goname] = name + f.NamePos[name] = sel.Pos() } f.Ref = append(f.Ref, &Ref{ Name: name, @@ -221,7 +239,7 @@ func (f *File) saveRef(n *ast.Expr, context string) { } // Save calls to C.xxx for later processing. -func (f *File) saveCall(call *ast.CallExpr, context string) { +func (f *File) saveCall(call *ast.CallExpr, context astContext) { sel, ok := call.Fun.(*ast.SelectorExpr) if !ok { return @@ -229,12 +247,12 @@ func (f *File) saveCall(call *ast.CallExpr, context string) { if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" { return } - c := &Call{Call: call, Deferred: context == "defer"} + c := &Call{Call: call, Deferred: context == ctxDefer} f.Calls = append(f.Calls, c) } // If a function should be exported add it to ExpFunc. -func (f *File) saveExport(x interface{}, context string) { +func (f *File) saveExport(x interface{}, context astContext) { n, ok := x.(*ast.FuncDecl) if !ok { return @@ -274,7 +292,7 @@ func (f *File) saveExport(x interface{}, context string) { } // Make f.ExpFunc[i] point at the Func from this AST instead of the other one. -func (f *File) saveExport2(x interface{}, context string) { +func (f *File) saveExport2(x interface{}, context astContext) { n, ok := x.(*ast.FuncDecl) if !ok { return @@ -288,8 +306,30 @@ func (f *File) saveExport2(x interface{}, context string) { } } +type astContext int + +const ( + ctxProg astContext = iota + ctxEmbedType + ctxType + ctxStmt + ctxExpr + ctxField + ctxParam + ctxAssign2 // assignment of a single expression to two variables + ctxSwitch + ctxTypeSwitch + ctxFile + ctxDecl + ctxSpec + ctxDefer + ctxCall // any function call other than ctxCall2 + ctxCall2 // function call whose result is assigned to two variables + ctxSelector +) + // walk walks the AST x, calling visit(f, x, context) for each node. -func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) { +func (f *File) walk(x interface{}, context astContext, visit func(*File, interface{}, astContext)) { visit(f, x, context) switch n := x.(type) { case *ast.Expr: @@ -304,10 +344,10 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} // These are ordered and grouped to match ../../go/ast/ast.go case *ast.Field: - if len(n.Names) == 0 && context == "field" { - f.walk(&n.Type, "embed-type", visit) + if len(n.Names) == 0 && context == ctxField { + f.walk(&n.Type, ctxEmbedType, visit) } else { - f.walk(&n.Type, "type", visit) + f.walk(&n.Type, ctxType, visit) } case *ast.FieldList: for _, field := range n.List { @@ -318,163 +358,163 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} case *ast.Ellipsis: case *ast.BasicLit: case *ast.FuncLit: - f.walk(n.Type, "type", visit) - f.walk(n.Body, "stmt", visit) + f.walk(n.Type, ctxType, visit) + f.walk(n.Body, ctxStmt, visit) case *ast.CompositeLit: - f.walk(&n.Type, "type", visit) - f.walk(n.Elts, "expr", visit) + f.walk(&n.Type, ctxType, visit) + f.walk(n.Elts, ctxExpr, visit) case *ast.ParenExpr: f.walk(&n.X, context, visit) case *ast.SelectorExpr: - f.walk(&n.X, "selector", visit) + f.walk(&n.X, ctxSelector, visit) case *ast.IndexExpr: - f.walk(&n.X, "expr", visit) - f.walk(&n.Index, "expr", visit) + f.walk(&n.X, ctxExpr, visit) + f.walk(&n.Index, ctxExpr, visit) case *ast.SliceExpr: - f.walk(&n.X, "expr", visit) + f.walk(&n.X, ctxExpr, visit) if n.Low != nil { - f.walk(&n.Low, "expr", visit) + f.walk(&n.Low, ctxExpr, visit) } if n.High != nil { - f.walk(&n.High, "expr", visit) + f.walk(&n.High, ctxExpr, visit) } if n.Max != nil { - f.walk(&n.Max, "expr", visit) + f.walk(&n.Max, ctxExpr, visit) } case *ast.TypeAssertExpr: - f.walk(&n.X, "expr", visit) - f.walk(&n.Type, "type", visit) + f.walk(&n.X, ctxExpr, visit) + f.walk(&n.Type, ctxType, visit) case *ast.CallExpr: - if context == "as2" { - f.walk(&n.Fun, "call2", visit) + if context == ctxAssign2 { + f.walk(&n.Fun, ctxCall2, visit) } else { - f.walk(&n.Fun, "call", visit) + f.walk(&n.Fun, ctxCall, visit) } - f.walk(n.Args, "expr", visit) + f.walk(n.Args, ctxExpr, visit) case *ast.StarExpr: f.walk(&n.X, context, visit) case *ast.UnaryExpr: - f.walk(&n.X, "expr", visit) + f.walk(&n.X, ctxExpr, visit) case *ast.BinaryExpr: - f.walk(&n.X, "expr", visit) - f.walk(&n.Y, "expr", visit) + f.walk(&n.X, ctxExpr, visit) + f.walk(&n.Y, ctxExpr, visit) case *ast.KeyValueExpr: - f.walk(&n.Key, "expr", visit) - f.walk(&n.Value, "expr", visit) + f.walk(&n.Key, ctxExpr, visit) + f.walk(&n.Value, ctxExpr, visit) case *ast.ArrayType: - f.walk(&n.Len, "expr", visit) - f.walk(&n.Elt, "type", visit) + f.walk(&n.Len, ctxExpr, visit) + f.walk(&n.Elt, ctxType, visit) case *ast.StructType: - f.walk(n.Fields, "field", visit) + f.walk(n.Fields, ctxField, visit) case *ast.FuncType: - f.walk(n.Params, "param", visit) + f.walk(n.Params, ctxParam, visit) if n.Results != nil { - f.walk(n.Results, "param", visit) + f.walk(n.Results, ctxParam, visit) } case *ast.InterfaceType: - f.walk(n.Methods, "field", visit) + f.walk(n.Methods, ctxField, visit) case *ast.MapType: - f.walk(&n.Key, "type", visit) - f.walk(&n.Value, "type", visit) + f.walk(&n.Key, ctxType, visit) + f.walk(&n.Value, ctxType, visit) case *ast.ChanType: - f.walk(&n.Value, "type", visit) + f.walk(&n.Value, ctxType, visit) case *ast.BadStmt: case *ast.DeclStmt: - f.walk(n.Decl, "decl", visit) + f.walk(n.Decl, ctxDecl, visit) case *ast.EmptyStmt: case *ast.LabeledStmt: - f.walk(n.Stmt, "stmt", visit) + f.walk(n.Stmt, ctxStmt, visit) case *ast.ExprStmt: - f.walk(&n.X, "expr", visit) + f.walk(&n.X, ctxExpr, visit) case *ast.SendStmt: - f.walk(&n.Chan, "expr", visit) - f.walk(&n.Value, "expr", visit) + f.walk(&n.Chan, ctxExpr, visit) + f.walk(&n.Value, ctxExpr, visit) case *ast.IncDecStmt: - f.walk(&n.X, "expr", visit) + f.walk(&n.X, ctxExpr, visit) case *ast.AssignStmt: - f.walk(n.Lhs, "expr", visit) + f.walk(n.Lhs, ctxExpr, visit) if len(n.Lhs) == 2 && len(n.Rhs) == 1 { - f.walk(n.Rhs, "as2", visit) + f.walk(n.Rhs, ctxAssign2, visit) } else { - f.walk(n.Rhs, "expr", visit) + f.walk(n.Rhs, ctxExpr, visit) } case *ast.GoStmt: - f.walk(n.Call, "expr", visit) + f.walk(n.Call, ctxExpr, visit) case *ast.DeferStmt: - f.walk(n.Call, "defer", visit) + f.walk(n.Call, ctxDefer, visit) case *ast.ReturnStmt: - f.walk(n.Results, "expr", visit) + f.walk(n.Results, ctxExpr, visit) case *ast.BranchStmt: case *ast.BlockStmt: f.walk(n.List, context, visit) case *ast.IfStmt: - f.walk(n.Init, "stmt", visit) - f.walk(&n.Cond, "expr", visit) - f.walk(n.Body, "stmt", visit) - f.walk(n.Else, "stmt", visit) + f.walk(n.Init, ctxStmt, visit) + f.walk(&n.Cond, ctxExpr, visit) + f.walk(n.Body, ctxStmt, visit) + f.walk(n.Else, ctxStmt, visit) case *ast.CaseClause: - if context == "typeswitch" { - context = "type" + if context == ctxTypeSwitch { + context = ctxType } else { - context = "expr" + context = ctxExpr } f.walk(n.List, context, visit) - f.walk(n.Body, "stmt", visit) + f.walk(n.Body, ctxStmt, visit) case *ast.SwitchStmt: - f.walk(n.Init, "stmt", visit) - f.walk(&n.Tag, "expr", visit) - f.walk(n.Body, "switch", visit) + f.walk(n.Init, ctxStmt, visit) + f.walk(&n.Tag, ctxExpr, visit) + f.walk(n.Body, ctxSwitch, visit) case *ast.TypeSwitchStmt: - f.walk(n.Init, "stmt", visit) - f.walk(n.Assign, "stmt", visit) - f.walk(n.Body, "typeswitch", visit) + f.walk(n.Init, ctxStmt, visit) + f.walk(n.Assign, ctxStmt, visit) + f.walk(n.Body, ctxTypeSwitch, visit) case *ast.CommClause: - f.walk(n.Comm, "stmt", visit) - f.walk(n.Body, "stmt", visit) + f.walk(n.Comm, ctxStmt, visit) + f.walk(n.Body, ctxStmt, visit) case *ast.SelectStmt: - f.walk(n.Body, "stmt", visit) + f.walk(n.Body, ctxStmt, visit) case *ast.ForStmt: - f.walk(n.Init, "stmt", visit) - f.walk(&n.Cond, "expr", visit) - f.walk(n.Post, "stmt", visit) - f.walk(n.Body, "stmt", visit) + f.walk(n.Init, ctxStmt, visit) + f.walk(&n.Cond, ctxExpr, visit) + f.walk(n.Post, ctxStmt, visit) + f.walk(n.Body, ctxStmt, visit) case *ast.RangeStmt: - f.walk(&n.Key, "expr", visit) - f.walk(&n.Value, "expr", visit) - f.walk(&n.X, "expr", visit) - f.walk(n.Body, "stmt", visit) + f.walk(&n.Key, ctxExpr, visit) + f.walk(&n.Value, ctxExpr, visit) + f.walk(&n.X, ctxExpr, visit) + f.walk(n.Body, ctxStmt, visit) case *ast.ImportSpec: case *ast.ValueSpec: - f.walk(&n.Type, "type", visit) + f.walk(&n.Type, ctxType, visit) if len(n.Names) == 2 && len(n.Values) == 1 { - f.walk(&n.Values[0], "as2", visit) + f.walk(&n.Values[0], ctxAssign2, visit) } else { - f.walk(n.Values, "expr", visit) + f.walk(n.Values, ctxExpr, visit) } case *ast.TypeSpec: - f.walk(&n.Type, "type", visit) + f.walk(&n.Type, ctxType, visit) case *ast.BadDecl: case *ast.GenDecl: - f.walk(n.Specs, "spec", visit) + f.walk(n.Specs, ctxSpec, visit) case *ast.FuncDecl: if n.Recv != nil { - f.walk(n.Recv, "param", visit) + f.walk(n.Recv, ctxParam, visit) } - f.walk(n.Type, "type", visit) + f.walk(n.Type, ctxType, visit) if n.Body != nil { - f.walk(n.Body, "stmt", visit) + f.walk(n.Body, ctxStmt, visit) } case *ast.File: - f.walk(n.Decls, "decl", visit) + f.walk(n.Decls, ctxDecl, visit) case *ast.Package: for _, file := range n.Files { - f.walk(file, "file", visit) + f.walk(file, ctxFile, visit) } case []ast.Decl: diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go index b2388829a87..c1bdf0659fa 100644 --- a/libgo/go/cmd/cgo/doc.go +++ b/libgo/go/cmd/cgo/doc.go @@ -102,11 +102,13 @@ the use of cgo, and to 0 to disable it. The go tool will set the build constraint "cgo" if cgo is enabled. When cross-compiling, you must specify a C cross-compiler for cgo to -use. You can do this by setting the CC_FOR_TARGET environment -variable when building the toolchain using make.bash, or by setting -the CC environment variable any time you run the go tool. The -CXX_FOR_TARGET and CXX environment variables work in a similar way for -C++ code. +use. You can do this by setting the generic CC_FOR_TARGET or the +more specific CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm) +environment variable when building the toolchain using make.bash, +or you can set the CC environment variable any time you run the go tool. + +The CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH}, and CXX +environment variables work in a similar way for C++ code. Go references to C @@ -126,12 +128,29 @@ C.complexfloat (complex float), and C.complexdouble (complex double). The C type void* is represented by Go's unsafe.Pointer. The C types __int128_t and __uint128_t are represented by [16]byte. +A few special C types which would normally be represented by a pointer +type in Go are instead represented by a uintptr. See the Special +cases section below. + To access a struct, union, or enum type directly, prefix it with struct_, union_, or enum_, as in C.struct_stat. The size of any C type T is available as C.sizeof_T, as in C.sizeof_struct_stat. +A C function may be declared in the Go file with a parameter type of +the special name _GoString_. This function may be called with an +ordinary Go string value. The string length, and a pointer to the +string contents, may be accessed by calling the C functions + + size_t _GoStringLen(_GoString_ s); + const char *_GoStringPtr(_GoString_ s); + +These functions are only available in the preamble, not in other C +files. The C code must not modify the contents of the pointer returned +by _GoStringPtr. Note that the string contents may not have a trailing +NUL byte. + As Go doesn't have support for C's union type in the general case, C's union types are represented as a Go byte array with the same length. @@ -241,7 +260,16 @@ They will be available in the C code as: found in the _cgo_export.h generated header, after any preambles copied from the cgo input files. Functions with multiple return values are mapped to functions returning a struct. + Not all Go types can be mapped to C types in a useful way. +Go struct types are not supported; use a C struct type. +Go array types are not supported; use a C pointer. + +Go functions that take arguments of type string may be called with the +C type _GoString_, described above. The _GoString_ type will be +automatically defined in the preamble. Note that there is no way for C +code to create a value of this type; this is only useful for passing +string values from Go to C and back to Go. Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not @@ -264,6 +292,14 @@ pointer is a Go pointer or a C pointer is a dynamic property determined by how the memory was allocated; it has nothing to do with the type of the pointer. +Note that values of some Go types, other than the type's zero value, +always include Go pointers. This is true of string, slice, interface, +channel, map, and function types. A pointer type may hold a Go pointer +or a C pointer. Array and struct types may or may not include Go +pointers, depending on the element types. All the discussion below +about Go pointers applies not just to pointer types, but also to other +types that include Go pointers. + Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers. The C code must preserve this property: it must not store any Go pointers in Go memory, even @@ -274,14 +310,17 @@ the Go memory in question is the entire array or the entire backing array of the slice. C code may not keep a copy of a Go pointer after the call returns. - -A Go function called by C code may not return a Go pointer. A Go -function called by C code may take C pointers as arguments, and it may -store non-pointer or C pointer data through those pointers, but it may -not store a Go pointer in memory pointed to by a C pointer. A Go -function called by C code may take a Go pointer as an argument, but it -must preserve the property that the Go memory to which it points does -not contain any Go pointers. +This includes the _GoString_ type, which, as noted above, includes a +Go pointer; _GoString_ values may not be retained by C code. + +A Go function called by C code may not return a Go pointer (which +implies that it may not return a string, slice, channel, and so +forth). A Go function called by C code may take C pointers as +arguments, and it may store non-pointer or C pointer data through +those pointers, but it may not store a Go pointer in memory pointed to +by a C pointer. A Go function called by C code may take a Go pointer +as an argument, but it must preserve the property that the Go memory +to which it points does not contain any Go pointers. Go code may not store a Go pointer in C memory. C code may store Go pointers in C memory, subject to the rule above: it must stop storing @@ -299,6 +338,84 @@ and of course there is nothing stopping the C code from doing anything it likes. However, programs that break these rules are likely to fail in unexpected and unpredictable ways. +Special cases + +A few special C types which would normally be represented by a pointer +type in Go are instead represented by a uintptr. Those types are +the CF*Ref types from the CoreFoundation library on Darwin, including: + + CFAllocatorRef + CFArrayRef + CFAttributedStringRef + CFBagRef + CFBinaryHeapRef + CFBitVectorRef + CFBooleanRef + CFBundleRef + CFCalendarRef + CFCharacterSetRef + CFDataRef + CFDateFormatterRef + CFDateRef + CFDictionaryRef + CFErrorRef + CFFileDescriptorRef + CFFileSecurityRef + CFLocaleRef + CFMachPortRef + CFMessagePortRef + CFMutableArrayRef + CFMutableAttributedStringRef + CFMutableBagRef + CFMutableBitVectorRef + CFMutableCharacterSetRef + CFMutableDataRef + CFMutableDictionaryRef + CFMutableSetRef + CFMutableStringRef + CFNotificationCenterRef + CFNullRef + CFNumberFormatterRef + CFNumberRef + CFPlugInInstanceRef + CFPlugInRef + CFPropertyListRef + CFReadStreamRef + CFRunLoopObserverRef + CFRunLoopRef + CFRunLoopSourceRef + CFRunLoopTimerRef + CFSetRef + CFSocketRef + CFStringRef + CFStringTokenizerRef + CFTimeZoneRef + CFTreeRef + CFTypeRef + CFURLCreateFromFSRef + CFURLEnumeratorRef + CFURLGetFSRef + CFURLRef + CFUUIDRef + CFUserNotificationRef + CFWriteStreamRef + CFXMLNodeRef + CFXMLParserRef + CFXMLTreeRef + +These types are uintptr on the Go side because they would otherwise +confuse the Go garbage collector; they are sometimes not really +pointers but data structures encoded in a pointer type. All operations +on these types must happen in C. The proper constant to initialize an +empty such reference is 0, not nil. + +This special case was introduced in Go 1.10. For auto-updating code +from Go 1.9 and earlier, use the cftype rewrite in the Go fix tool: + + go tool fix -r cftype + +It will replace nil with 0 in the appropriate places. + Using cgo directly Usage: @@ -312,32 +429,35 @@ invoking the C compiler to compile the C parts of the package. The following options are available when running cgo directly: + -V + Print cgo version and exit. + -debug-define + Debugging option. Print #defines. + -debug-gcc + Debugging option. Trace C compiler execution and output. -dynimport file Write list of symbols imported by file. Write to -dynout argument or to standard output. Used by go build when building a cgo package. + -dynlinker + Write dynamic linker as part of -dynimport output. -dynout file Write -dynimport output to file. -dynpackage package Set Go package for -dynimport output. - -dynlinker - Write dynamic linker as part of -dynimport output. - -godefs - Write out input file in Go syntax replacing C package - names with real values. Used to generate files in the - syscall package when bootstrapping a new target. - -srcdir directory - Find the Go input files, listed on the command line, - in directory. - -objdir directory - Put all generated files in directory. - -importpath string - The import path for the Go package. Optional; used for - nicer comments in the generated files. -exportheader file If there are any exported functions, write the generated export declarations to file. C code can #include this to see the declarations. + -importpath string + The import path for the Go package. Optional; used for + nicer comments in the generated files. + -import_runtime_cgo + If set (which it is by default) import runtime/cgo in + generated output. + -import_syscall + If set (which it is by default) import syscall in + generated output. -gccgo Generate output for the gccgo compiler rather than the gc compiler. @@ -345,16 +465,13 @@ The following options are available when running cgo directly: The -fgo-prefix option to be used with gccgo. -gccgopkgpath path The -fgo-pkgpath option to be used with gccgo. - -import_runtime_cgo - If set (which it is by default) import runtime/cgo in - generated output. - -import_syscall - If set (which it is by default) import syscall in - generated output. - -debug-define - Debugging option. Print #defines. - -debug-gcc - Debugging option. Trace C compiler execution and output. + -godefs + Write out input file in Go syntax replacing C package + names with real values. Used to generate files in the + syscall package when bootstrapping a new target. + -objdir directory + Put all generated files in directory. + -srcdir directory */ package main @@ -403,21 +520,19 @@ about simple #defines for constants and the like. These are recorded for later use. Next, cgo needs to identify the kinds for each identifier. For the -identifiers C.foo and C.bar, cgo generates this C program: +identifiers C.foo, cgo generates this C program: #line 1 "not-declared" - void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; } + void __cgo_f_1_1(void) { __typeof__(foo) *__cgo_undefined__1; } #line 1 "not-type" - void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; } - #line 1 "not-const" - void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; } - #line 2 "not-declared" - void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; } - #line 2 "not-type" - void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; } - #line 2 "not-const" - void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; } + void __cgo_f_1_2(void) { foo *__cgo_undefined__2; } + #line 1 "not-int-const" + void __cgo_f_1_3(void) { enum { __cgo_undefined__3 = (foo)*1 }; } + #line 1 "not-num-const" + void __cgo_f_1_4(void) { static const double __cgo_undefined__4 = (foo); } + #line 1 "not-str-lit" + void __cgo_f_1_5(void) { static const char __cgo_undefined__5[] = (foo); } This program will not compile, but cgo can use the presence or absence of an error message on a given line to deduce the information it @@ -427,45 +542,72 @@ errors that might stop parsing early. An error on not-declared:1 indicates that foo is undeclared. An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier). -An error on not-const:1 indicates that foo is not an integer constant. +An error on not-int-const:1 indicates that foo is not an integer constant. +An error on not-num-const:1 indicates that foo is not a number constant. +An error on not-str-lit:1 indicates that foo is not a string literal. +An error on not-signed-int-const:1 indicates that foo is not a signed integer constant. -The line number specifies the name involved. In the example, 1 is foo and 2 is bar. +The line number specifies the name involved. In the example, 1 is foo. Next, cgo must learn the details of each type, variable, function, or constant. It can do this by reading object files. If cgo has decided -that t1 is a type, v2 and v3 are variables or functions, and c4, c5, -and c6 are constants, it generates: +that t1 is a type, v2 and v3 are variables or functions, and i4, i5 +are integer constants, u6 is an unsigned integer constant, and f7 and f8 +are float constants, and s9 and s10 are string constants, it generates: __typeof__(t1) *__cgo__1; __typeof__(v2) *__cgo__2; __typeof__(v3) *__cgo__3; - __typeof__(c4) *__cgo__4; - enum { __cgo_enum__4 = c4 }; - __typeof__(c5) *__cgo__5; - enum { __cgo_enum__5 = c5 }; - __typeof__(c6) *__cgo__6; - enum { __cgo_enum__6 = c6 }; - - long long __cgo_debug_data[] = { + __typeof__(i4) *__cgo__4; + enum { __cgo_enum__4 = i4 }; + __typeof__(i5) *__cgo__5; + enum { __cgo_enum__5 = i5 }; + __typeof__(u6) *__cgo__6; + enum { __cgo_enum__6 = u6 }; + __typeof__(f7) *__cgo__7; + __typeof__(f8) *__cgo__8; + __typeof__(s9) *__cgo__9; + __typeof__(s10) *__cgo__10; + + long long __cgodebug_ints[] = { 0, // t1 0, // v2 0, // v3 - c4, - c5, - c6, + i4, + i5, + u6, + 0, // f7 + 0, // f8 + 0, // s9 + 0, // s10 1 }; + double __cgodebug_floats[] = { + 0, // t1 + 0, // v2 + 0, // v3 + 0, // i4 + 0, // i5 + 0, // u6 + f7, + f8, + 0, // s9 + 0, // s10 + 1 + }; + + const char __cgodebug_str__9[] = s9; + const unsigned long long __cgodebug_strlen__9 = sizeof(s9)-1; + const char __cgodebug_str__10[] = s10; + const unsigned long long __cgodebug_strlen__10 = sizeof(s10)-1; + and again invokes the system C compiler, to produce an object file containing debug information. Cgo parses the DWARF debug information for __cgo__N to learn the type of each identifier. (The types also -distinguish functions from global variables.) If using a standard gcc, -cgo can parse the DWARF debug information for the __cgo_enum__N to -learn the identifier's value. The LLVM-based gcc on OS X emits -incomplete DWARF information for enums; in that case cgo reads the -constant values from the __cgo_debug_data from the object file's data -segment. +distinguish functions from global variables.) Cgo reads the constant +values from the __cgodebug_* from the object file's data segment. At this point cgo knows the meaning of each C.xxx well enough to start the translation process. @@ -550,9 +692,12 @@ _cgo_main.c: int main() { return 0; } void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { } - uintptr_t _cgo_wait_runtime_init_done() { } + uintptr_t _cgo_wait_runtime_init_done() { return 0; } + void _cgo_release_context(uintptr_t ctxt) { } + char* _cgo_topofstack(void) { return (char*)0; } void _cgo_allocate(void *a, int c) { } void _cgo_panic(void *a, int c) { } + void _cgo_reginit(void) { } The extra functions here are stubs to satisfy the references in the C code generated for gcc. The build process links this stub, along with diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index 5453d1c94d0..f3bb528b4d5 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -188,21 +188,8 @@ func (p *Package) Translate(f *File) { p.loadDWARF(f, needType) } if p.rewriteCalls(f) { - // Add `import _cgo_unsafe "unsafe"` as the first decl - // after the package statement. - imp := &ast.GenDecl{ - Tok: token.IMPORT, - Specs: []ast.Spec{ - &ast.ImportSpec{ - Name: ast.NewIdent("_cgo_unsafe"), - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: `"unsafe"`, - }, - }, - }, - } - f.AST.Decls = append([]ast.Decl{imp}, f.AST.Decls...) + // Add `import _cgo_unsafe "unsafe"` after the package statement. + f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"") } p.rewriteRef(f) } @@ -211,8 +198,8 @@ func (p *Package) Translate(f *File) { // in the file f and saves relevant renamings in f.Name[name].Define. func (p *Package) loadDefines(f *File) { var b bytes.Buffer - b.WriteString(f.Preamble) b.WriteString(builtinProlog) + b.WriteString(f.Preamble) stdout := p.gccDefines(b.Bytes()) for _, line := range strings.Split(stdout, "\n") { @@ -283,10 +270,6 @@ func (p *Package) guessKinds(f *File) []*Name { if n.IsConst() { continue } - - if isName(n.Define) { - n.C = n.Define - } } // If this is a struct, union, or enum type name, no need to guess the kind. @@ -315,57 +298,45 @@ func (p *Package) guessKinds(f *File) []*Name { // For each name, we generate these lines, where xxx is the index in toSniff plus one. // // #line xxx "not-declared" - // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; } + // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__1; } // #line xxx "not-type" - // void __cgo_f_xxx_2(void) { name *__cgo_undefined__; } + // void __cgo_f_xxx_2(void) { name *__cgo_undefined__2; } // #line xxx "not-int-const" - // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; } + // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__3 = (name)*1 }; } // #line xxx "not-num-const" - // void __cgo_f_xxx_4(void) { static const double x = (name); } + // void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); } // #line xxx "not-str-lit" - // void __cgo_f_xxx_5(void) { static const char x[] = (name); } - // #line xxx "not-signed-int-const" - // #if 0 < -(name) - // #line xxx "not-signed-int-const" - // #error found unsigned int - // #endif + // void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); } // // If we see an error at not-declared:xxx, the corresponding name is not declared. // If we see an error at not-type:xxx, the corresponding name is a type. // If we see an error at not-int-const:xxx, the corresponding name is not an integer constant. // If we see an error at not-num-const:xxx, the corresponding name is not a number constant. // If we see an error at not-str-lit:xxx, the corresponding name is not a string literal. - // If we see an error at not-signed-int-const:xxx, the corresponding name is not a signed integer literal. // // The specific input forms are chosen so that they are valid C syntax regardless of // whether name denotes a type or an expression. var b bytes.Buffer - b.WriteString(f.Preamble) b.WriteString(builtinProlog) + b.WriteString(f.Preamble) for i, n := range names { fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+ - "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+ + "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+ "#line %d \"not-type\"\n"+ - "void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+ + "void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+ "#line %d \"not-int-const\"\n"+ - "void __cgo_f_%d_3(void) { enum { __cgo_undefined__ = (%s)*1 }; }\n"+ + "void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+ "#line %d \"not-num-const\"\n"+ - "void __cgo_f_%d_4(void) { static const double x = (%s); }\n"+ + "void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+ "#line %d \"not-str-lit\"\n"+ - "void __cgo_f_%d_5(void) { static const char s[] = (%s); }\n"+ - "#line %d \"not-signed-int-const\"\n"+ - "#if 0 < (%s)\n"+ - "#line %d \"not-signed-int-const\"\n"+ - "#error found unsigned int\n"+ - "#endif\n", + "void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n", i+1, i+1, n.C, i+1, i+1, n.C, i+1, i+1, n.C, i+1, i+1, n.C, i+1, i+1, n.C, - i+1, n.C, i+1, ) } fmt.Fprintf(&b, "#line 1 \"completed\"\n"+ @@ -384,7 +355,6 @@ func (p *Package) guessKinds(f *File) []*Name { notNumConst notStrLiteral notDeclared - notSignedIntConst ) sawUnmatchedErrors := false for _, line := range strings.Split(stderr, "\n") { @@ -438,8 +408,6 @@ func (p *Package) guessKinds(f *File) []*Name { sniff[i] |= notNumConst case "not-str-lit": sniff[i] |= notStrLiteral - case "not-signed-int-const": - sniff[i] |= notSignedIntConst default: if isError { sawUnmatchedErrors = true @@ -455,22 +423,11 @@ func (p *Package) guessKinds(f *File) []*Name { } for i, n := range names { - switch sniff[i] &^ notSignedIntConst { + switch sniff[i] { default: - var tpos token.Pos - for _, ref := range f.Ref { - if ref.Name == n { - tpos = ref.Pos() - break - } - } - error_(tpos, "could not determine kind of name for C.%s", fixGo(n.Go)) + error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go)) case notStrLiteral | notType: - if sniff[i]¬SignedIntConst != 0 { - n.Kind = "uconst" - } else { - n.Kind = "iconst" - } + n.Kind = "iconst" case notIntConst | notStrLiteral | notType: n.Kind = "fconst" case notIntConst | notNumConst | notType: @@ -510,12 +467,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) { // for each entry in names and then dereference the type we // learn for __cgo__i. var b bytes.Buffer - b.WriteString(f.Preamble) b.WriteString(builtinProlog) + b.WriteString(f.Preamble) b.WriteString("#line 1 \"cgo-dwarf-inference\"\n") for i, n := range names { fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i) - if n.Kind == "iconst" || n.Kind == "uconst" { + if n.Kind == "iconst" { fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) } } @@ -524,7 +481,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) { // so we can read them out of the object file. fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n") for _, n := range names { - if n.Kind == "iconst" || n.Kind == "uconst" { + if n.Kind == "iconst" { fmt.Fprintf(&b, "\t%s,\n", n.C) } else { fmt.Fprintf(&b, "\t0,\n") @@ -562,14 +519,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) { // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. types := make([]dwarf.Type, len(names)) - nameToIndex := make(map[*Name]int) - for i, n := range names { - nameToIndex[n] = i - } - nameToRef := make(map[*Name]*Ref) - for _, ref := range f.Ref { - nameToRef[ref.Name] = ref - } r := d.Reader() for { e, err := r.Next() @@ -620,10 +569,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) { if types[i] == nil { continue } - pos := token.NoPos - if ref, ok := nameToRef[n]; ok { - pos = ref.Pos() - } + pos := f.NamePos[n] f, fok := types[i].(*dwarf.FuncType) if n.Kind != "type" && fok { n.Kind = "func" @@ -633,11 +579,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) { switch n.Kind { case "iconst": if i < len(ints) { - n.Const = fmt.Sprintf("%#x", ints[i]) - } - case "uconst": - if i < len(ints) { - n.Const = fmt.Sprintf("%#x", uint64(ints[i])) + if _, ok := types[i].(*dwarf.UintType); ok { + n.Const = fmt.Sprintf("%#x", uint64(ints[i])) + } else { + n.Const = fmt.Sprintf("%#x", ints[i]) + } } case "fconst": if i < len(floats) { @@ -778,8 +724,9 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool { stmts = append(stmts, stmt) } + const cgoMarker = "__cgo__###__marker__" fcall := &ast.CallExpr{ - Fun: call.Call.Fun, + Fun: ast.NewIdent(cgoMarker), Args: nargs, } ftype := &ast.FuncType{ @@ -801,31 +748,26 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool { } } - // There is a Ref pointing to the old call.Call.Fun. + // If this call expects two results, we have to + // adjust the results of the function we generated. for _, ref := range f.Ref { - if ref.Expr == &call.Call.Fun { - ref.Expr = &fcall.Fun - - // If this call expects two results, we have to - // adjust the results of the function we generated. - if ref.Context == "call2" { - if ftype.Results == nil { - // An explicit void argument - // looks odd but it seems to - // be how cgo has worked historically. - ftype.Results = &ast.FieldList{ - List: []*ast.Field{ - &ast.Field{ - Type: ast.NewIdent("_Ctype_void"), - }, + if ref.Expr == &call.Call.Fun && ref.Context == ctxCall2 { + if ftype.Results == nil { + // An explicit void argument + // looks odd but it seems to + // be how cgo has worked historically. + ftype.Results = &ast.FieldList{ + List: []*ast.Field{ + &ast.Field{ + Type: ast.NewIdent("_Ctype_void"), }, - } + }, } - ftype.Results.List = append(ftype.Results.List, - &ast.Field{ - Type: ast.NewIdent("error"), - }) } + ftype.Results.List = append(ftype.Results.List, + &ast.Field{ + Type: ast.NewIdent("error"), + }) } } @@ -839,14 +781,16 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool { Results: []ast.Expr{fcall}, } } - call.Call.Fun = &ast.FuncLit{ + lit := &ast.FuncLit{ Type: ftype, Body: &ast.BlockStmt{ List: append(stmts, fbody), }, } - call.Call.Lparen = token.NoPos - call.Call.Rparen = token.NoPos + text := strings.Replace(gofmt(lit), "\n", ";", -1) + repl := strings.Split(text, cgoMarker) + f.Edit.Insert(f.offset(call.Call.Fun.Pos()), repl[0]) + f.Edit.Insert(f.offset(call.Call.Fun.End()), repl[1]) return needsUnsafe } @@ -1000,8 +944,8 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr // effect is a function call. func (p *Package) hasSideEffects(f *File, x ast.Expr) bool { found := false - f.walk(x, "expr", - func(f *File, x interface{}, context string) { + f.walk(x, ctxExpr, + func(f *File, x interface{}, context astContext) { switch x.(type) { case *ast.CallExpr: found = true @@ -1110,7 +1054,17 @@ func (p *Package) rewriteRef(f *File) { // Assign mangled names. for _, n := range f.Name { if n.Kind == "not-type" { - n.Kind = "var" + if n.Define == "" { + n.Kind = "var" + } else { + n.Kind = "macro" + n.FuncType = &FuncType{ + Result: n.Type, + Go: &ast.FuncType{ + Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}}, + }, + } + } } if n.Mangle == "" { p.mangleName(n) @@ -1130,10 +1084,10 @@ func (p *Package) rewriteRef(f *File) { } var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default switch r.Context { - case "call", "call2": + case ctxCall, ctxCall2: if r.Name.Kind != "func" { if r.Name.Kind == "type" { - r.Context = "type" + r.Context = ctxType if r.Name.Type == nil { error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) break @@ -1145,7 +1099,7 @@ func (p *Package) rewriteRef(f *File) { break } functions[r.Name.Go] = true - if r.Context == "call2" { + if r.Context == ctxCall2 { if r.Name.Go == "_CMalloc" { error_(r.Pos(), "no two-result form for C.malloc") break @@ -1163,8 +1117,9 @@ func (p *Package) rewriteRef(f *File) { r.Name = n break } - case "expr": - if r.Name.Kind == "func" { + case ctxExpr: + switch r.Name.Kind { + case "func": if builtinDefs[r.Name.C] != "" { error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C)) } @@ -1191,25 +1146,25 @@ func (p *Package) rewriteRef(f *File) { Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, Args: []ast.Expr{ast.NewIdent(name.Mangle)}, } - } else if r.Name.Kind == "type" { + case "type": // Okay - might be new(T) if r.Name.Type == nil { error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) break } expr = r.Name.Type.Go - } else if r.Name.Kind == "var" { + case "var": expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} + case "macro": + expr = &ast.CallExpr{Fun: expr} } - - case "selector": + case ctxSelector: if r.Name.Kind == "var" { expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} } else { error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go)) } - - case "type": + case ctxType: if r.Name.Kind != "type" { error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) } else if r.Name.Type == nil { @@ -1224,6 +1179,7 @@ func (p *Package) rewriteRef(f *File) { error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) } } + if *godefs { // Substitute definition for mangled type name. if id, ok := expr.(*ast.Ident); ok { @@ -1245,7 +1201,17 @@ func (p *Package) rewriteRef(f *File) { expr = &ast.Ident{NamePos: pos, Name: x.Name} } + // Change AST, because some later processing depends on it, + // and also because -godefs mode still prints the AST. + old := *r.Expr *r.Expr = expr + + // Record source-level edit for cgo output. + repl := gofmt(expr) + if r.Name.Kind != "type" { + repl = "(" + repl + ")" + } + f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl) } // Remove functions only used as expressions, so their respective @@ -1270,7 +1236,7 @@ func (p *Package) gccBaseCmd() []string { if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { return ret } - return strings.Fields(defaultCC) + return strings.Fields(defaultCC(goos, goarch)) } // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". @@ -2186,6 +2152,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { name := c.Ident("_Ctype_" + dt.Name) goIdent[name.Name] = name sub := c.Type(dt.Type, pos) + if badPointerTypedef(dt.Name) { + // Treat this typedef as a uintptr. + s := *sub + s.Go = c.uintptr + sub = &s + } t.Go = name if unionWithPointer[sub.Go] { unionWithPointer[t.Go] = true @@ -2266,7 +2238,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { if ss, ok := dwarfToName[s]; ok { s = ss } - s = strings.Join(strings.Split(s, " "), "") // strip spaces + s = strings.Replace(s, " ", "", -1) name := c.Ident("_Ctype_" + s) tt := *t typedef[name.Name] = &tt @@ -2344,6 +2316,17 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { if _, void := base(ptr.Type).(*dwarf.VoidType); void { break } + // ...or the typedef is one in which we expect bad pointers. + // It will be a uintptr instead of *X. + if badPointerTypedef(dt.Name) { + break + } + + // If we already know the typedef for t just use that. + // See issue 19832. + if def := typedef[t.Go.(*ast.Ident).Name]; def != nil { + break + } t = c.Type(ptr, pos) if t == nil { @@ -2500,7 +2483,9 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct size := t.Size talign := t.Align if f.BitSize > 0 { - if f.BitSize%8 != 0 { + switch f.BitSize { + case 8, 16, 32, 64: + default: continue } size = f.BitSize / 8 @@ -2676,3 +2661,51 @@ func fieldPrefix(fld []*ast.Field) string { } return prefix } + +// badPointerTypedef reports whether t is a C typedef that should not be considered a pointer in Go. +// A typedef is bad if C code sometimes stores non-pointers in this type. +// TODO: Currently our best solution is to find these manually and list them as +// they come up. A better solution is desired. +func badPointerTypedef(t string) bool { + // The real bad types are CFNumberRef and CFTypeRef. + // Sometimes non-pointers are stored in these types. + // CFTypeRef is a supertype of those, so it can have bad pointers in it as well. + // We return true for the other CF*Ref types just so casting between them is easier. + // See comment below for details about the bad pointers. + return goos == "darwin" && strings.HasPrefix(t, "CF") && strings.HasSuffix(t, "Ref") +} + +// Comment from Darwin's CFInternal.h +/* +// Tagged pointer support +// Low-bit set means tagged object, next 3 bits (currently) +// define the tagged object class, next 4 bits are for type +// information for the specific tagged object class. Thus, +// the low byte is for type info, and the rest of a pointer +// (32 or 64-bit) is for payload, whatever the tagged class. +// +// Note that the specific integers used to identify the +// specific tagged classes can and will change from release +// to release (that's why this stuff is in CF*Internal*.h), +// as can the definition of type info vs payload above. +// +#if __LP64__ +#define CF_IS_TAGGED_OBJ(PTR) ((uintptr_t)(PTR) & 0x1) +#define CF_TAGGED_OBJ_TYPE(PTR) ((uintptr_t)(PTR) & 0xF) +#else +#define CF_IS_TAGGED_OBJ(PTR) 0 +#define CF_TAGGED_OBJ_TYPE(PTR) 0 +#endif + +enum { + kCFTaggedObjectID_Invalid = 0, + kCFTaggedObjectID_Atom = (0 << 1) + 1, + kCFTaggedObjectID_Undefined3 = (1 << 1) + 1, + kCFTaggedObjectID_Undefined2 = (2 << 1) + 1, + kCFTaggedObjectID_Integer = (3 << 1) + 1, + kCFTaggedObjectID_DateTS = (4 << 1) + 1, + kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data + kCFTaggedObjectID_Date = (6 << 1) + 1, + kCFTaggedObjectID_Undefined7 = (7 << 1) + 1, +}; +*/ diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index c9a44fdd166..7e522a35f99 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -24,6 +24,9 @@ import ( "runtime" "sort" "strings" + + "cmd/internal/edit" + "cmd/internal/objabi" ) // A Package collects information about the package we're going to write. @@ -54,6 +57,12 @@ type File struct { Calls []*Call // all calls to C.xxx in AST ExpFunc []*ExpFunc // exported functions for this file Name map[string]*Name // map from Go name to Name + NamePos map[*Name]token.Pos // map from Name to position of the first reference + Edit *edit.Buffer +} + +func (f *File) offset(p token.Pos) int { + return fset.Position(p).Offset } func nameKeys(m map[string]*Name) []string { @@ -75,7 +84,7 @@ type Call struct { type Ref struct { Name *Name Expr *ast.Expr - Context string // "type", "expr", "call", or "call2" + Context astContext } func (r *Ref) Pos() token.Pos { @@ -88,7 +97,7 @@ type Name struct { Mangle string // name used in generated Go C string // name used in C Define string // #define expansion - Kind string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type" + Kind string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type" Type *Type // the type of xxx FuncType *FuncType AddError bool @@ -100,12 +109,12 @@ func (n *Name) IsVar() bool { return n.Kind == "var" || n.Kind == "fpvar" } -// IsConst reports whether Kind is either "iconst", "uconst", "fconst" or "sconst" +// IsConst reports whether Kind is either "iconst", "fconst" or "sconst" func (n *Name) IsConst() bool { return strings.HasSuffix(n.Kind, "const") } -// A ExpFunc is an exported function, callable from C. +// An ExpFunc is an exported function, callable from C. // Such functions are identified in the Go input file // by doc comments containing the line //export ExpName type ExpFunc struct { @@ -214,6 +223,7 @@ var importSyscall = flag.Bool("import_syscall", true, "import syscall in generat var goarch, goos string func main() { + objabi.AddVersionFlag() // -V flag.Usage = usage flag.Parse() @@ -294,6 +304,7 @@ func main() { } f := new(File) + f.Edit = edit.NewBuffer(b) f.ParseGo(input, b) f.DiscardCgoDirectives() fs[i] = f @@ -314,11 +325,13 @@ func main() { p.Translate(f) for _, cref := range f.Ref { switch cref.Context { - case "call", "call2": + case ctxCall, ctxCall2: if cref.Name.Kind != "type" { break } + old := *cref.Expr *cref.Expr = cref.Name.Type.Go + f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), gofmt(cref.Name.Type.Go)) } } if nerrors > 0 { diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go index 72dd884aedb..81eff779a80 100644 --- a/libgo/go/cmd/cgo/out.go +++ b/libgo/go/cmd/cgo/out.go @@ -16,6 +16,7 @@ import ( "go/token" "io" "os" + "path/filepath" "sort" "strings" ) @@ -116,7 +117,13 @@ func (p *Package) writeDefs() { // Which is not useful. Moreover we never override source info, // so subsequent source code uses the same source info. // Moreover, empty file name makes compile emit no source debug info at all. - noSourceConf.Fprint(fgo2, fset, def.Go) + var buf bytes.Buffer + noSourceConf.Fprint(&buf, fset, def.Go) + if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) { + // This typedef is of the form `typedef a b` and should be an alias. + fmt.Fprintf(fgo2, "= ") + } + fmt.Fprintf(fgo2, "%s", buf.Bytes()) fmt.Fprintf(fgo2, "\n\n") } if *gccgo { @@ -424,10 +431,12 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { inProlog := builtinDefs[name] != "" cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) paramnames := []string(nil) - for i, param := range d.Type.Params.List { - paramName := fmt.Sprintf("p%d", i) - param.Names = []*ast.Ident{ast.NewIdent(paramName)} - paramnames = append(paramnames, paramName) + if d.Type.Params != nil { + for i, param := range d.Type.Params.List { + paramName := fmt.Sprintf("p%d", i) + param.Names = []*ast.Ident{ast.NewIdent(paramName)} + paramnames = append(paramnames, paramName) + } } if *gccgo { @@ -526,8 +535,10 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") } fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n") - for i := range d.Type.Params.List { - fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) + if d.Type.Params != nil { + for i := range d.Type.Params.List { + fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) + } } fmt.Fprintf(fgo2, "\t}\n") fmt.Fprintf(fgo2, "\treturn\n") @@ -540,7 +551,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { if strings.HasSuffix(base, ".go") { base = base[0 : len(base)-3] } - base = strings.Map(slashToUnderscore, base) + base = filepath.Base(base) fgo1 := creat(*objDir + base + ".cgo1.go") fgcc := creat(*objDir + base + ".cgo2.c") @@ -549,10 +560,12 @@ func (p *Package) writeOutput(f *File, srcfile string) { // Write Go output: Go input with rewrites of C.xxx to _C_xxx. fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") - conf.Fprint(fgo1, fset, f.AST) + fmt.Fprintf(fgo1, "//line %s:1\n", srcfile) + fgo1.Write(f.Edit.Bytes()) // While we process the vars and funcs, also write gcc output. // Gcc output starts with the preamble. + fmt.Fprintf(fgcc, "%s\n", builtinProlog) fmt.Fprintf(fgcc, "%s\n", f.Preamble) fmt.Fprintf(fgcc, "%s\n", gccProlog) fmt.Fprintf(fgcc, "%s\n", tsanProlog) @@ -639,14 +652,18 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprint(fgcc, "(__typeof__(a->r)) ") } } - fmt.Fprintf(fgcc, "%s(", n.C) - for i := range n.FuncType.Params { - if i > 0 { - fmt.Fprintf(fgcc, ", ") + if n.Kind == "macro" { + fmt.Fprintf(fgcc, "%s;\n", n.C) + } else { + fmt.Fprintf(fgcc, "%s(", n.C) + for i := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + fmt.Fprintf(fgcc, "a->p%d", i) } - fmt.Fprintf(fgcc, "a->p%d", i) + fmt.Fprintf(fgcc, ");\n") } - fmt.Fprintf(fgcc, ");\n") if n.AddError { fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n") } @@ -702,14 +719,18 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "(void*)") } } - fmt.Fprintf(fgcc, "%s(", n.C) - for i := range n.FuncType.Params { - if i > 0 { - fmt.Fprintf(fgcc, ", ") + if n.Kind == "macro" { + fmt.Fprintf(fgcc, "%s;\n", n.C) + } else { + fmt.Fprintf(fgcc, "%s(", n.C) + for i := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + fmt.Fprintf(fgcc, "p%d", i) } - fmt.Fprintf(fgcc, "p%d", i) + fmt.Fprintf(fgcc, ");\n") } - fmt.Fprintf(fgcc, ");\n") fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n") if t := n.FuncType.Result; t != nil { fmt.Fprintf(fgcc, "\treturn ") @@ -1009,7 +1030,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { default: // Declare a result struct. fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) - fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName) + fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName) forFieldList(fntype.Results, func(i int, aname string, atype ast.Expr) { t := p.cgoType(atype) @@ -1020,7 +1041,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprint(fgcch, "\n") }) fmt.Fprintf(fgcch, "};\n") - fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName) + fmt.Fprintf(cdeclBuf, "struct %s_return", exp.ExpName) } cRet := cdeclBuf.String() @@ -1046,7 +1067,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcch, "\n%s", exp.Doc) } - fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams) + fmt.Fprintf(fgcch, "extern %s %s%s;\n", cRet, exp.ExpName, cParams) // We need to use a name that will be exported by the // Go code; otherwise gccgo will make it static and we @@ -1155,6 +1176,7 @@ func (p *Package) writeExportHeader(fgcch io.Writer) { pkg = p.PackagePath } fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg) + fmt.Fprintf(fgcch, "%s\n", builtinExportProlog) fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n") fmt.Fprintf(fgcch, "%s\n", p.Preamble) @@ -1247,8 +1269,9 @@ func (p *Package) cgoType(e ast.Expr) *Type { // Slice: pointer, len, cap. return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")} } + // Non-slice array types are not supported. case *ast.StructType: - // TODO + // Not supported. case *ast.FuncType: return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} case *ast.InterfaceType: @@ -1398,7 +1421,7 @@ const builtinProlog = ` /* Define intgo when compiling with GCC. */ typedef ptrdiff_t intgo; -typedef struct { char *p; intgo n; } _GoString_; +typedef struct { const char *p; intgo n; } _GoString_; typedef struct { char *p; intgo n; intgo c; } _GoBytes_; _GoString_ GoString(char *p); _GoString_ GoStringN(char *p, int l); @@ -1406,6 +1429,12 @@ _GoBytes_ GoBytes(void *p, int n); char *CString(_GoString_); void *CBytes(_GoBytes_); void *_CMalloc(size_t); + +__attribute__ ((unused)) +static size_t _GoStringLen(_GoString_ s) { return s.n; } + +__attribute__ ((unused)) +static const char *_GoStringPtr(_GoString_ s) { return s.p; } ` const goProlog = ` @@ -1637,6 +1666,27 @@ void localCgoCheckResult(Eface val) { } ` +// builtinExportProlog is a shorter version of builtinProlog, +// to be put into the _cgo_export.h file. +// For historical reasons we can't use builtinProlog in _cgo_export.h, +// because _cgo_export.h defines GoString as a struct while builtinProlog +// defines it as a function. We don't change this to avoid unnecessarily +// breaking existing code. +const builtinExportProlog = ` +#line 1 "cgo-builtin-prolog" + +#include /* for ptrdiff_t below */ + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +typedef ptrdiff_t intgo; + +typedef struct { const char *p; intgo n; } _GoString_; + +#endif +` + func (p *Package) gccExportHeaderProlog() string { return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1) } @@ -1670,7 +1720,7 @@ typedef double _Complex GoComplex128; */ typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1]; -typedef struct { const char *p; GoInt n; } GoString; +typedef _GoString_ GoString; typedef void *GoMap; typedef void *GoChan; typedef struct { void *t; void *v; } GoInterface; diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index 6f9dc326dc5..8b310d46c92 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -14,12 +14,12 @@ // The commands are: // // build compile packages and dependencies -// clean remove object files +// clean remove object files and cached files // doc show documentation for package or symbol // env print Go environment information // bug start a bug report -// fix run go tool fix on packages -// fmt run gofmt on package sources +// fix update packages to use new APIs +// fmt gofmt (reformat) package sources // generate generate Go files by processing source // get download and install packages and dependencies // install compile and install packages and dependencies @@ -28,7 +28,7 @@ // test test packages // tool run specified go tool // version print Go version -// vet run go tool vet on packages +// vet report likely mistakes in packages // // Use "go help [command]" for more information about a command. // @@ -104,15 +104,15 @@ // -x // print the commands. // -// -asmflags 'flag list' +// -asmflags '[pattern=]arg list' // arguments to pass on each go tool asm invocation. // -buildmode mode // build mode to use. See 'go help buildmode' for more. // -compiler name // name of compiler to use, as in runtime.Compiler (gccgo or gc). -// -gccgoflags 'arg list' +// -gccgoflags '[pattern=]arg list' // arguments to pass on each gccgo compiler/linker invocation. -// -gcflags 'arg list' +// -gcflags '[pattern=]arg list' // arguments to pass on each go tool compile invocation. // -installsuffix suffix // a suffix to use in the name of the package installation directory, @@ -121,7 +121,7 @@ // or, if set explicitly, has _race appended to it. Likewise for the -msan // flag. Using a -buildmode option that requires non-default compile flags // has a similar effect. -// -ldflags 'flag list' +// -ldflags '[pattern=]arg list' // arguments to pass on each go tool link invocation. // -linkshared // link against shared libraries previously created with @@ -139,9 +139,21 @@ // For example, instead of running asm, the go command will run // 'cmd args /path/to/asm '. // -// All the flags that take a list of arguments accept a space-separated -// list of strings. To embed spaces in an element in the list, surround -// it with either single or double quotes. +// The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a +// space-separated list of arguments to pass to an underlying tool +// during the build. To embed spaces in an element in the list, surround +// it with either single or double quotes. The argument list may be +// preceded by a package pattern and an equal sign, which restricts +// the use of that argument list to the building of packages matching +// that pattern (see 'go help packages' for a description of package +// patterns). Without a pattern, the argument list applies only to the +// packages named on the command line. The flags may be repeated +// with different patterns in order to specify different arguments for +// different sets of packages. If a package matches patterns given in +// multiple flags, the latest match on the command line wins. +// For example, 'go build -gcflags=-S fmt' prints the disassembly +// only for package fmt, while 'go build -gcflags=all=-S fmt' +// prints the disassembly for fmt and all its dependencies. // // For more about specifying packages, see 'go help packages'. // For more about where packages and binaries are installed, @@ -158,11 +170,11 @@ // See also: go install, go get, go clean. // // -// Remove object files +// Remove object files and cached files // // Usage: // -// go clean [-i] [-r] [-n] [-x] [build flags] [packages] +// go clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages] // // Clean removes object files from package source directories. // The go command builds most objects in a temporary directory, @@ -200,6 +212,11 @@ // // The -x flag causes clean to print remove commands as it executes them. // +// The -cache flag causes clean to remove the entire go build cache. +// +// The -testcache flag causes clean to expire all test results in the +// go build cache. +// // For more about build flags, see 'go help build'. // // For more about specifying packages, see 'go help packages'. @@ -328,6 +345,8 @@ // The -json flag prints the environment in JSON format // instead of as a shell script. // +// For more about environment variables, see 'go help environment'. +// // // Start a bug report // @@ -339,7 +358,7 @@ // The report includes useful system information. // // -// Run go tool fix on packages +// Update packages to use new APIs // // Usage: // @@ -355,7 +374,7 @@ // See also: go fmt, go vet. // // -// Run gofmt on package sources +// Gofmt (reformat) package sources // // Usage: // @@ -543,10 +562,11 @@ // // Usage: // -// go install [build flags] [packages] +// go install [-i] [build flags] [packages] // -// Install compiles and installs the packages named by the import paths, -// along with their dependencies. +// Install compiles and installs the packages named by the import paths. +// +// The -i flag installs the dependencies of the named packages as well. // // For more about the build flags, see 'go help build'. // For more about specifying packages, see 'go help packages'. @@ -719,10 +739,10 @@ // // 'Go test' recompiles each package along with any files with names matching // the file pattern "*_test.go". -// Files whose names begin with "_" (including "_test.go") or "." are ignored. // These additional files can contain test functions, benchmark functions, and // example functions. See 'go help testfunc' for more. // Each listed package causes the execution of a separate test binary. +// Files whose names begin with "_" (including "_test.go") or "." are ignored. // // Test files that declare a package with the suffix "_test" will be compiled as a // separate package, and then linked and run with the main test binary. @@ -730,11 +750,46 @@ // The go tool will ignore a directory named "testdata", making it available // to hold ancillary data needed by the tests. // -// By default, go test needs no arguments. It compiles and tests the package -// with source in the current directory, including tests, and runs the tests. -// -// The package is built in a temporary directory so it does not interfere with the -// non-test installation. +// As part of building a test binary, go test runs go vet on the package +// and its test source files to identify significant problems. If go vet +// finds any problems, go test reports those and does not run the test binary. +// Only a high-confidence subset of the default go vet checks are used. +// To disable the running of go vet, use the -vet=off flag. +// +// Go test runs in two different modes: local directory mode when invoked with +// no package arguments (for example, 'go test'), and package list mode when +// invoked with package arguments (for example 'go test math', 'go test ./...', +// and even 'go test .'). +// +// In local directory mode, go test compiles and tests the package sources +// found in the current directory and then runs the resulting test binary. +// In this mode, caching (discussed below) is disabled. After the package test +// finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'), +// package name, and elapsed time. +// +// In package list mode, go test compiles and tests each of the packages +// listed on the command line. If a package test passes, go test prints only +// the final 'ok' summary line. If a package test fails, go test prints the +// full test output. If invoked with the -bench or -v flag, go test prints +// the full output even for passing package tests, in order to display the +// requested benchmark results or verbose logging. +// +// All test output and summary lines are printed to the go command's standard +// output, even if the test printed them to its own standard error. +// (The go command's standard error is reserved for printing errors building +// the tests.) +// +// In package list mode, go test also caches successful package test results. +// If go test has cached a previous test run using the same test binary and +// the same command line consisting entirely of cacheable test flags +// (defined as -cpu, -list, -parallel, -run, -short, and -v), +// go test will redisplay the previous output instead of running the test +// binary again. In the summary line, go test prints '(cached)' in place of +// the elapsed time. To disable test caching, use any test flag or argument +// other than the cacheable flags. The idiomatic way to disable test caching +// explicitly is to use -count=1. A cached result is treated as executing in +// no time at all, so a successful package test result will be cached and reused +// regardless of -timeout setting. // // In addition to the build flags, the flags handled by 'go test' itself are: // @@ -757,6 +812,10 @@ // Install packages that are dependencies of the test. // Do not run the test. // +// -json +// Convert test output to JSON suitable for automated processing. +// See 'go doc test2json' for the encoding details. +// // -o file // Compile the test binary to the named file. // The test still runs (unless -c or -i is specified). @@ -782,7 +841,7 @@ // The -n flag causes tool to print the command that would be // executed but not execute it. // -// For more about each tool command, see 'go tool command -h'. +// For more about each tool command, see 'go doc cmd/'. // // // Print Go version @@ -794,7 +853,7 @@ // Version prints the Go version, as reported by runtime.Version. // // -// Run go tool vet on packages +// Report likely mistakes in packages // // Usage: // @@ -808,7 +867,9 @@ // The -n flag prints commands that would be executed. // The -x flag prints commands as they are executed. // -// For more about build flags, see 'go help build'. +// The build flags supported by go vet are those that control package resolution +// and execution, such as -n, -x, -v, -tags, and -toolexec. +// For more about these flags, see 'go help build'. // // See also: go fmt, go fix. // @@ -917,8 +978,10 @@ // comment, indicating that the package sources are included // for documentation only and must not be used to build the // package binary. This enables distribution of Go packages in -// their compiled form alone. See the go/build package documentation -// for more details. +// their compiled form alone. Even binary-only packages require +// accurate import blocks listing required dependencies, so that +// those dependencies can be supplied when linking the resulting +// command. // // // GOPATH environment variable @@ -1096,6 +1159,12 @@ // See https://golang.org/doc/articles/race_detector.html. // GOROOT // The root of the go tree. +// GOTMPDIR +// The directory where the go command will write +// temporary source files, packages, and binaries. +// GOCACHE +// The directory where the go command will store +// cached information for reuse in future builds. // // Environment variables for use with cgo: // @@ -1130,6 +1199,9 @@ // GO386 // For GOARCH=386, the floating point instruction set. // Valid values are 387, sse2. +// GOMIPS +// For GOARCH=mips{,le}, whether to use floating point instructions. +// Valid values are hardfloat (default), softfloat. // // Special-purpose environment variables: // @@ -1460,10 +1532,10 @@ // significantly more expensive. // Sets -cover. // -// -coverpkg pkg1,pkg2,pkg3 -// Apply coverage analysis in each test to the given list of packages. +// -coverpkg pattern1,pattern2,pattern3 +// Apply coverage analysis in each test to packages matching the patterns. // The default is for each test to analyze only the package being tested. -// Packages are specified as import paths. +// See 'go help packages' for a description of package patterns. // Sets -cover. // // -cpu 1,2,4 @@ -1471,6 +1543,9 @@ // benchmarks should be executed. The default is the current value // of GOMAXPROCS. // +// -failfast +// Do not start new tests after the first test failure. +// // -list regexp // List tests, benchmarks, or examples matching the regular expression. // No tests, benchmarks or examples will be run. This will only @@ -1503,12 +1578,20 @@ // // -timeout d // If a test binary runs longer than duration d, panic. +// If d is 0, the timeout is disabled. // The default is 10 minutes (10m). // // -v // Verbose output: log all tests as they are run. Also print all // text from Log and Logf calls even if the test succeeds. // +// -vet list +// Configure the invocation of "go vet" during "go test" +// to use the comma-separated list of vet checks. +// If list is empty, "go test" runs "go vet" with a curated list of +// checks believed to be always worth addressing. +// If list is "off", "go test" does not run "go vet" at all. +// // The following flags are also recognized by 'go test' and can be used to // profile the tests during execution: // diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go index 28fb5efe328..509bd0b50be 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -6,6 +6,8 @@ package main_test import ( "bytes" + "debug/elf" + "debug/macho" "fmt" "go/format" "internal/race" @@ -27,6 +29,7 @@ var ( canRun = true // whether we can run go or ./testgo canRace = false // whether we can run the race detector canCgo = false // whether we can use cgo + canMSan = false // whether we can run the memory sanitizer exeSuffix string // ".exe" on Windows @@ -83,25 +86,61 @@ var testCC string // The TestMain function creates a go command for testing purposes and // deletes it after the tests have been run. func TestMain(m *testing.M) { + if os.Getenv("GO_GCFLAGS") != "" { + fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go + fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n") + fmt.Printf("SKIP\n") + return + } + if canRun { args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix} if race.Enabled { args = append(args, "-race") } - out, err := exec.Command("go", args...).CombinedOutput() + gotool, err := testenv.GoTool() if err != nil { - fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) + fmt.Fprintln(os.Stderr, err) os.Exit(2) } - out, err = exec.Command("go", "env", "GOROOT").CombinedOutput() + goEnv := func(name string) string { + out, err := exec.Command(gotool, "env", name).CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "go env %s: %v\n%s", name, err, out) + os.Exit(2) + } + return strings.TrimSpace(string(out)) + } + testGOROOT = goEnv("GOROOT") + + // The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH + // toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH). + // The testgo.exe we are about to create will be built for GOOS/GOARCH, + // which means it will use the GOOS/GOARCH toolchain + // (installed in GOROOT/pkg/tool/GOOS_GOARCH). + // If these are not the same toolchain, then the entire standard library + // will look out of date (the compilers in those two different tool directories + // are built for different architectures and have different buid IDs), + // which will cause many tests to do unnecessary rebuilds and some + // tests to attempt to overwrite the installed standard library. + // Bail out entirely in this case. + hostGOOS := goEnv("GOHOSTOS") + hostGOARCH := goEnv("GOHOSTARCH") + if hostGOOS != runtime.GOOS || hostGOARCH != runtime.GOARCH { + fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go + fmt.Printf("cmd/go test is not compatible with GOOS/GOARCH != GOHOSTOS/GOHOSTARCH (%s/%s != %s/%s)\n", runtime.GOOS, runtime.GOARCH, hostGOOS, hostGOARCH) + fmt.Printf("SKIP\n") + return + } + + out, err := exec.Command(gotool, args...).CombinedOutput() if err != nil { - fmt.Fprintf(os.Stderr, "could not find testing GOROOT: %v\n%s", err, out) + fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) os.Exit(2) } - testGOROOT = strings.TrimSpace(string(out)) - out, err = exec.Command("go", "env", "CC").CombinedOutput() + out, err = exec.Command(gotool, "env", "CC").CombinedOutput() if err != nil { fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out) os.Exit(2) @@ -118,6 +157,10 @@ func TestMain(m *testing.M) { } } + // As of Sept 2017, MSan is only supported on linux/amd64. + // https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer + canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64" + switch runtime.GOOS { case "linux", "darwin", "freebsd", "windows": // The race detector doesn't work on Alpine Linux: @@ -125,7 +168,6 @@ func TestMain(m *testing.M) { canRace = canCgo && runtime.GOARCH == "amd64" && !isAlpineLinux() && runtime.Compiler != "gccgo" } } - // Don't let these environment variables confuse the test. os.Unsetenv("GOBIN") os.Unsetenv("GOPATH") @@ -137,6 +179,9 @@ func TestMain(m *testing.M) { os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache")) } os.Setenv("HOME", "/test-go-home-does-not-exist") + if os.Getenv("GOCACHE") == "" { + os.Setenv("GOCACHE", "off") // because $HOME is gone + } r := m.Run() @@ -182,10 +227,11 @@ func skipIfGccgo(t *testing.T, msg string) { // testgo sets up for a test that runs testgo. func testgo(t *testing.T) *testgoData { + t.Helper() testenv.MustHaveGoBuild(t) if skipExternal { - t.Skip("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH) + t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH) } return &testgoData{t: t} @@ -193,6 +239,7 @@ func testgo(t *testing.T) *testgoData { // must gives a fatal error if err is not nil. func (tg *testgoData) must(err error) { + tg.t.Helper() if err != nil { tg.t.Fatal(err) } @@ -200,6 +247,7 @@ func (tg *testgoData) must(err error) { // check gives a test non-fatal error if err is not nil. func (tg *testgoData) check(err error) { + tg.t.Helper() if err != nil { tg.t.Error(err) } @@ -207,6 +255,7 @@ func (tg *testgoData) check(err error) { // parallel runs the test in parallel by calling t.Parallel. func (tg *testgoData) parallel() { + tg.t.Helper() if tg.ran { tg.t.Fatal("internal testsuite error: call to parallel after run") } @@ -227,6 +276,7 @@ func (tg *testgoData) parallel() { // pwd returns the current directory. func (tg *testgoData) pwd() string { + tg.t.Helper() wd, err := os.Getwd() if err != nil { tg.t.Fatalf("could not get working directory: %v", err) @@ -238,6 +288,7 @@ func (tg *testgoData) pwd() string { // using this means that the test must not be run in parallel with any // other tests. func (tg *testgoData) cd(dir string) { + tg.t.Helper() if tg.inParallel { tg.t.Fatal("internal testsuite error: changing directory when running in parallel") } @@ -261,6 +312,7 @@ func (tg *testgoData) sleep() { // setenv sets an environment variable to use when running the test go // command. func (tg *testgoData) setenv(name, val string) { + tg.t.Helper() if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) { tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val) } @@ -291,6 +343,7 @@ func (tg *testgoData) goTool() string { // doRun runs the test go command, recording stdout and stderr and // returning exit status. func (tg *testgoData) doRun(args []string) error { + tg.t.Helper() if !canRun { panic("testgoData.doRun called but canRun false") } @@ -336,6 +389,7 @@ func (tg *testgoData) doRun(args []string) error { // run runs the test go command, and expects it to succeed. func (tg *testgoData) run(args ...string) { + tg.t.Helper() if status := tg.doRun(args); status != nil { tg.t.Logf("go %v failed unexpectedly: %v", args, status) tg.t.FailNow() @@ -344,6 +398,7 @@ func (tg *testgoData) run(args ...string) { // runFail runs the test go command, and expects it to fail. func (tg *testgoData) runFail(args ...string) { + tg.t.Helper() if status := tg.doRun(args); status == nil { tg.t.Fatal("testgo succeeded unexpectedly") } else { @@ -353,6 +408,7 @@ func (tg *testgoData) runFail(args ...string) { // runGit runs a git command, and expects it to succeed. func (tg *testgoData) runGit(dir string, args ...string) { + tg.t.Helper() cmd := exec.Command("git", args...) tg.stdout.Reset() tg.stderr.Reset() @@ -377,6 +433,7 @@ func (tg *testgoData) runGit(dir string, args ...string) { // getStdout returns standard output of the testgo run as a string. func (tg *testgoData) getStdout() string { + tg.t.Helper() if !tg.ran { tg.t.Fatal("internal testsuite error: stdout called before run") } @@ -385,6 +442,7 @@ func (tg *testgoData) getStdout() string { // getStderr returns standard error of the testgo run as a string. func (tg *testgoData) getStderr() string { + tg.t.Helper() if !tg.ran { tg.t.Fatal("internal testsuite error: stdout called before run") } @@ -395,6 +453,7 @@ func (tg *testgoData) getStderr() string { // whether it is found. The regular expression is matched against // each line separately, as with the grep command. func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool { + tg.t.Helper() if !tg.ran { tg.t.Fatal("internal testsuite error: grep called before run") } @@ -412,6 +471,7 @@ func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool { // searching, "output" or "error". The msg argument is logged on // failure. func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) { + tg.t.Helper() if !tg.doGrepMatch(match, b) { tg.t.Log(msg) tg.t.Logf("pattern %v not found in standard %s", match, name) @@ -422,18 +482,21 @@ func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) { // grepStdout looks for a regular expression in the test run's // standard output and fails, logging msg, if it is not found. func (tg *testgoData) grepStdout(match, msg string) { + tg.t.Helper() tg.doGrep(match, &tg.stdout, "output", msg) } // grepStderr looks for a regular expression in the test run's // standard error and fails, logging msg, if it is not found. func (tg *testgoData) grepStderr(match, msg string) { + tg.t.Helper() tg.doGrep(match, &tg.stderr, "error", msg) } // grepBoth looks for a regular expression in the test run's standard // output or stand error and fails, logging msg, if it is not found. func (tg *testgoData) grepBoth(match, msg string) { + tg.t.Helper() if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) { tg.t.Log(msg) tg.t.Logf("pattern %v not found in standard output or standard error", match) @@ -444,6 +507,7 @@ func (tg *testgoData) grepBoth(match, msg string) { // doGrepNot looks for a regular expression in a buffer and fails if // it is found. The name and msg arguments are as for doGrep. func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) { + tg.t.Helper() if tg.doGrepMatch(match, b) { tg.t.Log(msg) tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name) @@ -454,12 +518,14 @@ func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) // grepStdoutNot looks for a regular expression in the test run's // standard output and fails, logging msg, if it is found. func (tg *testgoData) grepStdoutNot(match, msg string) { + tg.t.Helper() tg.doGrepNot(match, &tg.stdout, "output", msg) } // grepStderrNot looks for a regular expression in the test run's // standard error and fails, logging msg, if it is found. func (tg *testgoData) grepStderrNot(match, msg string) { + tg.t.Helper() tg.doGrepNot(match, &tg.stderr, "error", msg) } @@ -467,6 +533,7 @@ func (tg *testgoData) grepStderrNot(match, msg string) { // standard output or stand error and fails, logging msg, if it is // found. func (tg *testgoData) grepBothNot(match, msg string) { + tg.t.Helper() if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) { tg.t.Log(msg) tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match) @@ -475,6 +542,7 @@ func (tg *testgoData) grepBothNot(match, msg string) { // doGrepCount counts the number of times a regexp is seen in a buffer. func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int { + tg.t.Helper() if !tg.ran { tg.t.Fatal("internal testsuite error: doGrepCount called before run") } @@ -491,6 +559,7 @@ func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int { // grepCountBoth returns the number of times a regexp is seen in both // standard output and standard error. func (tg *testgoData) grepCountBoth(match string) int { + tg.t.Helper() return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr) } @@ -499,6 +568,7 @@ func (tg *testgoData) grepCountBoth(match string) int { // removed. When the test completes, the file or directory will be // removed if it exists. func (tg *testgoData) creatingTemp(path string) { + tg.t.Helper() if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) { tg.t.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path) } @@ -515,6 +585,7 @@ func (tg *testgoData) creatingTemp(path string) { // makeTempdir makes a temporary directory for a run of testgo. If // the temporary directory was already created, this does nothing. func (tg *testgoData) makeTempdir() { + tg.t.Helper() if tg.tempdir == "" { var err error tg.tempdir, err = ioutil.TempDir("", "gotest") @@ -524,6 +595,7 @@ func (tg *testgoData) makeTempdir() { // tempFile adds a temporary file for a run of testgo. func (tg *testgoData) tempFile(path, contents string) { + tg.t.Helper() tg.makeTempdir() tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755)) bytes := []byte(contents) @@ -538,6 +610,7 @@ func (tg *testgoData) tempFile(path, contents string) { // tempDir adds a temporary directory for a run of testgo. func (tg *testgoData) tempDir(path string) { + tg.t.Helper() tg.makeTempdir() if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) { tg.t.Fatal(err) @@ -547,6 +620,7 @@ func (tg *testgoData) tempDir(path string) { // path returns the absolute pathname to file with the temporary // directory. func (tg *testgoData) path(name string) string { + tg.t.Helper() if tg.tempdir == "" { tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name) } @@ -558,6 +632,7 @@ func (tg *testgoData) path(name string) string { // mustExist fails if path does not exist. func (tg *testgoData) mustExist(path string) { + tg.t.Helper() if _, err := os.Stat(path); err != nil { if os.IsNotExist(err) { tg.t.Fatalf("%s does not exist but should", path) @@ -568,13 +643,28 @@ func (tg *testgoData) mustExist(path string) { // mustNotExist fails if path exists. func (tg *testgoData) mustNotExist(path string) { + tg.t.Helper() if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) { tg.t.Fatalf("%s exists but should not (%v)", path, err) } } +// mustHaveContent succeeds if filePath is a path to a file, +// and that file is readable and not empty. +func (tg *testgoData) mustHaveContent(filePath string) { + tg.mustExist(filePath) + f, err := os.Stat(filePath) + if err != nil { + tg.t.Fatal(err) + } + if f.Size() == 0 { + tg.t.Fatalf("expected %s to have data, but is empty", filePath) + } +} + // wantExecutable fails with msg if path is not executable. func (tg *testgoData) wantExecutable(path, msg string) { + tg.t.Helper() if st, err := os.Stat(path); err != nil { if !os.IsNotExist(err) { tg.t.Log(err) @@ -589,6 +679,7 @@ func (tg *testgoData) wantExecutable(path, msg string) { // wantArchive fails if path is not an archive. func (tg *testgoData) wantArchive(path string) { + tg.t.Helper() f, err := os.Open(path) if err != nil { tg.t.Fatal(err) @@ -603,6 +694,7 @@ func (tg *testgoData) wantArchive(path string) { // isStale reports whether pkg is stale, and why func (tg *testgoData) isStale(pkg string) (bool, string) { + tg.t.Helper() tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg) v := strings.TrimSpace(tg.getStdout()) f := strings.SplitN(v, ":", 2) @@ -620,6 +712,7 @@ func (tg *testgoData) isStale(pkg string) (bool, string) { // wantStale fails with msg if pkg is not stale. func (tg *testgoData) wantStale(pkg, reason, msg string) { + tg.t.Helper() stale, why := tg.isStale(pkg) if !stale { tg.t.Fatal(msg) @@ -631,6 +724,7 @@ func (tg *testgoData) wantStale(pkg, reason, msg string) { // wantNotStale fails with msg if pkg is stale. func (tg *testgoData) wantNotStale(pkg, reason, msg string) { + tg.t.Helper() stale, why := tg.isStale(pkg) if stale { tg.t.Fatal(msg) @@ -642,6 +736,7 @@ func (tg *testgoData) wantNotStale(pkg, reason, msg string) { // cleanup cleans up a test that runs testgo. func (tg *testgoData) cleanup() { + tg.t.Helper() if tg.wd != "" { if err := os.Chdir(tg.wd); err != nil { // We are unlikely to be able to continue. @@ -660,6 +755,7 @@ func (tg *testgoData) cleanup() { // failSSH puts an ssh executable in the PATH that always fails. // This is to stub out uses of ssh by go get. func (tg *testgoData) failSSH() { + tg.t.Helper() wd, err := os.Getwd() if err != nil { tg.t.Fatal(err) @@ -668,6 +764,20 @@ func (tg *testgoData) failSSH() { tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH"))) } +func TestBuildComplex(t *testing.T) { + // Simple smoke test for build configuration. + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("build", "-x", "-o", os.DevNull, "complex") + + if _, err := exec.LookPath("gccgo"); err == nil { + t.Skip("golang.org/issue/22472") + tg.run("build", "-x", "-o", os.DevNull, "-compiler=gccgo", "complex") + } +} + func TestFileLineInErrorMessages(t *testing.T) { tg := testgo(t) defer tg.cleanup() @@ -767,40 +877,36 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { } } - tg.setenv("TESTGO_IS_GO_RELEASE", "1") - tg.tempFile("d1/src/p1/p1.go", `package p1`) tg.setenv("GOPATH", tg.path("d1")) tg.run("install", "-a", "p1") - tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly") - tg.sleep() + tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, before any changes") - // Changing mtime and content of runtime/internal/sys/sys.go - // should have no effect: we're in a release, which doesn't rebuild - // for general mtime or content changes. + // Changing mtime of runtime/internal/sys/sys.go + // should have no effect: only the content matters. + // In fact this should be true even outside a release branch. sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go" + tg.sleep() restore := addNL(sys) - defer restore() - tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go") restore() - tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go") + tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating mtime of runtime/internal/sys/sys.go") - // But changing runtime/internal/sys/zversion.go should have an effect: - // that's how we tell when we flip from one release to another. - zversion := runtime.GOROOT() + "/src/runtime/internal/sys/zversion.go" - restore = addNL(zversion) + // But changing content of any file should have an effect. + // Previously zversion.go was the only one that mattered; + // now they all matter, so keep using sys.go. + restore = addNL(sys) defer restore() - tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release") + tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go") restore() tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release") - addNL(zversion) - tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release") + addNL(sys) + tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go again") tg.run("install", "p1") tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release") // Restore to "old" release. restore() - tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build") + tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after restoring sys.go") tg.run("install", "p1") tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release") @@ -887,7 +993,7 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) { func F() {}`) sep := string(filepath.ListSeparator) tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2")) - tg.run("install", "p1") + tg.run("install", "-i", "p1") tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly") tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly") tg.sleep() @@ -898,10 +1004,10 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) { } else { tg.must(f.Close()) } - tg.wantStale("p2", "newer source file", "./testgo list claims p2 is NOT stale, incorrectly") - tg.wantStale("p1", "stale dependency", "./testgo list claims p1 is NOT stale, incorrectly") + tg.wantStale("p2", "build ID mismatch", "./testgo list claims p2 is NOT stale, incorrectly") + tg.wantStale("p1", "stale dependency: p2", "./testgo list claims p1 is NOT stale, incorrectly") - tg.run("install", "p1") + tg.run("install", "-i", "p1") tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly") tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly") } @@ -999,6 +1105,7 @@ func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) { } func testLocalRun(tg *testgoData, exepath, local, match string) { + tg.t.Helper() out, err := exec.Command(exepath).Output() if err != nil { tg.t.Fatalf("error running %v: %v", exepath, err) @@ -1010,6 +1117,7 @@ func testLocalRun(tg *testgoData, exepath, local, match string) { } func testLocalEasy(tg *testgoData, local string) { + tg.t.Helper() exepath := "./easy" + exeSuffix tg.creatingTemp(exepath) tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easy.go")) @@ -1017,6 +1125,7 @@ func testLocalEasy(tg *testgoData, local string) { } func testLocalEasySub(tg *testgoData, local string) { + tg.t.Helper() exepath := "./easysub" + exeSuffix tg.creatingTemp(exepath) tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easysub", "main.go")) @@ -1024,6 +1133,7 @@ func testLocalEasySub(tg *testgoData, local string) { } func testLocalHard(tg *testgoData, local string) { + tg.t.Helper() exepath := "./hard" + exeSuffix tg.creatingTemp(exepath) tg.run("build", "-o", exepath, filepath.Join("testdata", local, "hard.go")) @@ -1031,6 +1141,7 @@ func testLocalHard(tg *testgoData, local string) { } func testLocalInstall(tg *testgoData, local string) { + tg.t.Helper() tg.runFail("install", filepath.Join("testdata", local, "easy.go")) } @@ -1061,6 +1172,7 @@ func TestLocalImportsGoInstallShouldFail(t *testing.T) { const badDirName = `#$%:, &()*;<=>?\^{}` func copyBad(tg *testgoData) { + tg.t.Helper() if runtime.GOOS == "windows" { tg.t.Skipf("skipping test because %q is an invalid directory name", badDirName) } @@ -1176,7 +1288,7 @@ func testMove(t *testing.T, vcs, url, base, config string) { tg.runFail("get", "-d", "-u", url) tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason") tg.runFail("get", "-d", "-f", "-u", url) - tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason") + tg.grepStderr("validating server certificate|[nN]ot [fF]ound", "go get -d -f -u "+url+" failed for wrong reason") } func TestInternalPackageErrorsAreHandled(t *testing.T) { @@ -1197,10 +1309,9 @@ func TestMoveGit(t *testing.T) { testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config") } -// TODO(rsc): Set up a test case on bitbucket for hg. -// func TestMoveHG(t *testing.T) { -// testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc") -// } +func TestMoveHG(t *testing.T) { + testMove(t, "hg", "vcs-test.golang.org/go/custom-hg-hello", "custom-hg-hello", "vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc") +} // TODO(rsc): Set up a test case on SourceForge (?) for svn. // func testMoveSVN(t *testing.T) { @@ -1329,6 +1440,25 @@ func TestGetGitDefaultBranch(t *testing.T) { tg.grepStdout(`\* another-branch`, "not on correct default branch") } +func TestAccidentalGitCheckout(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + if _, err := exec.LookPath("git"); err != nil { + t.Skip("skipping because git binary not found") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + + tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git") + tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason") + + tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main") + tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason") +} + func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) { tg := testgo(t) defer tg.cleanup() @@ -1355,6 +1485,10 @@ func TestRelativeImportsGoTest(t *testing.T) { func TestRelativeImportsGoTestDashI(t *testing.T) { tg := testgo(t) defer tg.cleanup() + + // don't let test -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before test -i") + tg.run("test", "-i", "./testdata/testimport") } @@ -1401,6 +1535,28 @@ func TestInstallFailsWithNoBuildableFiles(t *testing.T) { tg.grepStderr("build constraints exclude all Go files", "go install cgotest did not report 'build constraints exclude all Go files'") } +// Issue 21895 +func TestMSanAndRaceRequireCgo(t *testing.T) { + if !canMSan && !canRace { + t.Skip("skipping because both msan and the race detector are not supported") + } + + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("triv.go", `package main; func main() {}`) + tg.setenv("CGO_ENABLED", "0") + if canRace { + tg.runFail("install", "-race", "triv.go") + tg.grepStderr("-race requires cgo", "did not correctly report that -race requires cgo") + tg.grepStderrNot("-msan", "reported that -msan instead of -race requires cgo") + } + if canMSan { + tg.runFail("install", "-msan", "triv.go") + tg.grepStderr("-msan requires cgo", "did not correctly report that -msan requires cgo") + tg.grepStderrNot("-race", "reported that -race instead of -msan requires cgo") + } +} + func TestRelativeGOBINFail(t *testing.T) { tg := testgo(t) defer tg.cleanup() @@ -1458,19 +1614,16 @@ func TestPackageNotStaleWithTrailingSlash(t *testing.T) { defer tg.cleanup() // Make sure the packages below are not stale. - tg.run("install", "runtime", "os", "io") + tg.wantNotStale("runtime", "", "must be non-stale before test runs") + tg.wantNotStale("os", "", "must be non-stale before test runs") + tg.wantNotStale("io", "", "must be non-stale before test runs") goroot := runtime.GOROOT() tg.setenv("GOROOT", goroot+"/") - want := "" - if isGoRelease { - want = "standard package in Go release distribution" - } - - tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale") - tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale") - tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale") + tg.wantNotStale("runtime", "", "with trailing slash in GOROOT, runtime listed as stale") + tg.wantNotStale("os", "", "with trailing slash in GOROOT, os listed as stale") + tg.wantNotStale("io", "", "with trailing slash in GOROOT, io listed as stale") } // With $GOBIN set, binaries get installed to $GOBIN. @@ -1612,6 +1765,27 @@ func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) { tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries") } +// Issue 21928. +func TestRejectBlankPathsInGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", " "+sep+filepath.Join(tg.pwd(), "testdata")) + tg.runFail("build", "go-cmd-test") + tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries") +} + +// Issue 21928. +func TestIgnoreEmptyPathsInGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix) + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", ""+sep+filepath.Join(tg.pwd(), "testdata")) + tg.run("install", "go-cmd-test") + tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test") +} + // Issue 4104. func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { tg := testgo(t) @@ -1671,6 +1845,20 @@ func TestGoListDedupsPackages(t *testing.T) { } } +func TestGoListDeps(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/p1/p2/p3/p4") + tg.setenv("GOPATH", tg.path(".")) + tg.tempFile("src/p1/p.go", "package p1\nimport _ \"p1/p2\"\n") + tg.tempFile("src/p1/p2/p.go", "package p2\nimport _ \"p1/p2/p3\"\n") + tg.tempFile("src/p1/p2/p3/p.go", "package p3\nimport _ \"p1/p2/p3/p4\"\n") + tg.tempFile("src/p1/p2/p3/p4/p.go", "package p4\n") + tg.run("list", "-f", "{{.Deps}}", "p1") + tg.grepStdout("p1/p2/p3/p4", "Deps(p1) does not mention p4") +} + // Issue 4096. Validate the output of unsuccessful go install foo/quxx. func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) { tg := testgo(t) @@ -1906,6 +2094,16 @@ func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) { tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test") } +func TestGoBuildNonMain(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + // TODO: tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("build", "-buildmode=exe", "-o", "not_main"+exeSuffix, "not_main") + tg.grepStderr("-buildmode=exe requires exactly one main package", "go build with -o and -buildmode=exe should on a non-main package should throw an error") + tg.mustNotExist("not_main" + exeSuffix) +} + func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { skipIfGccgo(t, "gccgo has no standard packages") tg := testgo(t) @@ -1932,6 +2130,10 @@ func TestGoTestDashIDashOWritesBinary(t *testing.T) { defer tg.cleanup() tg.parallel() tg.makeTempdir() + + // don't let test -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before test -i") + tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors") tg.grepBothNot("PASS|FAIL", "test should not have run") tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test") @@ -2104,7 +2306,7 @@ func TestSymlinkWarning(t *testing.T) { tg.tempDir("yy/zz") tg.tempFile("yy/zz/zz.go", "package zz\n") if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil { - t.Skip("symlink failed: %v", err) + t.Skipf("symlink failed: %v", err) } tg.run("list", "example/xx/z...") tg.grepStdoutNot(".", "list should not have matched anything") @@ -2199,16 +2401,17 @@ func TestSourceFileNameOrderPreserved(t *testing.T) { // Check that coverage analysis works at all. // Don't worry about the exact numbers but require not 0.0%. func checkCoverage(tg *testgoData, data string) { + tg.t.Helper() if regexp.MustCompile(`[^0-9]0\.0%`).MatchString(data) { tg.t.Error("some coverage results are 0.0%") } - tg.t.Log(data) } func TestCoverageRuns(t *testing.T) { if testing.Short() { t.Skip("don't build libraries for coverage in short mode") } + skipIfGccgo(t, "gccgo has no cover tool") tg := testgo(t) defer tg.cleanup() tg.run("test", "-short", "-coverpkg=strings", "strings", "regexp") @@ -2219,14 +2422,16 @@ func TestCoverageRuns(t *testing.T) { } // Check that coverage analysis uses set mode. +// Also check that coverage profiles merge correctly. func TestCoverageUsesSetMode(t *testing.T) { if testing.Short() { t.Skip("don't build libraries for coverage in short mode") } + skipIfGccgo(t, "gccgo has no cover tool") tg := testgo(t) defer tg.cleanup() tg.creatingTemp("testdata/cover.out") - tg.run("test", "-short", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out") + tg.run("test", "-short", "-cover", "encoding/binary", "errors", "-coverprofile=testdata/cover.out") data := tg.getStdout() + tg.getStderr() if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { t.Error(err) @@ -2234,6 +2439,15 @@ func TestCoverageUsesSetMode(t *testing.T) { if !bytes.Contains(out, []byte("mode: set")) { t.Error("missing mode: set") } + if !bytes.Contains(out, []byte("errors.go")) { + t.Error("missing errors.go") + } + if !bytes.Contains(out, []byte("binary.go")) { + t.Error("missing binary.go") + } + if bytes.Count(out, []byte("mode: set")) != 1 { + t.Error("too many mode: set") + } } checkCoverage(tg, data) } @@ -2245,6 +2459,7 @@ func TestCoverageUsesAtomicModeForRace(t *testing.T) { if !canRace { t.Skip("skipping because race detector not supported") } + skipIfGccgo(t, "gccgo has no cover tool") tg := testgo(t) defer tg.cleanup() @@ -2261,7 +2476,17 @@ func TestCoverageUsesAtomicModeForRace(t *testing.T) { checkCoverage(tg, data) } +func TestCoverageSyncAtomicImport(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("test", "-short", "-cover", "-covermode=atomic", "-coverpkg=coverdep/p1", "coverdep") +} + func TestCoverageImportMainLoop(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) @@ -2271,6 +2496,76 @@ func TestCoverageImportMainLoop(t *testing.T) { tg.grepStderr("not an importable package", "did not detect import main") } +func TestCoveragePattern(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + + // If coverpkg=sleepy... expands by package loading + // (as opposed to pattern matching on deps) + // then it will try to load sleepybad, which does not compile, + // and the test command will fail. + tg.run("test", "-coverprofile="+filepath.Join(tg.tempdir, "cover.out"), "-coverpkg=sleepy...", "-run=^$", "sleepy1") +} + +func TestCoverageErrorLine(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GOTMPDIR", tg.tempdir) + + tg.runFail("test", "coverbad") + tg.grepStderr(`coverbad[\\/]p\.go:4`, "did not find coverbad/p.go:4") + if canCgo { + tg.grepStderr(`coverbad[\\/]p1\.go:6`, "did not find coverbad/p1.go:6") + } + tg.grepStderrNot(regexp.QuoteMeta(tg.tempdir), "found temporary directory in error") + stderr := tg.getStderr() + + tg.runFail("test", "-cover", "coverbad") + stderr2 := tg.getStderr() + + // It's OK that stderr2 drops the character position in the error, + // because of the //line directive (see golang.org/issue/22662). + stderr = strings.Replace(stderr, "p.go:4:2:", "p.go:4:", -1) + if stderr != stderr2 { + t.Logf("test -cover changed error messages:\nbefore:\n%s\n\nafter:\n%s", stderr, stderr2) + t.Skip("golang.org/issue/22660") + t.FailNow() + } +} + +func TestTestBuildFailureOutput(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + + // Doesn't build, -x output should not claim to run test. + tg.runFail("test", "-x", "coverbad") + tg.grepStderrNot(`[\\/]coverbad\.test( |$)`, "claimed to run test") +} + +func TestCoverageFunc(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + + tg.run("test", "-outputdir="+tg.tempdir, "-coverprofile=cover.out", "coverasm") + tg.run("tool", "cover", "-func="+filepath.Join(tg.tempdir, "cover.out")) + tg.grepStdout(`\tg\t*100.0%`, "did not find g 100% covered") + tg.grepStdoutNot(`\tf\t*[0-9]`, "reported coverage for assembly function f") +} + func TestPluginNonMain(t *testing.T) { wd, err := os.Getwd() if err != nil { @@ -2509,14 +2804,64 @@ func main() { tg.run("run", tg.path("foo.go")) } -// "go test -c -test.bench=XXX errors" should not hang +// "go test -c -test.bench=XXX errors" should not hang. +// "go test -c" should also produce reproducible binaries. +// "go test -c" should also appear to write a new binary every time, +// even if it's really just updating the mtime on an existing up-to-date binary. func TestIssue6480(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") tg := testgo(t) defer tg.cleanup() // TODO: tg.parallel() tg.makeTempdir() tg.cd(tg.path(".")) tg.run("test", "-c", "-test.bench=XXX", "errors") + tg.run("test", "-c", "-o", "errors2.test", "errors") + + data1, err := ioutil.ReadFile("errors.test" + exeSuffix) + tg.must(err) + data2, err := ioutil.ReadFile("errors2.test") // no exeSuffix because -o above doesn't have it + tg.must(err) + if !bytes.Equal(data1, data2) { + t.Fatalf("go test -c errors produced different binaries when run twice") + } + + start := time.Now() + tg.run("test", "-x", "-c", "-test.bench=XXX", "errors") + tg.grepStderrNot(`[\\/]link|gccgo`, "incorrectly relinked up-to-date test binary") + info, err := os.Stat("errors.test" + exeSuffix) + if err != nil { + t.Fatal(err) + } + start = truncateLike(start, info.ModTime()) + if info.ModTime().Before(start) { + t.Fatalf("mtime of errors.test predates test -c command (%v < %v)", info.ModTime(), start) + } + + start = time.Now() + tg.run("test", "-x", "-c", "-o", "errors2.test", "errors") + tg.grepStderrNot(`[\\/]link|gccgo`, "incorrectly relinked up-to-date test binary") + info, err = os.Stat("errors2.test") + if err != nil { + t.Fatal(err) + } + start = truncateLike(start, info.ModTime()) + if info.ModTime().Before(start) { + t.Fatalf("mtime of errors2.test predates test -c command (%v < %v)", info.ModTime(), start) + } +} + +// truncateLike returns the result of truncating t to the apparent precision of p. +func truncateLike(t, p time.Time) time.Time { + nano := p.UnixNano() + d := 1 * time.Nanosecond + for nano%int64(d) == 0 && d < 1*time.Second { + d *= 10 + } + for nano%int64(d) == 0 && d < 2*time.Second { + d *= 2 + } + return t.Truncate(d) } // cmd/cgo: undefined reference when linking a C-library using gccgo @@ -2527,6 +2872,7 @@ func TestIssue7573(t *testing.T) { if _, err := exec.LookPath("gccgo"); err != nil { t.Skip("skipping because no gccgo compiler found") } + t.Skip("golang.org/issue/22472") tg := testgo(t) defer tg.cleanup() @@ -2609,17 +2955,21 @@ func TestBuildDashIInstallsDependencies(t *testing.T) { func F() { foo.F() }`) tg.setenv("GOPATH", tg.path(".")) + // don't let build -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before build -i") + checkbar := func(desc string) { - tg.sleep() - tg.must(os.Chtimes(tg.path("src/x/y/foo/foo.go"), time.Now(), time.Now())) - tg.sleep() tg.run("build", "-v", "-i", "x/y/bar") tg.grepBoth("x/y/foo", "first build -i "+desc+" did not build x/y/foo") tg.run("build", "-v", "-i", "x/y/bar") tg.grepBothNot("x/y/foo", "second build -i "+desc+" built x/y/foo") } checkbar("pkg") + tg.creatingTemp("bar" + exeSuffix) + tg.sleep() + tg.tempFile("src/x/y/foo/foo.go", `package foo + func F() { F() }`) tg.tempFile("src/x/y/bar/bar.go", `package main import "x/y/foo" func main() { foo.F() }`) @@ -2650,6 +3000,21 @@ func TestGoTestFooTestWorks(t *testing.T) { tg.run("test", "testdata/standalone_test.go") } +// Issue 22388 +func TestGoTestMainWithWrongSignature(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("test", "testdata/standalone_main_wrong_test.go") + tg.grepStderr(`wrong signature for TestMain, must be: func TestMain\(m \*testing.M\)`, "detected wrong error message") +} + +func TestGoTestMainAsNormalTest(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "testdata/standalone_main_normal_test.go") + tg.grepBoth(okPattern, "go test did not say ok") +} + func TestGoTestFlagsAfterPackage(t *testing.T) { tg := testgo(t) defer tg.cleanup() @@ -2773,10 +3138,9 @@ func TestGoVetWithExternalTests(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.makeTempdir() - tg.run("install", "cmd/vet") tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) tg.runFail("vet", "vetpkg") - tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf") + tg.grepBoth("Printf", "go vet vetpkg did not find missing argument for Printf") } func TestGoVetWithTags(t *testing.T) { @@ -2784,10 +3148,9 @@ func TestGoVetWithTags(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.makeTempdir() - tg.run("install", "cmd/vet") tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) tg.runFail("vet", "-tags", "tagtest", "vetpkg") - tg.grepBoth(`c\.go.*wrong number of args for format`, "go vet vetpkg did not run scan tagged file") + tg.grepBoth(`c\.go.*Printf`, "go vet vetpkg did not run scan tagged file") } func TestGoVetWithFlagsOn(t *testing.T) { @@ -2795,10 +3158,9 @@ func TestGoVetWithFlagsOn(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.makeTempdir() - tg.run("install", "cmd/vet") tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) tg.runFail("vet", "-printf", "vetpkg") - tg.grepBoth("missing argument for Printf", "go vet -printf vetpkg did not find missing argument for Printf") + tg.grepBoth("Printf", "go vet -printf vetpkg did not find missing argument for Printf") } func TestGoVetWithFlagsOff(t *testing.T) { @@ -2806,7 +3168,6 @@ func TestGoVetWithFlagsOff(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.makeTempdir() - tg.run("install", "cmd/vet") tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) tg.run("vet", "-printf=false", "vetpkg") } @@ -2857,7 +3218,7 @@ func TestImportMain(t *testing.T) { func TestFoo(t *testing.T) {} `) tg.setenv("GOPATH", tg.path(".")) - tg.creatingTemp("x") + tg.creatingTemp("x" + exeSuffix) tg.run("build", "x") tg.run("test", "x") @@ -3153,11 +3514,12 @@ func TestGoInstallPkgdir(t *testing.T) { defer tg.cleanup() tg.makeTempdir() pkg := tg.path(".") - tg.run("install", "-pkgdir", pkg, "errors") - _, err := os.Stat(filepath.Join(pkg, "errors.a")) - tg.must(err) - _, err = os.Stat(filepath.Join(pkg, "runtime.a")) - tg.must(err) + tg.run("install", "-pkgdir", pkg, "sync") + tg.mustExist(filepath.Join(pkg, "sync.a")) + tg.mustNotExist(filepath.Join(pkg, "sync/atomic.a")) + tg.run("install", "-i", "-pkgdir", pkg, "sync") + tg.mustExist(filepath.Join(pkg, "sync.a")) + tg.mustExist(filepath.Join(pkg, "sync/atomic.a")) } func TestGoTestRaceInstallCgo(t *testing.T) { @@ -3469,16 +3831,6 @@ func TestGoBuildARM(t *testing.T) { tg.grepStderrNot("unable to find math.a", "did not build math.a correctly") } -func TestIssue13655(t *testing.T) { - skipIfGccgo(t, "gccgo has no standard packages") - tg := testgo(t) - defer tg.cleanup() - for _, pkg := range []string{"runtime", "runtime/internal/atomic"} { - tg.run("list", "-f", "{{.Deps}}", pkg) - tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys") - } -} - // For issue 14337. func TestParallelTest(t *testing.T) { tg := testgo(t) @@ -3576,9 +3928,9 @@ func TestBinaryOnlyPackages(t *testing.T) { package p1 `) - tg.wantStale("p1", "cannot access install target", "p1 is binary-only but has no binary, should be stale") + tg.wantStale("p1", "missing or invalid binary-only package", "p1 is binary-only but has no binary, should be stale") tg.runFail("install", "p1") - tg.grepStderr("missing or invalid package binary", "did not report attempt to compile binary-only package") + tg.grepStderr("missing or invalid binary-only package", "did not report attempt to compile binary-only package") tg.tempFile("src/p1/p1.go", ` package p1 @@ -3601,11 +3953,12 @@ func TestBinaryOnlyPackages(t *testing.T) { tg.tempFile("src/p1/missing.go", `//go:binary-only-package package p1 + import _ "fmt" func G() `) - tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (first)") + tg.wantNotStale("p1", "binary-only package", "should NOT want to rebuild p1 (first)") tg.run("install", "-x", "p1") // no-op, up to date - tg.grepBothNot("/compile", "should not have run compiler") + tg.grepBothNot(`[\\/]compile`, "should not have run compiler") tg.run("install", "p2") // does not rebuild p1 (or else p2 will fail) tg.wantNotStale("p2", "", "should NOT want to rebuild p2") @@ -3615,7 +3968,7 @@ func TestBinaryOnlyPackages(t *testing.T) { package p1 func H() `) - tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (second)") + tg.wantNotStale("p1", "binary-only package", "should NOT want to rebuild p1 (second)") tg.wantNotStale("p2", "", "should NOT want to rebuild p2") tg.tempFile("src/p3/p3.go", ` @@ -3635,9 +3988,11 @@ func TestBinaryOnlyPackages(t *testing.T) { tg.grepStdout("hello from p1", "did not see message from p1") tg.tempFile("src/p4/p4.go", `package main`) + // The odd string split below avoids vet complaining about + // a // +build line appearing too late in this source file. tg.tempFile("src/p4/p4not.go", `//go:binary-only-package - // +build asdf + /`+`/ +build asdf package main `) @@ -3723,6 +4078,7 @@ func TestGoEnv(t *testing.T) { tg := testgo(t) tg.parallel() defer tg.cleanup() + tg.setenv("GOOS", "freebsd") // to avoid invalid pair errors tg.setenv("GOARCH", "arm") tg.run("env", "GOARCH") tg.grepStdout("^arm$", "GOARCH not honored") @@ -3877,6 +4233,24 @@ func TestBenchTimeout(t *testing.T) { tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go") } +// Issue 19394 +func TestWriteProfilesOnTimeout(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempDir("profiling") + tg.tempFile("profiling/timeouttest_test.go", `package timeouttest_test +import "testing" +import "time" +func TestSleep(t *testing.T) { time.Sleep(time.Second) }`) + tg.cd(tg.path("profiling")) + tg.runFail( + "test", + "-cpuprofile", tg.path("profiling/cpu.pprof"), "-memprofile", tg.path("profiling/mem.pprof"), + "-timeout", "1ms") + tg.mustHaveContent(tg.path("profiling/cpu.pprof")) + tg.mustHaveContent(tg.path("profiling/mem.pprof")) +} + func TestLinkXImportPathEscape(t *testing.T) { // golang.org/issue/16710 skipIfGccgo(t, "gccgo does not support -ldflags -X") @@ -4023,9 +4397,7 @@ func TestBuildTagsNoComma(t *testing.T) { defer tg.cleanup() tg.makeTempdir() tg.setenv("GOPATH", tg.path("go")) - tg.run("install", "-tags", "tag1 tag2", "math") - tg.runFail("install", "-tags", "tag1,tag2", "math") - tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error") + tg.run("build", "-tags", "tag1 tag2", "math") tg.runFail("build", "-tags", "tag1,tag2", "math") tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error") } @@ -4105,7 +4477,7 @@ func TestExecutableGOROOT(t *testing.T) { if err != nil { t.Fatal(err) } - m := regexp.MustCompile("const DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data)) + m := regexp.MustCompile("var DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data)) if m == nil { t.Fatal("cannot find DefaultGoroot in ../../runtime/internal/sys/zversion.go") } @@ -4130,6 +4502,43 @@ func TestExecutableGOROOT(t *testing.T) { } check(t, symGoTool, newRoot) }) + + tg.must(os.RemoveAll(tg.path("new/pkg"))) + + // Binaries built in the new tree should report the + // new tree when they call runtime.GOROOT(). + // This is implemented by having the go tool pass a -X option + // to the linker setting runtime/internal/sys.DefaultGoroot. + t.Run("RuntimeGoroot", func(t *testing.T) { + // Build a working GOROOT the easy way, with symlinks. + testenv.MustHaveSymlink(t) + if err := os.Symlink(filepath.Join(testGOROOT, "src"), tg.path("new/src")); err != nil { + t.Fatal(err) + } + if err := os.Symlink(filepath.Join(testGOROOT, "pkg"), tg.path("new/pkg")); err != nil { + t.Fatal(err) + } + + cmd := exec.Command(newGoTool, "run", "testdata/print_goroot.go") + cmd.Env = env + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%s run testdata/print_goroot.go: %v, %s", newGoTool, err, out) + } + goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out))) + if err != nil { + t.Fatal(err) + } + want, err := filepath.EvalSymlinks(tg.path("new")) + if err != nil { + t.Fatal(err) + } + if !strings.EqualFold(goroot, want) { + t.Errorf("go run testdata/print_goroot.go:\nhave %s\nwant %s", goroot, want) + } else { + t.Logf("go run testdata/print_goroot.go: %s", goroot) + } + }) } func TestNeedVersion(t *testing.T) { @@ -4158,7 +4567,8 @@ func TestUserOverrideFlags(t *testing.T) { tg := testgo(t) defer tg.cleanup() - tg.parallel() + // Don't call tg.parallel, as creating override.h and override.a may + // confuse other tests. tg.tempFile("override.go", `package main import "C" @@ -4169,7 +4579,7 @@ func GoFunc() {} func main() {}`) tg.creatingTemp("override.a") tg.creatingTemp("override.h") - tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=-shared=false", tg.path("override.go")) + tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=all=-shared=false", tg.path("override.go")) tg.grepStderr("compile .*-shared .*-shared=false", "user can not override code generation flag") } @@ -4177,69 +4587,22 @@ func TestCgoFlagContainsSpace(t *testing.T) { if !canCgo { t.Skip("skipping because cgo not enabled") } - tg := testgo(t) defer tg.cleanup() - ccName := filepath.Base(testCC) - - tg.tempFile(fmt.Sprintf("src/%s/main.go", ccName), fmt.Sprintf(`package main - import ( - "os" - "os/exec" - "path/filepath" - "strings" - ) - - func main() { - cmd := exec.Command(%q, os.Args[1:]...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err != nil { - panic(err) - } - - if os.Args[len(os.Args)-1] == "trivial.c" { - return - } - if filepath.Base(os.Args[len(os.Args)-1]) == "_cgo_defun.c" { - return - } - - var success bool - for _, arg := range os.Args { - switch { - case strings.Contains(arg, "c flags"): - if success { - panic("duplicate CFLAGS") - } - success = true - case strings.Contains(arg, "ld flags"): - if success { - panic("duplicate LDFLAGS") - } - success = true - } - } - if !success { - panic("args should contains '-Ic flags' or '-Lld flags'") - } - } - `, testCC)) - tg.cd(tg.path(fmt.Sprintf("src/%s", ccName))) - tg.run("build") - tg.setenv("CC", tg.path(fmt.Sprintf("src/%s/%s", ccName, ccName))) - - tg.tempFile("src/cgo/main.go", `package main + tg.makeTempdir() + tg.cd(tg.path(".")) + tg.tempFile("main.go", `package main // #cgo CFLAGS: -I"c flags" // #cgo LDFLAGS: -L"ld flags" import "C" func main() {} `) - tg.cd(tg.path("src/cgo")) - tg.run("run", "main.go") + tg.run("run", "-x", "main.go") + tg.grepStderr(`"-I[^"]+c flags"`, "did not find quoted c flags") + tg.grepStderrNot(`"-I[^"]+c flags".*"-I[^"]+c flags"`, "found too many quoted c flags") + tg.grepStderr(`"-L[^"]+ld flags"`, "did not find quoted ld flags") + tg.grepStderrNot(`"-L[^"]+c flags".*"-L[^"]+c flags"`, "found too many quoted ld flags") } // Issue #20435. @@ -4280,7 +4643,7 @@ func main() {}`) before() tg.run("install", "mycmd") after() - tg.wantStale("mycmd", "build ID mismatch", "should be stale after environment variable change") + tg.wantStale("mycmd", "stale dependency: runtime/internal/sys", "should be stale after environment variable change") } } @@ -4373,3 +4736,665 @@ func TestListTests(t *testing.T) { t.Run("Example1", testWith("Example", "ExampleSimple")) t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput")) } + +func TestBuildmodePIE(t *testing.T) { + platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386": + case "darwin/amd64": + default: + t.Skipf("skipping test because buildmode=pie is not supported on %s", platform) + } + + tg := testgo(t) + defer tg.cleanup() + + tg.tempFile("main.go", `package main; func main() { print("hello") }`) + src := tg.path("main.go") + obj := tg.path("main") + tg.run("build", "-buildmode=pie", "-o", obj, src) + + switch runtime.GOOS { + case "linux", "android": + f, err := elf.Open(obj) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if f.Type != elf.ET_DYN { + t.Errorf("PIE type must be ET_DYN, but %s", f.Type) + } + case "darwin": + f, err := macho.Open(obj) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if f.Flags&macho.FlagDyldLink == 0 { + t.Error("PIE must have DyldLink flag, but not") + } + if f.Flags&macho.FlagPIE == 0 { + t.Error("PIE must have PIE flag, but not") + } + default: + panic("unreachable") + } + + out, err := exec.Command(obj).CombinedOutput() + if err != nil { + t.Fatal(err) + } + + if string(out) != "hello" { + t.Errorf("got %q; want %q", out, "hello") + } +} + +func TestExecBuildX(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" { + t.Skipf("skipping because unix shell is not supported on %s", runtime.GOOS) + } + + tg := testgo(t) + defer tg.cleanup() + + tg.tempFile("main.go", `package main; import "C"; func main() { print("hello") }`) + src := tg.path("main.go") + obj := tg.path("main") + tg.run("build", "-x", "-o", obj, src) + sh := tg.path("test.sh") + err := ioutil.WriteFile(sh, []byte(tg.getStderr()), 0666) + if err != nil { + t.Fatal(err) + } + + out, err := exec.Command(obj).CombinedOutput() + if err != nil { + t.Fatal(err) + } + if string(out) != "hello" { + t.Fatalf("got %q; want %q", out, "hello") + } + + err = os.Remove(obj) + if err != nil { + t.Fatal(err) + } + + out, err = exec.Command("/usr/bin/env", "bash", "-x", sh).CombinedOutput() + if err != nil { + t.Fatalf("/bin/sh %s: %v\n%s", sh, err, out) + } + t.Logf("shell output:\n%s", out) + + out, err = exec.Command(obj).CombinedOutput() + if err != nil { + t.Fatal(err) + } + if string(out) != "hello" { + t.Fatalf("got %q; want %q", out, "hello") + } +} + +func TestParallelNumber(t *testing.T) { + for _, n := range [...]string{"-1", "0"} { + t.Run(n, func(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("test", "-parallel", n, "testdata/standalone_parallel_sub_test.go") + tg.grepBoth("-parallel can only be given", "go test -parallel with N<1 did not error") + }) + } +} + +func TestWrongGOOSErrorBeforeLoadError(t *testing.T) { + skipIfGccgo(t, "gccgo assumes cross-compilation is always possible") + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GOOS", "windwos") + tg.runFail("build", "exclude") + tg.grepStderr("unsupported GOOS/GOARCH pair", "GOOS=windwos go build exclude did not report 'unsupported GOOS/GOARCH pair'") +} + +func TestUpxCompression(t *testing.T) { + if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { + t.Skipf("skipping upx test on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + out, err := exec.Command("upx", "--version").CombinedOutput() + if err != nil { + t.Skip("skipping because upx is not available") + } + + // upx --version prints `upx ` in the first line of output: + // upx 3.94 + // [...] + re := regexp.MustCompile(`([[:digit:]]+)\.([[:digit:]]+)`) + upxVersion := re.FindStringSubmatch(string(out)) + if len(upxVersion) != 3 { + t.Errorf("bad upx version string: %s", upxVersion) + } + + major, err1 := strconv.Atoi(upxVersion[1]) + minor, err2 := strconv.Atoi(upxVersion[2]) + if err1 != nil || err2 != nil { + t.Errorf("bad upx version string: %s", upxVersion[0]) + } + + // Anything below 3.94 is known not to work with go binaries + if (major < 3) || (major == 3 && minor < 94) { + t.Skipf("skipping because upx version %v.%v is too old", major, minor) + } + + tg := testgo(t) + defer tg.cleanup() + + tg.tempFile("main.go", `package main; import "fmt"; func main() { fmt.Print("hello upx") }`) + src := tg.path("main.go") + obj := tg.path("main") + tg.run("build", "-o", obj, src) + + out, err = exec.Command("upx", obj).CombinedOutput() + if err != nil { + t.Logf("executing upx\n%s\n", out) + t.Fatalf("upx failed with %v", err) + } + + out, err = exec.Command(obj).CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Fatalf("running compressed go binary failed with error %s", err) + } + if string(out) != "hello upx" { + t.Fatalf("bad output from compressed go binary:\ngot %q; want %q", out, "hello upx") + } +} + +func TestGOTMPDIR(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.makeTempdir() + tg.setenv("GOTMPDIR", tg.tempdir) + tg.setenv("GOCACHE", "off") + + // complex/x is a trivial non-main package. + tg.run("build", "-work", "-x", "complex/w") + tg.grepStderr("WORK="+regexp.QuoteMeta(tg.tempdir), "did not work in $GOTMPDIR") +} + +func TestBuildCache(t *testing.T) { + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + // complex/w is a trivial non-main package. + // It imports nothing, so there should be no Deps. + tg.run("list", "-f={{join .Deps \" \"}}", "complex/w") + tg.grepStdoutNot(".+", "complex/w depends on unexpected packages") + + tg.run("build", "-x", "complex/w") + tg.grepStderr(`[\\/]compile|gccgo`, "did not run compiler") + + tg.run("build", "-x", "complex/w") + tg.grepStderrNot(`[\\/]compile|gccgo`, "ran compiler incorrectly") + + tg.run("build", "-a", "-x", "complex/w") + tg.grepStderr(`[\\/]compile|gccgo`, "did not run compiler with -a") + + // complex is a non-trivial main package. + // the link step should not be cached. + tg.run("build", "-o", os.DevNull, "-x", "complex") + tg.grepStderr(`[\\/]link|gccgo`, "did not run linker") + + tg.run("build", "-o", os.DevNull, "-x", "complex") + tg.grepStderr(`[\\/]link|gccgo`, "did not run linker") +} + +func TestCacheOutput(t *testing.T) { + // Test that command output is cached and replayed too. + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + tg.run("build", "-gcflags=-m", "errors") + stdout1 := tg.getStdout() + stderr1 := tg.getStderr() + + tg.run("build", "-gcflags=-m", "errors") + stdout2 := tg.getStdout() + stderr2 := tg.getStderr() + + if stdout2 != stdout1 || stderr2 != stderr1 { + t.Errorf("cache did not reproduce output:\n\nstdout1:\n%s\n\nstdout2:\n%s\n\nstderr1:\n%s\n\nstderr2:\n%s", + stdout1, stdout2, stderr1, stderr2) + } +} + +func TestCacheCoverage(t *testing.T) { + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.makeTempdir() + + tg.setenv("GOCACHE", filepath.Join(tg.tempdir, "c1")) + tg.run("test", "-cover", "strings") + tg.run("test", "-cover", "math", "strings") +} + +func TestIssue22588(t *testing.T) { + // Don't get confused by stderr coming from tools. + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + if _, err := os.Stat("/usr/bin/time"); err != nil { + t.Skip(err) + } + + tg.run("list", "-f={{.Stale}}", "runtime") + tg.run("list", "-toolexec=/usr/bin/time", "-f={{.Stale}}", "runtime") + tg.grepStdout("false", "incorrectly reported runtime as stale") +} + +func TestIssue22531(t *testing.T) { + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + tg.setenv("GOCACHE", filepath.Join(tg.tempdir, "cache")) + tg.tempFile("src/m/main.go", "package main /* c1 */; func main() {}\n") + tg.run("install", "-x", "m") + tg.run("list", "-f", "{{.Stale}}", "m") + tg.grepStdout("false", "reported m as stale after install") + tg.run("tool", "buildid", filepath.Join(tg.tempdir, "bin/m"+exeSuffix)) + + // The link action ID did not include the full main build ID, + // even though the full main build ID is written into the + // eventual binary. That caused the following install to + // be a no-op, thinking the gofmt binary was up-to-date, + // even though .Stale could see it was not. + tg.tempFile("src/m/main.go", "package main /* c2 */; func main() {}\n") + tg.run("install", "-x", "m") + tg.run("list", "-f", "{{.Stale}}", "m") + tg.grepStdout("false", "reported m as stale after reinstall") + tg.run("tool", "buildid", filepath.Join(tg.tempdir, "bin/m"+exeSuffix)) +} + +func TestIssue22596(t *testing.T) { + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", filepath.Join(tg.tempdir, "cache")) + tg.tempFile("gopath1/src/p/p.go", "package p; func F(){}\n") + tg.tempFile("gopath2/src/p/p.go", "package p; func F(){}\n") + + tg.setenv("GOPATH", filepath.Join(tg.tempdir, "gopath1")) + tg.run("list", "-f={{.Target}}", "p") + target1 := strings.TrimSpace(tg.getStdout()) + tg.run("install", "p") + tg.wantNotStale("p", "", "p stale after install") + + tg.setenv("GOPATH", filepath.Join(tg.tempdir, "gopath2")) + tg.run("list", "-f={{.Target}}", "p") + target2 := strings.TrimSpace(tg.getStdout()) + tg.must(os.MkdirAll(filepath.Dir(target2), 0777)) + tg.must(copyFile(target1, target2, 0666)) + tg.wantStale("p", "build ID mismatch", "p not stale after copy from gopath1") + tg.run("install", "p") + tg.wantNotStale("p", "", "p stale after install2") +} + +func TestTestCache(t *testing.T) { + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + tg.setenv("GOCACHE", filepath.Join(tg.tempdir, "cache")) + + if runtime.Compiler != "gccgo" { + // timeout here should not affect result being cached + // or being retrieved later. + tg.run("test", "-x", "-timeout=10s", "errors") + tg.grepStderr(`[\\/](compile|gccgo) `, "did not run compiler") + tg.grepStderr(`[\\/](link|gccgo) `, "did not run linker") + tg.grepStderr(`errors\.test`, "did not run test") + + tg.run("test", "-x", "errors") + tg.grepStdout(`ok \terrors\t\(cached\)`, "did not report cached result") + tg.grepStderrNot(`[\\/](compile|gccgo) `, "incorrectly ran compiler") + tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker") + tg.grepStderrNot(`errors\.test`, "incorrectly ran test") + tg.grepStderrNot("DO NOT USE", "poisoned action status leaked") + + // Even very low timeouts do not disqualify cached entries. + tg.run("test", "-timeout=1ns", "-x", "errors") + tg.grepStderrNot(`errors\.test`, "incorrectly ran test") + + tg.run("clean", "-testcache") + tg.run("test", "-x", "errors") + tg.grepStderr(`errors\.test`, "did not run test") + } + + // The -p=1 in the commands below just makes the -x output easier to read. + + t.Log("\n\nINITIAL\n\n") + + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 1\n") + tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\nvar X = 1\n") + tg.tempFile("src/t/t1/t1_test.go", "package t\nimport \"testing\"\nfunc Test1(*testing.T) {}\n") + tg.tempFile("src/t/t2/t2_test.go", "package t\nimport _ \"p1\"\nimport \"testing\"\nfunc Test2(*testing.T) {}\n") + tg.tempFile("src/t/t3/t3_test.go", "package t\nimport \"p1\"\nimport \"testing\"\nfunc Test3(t *testing.T) {t.Log(p1.X)}\n") + tg.tempFile("src/t/t4/t4_test.go", "package t\nimport \"p2\"\nimport \"testing\"\nfunc Test4(t *testing.T) {t.Log(p2.X)}") + tg.run("test", "-x", "-v", "-short", "t/...") + + t.Log("\n\nREPEAT\n\n") + + tg.run("test", "-x", "-v", "-short", "t/...") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t1") + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t2") + tg.grepStdout(`ok \tt/t3\t\(cached\)`, "did not cache t3") + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t4") + tg.grepStderrNot(`[\\/](compile|gccgo) `, "incorrectly ran compiler") + tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker") + tg.grepStderrNot(`p[0-9]\.test`, "incorrectly ran test") + + t.Log("\n\nCOMMENT\n\n") + + // Changing the program text without affecting the compiled package + // should result in the package being rebuilt but nothing more. + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 01\n") + tg.run("test", "-p=1", "-x", "-v", "-short", "t/...") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t1") + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t2") + tg.grepStdout(`ok \tt/t3\t\(cached\)`, "did not cache t3") + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t4") + tg.grepStderrNot(`([\\/](compile|gccgo) ).*t[0-9]_test\.go`, "incorrectly ran compiler") + tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker") + tg.grepStderrNot(`t[0-9]\.test.*test\.short`, "incorrectly ran test") + + t.Log("\n\nCHANGE\n\n") + + // Changing the actual package should have limited effects. + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 02\n") + tg.run("test", "-p=1", "-x", "-v", "-short", "t/...") + + // p2 should have been rebuilt. + tg.grepStderr(`([\\/]compile|gccgo).*p2.go`, "did not recompile p2") + + // t1 does not import anything, should not have been rebuilt. + tg.grepStderrNot(`([\\/]compile|gccgo).*t1_test.go`, "incorrectly recompiled t1") + tg.grepStderrNot(`([\\/]link|gccgo).*t1_test`, "incorrectly relinked t1_test") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t/t1") + + // t2 imports p1 and must be rebuilt and relinked, + // but the change should not have any effect on the test binary, + // so the test should not have been rerun. + tg.grepStderr(`([\\/]compile|gccgo).*t2_test.go`, "did not recompile t2") + tg.grepStderr(`([\\/]link|gccgo).*t2\.test`, "did not relink t2_test") + // This check does not currently work with gccgo, as garbage + // collection of unused variables is not turned on by default. + if runtime.Compiler != "gccgo" { + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t/t2") + } + + // t3 imports p1, and changing X changes t3's test binary. + tg.grepStderr(`([\\/]compile|gccgo).*t3_test.go`, "did not recompile t3") + tg.grepStderr(`([\\/]link|gccgo).*t3\.test`, "did not relink t3_test") + tg.grepStderr(`t3\.test.*-test.short`, "did not rerun t3_test") + tg.grepStdoutNot(`ok \tt/t3\t\(cached\)`, "reported cached t3_test result") + + // t4 imports p2, but p2 did not change, so t4 should be relinked, not recompiled, + // and not rerun. + tg.grepStderrNot(`([\\/]compile|gccgo).*t4_test.go`, "incorrectly recompiled t4") + tg.grepStderr(`([\\/]link|gccgo).*t4\.test`, "did not relink t4_test") + // This check does not currently work with gccgo, as garbage + // collection of unused variables is not turned on by default. + if runtime.Compiler != "gccgo" { + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t/t4") + } +} + +func TestTestVet(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("p1_test.go", ` + package p + import "testing" + func Test(t *testing.T) { + t.Logf("%d") // oops + } + `) + + tg.runFail("test", filepath.Join(tg.tempdir, "p1_test.go")) + tg.grepStderr(`Logf format %d`, "did not diagnose bad Logf") + tg.run("test", "-vet=off", filepath.Join(tg.tempdir, "p1_test.go")) + tg.grepStdout(`^ok`, "did not print test summary") + + tg.tempFile("p1.go", ` + package p + import "fmt" + func F() { + fmt.Printf("%d") // oops + } + `) + tg.runFail("test", filepath.Join(tg.tempdir, "p1.go")) + tg.grepStderr(`Printf format %d`, "did not diagnose bad Printf") + tg.run("test", "-x", "-vet=shift", filepath.Join(tg.tempdir, "p1.go")) + tg.grepStderr(`[\\/]vet.*-shift`, "did not run vet with -shift") + tg.grepStdout(`\[no test files\]`, "did not print test summary") + tg.run("test", "-vet=off", filepath.Join(tg.tempdir, "p1.go")) + tg.grepStdout(`\[no test files\]`, "did not print test summary") + + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("test", "vetcycle") // must not fail; #22890 +} + +func TestInstallDeps(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 1\n") + tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\n") + tg.tempFile("src/main1/main.go", "package main\nimport _ \"p2\"\nfunc main() {}\n") + + tg.run("list", "-f={{.Target}}", "p1") + p1 := strings.TrimSpace(tg.getStdout()) + tg.run("list", "-f={{.Target}}", "p2") + p2 := strings.TrimSpace(tg.getStdout()) + tg.run("list", "-f={{.Target}}", "main1") + main1 := strings.TrimSpace(tg.getStdout()) + + tg.run("install", "main1") + + tg.mustExist(main1) + tg.mustNotExist(p2) + tg.mustNotExist(p1) + + tg.run("install", "p2") + tg.mustExist(p2) + tg.mustNotExist(p1) + + // don't let install -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before install -i") + + tg.run("install", "-i", "main1") + tg.mustExist(p1) + tg.must(os.Remove(p1)) + + tg.run("install", "-i", "p2") + tg.mustExist(p1) +} + +func TestFmtLoadErrors(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("fmt", "does-not-exist") + tg.run("fmt", "-n", "exclude") +} + +func TestRelativePkgdir(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOCACHE", "off") + tg.cd(tg.tempdir) + + tg.run("build", "-i", "-pkgdir=.", "runtime") +} + +func TestGcflagsPatterns(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", "") + tg.setenv("GOCACHE", "off") + + tg.run("build", "-v", "-gcflags= \t\r\n -e", "fmt") + tg.grepStderr("fmt", "did not rebuild fmt") + tg.grepStderrNot("reflect", "incorrectly rebuilt reflect") + + tg.run("build", "-v", "-gcflags=-e", "fmt", "reflect") + tg.grepStderr("fmt", "did not rebuild fmt") + tg.grepStderr("reflect", "did not rebuild reflect") + tg.grepStderrNot("runtime", "incorrectly rebuilt runtime") + + tg.run("build", "-x", "-v", "-gcflags= \t\r\n reflect \t\r\n = \t\r\n -N", "fmt") + tg.grepStderr("fmt", "did not rebuild fmt") + tg.grepStderr("reflect", "did not rebuild reflect") + tg.grepStderr("compile.* -N .*-p reflect", "did not build reflect with -N flag") + tg.grepStderrNot("compile.* -N .*-p fmt", "incorrectly built fmt with -N flag") + + tg.run("test", "-c", "-n", "-gcflags=-N", "strings") + tg.grepStderr("compile.* -N .*compare_test.go", "did not build strings_test package with -N flag") + + tg.run("test", "-c", "-n", "-gcflags=strings=-N", "strings") + tg.grepStderr("compile.* -N .*compare_test.go", "did not build strings_test package with -N flag") +} + +func TestGoTestMinusN(t *testing.T) { + // Intent here is to verify that 'go test -n' works without crashing. + // This reuses flag_test.go, but really any test would do. + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "testdata/flag_test.go", "-n", "-args", "-v=7") +} + +func TestGoTestJSON(t *testing.T) { + skipIfGccgo(t, "gccgo does not have standard packages") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + + // It would be nice to test that the output is interlaced + // but it seems to be impossible to do that in a short test + // that isn't also flaky. Just check that we get JSON output. + tg.run("test", "-json", "-short", "-v", "errors", "empty/pkg", "skipper") + tg.grepStdout(`"Package":"errors"`, "did not see JSON output") + tg.grepStdout(`"Action":"run"`, "did not see JSON output") + + tg.grepStdout(`"Action":"output","Package":"empty/pkg","Output":".*no test files`, "did not see no test files print") + tg.grepStdout(`"Action":"skip","Package":"empty/pkg"`, "did not see skip") + + tg.grepStdout(`"Action":"output","Package":"skipper","Test":"Test","Output":"--- SKIP:`, "did not see SKIP output") + tg.grepStdout(`"Action":"skip","Package":"skipper","Test":"Test"`, "did not see skip result for Test") + + tg.run("test", "-json", "-bench=NONE", "-short", "-v", "errors") + tg.grepStdout(`"Package":"errors"`, "did not see JSON output") + tg.grepStdout(`"Action":"run"`, "did not see JSON output") + + tg.run("test", "-o", filepath.Join(tg.tempdir, "errors.test.exe"), "-c", "errors") + tg.run("tool", "test2json", "-p", "errors", filepath.Join(tg.tempdir, "errors.test.exe"), "-test.v", "-test.short") + tg.grepStdout(`"Package":"errors"`, "did not see JSON output") + tg.grepStdout(`"Action":"run"`, "did not see JSON output") + tg.grepStdout(`\{"Action":"pass","Package":"errors"\}`, "did not see final pass") +} + +func TestFailFast(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + + tests := []struct { + run string + failfast bool + nfail int + }{ + {"TestFailingA", true, 1}, + {"TestFailing[AB]", true, 1}, + {"TestFailing[AB]", false, 2}, + // mix with non-failing tests: + {"TestA|TestFailing[AB]", true, 1}, + {"TestA|TestFailing[AB]", false, 2}, + // mix with parallel tests: + {"TestFailingB|TestParallelFailingA", true, 2}, + {"TestFailingB|TestParallelFailingA", false, 2}, + {"TestFailingB|TestParallelFailing[AB]", true, 3}, + {"TestFailingB|TestParallelFailing[AB]", false, 3}, + // mix with parallel sub-tests + {"TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA", true, 3}, + {"TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA", false, 5}, + {"TestParallelFailingSubtestsA", true, 1}, + // only parallels: + {"TestParallelFailing[AB]", false, 2}, + // non-parallel subtests: + {"TestFailingSubtestsA", true, 1}, + {"TestFailingSubtestsA", false, 2}, + } + + for _, tt := range tests { + t.Run(tt.run, func(t *testing.T) { + tg.runFail("test", "./testdata/src/failfast_test.go", "-run="+tt.run, "-failfast="+strconv.FormatBool(tt.failfast)) + + nfail := strings.Count(tg.getStdout(), "FAIL - ") + + if nfail != tt.nfail { + t.Errorf("go test -run=%s -failfast=%t printed %d FAILs, want %d", tt.run, tt.failfast, nfail, tt.nfail) + } + }) + } +} diff --git a/libgo/go/cmd/go/go_windows_test.go b/libgo/go/cmd/go/go_windows_test.go index d8d04aaf497..aa68a195802 100644 --- a/libgo/go/cmd/go/go_windows_test.go +++ b/libgo/go/cmd/go/go_windows_test.go @@ -5,12 +5,14 @@ package main import ( + "fmt" "internal/testenv" "io/ioutil" "os" "os/exec" "path/filepath" "strings" + "syscall" "testing" ) @@ -54,3 +56,82 @@ func TestAbsolutePath(t *testing.T) { t.Fatalf("wrong output found: %v %v", err, string(output)) } } + +func isWindowsXP(t *testing.T) bool { + v, err := syscall.GetVersion() + if err != nil { + t.Fatalf("GetVersion failed: %v", err) + } + major := byte(v) + return major < 6 +} + +func runIcacls(t *testing.T, args ...string) string { + t.Helper() + out, err := exec.Command("icacls", args...).CombinedOutput() + if err != nil { + t.Fatalf("icacls failed: %v\n%v", err, string(out)) + } + return string(out) +} + +func runGetACL(t *testing.T, path string) string { + t.Helper() + cmd := fmt.Sprintf(`Get-Acl "%s" | Select -expand AccessToString`, path) + out, err := exec.Command("powershell", "-Command", cmd).CombinedOutput() + if err != nil { + t.Fatalf("Get-Acl failed: %v\n%v", err, string(out)) + } + return string(out) +} + +// For issue 22343: verify that executable file created by "go build" command +// has discretionary access control list (DACL) set as if the file +// was created in the destination directory. +func TestACL(t *testing.T) { + if isWindowsXP(t) { + t.Skip("Windows XP does not have powershell command") + } + + tmpdir, err := ioutil.TempDir("", "TestACL") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + newtmpdir := filepath.Join(tmpdir, "tmp") + err = os.Mkdir(newtmpdir, 0777) + if err != nil { + t.Fatal(err) + } + + // When TestACL/tmp directory is created, it will have + // the same security attributes as TestACL. + // Add Guest account full access to TestACL/tmp - this + // will make all files created in TestACL/tmp have different + // security attributes to the files created in TestACL. + runIcacls(t, newtmpdir, + "/grant", "guest:(oi)(ci)f", // add Guest user to have full access + ) + + src := filepath.Join(tmpdir, "main.go") + err = ioutil.WriteFile(src, []byte("package main; func main() { }\n"), 0644) + if err != nil { + t.Fatal(err) + } + exe := filepath.Join(tmpdir, "main.exe") + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src) + cmd.Env = append(os.Environ(), + "TMP="+newtmpdir, + "TEMP="+newtmpdir, + ) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("go command failed: %v\n%v", err, string(out)) + } + + // exe file is expected to have the same security attributes as the src. + if got, expected := runGetACL(t, exe), runGetACL(t, src); got != expected { + t.Fatalf("expected Get-Acl output of \n%v\n, got \n%v\n", expected, got) + } +} diff --git a/libgo/go/cmd/go/internal/base/base.go b/libgo/go/cmd/go/internal/base/base.go index aff33f70d8d..286efbc0410 100644 --- a/libgo/go/cmd/go/internal/base/base.go +++ b/libgo/go/cmd/go/internal/base/base.go @@ -62,8 +62,8 @@ func (c *Command) Name() string { } func (c *Command) Usage() { - fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine) - fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long)) + fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine) + fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.Name()) os.Exit(2) } diff --git a/libgo/go/cmd/go/internal/base/path.go b/libgo/go/cmd/go/internal/base/path.go index 4f12fa8c28c..7a51181c973 100644 --- a/libgo/go/cmd/go/internal/base/path.go +++ b/libgo/go/cmd/go/internal/base/path.go @@ -44,28 +44,6 @@ func RelPaths(paths []string) []string { return out } -// FilterDotUnderscoreFiles returns a slice containing all elements -// of path whose base name doesn't begin with "." or "_". -func FilterDotUnderscoreFiles(path []string) []string { - var out []string // lazily initialized - for i, p := range path { - base := filepath.Base(p) - if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") { - if out == nil { - out = append(make([]string, 0, len(path)), path[:i]...) - } - continue - } - if out != nil { - out = append(out, p) - } - } - if out == nil { - return path - } - return out -} - // IsTestFile reports whether the source file is a set of tests and should therefore // be excluded from coverage analysis. func IsTestFile(file string) bool { diff --git a/libgo/go/cmd/go/internal/base/tool.go b/libgo/go/cmd/go/internal/base/tool.go index c907772c00a..d0da65e03ce 100644 --- a/libgo/go/cmd/go/internal/base/tool.go +++ b/libgo/go/cmd/go/internal/base/tool.go @@ -36,18 +36,9 @@ func Tool(toolName string) string { } // Give a nice message if there is no tool with that name. if _, err := os.Stat(toolPath); err != nil { - if isInGoToolsRepo(toolName) { - fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName) - } else { - fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) - } + fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) SetExitStatus(2) Exit() } return toolPath } - -// TODO: Delete. -func isInGoToolsRepo(toolName string) bool { - return false -} diff --git a/libgo/go/cmd/go/internal/cache/cache.go b/libgo/go/cmd/go/internal/cache/cache.go new file mode 100644 index 00000000000..794d63d20b0 --- /dev/null +++ b/libgo/go/cmd/go/internal/cache/cache.go @@ -0,0 +1,453 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cache implements a build artifact cache. +package cache + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "time" +) + +// An ActionID is a cache action key, the hash of a complete description of a +// repeatable computation (command line, environment variables, +// input file contents, executable contents). +type ActionID [HashSize]byte + +// An OutputID is a cache output key, the hash of an output of a computation. +type OutputID [HashSize]byte + +// A Cache is a package cache, backed by a file system directory tree. +type Cache struct { + dir string + log *os.File + now func() time.Time +} + +// Open opens and returns the cache in the given directory. +// +// It is safe for multiple processes on a single machine to use the +// same cache directory in a local file system simultaneously. +// They will coordinate using operating system file locks and may +// duplicate effort but will not corrupt the cache. +// +// However, it is NOT safe for multiple processes on different machines +// to share a cache directory (for example, if the directory were stored +// in a network file system). File locking is notoriously unreliable in +// network file systems and may not suffice to protect the cache. +// +func Open(dir string) (*Cache, error) { + info, err := os.Stat(dir) + if err != nil { + return nil, err + } + if !info.IsDir() { + return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} + } + for i := 0; i < 256; i++ { + name := filepath.Join(dir, fmt.Sprintf("%02x", i)) + if err := os.MkdirAll(name, 0777); err != nil { + return nil, err + } + } + f, err := os.OpenFile(filepath.Join(dir, "log.txt"), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + if err != nil { + return nil, err + } + c := &Cache{ + dir: dir, + log: f, + now: time.Now, + } + return c, nil +} + +// fileName returns the name of the file corresponding to the given id. +func (c *Cache) fileName(id [HashSize]byte, key string) string { + return filepath.Join(c.dir, fmt.Sprintf("%02x", id[0]), fmt.Sprintf("%x", id)+"-"+key) +} + +var errMissing = errors.New("cache entry not found") + +const ( + // action entry file is "v1 \n" + hexSize = HashSize * 2 + entrySize = 2 + 1 + hexSize + 1 + hexSize + 1 + 20 + 1 + 20 + 1 +) + +// verify controls whether to run the cache in verify mode. +// In verify mode, the cache always returns errMissing from Get +// but then double-checks in Put that the data being written +// exactly matches any existing entry. This provides an easy +// way to detect program behavior that would have been different +// had the cache entry been returned from Get. +// +// verify is enabled by setting the environment variable +// GODEBUG=gocacheverify=1. +var verify = false + +func init() { initEnv() } + +func initEnv() { + verify = false + debugHash = false + debug := strings.Split(os.Getenv("GODEBUG"), ",") + for _, f := range debug { + if f == "gocacheverify=1" { + verify = true + } + if f == "gocachehash=1" { + debugHash = true + } + } +} + +// Get looks up the action ID in the cache, +// returning the corresponding output ID and file size, if any. +// Note that finding an output ID does not guarantee that the +// saved file for that output ID is still available. +func (c *Cache) Get(id ActionID) (Entry, error) { + if verify { + return Entry{}, errMissing + } + return c.get(id) +} + +type Entry struct { + OutputID OutputID + Size int64 + Time time.Time +} + +// get is Get but does not respect verify mode, so that Put can use it. +func (c *Cache) get(id ActionID) (Entry, error) { + missing := func() (Entry, error) { + fmt.Fprintf(c.log, "%d miss %x\n", c.now().Unix(), id) + return Entry{}, errMissing + } + f, err := os.Open(c.fileName(id, "a")) + if err != nil { + return missing() + } + defer f.Close() + entry := make([]byte, entrySize+1) // +1 to detect whether f is too long + if n, err := io.ReadFull(f, entry); n != entrySize || err != io.ErrUnexpectedEOF { + return missing() + } + if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' { + return missing() + } + eid, entry := entry[3:3+hexSize], entry[3+hexSize:] + eout, entry := entry[1:1+hexSize], entry[1+hexSize:] + esize, entry := entry[1:1+20], entry[1+20:] + etime, entry := entry[1:1+20], entry[1+20:] + var buf [HashSize]byte + if _, err := hex.Decode(buf[:], eid); err != nil || buf != id { + return missing() + } + if _, err := hex.Decode(buf[:], eout); err != nil { + return missing() + } + i := 0 + for i < len(esize) && esize[i] == ' ' { + i++ + } + size, err := strconv.ParseInt(string(esize[i:]), 10, 64) + if err != nil || size < 0 { + return missing() + } + i = 0 + for i < len(etime) && etime[i] == ' ' { + i++ + } + tm, err := strconv.ParseInt(string(etime[i:]), 10, 64) + if err != nil || size < 0 { + return missing() + } + + fmt.Fprintf(c.log, "%d get %x\n", c.now().Unix(), id) + + c.used(c.fileName(id, "a")) + + return Entry{buf, size, time.Unix(0, tm)}, nil +} + +// GetBytes looks up the action ID in the cache and returns +// the corresponding output bytes. +// GetBytes should only be used for data that can be expected to fit in memory. +func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) { + entry, err := c.Get(id) + if err != nil { + return nil, entry, err + } + data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID)) + if sha256.Sum256(data) != entry.OutputID { + return nil, entry, errMissing + } + return data, entry, nil +} + +// OutputFile returns the name of the cache file storing output with the given OutputID. +func (c *Cache) OutputFile(out OutputID) string { + file := c.fileName(out, "d") + c.used(file) + return file +} + +// Time constants for cache expiration. +// +// We set the mtime on a cache file on each use, but at most one per mtimeInterval (1 hour), +// to avoid causing many unnecessary inode updates. The mtimes therefore +// roughly reflect "time of last use" but may in fact be older by at most an hour. +// +// We scan the cache for entries to delete at most once per trimInterval (1 day). +// +// When we do scan the cache, we delete entries that have not been used for +// at least trimLimit (5 days). Statistics gathered from a month of usage by +// Go developers found that essentially all reuse of cached entries happened +// within 5 days of the previous reuse. See golang.org/issue/22990. +const ( + mtimeInterval = 1 * time.Hour + trimInterval = 24 * time.Hour + trimLimit = 5 * 24 * time.Hour +) + +// used makes a best-effort attempt to update mtime on file, +// so that mtime reflects cache access time. +// +// Because the reflection only needs to be approximate, +// and to reduce the amount of disk activity caused by using +// cache entries, used only updates the mtime if the current +// mtime is more than an hour old. This heuristic eliminates +// nearly all of the mtime updates that would otherwise happen, +// while still keeping the mtimes useful for cache trimming. +func (c *Cache) used(file string) { + info, err := os.Stat(file) + if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval { + return + } + os.Chtimes(file, c.now(), c.now()) +} + +// Trim removes old cache entries that are likely not to be reused. +func (c *Cache) Trim() { + now := c.now() + + // We maintain in dir/trim.txt the time of the last completed cache trim. + // If the cache has been trimmed recently enough, do nothing. + // This is the common case. + data, _ := ioutil.ReadFile(filepath.Join(c.dir, "trim.txt")) + t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64) + if err == nil && now.Sub(time.Unix(t, 0)) < trimInterval { + return + } + + // Trim each of the 256 subdirectories. + // We subtract an additional mtimeInterval + // to account for the imprecision of our "last used" mtimes. + cutoff := now.Add(-trimLimit - mtimeInterval) + for i := 0; i < 256; i++ { + subdir := filepath.Join(c.dir, fmt.Sprintf("%02x", i)) + c.trimSubdir(subdir, cutoff) + } + + ioutil.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666) +} + +// trimSubdir trims a single cache subdirectory. +func (c *Cache) trimSubdir(subdir string, cutoff time.Time) { + // Read all directory entries from subdir before removing + // any files, in case removing files invalidates the file offset + // in the directory scan. Also, ignore error from f.Readdirnames, + // because we don't care about reporting the error and we still + // want to process any entries found before the error. + f, err := os.Open(subdir) + if err != nil { + return + } + names, _ := f.Readdirnames(-1) + f.Close() + + for _, name := range names { + // Remove only cache entries (xxxx-a and xxxx-d). + if !strings.HasSuffix(name, "-a") && !strings.HasSuffix(name, "-d") { + continue + } + entry := filepath.Join(subdir, name) + info, err := os.Stat(entry) + if err == nil && info.ModTime().Before(cutoff) { + os.Remove(entry) + } + } +} + +// putIndexEntry adds an entry to the cache recording that executing the action +// with the given id produces an output with the given output id (hash) and size. +func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify bool) error { + // Note: We expect that for one reason or another it may happen + // that repeating an action produces a different output hash + // (for example, if the output contains a time stamp or temp dir name). + // While not ideal, this is also not a correctness problem, so we + // don't make a big deal about it. In particular, we leave the action + // cache entries writable specifically so that they can be overwritten. + // + // Setting GODEBUG=gocacheverify=1 does make a big deal: + // in verify mode we are double-checking that the cache entries + // are entirely reproducible. As just noted, this may be unrealistic + // in some cases but the check is also useful for shaking out real bugs. + entry := []byte(fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano())) + if verify && allowVerify { + old, err := c.get(id) + if err == nil && (old.OutputID != out || old.Size != size) { + // panic to show stack trace, so we can see what code is generating this cache entry. + msg := fmt.Sprintf("go: internal cache error: cache verify failed: id=%x changed:<<<\n%s\n>>>\nold: %x %d\nnew: %x %d", id, reverseHash(id), out, size, old.OutputID, old.Size) + panic(msg) + } + } + file := c.fileName(id, "a") + if err := ioutil.WriteFile(file, entry, 0666); err != nil { + os.Remove(file) + return err + } + os.Chtimes(file, c.now(), c.now()) // mainly for tests + + fmt.Fprintf(c.log, "%d put %x %x %d\n", c.now().Unix(), id, out, size) + return nil +} + +// Put stores the given output in the cache as the output for the action ID. +// It may read file twice. The content of file must not change between the two passes. +func (c *Cache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error) { + return c.put(id, file, true) +} + +// PutNoVerify is like Put but disables the verify check +// when GODEBUG=goverifycache=1 is set. +// It is meant for data that is OK to cache but that we expect to vary slightly from run to run, +// like test output containing times and the like. +func (c *Cache) PutNoVerify(id ActionID, file io.ReadSeeker) (OutputID, int64, error) { + return c.put(id, file, false) +} + +func (c *Cache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) { + // Compute output ID. + h := sha256.New() + if _, err := file.Seek(0, 0); err != nil { + return OutputID{}, 0, err + } + size, err := io.Copy(h, file) + if err != nil { + return OutputID{}, 0, err + } + var out OutputID + h.Sum(out[:0]) + + // Copy to cached output file (if not already present). + if err := c.copyFile(file, out, size); err != nil { + return out, size, err + } + + // Add to cache index. + return out, size, c.putIndexEntry(id, out, size, allowVerify) +} + +// PutBytes stores the given bytes in the cache as the output for the action ID. +func (c *Cache) PutBytes(id ActionID, data []byte) error { + _, _, err := c.Put(id, bytes.NewReader(data)) + return err +} + +// copyFile copies file into the cache, expecting it to have the given +// output ID and size, if that file is not present already. +func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error { + name := c.fileName(out, "d") + info, err := os.Stat(name) + if err == nil && info.Size() == size { + // Check hash. + if f, err := os.Open(name); err == nil { + h := sha256.New() + io.Copy(h, f) + f.Close() + var out2 OutputID + h.Sum(out2[:0]) + if out == out2 { + return nil + } + } + // Hash did not match. Fall through and rewrite file. + } + + // Copy file to cache directory. + mode := os.O_RDWR | os.O_CREATE + if err == nil && info.Size() > size { // shouldn't happen but fix in case + mode |= os.O_TRUNC + } + f, err := os.OpenFile(name, mode, 0666) + if err != nil { + return err + } + defer f.Close() + if size == 0 { + // File now exists with correct size. + // Only one possible zero-length file, so contents are OK too. + // Early return here makes sure there's a "last byte" for code below. + return nil + } + + // From here on, if any of the I/O writing the file fails, + // we make a best-effort attempt to truncate the file f + // before returning, to avoid leaving bad bytes in the file. + + // Copy file to f, but also into h to double-check hash. + if _, err := file.Seek(0, 0); err != nil { + f.Truncate(0) + return err + } + h := sha256.New() + w := io.MultiWriter(f, h) + if _, err := io.CopyN(w, file, size-1); err != nil { + f.Truncate(0) + return err + } + // Check last byte before writing it; writing it will make the size match + // what other processes expect to find and might cause them to start + // using the file. + buf := make([]byte, 1) + if _, err := file.Read(buf); err != nil { + f.Truncate(0) + return err + } + h.Write(buf) + sum := h.Sum(nil) + if !bytes.Equal(sum, out[:]) { + f.Truncate(0) + return fmt.Errorf("file content changed underfoot") + } + + // Commit cache file entry. + if _, err := f.Write(buf); err != nil { + f.Truncate(0) + return err + } + if err := f.Close(); err != nil { + // Data might not have been written, + // but file may look like it is the right size. + // To be extra careful, remove cached file. + os.Remove(name) + return err + } + os.Chtimes(name, c.now(), c.now()) // mainly for tests + + return nil +} diff --git a/libgo/go/cmd/go/internal/cache/cache_test.go b/libgo/go/cmd/go/internal/cache/cache_test.go new file mode 100644 index 00000000000..d3dafccd137 --- /dev/null +++ b/libgo/go/cmd/go/internal/cache/cache_test.go @@ -0,0 +1,319 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cache + +import ( + "bytes" + "encoding/binary" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" +) + +func init() { + verify = false // even if GODEBUG is set +} + +func TestBasic(t *testing.T) { + dir, err := ioutil.TempDir("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + _, err = Open(filepath.Join(dir, "notexist")) + if err == nil { + t.Fatal(`Open("tmp/notexist") succeeded, want failure`) + } + + cdir := filepath.Join(dir, "c1") + if err := os.Mkdir(cdir, 0777); err != nil { + t.Fatal(err) + } + + c1, err := Open(cdir) + if err != nil { + t.Fatalf("Open(c1) (create): %v", err) + } + if err := c1.putIndexEntry(dummyID(1), dummyID(12), 13, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + if err := c1.putIndexEntry(dummyID(1), dummyID(2), 3, true); err != nil { // overwrite entry + t.Fatalf("addIndexEntry: %v", err) + } + if entry, err := c1.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { + t.Fatalf("c1.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) + } + + c2, err := Open(cdir) + if err != nil { + t.Fatalf("Open(c2) (reuse): %v", err) + } + if entry, err := c2.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { + t.Fatalf("c2.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) + } + if err := c2.putIndexEntry(dummyID(2), dummyID(3), 4, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + if entry, err := c1.Get(dummyID(2)); err != nil || entry.OutputID != dummyID(3) || entry.Size != 4 { + t.Fatalf("c1.Get(2) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(3), 4) + } +} + +func TestGrowth(t *testing.T) { + dir, err := ioutil.TempDir("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + + n := 10000 + if testing.Short() { + n = 1000 + } + + for i := 0; i < n; i++ { + if err := c.putIndexEntry(dummyID(i), dummyID(i*99), int64(i)*101, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + id := ActionID(dummyID(i)) + entry, err := c.Get(id) + if err != nil { + t.Fatalf("Get(%x): %v", id, err) + } + if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { + t.Errorf("Get(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) + } + } + for i := 0; i < n; i++ { + id := ActionID(dummyID(i)) + entry, err := c.Get(id) + if err != nil { + t.Fatalf("Get2(%x): %v", id, err) + } + if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { + t.Errorf("Get2(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) + } + } +} + +func TestVerifyPanic(t *testing.T) { + os.Setenv("GODEBUG", "gocacheverify=1") + initEnv() + defer func() { + os.Unsetenv("GODEBUG") + verify = false + }() + + if !verify { + t.Fatal("initEnv did not set verify") + } + + dir, err := ioutil.TempDir("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + + id := ActionID(dummyID(1)) + if err := c.PutBytes(id, []byte("abc")); err != nil { + t.Fatal(err) + } + + defer func() { + if err := recover(); err != nil { + t.Log(err) + return + } + }() + c.PutBytes(id, []byte("def")) + t.Fatal("mismatched Put did not panic in verify mode") +} + +func TestCacheLog(t *testing.T) { + dir, err := ioutil.TempDir("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + c.now = func() time.Time { return time.Unix(1e9, 0) } + + id := ActionID(dummyID(1)) + c.Get(id) + c.PutBytes(id, []byte("abc")) + c.Get(id) + + c, err = Open(dir) + if err != nil { + t.Fatalf("Open #2: %v", err) + } + c.now = func() time.Time { return time.Unix(1e9+1, 0) } + c.Get(id) + + id2 := ActionID(dummyID(2)) + c.Get(id2) + c.PutBytes(id2, []byte("abc")) + c.Get(id2) + c.Get(id) + + data, err := ioutil.ReadFile(filepath.Join(dir, "log.txt")) + if err != nil { + t.Fatal(err) + } + want := `1000000000 miss 0100000000000000000000000000000000000000000000000000000000000000 +1000000000 put 0100000000000000000000000000000000000000000000000000000000000000 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 3 +1000000000 get 0100000000000000000000000000000000000000000000000000000000000000 +1000000001 get 0100000000000000000000000000000000000000000000000000000000000000 +1000000001 miss 0200000000000000000000000000000000000000000000000000000000000000 +1000000001 put 0200000000000000000000000000000000000000000000000000000000000000 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad 3 +1000000001 get 0200000000000000000000000000000000000000000000000000000000000000 +1000000001 get 0100000000000000000000000000000000000000000000000000000000000000 +` + if string(data) != want { + t.Fatalf("log:\n%s\nwant:\n%s", string(data), want) + } +} + +func dummyID(x int) [HashSize]byte { + var out [HashSize]byte + binary.LittleEndian.PutUint64(out[:], uint64(x)) + return out +} + +func TestCacheTrim(t *testing.T) { + dir, err := ioutil.TempDir("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + const start = 1000000000 + now := int64(start) + c.now = func() time.Time { return time.Unix(now, 0) } + + checkTime := func(name string, mtime int64) { + t.Helper() + file := filepath.Join(c.dir, name[:2], name) + info, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } + if info.ModTime().Unix() != mtime { + t.Fatalf("%s mtime = %d, want %d", name, info.ModTime().Unix(), mtime) + } + } + + id := ActionID(dummyID(1)) + c.PutBytes(id, []byte("abc")) + entry, _ := c.Get(id) + c.PutBytes(ActionID(dummyID(2)), []byte("def")) + mtime := now + checkTime(fmt.Sprintf("%x-a", id), mtime) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) + + // Get should not change recent mtimes. + now = start + 10 + c.Get(id) + checkTime(fmt.Sprintf("%x-a", id), mtime) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) + + // Get should change distant mtimes. + now = start + 5000 + mtime2 := now + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + checkTime(fmt.Sprintf("%x-a", id), mtime2) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime2) + + // Trim should leave everything alone: it's all too new. + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + data, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) + if err != nil { + t.Fatal(err) + } + checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) + + // Trim less than a day later should not do any work at all. + now = start + 80000 + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + data2, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(data, data2) { + t.Fatalf("second trim did work: %q -> %q", data, data2) + } + + // Fast forward and do another trim just before the 5 day cutoff. + // Note that because of usedQuantum the cutoff is actually 5 days + 1 hour. + // We used c.Get(id) just now, so 5 days later it should still be kept. + // On the other hand almost a full day has gone by since we wrote dummyID(2) + // and we haven't looked at it since, so 5 days later it should be gone. + now += 5 * 86400 + checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + mtime3 := now + if _, err := c.Get(dummyID(2)); err == nil { // haven't done a Get for this since original write above + t.Fatalf("Trim did not remove dummyID(2)") + } + + // The c.Get(id) refreshed id's mtime again. + // Check that another 5 days later it is still not gone, + // but check by using checkTime, which doesn't bring mtime forward. + now += 5 * 86400 + c.Trim() + checkTime(fmt.Sprintf("%x-a", id), mtime3) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) + + // Half a day later Trim should still be a no-op, because there was a Trim recently. + // Even though the entry for id is now old enough to be trimmed, + // it gets a reprieve until the time comes for a new Trim scan. + now += 86400 / 2 + c.Trim() + checkTime(fmt.Sprintf("%x-a", id), mtime3) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) + + // Another half a day later, Trim should actually run, and it should remove id. + now += 86400/2 + 1 + c.Trim() + if _, err := c.Get(dummyID(1)); err == nil { + t.Fatal("Trim did not remove dummyID(1)") + } +} diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go new file mode 100644 index 00000000000..6411ec7a563 --- /dev/null +++ b/libgo/go/cmd/go/internal/cache/default.go @@ -0,0 +1,100 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cache + +import ( + "cmd/go/internal/base" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sync" +) + +// Default returns the default cache to use, or nil if no cache should be used. +func Default() *Cache { + defaultOnce.Do(initDefaultCache) + return defaultCache +} + +var ( + defaultOnce sync.Once + defaultCache *Cache +) + +// cacheREADME is a message stored in a README in the cache directory. +// Because the cache lives outside the normal Go trees, we leave the +// README as a courtesy to explain where it came from. +const cacheREADME = `This directory holds cached build artifacts from the Go build system. +Run "go clean -cache" if the directory is getting too large. +See golang.org to learn more about Go. +` + +// initDefaultCache does the work of finding the default cache +// the first time Default is called. +func initDefaultCache() { + dir := DefaultDir() + if dir == "off" { + return + } + if err := os.MkdirAll(dir, 0777); err != nil { + base.Fatalf("initializing cache in $GOCACHE: %s", err) + } + if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { + // Best effort. + ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666) + } + + c, err := Open(dir) + if err != nil { + base.Fatalf("initializing cache in $GOCACHE: %s", err) + } + defaultCache = c +} + +// DefaultDir returns the effective GOCACHE setting. +// It returns "off" if the cache is disabled. +func DefaultDir() string { + dir := os.Getenv("GOCACHE") + if dir != "" { + return dir + } + + // Compute default location. + // TODO(rsc): This code belongs somewhere else, + // like maybe ioutil.CacheDir or os.CacheDir. + switch runtime.GOOS { + case "windows": + dir = os.Getenv("LocalAppData") + + case "darwin": + dir = os.Getenv("HOME") + if dir == "" { + return "off" + } + dir += "/Library/Caches" + + case "plan9": + dir = os.Getenv("home") + if dir == "" { + return "off" + } + // Plan 9 has no established per-user cache directory, + // but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix. + dir += "/lib/cache" + + default: // Unix + // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + dir = os.Getenv("XDG_CACHE_HOME") + if dir == "" { + dir = os.Getenv("HOME") + if dir == "" { + return "off" + } + dir += "/.cache" + } + } + return filepath.Join(dir, "go-build") +} diff --git a/libgo/go/cmd/go/internal/cache/hash.go b/libgo/go/cmd/go/internal/cache/hash.go new file mode 100644 index 00000000000..0e45e7db547 --- /dev/null +++ b/libgo/go/cmd/go/internal/cache/hash.go @@ -0,0 +1,174 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cache + +import ( + "bytes" + "crypto/sha256" + "fmt" + "hash" + "io" + "os" + "runtime" + "sync" +) + +var debugHash = false // set when GODEBUG=gocachehash=1 + +// HashSize is the number of bytes in a hash. +const HashSize = 32 + +// A Hash provides access to the canonical hash function used to index the cache. +// The current implementation uses salted SHA256, but clients must not assume this. +type Hash struct { + h hash.Hash + name string // for debugging + buf *bytes.Buffer // for verify +} + +// hashSalt is a salt string added to the beginning of every hash +// created by NewHash. Using the Go version makes sure that different +// versions of the go command (or even different Git commits during +// work on the development branch) do not address the same cache +// entries, so that a bug in one version does not affect the execution +// of other versions. This salt will result in additional ActionID files +// in the cache, but not additional copies of the large output files, +// which are still addressed by unsalted SHA256. +var hashSalt = []byte(runtime.Version()) + +// Subkey returns an action ID corresponding to mixing a parent +// action ID with a string description of the subkey. +func Subkey(parent ActionID, desc string) ActionID { + h := sha256.New() + h.Write([]byte("subkey:")) + h.Write(parent[:]) + h.Write([]byte(desc)) + var out ActionID + h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out) + } + if verify { + hashDebug.Lock() + hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc) + hashDebug.Unlock() + } + return out +} + +// NewHash returns a new Hash. +// The caller is expected to Write data to it and then call Sum. +func NewHash(name string) *Hash { + h := &Hash{h: sha256.New(), name: name} + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name) + } + h.Write(hashSalt) + if verify { + h.buf = new(bytes.Buffer) + } + return h +} + +// Write writes data to the running hash. +func (h *Hash) Write(b []byte) (int, error) { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b) + } + if h.buf != nil { + h.buf.Write(b) + } + return h.h.Write(b) +} + +// Sum returns the hash of the data written previously. +func (h *Hash) Sum() [HashSize]byte { + var out [HashSize]byte + h.h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out) + } + if h.buf != nil { + hashDebug.Lock() + if hashDebug.m == nil { + hashDebug.m = make(map[[HashSize]byte]string) + } + hashDebug.m[out] = h.buf.String() + hashDebug.Unlock() + } + return out +} + +// In GODEBUG=gocacheverify=1 mode, +// hashDebug holds the input to every computed hash ID, +// so that we can work backward from the ID involved in a +// cache entry mismatch to a description of what should be there. +var hashDebug struct { + sync.Mutex + m map[[HashSize]byte]string +} + +// reverseHash returns the input used to compute the hash id. +func reverseHash(id [HashSize]byte) string { + hashDebug.Lock() + s := hashDebug.m[id] + hashDebug.Unlock() + return s +} + +var hashFileCache struct { + sync.Mutex + m map[string][HashSize]byte +} + +// HashFile returns the hash of the named file. +// It caches repeated lookups for a given file, +// and the cache entry for a file can be initialized +// using SetFileHash. +// The hash used by FileHash is not the same as +// the hash used by NewHash. +func FileHash(file string) ([HashSize]byte, error) { + hashFileCache.Lock() + out, ok := hashFileCache.m[file] + hashFileCache.Unlock() + + if ok { + return out, nil + } + + h := sha256.New() + f, err := os.Open(file) + if err != nil { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err) + } + return [HashSize]byte{}, err + } + _, err = io.Copy(h, f) + f.Close() + if err != nil { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err) + } + return [HashSize]byte{}, err + } + h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out) + } + + SetFileHash(file, out) + return out, nil +} + +// SetFileHash sets the hash returned by FileHash for file. +func SetFileHash(file string, sum [HashSize]byte) { + hashFileCache.Lock() + if hashFileCache.m == nil { + hashFileCache.m = make(map[string][HashSize]byte) + } + hashFileCache.m[file] = sum + hashFileCache.Unlock() +} diff --git a/libgo/go/cmd/go/internal/cache/hash_test.go b/libgo/go/cmd/go/internal/cache/hash_test.go new file mode 100644 index 00000000000..3bf7143039c --- /dev/null +++ b/libgo/go/cmd/go/internal/cache/hash_test.go @@ -0,0 +1,52 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cache + +import ( + "fmt" + "io/ioutil" + "os" + "testing" +) + +func TestHash(t *testing.T) { + oldSalt := hashSalt + hashSalt = nil + defer func() { + hashSalt = oldSalt + }() + + h := NewHash("alice") + h.Write([]byte("hello world")) + sum := fmt.Sprintf("%x", h.Sum()) + want := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" + if sum != want { + t.Errorf("hash(hello world) = %v, want %v", sum, want) + } +} + +func TestHashFile(t *testing.T) { + f, err := ioutil.TempFile("", "cmd-go-test-") + if err != nil { + t.Fatal(err) + } + name := f.Name() + fmt.Fprintf(f, "hello world") + defer os.Remove(name) + if err := f.Close(); err != nil { + t.Fatal(err) + } + + var h ActionID // make sure hash result is assignable to ActionID + h, err = FileHash(name) + if err != nil { + t.Fatal(err) + } + sum := fmt.Sprintf("%x", h) + want := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" + if sum != want { + t.Errorf("hash(hello world) = %v, want %v", sum, want) + } +} diff --git a/libgo/go/cmd/go/internal/cfg/cfg.go b/libgo/go/cmd/go/internal/cfg/cfg.go index 8257a0e5116..45161ae26b7 100644 --- a/libgo/go/cmd/go/internal/cfg/cfg.go +++ b/libgo/go/cmd/go/internal/cfg/cfg.go @@ -22,7 +22,6 @@ var ( BuildBuildmode string // -buildmode flag BuildContext = build.Default BuildI bool // -i flag - BuildLdflags []string // -ldflags flag BuildLinkshared bool // -linkshared flag BuildMSan bool // -msan flag BuildN bool // -n flag @@ -37,6 +36,10 @@ var ( BuildV bool // -v flag BuildWork bool // -work flag BuildX bool // -x flag + + CmdName string // "build", "install", "list", etc. + + DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable) ) func init() { @@ -80,8 +83,9 @@ var ( GOROOTsrc = filepath.Join(GOROOT, "src") // Used in envcmd.MkEnv and build ID computations. - GOARM = fmt.Sprint(objabi.GOARM) - GO386 = objabi.GO386 + GOARM = fmt.Sprint(objabi.GOARM) + GO386 = objabi.GO386 + GOMIPS = objabi.GOMIPS ) // Update build context to use our computed GOROOT. @@ -100,24 +104,44 @@ func findGOROOT() string { if env := os.Getenv("GOROOT"); env != "" { return filepath.Clean(env) } - if runtime.Compiler != "gccgo" { - exe, err := os.Executable() + def := filepath.Clean(runtime.GOROOT()) + if runtime.Compiler == "gccgo" { + return def + } + exe, err := os.Executable() + if err == nil { + exe, err = filepath.Abs(exe) if err == nil { - exe, err = filepath.Abs(exe) + if dir := filepath.Join(exe, "../.."); isGOROOT(dir) { + // If def (runtime.GOROOT()) and dir are the same + // directory, prefer the spelling used in def. + if isSameDir(def, dir) { + return def + } + return dir + } + exe, err = filepath.EvalSymlinks(exe) if err == nil { if dir := filepath.Join(exe, "../.."); isGOROOT(dir) { - return dir - } - exe, err = filepath.EvalSymlinks(exe) - if err == nil { - if dir := filepath.Join(exe, "../.."); isGOROOT(dir) { - return dir + if isSameDir(def, dir) { + return def } + return dir } } } } - return filepath.Clean(runtime.GOROOT()) + return def +} + +// isSameDir reports whether dir1 and dir2 are the same directory. +func isSameDir(dir1, dir2 string) bool { + if dir1 == dir2 { + return true + } + info1, err1 := os.Stat(dir1) + info2, err2 := os.Stat(dir2) + return err1 == nil && err2 == nil && os.SameFile(info1, info2) } // isGOROOT reports whether path looks like a GOROOT. diff --git a/libgo/go/cmd/go/internal/clean/clean.go b/libgo/go/cmd/go/internal/clean/clean.go index 454cac1f47b..fa5af944af6 100644 --- a/libgo/go/cmd/go/internal/clean/clean.go +++ b/libgo/go/cmd/go/internal/clean/clean.go @@ -11,16 +11,18 @@ import ( "os" "path/filepath" "strings" + "time" "cmd/go/internal/base" + "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/work" ) var CmdClean = &base.Command{ - UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]", - Short: "remove object files", + UsageLine: "clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages]", + Short: "remove object files and cached files", Long: ` Clean removes object files from package source directories. The go command builds most objects in a temporary directory, @@ -58,14 +60,23 @@ dependencies of the packages named by the import paths. The -x flag causes clean to print remove commands as it executes them. +The -cache flag causes clean to remove the entire go build cache. + +The -testcache flag causes clean to expire all test results in the +go build cache. + For more about build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. `, } -var cleanI bool // clean -i flag -var cleanR bool // clean -r flag +var ( + cleanI bool // clean -i flag + cleanR bool // clean -r flag + cleanCache bool // clean -cache flag + cleanTestcache bool // clean -testcache flag +) func init() { // break init cycle @@ -73,6 +84,9 @@ func init() { CmdClean.Flag.BoolVar(&cleanI, "i", false, "") CmdClean.Flag.BoolVar(&cleanR, "r", false, "") + CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "") + CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "") + // -n and -x are important enough to be // mentioned explicitly in the docs but they // are part of the build flags. @@ -84,6 +98,46 @@ func runClean(cmd *base.Command, args []string) { for _, pkg := range load.PackagesAndErrors(args) { clean(pkg) } + + if cleanCache { + var b work.Builder + b.Print = fmt.Print + dir := cache.DefaultDir() + if dir != "off" { + // Remove the cache subdirectories but not the top cache directory. + // The top cache directory may have been created with special permissions + // and not something that we want to remove. Also, we'd like to preserve + // the access log for future analysis, even if the cache is cleared. + subdirs, _ := filepath.Glob(filepath.Join(dir, "[0-9a-f][0-9a-f]")) + if len(subdirs) > 0 { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "rm -r %s", strings.Join(subdirs, " ")) + } + printedErrors := false + for _, d := range subdirs { + // Only print the first error - there may be many. + // This also mimics what os.RemoveAll(dir) would do. + if err := os.RemoveAll(d); err != nil && !printedErrors { + printedErrors = true + base.Errorf("go clean -cache: %v", err) + } + } + } + } + } + + if cleanTestcache && !cleanCache { + // Instead of walking through the entire cache looking for test results, + // we write a file to the cache indicating that all test results from before + // right now are to be ignored. + dir := cache.DefaultDir() + if dir != "off" { + err := ioutil.WriteFile(filepath.Join(dir, "testexpire.txt"), []byte(fmt.Sprintf("%d\n", time.Now().UnixNano())), 0666) + if err != nil { + base.Errorf("go clean -testcache: %v", err) + } + } + } } var cleaned = map[*load.Package]bool{} @@ -213,12 +267,12 @@ func clean(p *load.Package) { } } - if cleanI && p.Internal.Target != "" { + if cleanI && p.Target != "" { if cfg.BuildN || cfg.BuildX { - b.Showcmd("", "rm -f %s", p.Internal.Target) + b.Showcmd("", "rm -f %s", p.Target) } if !cfg.BuildN { - removeFile(p.Internal.Target) + removeFile(p.Target) } } diff --git a/libgo/go/cmd/go/internal/envcmd/env.go b/libgo/go/cmd/go/internal/envcmd/env.go index 43d4334f060..fa19bebe218 100644 --- a/libgo/go/cmd/go/internal/envcmd/env.go +++ b/libgo/go/cmd/go/internal/envcmd/env.go @@ -13,6 +13,7 @@ import ( "strings" "cmd/go/internal/base" + "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/work" @@ -31,6 +32,8 @@ each named variable on its own line. The -json flag prints the environment in JSON format instead of as a shell script. + +For more about environment variables, see 'go help environment'. `, } @@ -47,6 +50,7 @@ func MkEnv() []cfg.EnvVar { env := []cfg.EnvVar{ {Name: "GOARCH", Value: cfg.Goarch}, {Name: "GOBIN", Value: cfg.GOBIN}, + {Name: "GOCACHE", Value: cache.DefaultDir()}, {Name: "GOEXE", Value: cfg.ExeSuffix}, {Name: "GOHOSTARCH", Value: runtime.GOARCH}, {Name: "GOHOSTOS", Value: runtime.GOOS}, @@ -54,6 +58,7 @@ func MkEnv() []cfg.EnvVar { {Name: "GOPATH", Value: cfg.BuildContext.GOPATH}, {Name: "GORACE", Value: os.Getenv("GORACE")}, {Name: "GOROOT", Value: cfg.GOROOT}, + {Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")}, {Name: "GOTOOLDIR", Value: base.ToolDir}, // disable escape codes in clang errors @@ -71,13 +76,20 @@ func MkEnv() []cfg.EnvVar { env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM}) case "386": env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386}) + case "mips", "mipsle": + env = append(env, cfg.EnvVar{Name: "GOMIPS", Value: cfg.GOMIPS}) } - cmd := b.GccCmd(".") - env = append(env, cfg.EnvVar{Name: "CC", Value: cmd[0]}) - env = append(env, cfg.EnvVar{Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")}) - cmd = b.GxxCmd(".") - env = append(env, cfg.EnvVar{Name: "CXX", Value: cmd[0]}) + cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch) + if env := strings.Fields(os.Getenv("CC")); len(env) > 0 { + cc = env[0] + } + cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch) + if env := strings.Fields(os.Getenv("CXX")); len(env) > 0 { + cxx = env[0] + } + env = append(env, cfg.EnvVar{Name: "CC", Value: cc}) + env = append(env, cfg.EnvVar{Name: "CXX", Value: cxx}) if cfg.BuildContext.CgoEnabled { env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"}) @@ -102,19 +114,45 @@ func ExtraEnvVars() []cfg.EnvVar { var b work.Builder b.Init() cppflags, cflags, cxxflags, fflags, ldflags := b.CFlags(&load.Package{}) + cmd := b.GccCmd(".", "") return []cfg.EnvVar{ + // Note: Update the switch in runEnv below when adding to this list. {Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")}, {Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")}, {Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")}, {Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")}, {Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")}, {Name: "PKG_CONFIG", Value: b.PkgconfigCmd()}, + {Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")}, } } func runEnv(cmd *base.Command, args []string) { env := cfg.CmdEnv - env = append(env, ExtraEnvVars()...) + + // Do we need to call ExtraEnvVars, which is a bit expensive? + // Only if we're listing all environment variables ("go env") + // or the variables being requested are in the extra list. + needExtra := true + if len(args) > 0 { + needExtra = false + for _, arg := range args { + switch arg { + case "CGO_CFLAGS", + "CGO_CPPFLAGS", + "CGO_CXXFLAGS", + "CGO_FFLAGS", + "CGO_LDFLAGS", + "PKG_CONFIG", + "GOGCCFLAGS": + needExtra = true + } + } + } + if needExtra { + env = append(env, ExtraEnvVars()...) + } + if len(args) > 0 { if *envJson { var es []cfg.EnvVar diff --git a/libgo/go/cmd/go/internal/fix/fix.go b/libgo/go/cmd/go/internal/fix/fix.go index 788d49bcb60..99c7ca51acf 100644 --- a/libgo/go/cmd/go/internal/fix/fix.go +++ b/libgo/go/cmd/go/internal/fix/fix.go @@ -15,7 +15,7 @@ import ( var CmdFix = &base.Command{ Run: runFix, UsageLine: "fix [packages]", - Short: "run go tool fix on packages", + Short: "update packages to use new APIs", Long: ` Fix runs the Go fix command on the packages named by the import paths. @@ -33,7 +33,7 @@ func runFix(cmd *base.Command, args []string) { // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles)) + files := base.RelPaths(pkg.InternalAllGoFiles()) base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files)) } } diff --git a/libgo/go/cmd/go/internal/fmtcmd/fmt.go b/libgo/go/cmd/go/internal/fmtcmd/fmt.go index 0563a0410b3..eb96823fa6a 100644 --- a/libgo/go/cmd/go/internal/fmtcmd/fmt.go +++ b/libgo/go/cmd/go/internal/fmtcmd/fmt.go @@ -8,6 +8,9 @@ package fmtcmd import ( "os" "path/filepath" + "runtime" + "strings" + "sync" "cmd/go/internal/base" "cmd/go/internal/cfg" @@ -22,7 +25,7 @@ func init() { var CmdFmt = &base.Command{ Run: runFmt, UsageLine: "fmt [-n] [-x] [packages]", - Short: "run gofmt on package sources", + Short: "gofmt (reformat) package sources", Long: ` Fmt runs the command 'gofmt -l -w' on the packages named by the import paths. It prints the names of the files that are modified. @@ -41,13 +44,38 @@ See also: go fix, go vet. func runFmt(cmd *base.Command, args []string) { gofmt := gofmtPath() - for _, pkg := range load.Packages(args) { + procs := runtime.GOMAXPROCS(0) + var wg sync.WaitGroup + wg.Add(procs) + fileC := make(chan string, 2*procs) + for i := 0; i < procs; i++ { + go func() { + defer wg.Done() + for file := range fileC { + base.Run(str.StringList(gofmt, "-l", "-w", file)) + } + }() + } + for _, pkg := range load.PackagesAndErrors(args) { + if pkg.Error != nil { + if strings.HasPrefix(pkg.Error.Err, "build constraints exclude all Go files") { + // Skip this error, as we will format + // all files regardless. + } else { + base.Errorf("can't load package: %s", pkg.Error) + continue + } + } // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles)) - base.Run(str.StringList(gofmt, "-l", "-w", files)) + files := base.RelPaths(pkg.InternalAllGoFiles()) + for _, file := range files { + fileC <- file + } } + close(fileC) + wg.Wait() } func gofmtPath() string { diff --git a/libgo/go/cmd/go/internal/generate/generate.go b/libgo/go/cmd/go/internal/generate/generate.go index d47c9b73236..75c0d3b09d6 100644 --- a/libgo/go/cmd/go/internal/generate/generate.go +++ b/libgo/go/cmd/go/internal/generate/generate.go @@ -153,7 +153,7 @@ func runGenerate(cmd *base.Command, args []string) { } // Even if the arguments are .go files, this loop suffices. for _, pkg := range load.Packages(args) { - for _, file := range pkg.Internal.GoFiles { + for _, file := range pkg.InternalGoFiles() { if !generate(pkg.Name, file) { break } @@ -385,7 +385,7 @@ func (g *Generator) setShorthand(words []string) { } command := words[1] if g.commands[command] != nil { - g.errorf("command %q defined multiply defined", command) + g.errorf("command %q multiply defined", command) } g.commands[command] = words[2:len(words):len(words)] // force later append to make copy } diff --git a/libgo/go/cmd/go/internal/get/get.go b/libgo/go/cmd/go/internal/get/get.go index 550321198d1..d42dae6e61f 100644 --- a/libgo/go/cmd/go/internal/get/get.go +++ b/libgo/go/cmd/go/internal/get/get.go @@ -90,8 +90,7 @@ func init() { } func runGet(cmd *base.Command, args []string) { - work.InstrumentInit() - work.BuildModeInit() + work.BuildInit() if *getF && !*getU { base.Fatalf("go get: cannot use -f flag without -u") @@ -301,7 +300,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) // due to wildcard expansion. for _, p := range pkgs { if *getFix { - files := base.FilterDotUnderscoreFiles(base.RelPaths(p.Internal.AllGoFiles)) + files := base.RelPaths(p.InternalAllGoFiles()) base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) // The imports might have changed, so reload again. @@ -439,6 +438,11 @@ func downloadPackage(p *load.Package) error { p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg") } root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) + + if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil { + return err + } + // If we've considered this repository already, don't do it again. if downloadRootCache[root] { return nil @@ -452,12 +456,8 @@ func downloadPackage(p *load.Package) error { // Check that this is an appropriate place for the repo to be checked out. // The target directory must either not exist or have a repo checked out already. meta := filepath.Join(root, "."+vcs.cmd) - st, err := os.Stat(meta) - if err == nil && !st.IsDir() { - return fmt.Errorf("%s exists but is not a directory", meta) - } - if err != nil { - // Metadata directory does not exist. Prepare to checkout new copy. + if _, err := os.Stat(meta); err != nil { + // Metadata file or directory does not exist. Prepare to checkout new copy. // Some version control tools require the target directory not to exist. // We require that too, just to avoid stepping on existing work. if _, err := os.Stat(root); err == nil { diff --git a/libgo/go/cmd/go/internal/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go index 71d0b51344a..26693b13a93 100644 --- a/libgo/go/cmd/go/internal/get/vcs.go +++ b/libgo/go/cmd/go/internal/get/vcs.go @@ -93,6 +93,7 @@ var vcsList = []*vcsCmd{ vcsGit, vcsSvn, vcsBzr, + vcsFossil, } // vcsByCmd returns the version control system for the given @@ -324,6 +325,34 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error return strings.TrimSpace(out), nil } +// fossilRepoName is the name go get associates with a fossil repository. In the +// real world the file can be named anything. +const fossilRepoName = ".fossil" + +// vcsFossil describes how to use Fossil (fossil-scm.org) +var vcsFossil = &vcsCmd{ + name: "Fossil", + cmd: "fossil", + + createCmd: []string{"-go-internal-mkdir {dir} clone {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"}, + downloadCmd: []string{"up"}, + + tagCmd: []tagCmd{{"tag ls", `(.*)`}}, + tagSyncCmd: []string{"up tag:{tag}"}, + tagSyncDefault: []string{"up trunk"}, + + scheme: []string{"https", "http"}, + remoteRepo: fossilRemoteRepo, +} + +func fossilRemoteRepo(vcsFossil *vcsCmd, rootDir string) (remoteRepo string, err error) { + out, err := vcsFossil.runOutput(rootDir, "remote-url") + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil +} + func (v *vcsCmd) String() string { return v.name } @@ -362,6 +391,19 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) args[i] = expand(m, arg) } + if len(args) >= 2 && args[0] == "-go-internal-mkdir" { + var err error + if filepath.IsAbs(args[1]) { + err = os.Mkdir(args[1], os.ModePerm) + } else { + err = os.Mkdir(filepath.Join(dir, args[1]), os.ModePerm) + } + if err != nil { + return nil, err + } + args = args[2:] + } + if len(args) >= 2 && args[0] == "-go-internal-cd" { if filepath.IsAbs(args[1]) { dir = args[1] @@ -506,11 +548,28 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) { return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) } + var vcsRet *vcsCmd + var rootRet string + origDir := dir for len(dir) > len(srcRoot) { for _, vcs := range vcsList { if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil { - return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil + root := filepath.ToSlash(dir[len(srcRoot)+1:]) + // Record first VCS we find, but keep looking, + // to detect mistakes like one kind of VCS inside another. + if vcsRet == nil { + vcsRet = vcs + rootRet = root + continue + } + // Allow .git inside .git, which can arise due to submodules. + if vcsRet == vcs && vcs.cmd == "git" { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s", + filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd) } } @@ -523,9 +582,48 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) { dir = ndir } + if vcsRet != nil { + return vcsRet, rootRet, nil + } + return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir) } +// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS +// situation for dir, checking parents up until srcRoot. +func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error { + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + otherDir := dir + for len(otherDir) > len(srcRoot) { + for _, otherVCS := range vcsList { + if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.cmd)); err == nil { + // Allow expected vcs in original dir. + if otherDir == dir && otherVCS == vcs { + continue + } + // Allow .git inside .git, which can arise due to submodules. + if otherVCS == vcs && vcs.cmd == "git" { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd) + } + } + // Move to parent. + newDir := filepath.Dir(otherDir) + if len(newDir) >= len(otherDir) { + // Shouldn't happen, but just in case, stop. + break + } + otherDir = newDir + } + + return nil +} + // repoRoot represents a version control system, a repo, and a root of // where to put it on disk. type repoRoot struct { @@ -872,7 +970,7 @@ var vcsPaths = []*vcsPath{ // IBM DevOps Services (JazzHub) { - prefix: "hub.jazz.net/git", + prefix: "hub.jazz.net/git/", re: `^(?Phub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`, vcs: "git", repo: "https://{root}", @@ -881,7 +979,7 @@ var vcsPaths = []*vcsPath{ // Git at Apache { - prefix: "git.apache.org", + prefix: "git.apache.org/", re: `^(?Pgit.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`, vcs: "git", repo: "https://{root}", @@ -889,16 +987,24 @@ var vcsPaths = []*vcsPath{ // Git at OpenStack { - prefix: "git.openstack.org", + prefix: "git.openstack.org/", re: `^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`, vcs: "git", repo: "https://{root}", }, + // chiselapp.com for fossil + { + prefix: "chiselapp.com/", + re: `^(?Pchiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`, + vcs: "fossil", + repo: "https://{root}", + }, + // General syntax for any server. // Must be last. { - re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?Pbzr|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`, + re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?Pbzr|fossil|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`, ping: true, }, } diff --git a/libgo/go/cmd/go/internal/get/vcs_test.go b/libgo/go/cmd/go/internal/get/vcs_test.go index 62d352ae575..e29338aec19 100644 --- a/libgo/go/cmd/go/internal/get/vcs_test.go +++ b/libgo/go/cmd/go/internal/get/vcs_test.go @@ -154,6 +154,22 @@ func TestRepoRootForImportPath(t *testing.T) { repo: "https://git.apache.org/package-name_2.x.git", }, }, + { + "chiselapp.com/user/kyle/repository/fossilgg", + &repoRoot{ + vcs: vcsFossil, + repo: "https://chiselapp.com/user/kyle/repository/fossilgg", + }, + }, + { + // must have a user/$name/repository/$repo path + "chiselapp.com/kyle/repository/fossilgg", + nil, + }, + { + "chiselapp.com/user/kyle/fossilgg", + nil, + }, } for _, test := range tests { @@ -241,6 +257,8 @@ func TestIsSecure(t *testing.T) { {vcsGit, "example.com:path/to/repo.git", false}, {vcsGit, "path/that/contains/a:colon/repo.git", false}, {vcsHg, "ssh://user@example.com/path/to/repo.hg", true}, + {vcsFossil, "http://example.com/foo", false}, + {vcsFossil, "https://example.com/foo", true}, } for _, test := range tests { diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index 516fff3528e..6dcba3722c6 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -471,6 +471,12 @@ General-purpose environment variables: See https://golang.org/doc/articles/race_detector.html. GOROOT The root of the go tree. + GOTMPDIR + The directory where the go command will write + temporary source files, packages, and binaries. + GOCACHE + The directory where the go command will store + cached information for reuse in future builds. Environment variables for use with cgo: @@ -505,6 +511,9 @@ Architecture-specific environment variables: GO386 For GOARCH=386, the floating point instruction set. Valid values are 387, sse2. + GOMIPS + For GOARCH=mips{,le}, whether to use floating point instructions. + Valid values are hardfloat (default), softfloat. Special-purpose environment variables: @@ -568,8 +577,10 @@ Non-test Go source files can also include a //go:binary-only-package comment, indicating that the package sources are included for documentation only and must not be used to build the package binary. This enables distribution of Go packages in -their compiled form alone. See the go/build package documentation -for more details. +their compiled form alone. Even binary-only packages require +accurate import blocks listing required dependencies, so that +those dependencies can be supplied when linking the resulting +command. `, } diff --git a/libgo/go/cmd/go/internal/list/list.go b/libgo/go/cmd/go/internal/list/list.go index 241d0894c01..74352730004 100644 --- a/libgo/go/cmd/go/internal/list/list.go +++ b/libgo/go/cmd/go/internal/list/list.go @@ -152,7 +152,7 @@ var listJson = CmdList.Flag.Bool("json", false, "") var nl = []byte{'\n'} func runList(cmd *base.Command, args []string) { - work.BuildModeInit() + work.BuildInit() out := newTrackingWriter(os.Stdout) defer out.w.Flush() @@ -194,12 +194,29 @@ func runList(cmd *base.Command, args []string) { } } - loadpkgs := load.Packages + var pkgs []*load.Package if *listE { - loadpkgs = load.PackagesAndErrors + pkgs = load.PackagesAndErrors(args) + } else { + pkgs = load.Packages(args) + } + + // Estimate whether staleness information is needed, + // since it's a little bit of work to compute. + needStale := *listJson || strings.Contains(*listFmt, ".Stale") + if needStale { + var b work.Builder + b.Init() + b.ComputeStaleOnly = true + a := &work.Action{} + // TODO: Use pkgsFilter? + for _, p := range pkgs { + a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) + } + b.Do(a) } - for _, pkg := range loadpkgs(args) { + for _, pkg := range pkgs { // Show vendor-expanded paths in listing pkg.TestImports = pkg.Vendored(pkg.TestImports) pkg.XTestImports = pkg.Vendored(pkg.XTestImports) diff --git a/libgo/go/cmd/go/internal/load/flag.go b/libgo/go/cmd/go/internal/load/flag.go new file mode 100644 index 00000000000..7ad4208ccc0 --- /dev/null +++ b/libgo/go/cmd/go/internal/load/flag.go @@ -0,0 +1,121 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package load + +import ( + "cmd/go/internal/base" + "cmd/go/internal/str" + "fmt" + "strings" +) + +var ( + BuildAsmflags PerPackageFlag // -asmflags + BuildGcflags PerPackageFlag // -gcflags + BuildLdflags PerPackageFlag // -ldflags + BuildGccgoflags PerPackageFlag // -gccgoflags +) + +// A PerPackageFlag is a command-line flag implementation (a flag.Value) +// that allows specifying different effective flags for different packages. +// See 'go help build' for more details about per-package flags. +type PerPackageFlag struct { + present bool + values []ppfValue +} + +// A ppfValue is a single = per-package flag value. +type ppfValue struct { + match func(*Package) bool // compiled pattern + flags []string +} + +// Set is called each time the flag is encountered on the command line. +func (f *PerPackageFlag) Set(v string) error { + return f.set(v, base.Cwd) +} + +// set is the implementation of Set, taking a cwd (current working directory) for easier testing. +func (f *PerPackageFlag) set(v, cwd string) error { + f.present = true + match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern + // For backwards compatibility with earlier flag splitting, ignore spaces around flags. + v = strings.TrimSpace(v) + if v == "" { + // Special case: -gcflags="" means no flags for command-line arguments + // (overrides previous -gcflags="-whatever"). + f.values = append(f.values, ppfValue{match, []string{}}) + return nil + } + if !strings.HasPrefix(v, "-") { + i := strings.Index(v, "=") + if i < 0 { + return fmt.Errorf("missing = in =") + } + if i == 0 { + return fmt.Errorf("missing in =") + } + pattern := strings.TrimSpace(v[:i]) + match = MatchPackage(pattern, cwd) + v = v[i+1:] + } + flags, err := str.SplitQuotedFields(v) + if err != nil { + return err + } + if flags == nil { + flags = []string{} + } + f.values = append(f.values, ppfValue{match, flags}) + return nil +} + +// String is required to implement flag.Value. +// It is not used, because cmd/go never calls flag.PrintDefaults. +func (f *PerPackageFlag) String() string { return "" } + +// Present reports whether the flag appeared on the command line. +func (f *PerPackageFlag) Present() bool { + return f.present +} + +// For returns the flags to use for the given package. +func (f *PerPackageFlag) For(p *Package) []string { + flags := []string{} + for _, v := range f.values { + if v.match(p) { + flags = v.flags + } + } + return flags +} + +var cmdlineMatchers []func(*Package) bool + +// SetCmdlinePatterns records the set of patterns given on the command line, +// for use by the PerPackageFlags. +func SetCmdlinePatterns(args []string) { + setCmdlinePatterns(args, base.Cwd) +} + +func setCmdlinePatterns(args []string, cwd string) { + if len(args) == 0 { + args = []string{"."} + } + cmdlineMatchers = nil // allow reset for testing + for _, arg := range args { + cmdlineMatchers = append(cmdlineMatchers, MatchPackage(arg, cwd)) + } +} + +// isCmdlinePkg reports whether p is a package listed on the command line. +func isCmdlinePkg(p *Package) bool { + for _, m := range cmdlineMatchers { + if m(p) { + return true + } + } + return false +} diff --git a/libgo/go/cmd/go/internal/load/flag_test.go b/libgo/go/cmd/go/internal/load/flag_test.go new file mode 100644 index 00000000000..d3223e12d52 --- /dev/null +++ b/libgo/go/cmd/go/internal/load/flag_test.go @@ -0,0 +1,135 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package load + +import ( + "fmt" + "path/filepath" + "reflect" + "testing" +) + +type ppfTestPackage struct { + path string + dir string + cmdline bool + flags []string +} + +type ppfTest struct { + args []string + pkgs []ppfTestPackage +} + +var ppfTests = []ppfTest{ + // -gcflags=-S applies only to packages on command line. + { + args: []string{"-S"}, + pkgs: []ppfTestPackage{ + {cmdline: true, flags: []string{"-S"}}, + {cmdline: false, flags: []string{}}, + }, + }, + + // -gcflags=-S -gcflags= overrides the earlier -S. + { + args: []string{"-S", ""}, + pkgs: []ppfTestPackage{ + {cmdline: true, flags: []string{}}, + }, + }, + + // -gcflags=net=-S applies only to package net + { + args: []string{"net=-S"}, + pkgs: []ppfTestPackage{ + {path: "math", cmdline: true, flags: []string{}}, + {path: "net", flags: []string{"-S"}}, + }, + }, + + // -gcflags=net=-S -gcflags=net= also overrides the earlier -S + { + args: []string{"net=-S", "net="}, + pkgs: []ppfTestPackage{ + {path: "net", flags: []string{}}, + }, + }, + + // -gcflags=net/...=-S net math + // applies -S to net and net/http but not math + { + args: []string{"net/...=-S"}, + pkgs: []ppfTestPackage{ + {path: "net", flags: []string{"-S"}}, + {path: "net/http", flags: []string{"-S"}}, + {path: "math", flags: []string{}}, + }, + }, + + // -gcflags=net/...=-S -gcflags=-m net math + // applies -m to net and math and -S to other packages matching net/... + // (net matches too, but it was grabbed by the later -gcflags). + { + args: []string{"net/...=-S", "-m"}, + pkgs: []ppfTestPackage{ + {path: "net", cmdline: true, flags: []string{"-m"}}, + {path: "math", cmdline: true, flags: []string{"-m"}}, + {path: "net", cmdline: false, flags: []string{"-S"}}, + {path: "net/http", flags: []string{"-S"}}, + {path: "math", flags: []string{}}, + }, + }, + + // relative path patterns + // ppfDirTest(pattern, n, dirs...) says the first n dirs should match and the others should not. + ppfDirTest(".", 1, "/my/test/dir", "/my/test", "/my/test/other", "/my/test/dir/sub"), + ppfDirTest("..", 1, "/my/test", "/my/test/dir", "/my/test/other", "/my/test/dir/sub"), + ppfDirTest("./sub", 1, "/my/test/dir/sub", "/my/test", "/my/test/dir", "/my/test/other", "/my/test/dir/sub/sub"), + ppfDirTest("../other", 1, "/my/test/other", "/my/test", "/my/test/dir", "/my/test/other/sub", "/my/test/dir/other", "/my/test/dir/sub"), + ppfDirTest("./...", 3, "/my/test/dir", "/my/test/dir/sub", "/my/test/dir/sub/sub", "/my/test/other", "/my/test/other/sub"), + ppfDirTest("../...", 4, "/my/test/dir", "/my/test/other", "/my/test/dir/sub", "/my/test/other/sub", "/my/other/test"), + ppfDirTest("../...sub...", 3, "/my/test/dir/sub", "/my/test/othersub", "/my/test/yellowsubmarine", "/my/other/test"), +} + +func ppfDirTest(pattern string, nmatch int, dirs ...string) ppfTest { + var pkgs []ppfTestPackage + for i, d := range dirs { + flags := []string{} + if i < nmatch { + flags = []string{"-S"} + } + pkgs = append(pkgs, ppfTestPackage{path: "p", dir: d, flags: flags}) + } + return ppfTest{args: []string{pattern + "=-S"}, pkgs: pkgs} +} + +func TestPerPackageFlag(t *testing.T) { + nativeDir := func(d string) string { + if filepath.Separator == '\\' { + return `C:` + filepath.FromSlash(d) + } + return d + } + + for i, tt := range ppfTests { + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + ppFlags := new(PerPackageFlag) + for _, arg := range tt.args { + t.Logf("set(%s)", arg) + if err := ppFlags.set(arg, nativeDir("/my/test/dir")); err != nil { + t.Fatal(err) + } + } + for _, p := range tt.pkgs { + dir := nativeDir(p.dir) + flags := ppFlags.For(&Package{PackagePublic: PackagePublic{ImportPath: p.path, Dir: dir}, Internal: PackageInternal{CmdlinePkg: p.cmdline}}) + if !reflect.DeepEqual(flags, p.flags) { + t.Errorf("For(%v, %v, %v) = %v, want %v", p.path, dir, p.cmdline, flags, p.flags) + } + } + }) + } +} diff --git a/libgo/go/cmd/go/internal/load/icfg.go b/libgo/go/cmd/go/internal/load/icfg.go new file mode 100644 index 00000000000..0b346df0772 --- /dev/null +++ b/libgo/go/cmd/go/internal/load/icfg.go @@ -0,0 +1,75 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package load + +import ( + "bytes" + "encoding/json" + "errors" + "io/ioutil" +) + +// DebugDeprecatedImportcfg is installed as the undocumented -debug-deprecated-importcfg build flag. +// It is useful for debugging subtle problems in the go command logic but not something +// we want users to depend on. The hope is that the "deprecated" will make that clear. +// We intend to remove this flag in Go 1.11. +var DebugDeprecatedImportcfg debugDeprecatedImportcfgFlag + +type debugDeprecatedImportcfgFlag struct { + enabled bool + pkgs map[string]*debugDeprecatedImportcfgPkg +} + +type debugDeprecatedImportcfgPkg struct { + Dir string + Import map[string]string +} + +var ( + debugDeprecatedImportcfgMagic = []byte("# debug-deprecated-importcfg\n") + errImportcfgSyntax = errors.New("malformed syntax") +) + +func (f *debugDeprecatedImportcfgFlag) String() string { return "" } + +func (f *debugDeprecatedImportcfgFlag) Set(x string) error { + if x == "" { + *f = debugDeprecatedImportcfgFlag{} + return nil + } + data, err := ioutil.ReadFile(x) + if err != nil { + return err + } + + if !bytes.HasPrefix(data, debugDeprecatedImportcfgMagic) { + return errImportcfgSyntax + } + data = data[len(debugDeprecatedImportcfgMagic):] + + f.pkgs = nil + if err := json.Unmarshal(data, &f.pkgs); err != nil { + return errImportcfgSyntax + } + f.enabled = true + return nil +} + +func (f *debugDeprecatedImportcfgFlag) lookup(parent *Package, path string) (dir, newPath string) { + if parent == nil { + if p1 := f.pkgs[path]; p1 != nil { + return p1.Dir, path + } + return "", "" + } + if p1 := f.pkgs[parent.ImportPath]; p1 != nil { + if newPath := p1.Import[path]; newPath != "" { + if p2 := f.pkgs[newPath]; p2 != nil { + return p2.Dir, newPath + } + } + } + return "", "" +} diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go index acb20fe03e4..8ea56f24073 100644 --- a/libgo/go/cmd/go/internal/load/pkg.go +++ b/libgo/go/cmd/go/internal/load/pkg.go @@ -6,7 +6,6 @@ package load import ( - "crypto/sha1" "fmt" "go/build" "go/token" @@ -20,7 +19,6 @@ import ( "unicode" "cmd/go/internal/base" - "cmd/go/internal/buildid" "cmd/go/internal/cfg" "cmd/go/internal/str" ) @@ -42,16 +40,20 @@ type PackagePublic struct { ImportComment string `json:",omitempty"` // path in import comment on package statement Name string `json:",omitempty"` // package name Doc string `json:",omitempty"` // package documentation string - Target string `json:",omitempty"` // install path + Target string `json:",omitempty"` // installed target for this package (may be executable) Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared) Goroot bool `json:",omitempty"` // is this package found in the Go root? Standard bool `json:",omitempty"` // is this package part of the standard Go library? - Stale bool `json:",omitempty"` // would 'go install' do anything for this package? - StaleReason string `json:",omitempty"` // why is Stale true? Root string `json:",omitempty"` // Go root or Go path dir containing this package ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory BinaryOnly bool `json:",omitempty"` // package cannot be recompiled + // Stale and StaleReason remain here *only* for the list command. + // They are only initialized in preparation for list execution. + // The regular build determines staleness on the fly during action execution. + Stale bool `json:",omitempty"` // would 'go install' do anything for this package? + StaleReason string `json:",omitempty"` // why is Stale true? + // Source files GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) CgoFiles []string `json:",omitempty"` // .go sources files that import "C" @@ -93,25 +95,23 @@ type PackagePublic struct { type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package - Pkgdir string // overrides build.PkgDir - Imports []*Package - Deps []*Package - GoFiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths - SFiles []string - AllGoFiles []string // gofiles + IgnoredGoFiles, absolute paths - Target string // installed file for this package (may be executable) - Fake bool // synthesized package - External bool // synthesized external test package + Imports []*Package // this package's direct imports + RawImports []string // this package's original imports as they appear in the text of the program ForceLibrary bool // this package is a library (even if named "main") - Cmdline bool // defined by files listed on command line + CmdlineFiles bool // package built from files listed on command line + CmdlinePkg bool // package listed on command line Local bool // imported via local path (./ or ../) LocalPrefix string // interpret ./ and ../ imports relative to this prefix ExeName string // desired name for temporary executable CoverMode string // preprocess Go source files with the coverage tool in this mode CoverVars map[string]*CoverVar // variables created by coverage analysis OmitDebug bool // tell linker not to write debug information - BuildID string // expected build ID for generated package GobinSubdir bool // install target would be subdir of GOBIN + + Asmflags []string // -asmflags for this package + Gcflags []string // -gcflags for this package + Ldflags []string // -ldflags for this package + Gccgoflags []string // -gccgoflags for this package } type NoGoError struct { @@ -219,6 +219,7 @@ func (p *Package) copyBuild(pp *build.Package) { // We modify p.Imports in place, so make copy now. p.Imports = make([]string, len(pp.Imports)) copy(p.Imports, pp.Imports) + p.Internal.RawImports = pp.Imports p.TestGoFiles = pp.TestGoFiles p.TestImports = pp.TestImports p.XTestGoFiles = pp.XTestGoFiles @@ -354,7 +355,7 @@ func makeImportValid(r rune) rune { // Mode flags for loadImport and download (in get.go). const ( - // useVendor means that loadImport should do vendor expansion + // UseVendor means that loadImport should do vendor expansion // (provided the vendoring experiment is enabled). // That is, useVendor means that the import path came from // a source file and has not been vendor-expanded yet. @@ -365,12 +366,12 @@ const ( // disallowVendor will reject direct use of paths containing /vendor/. UseVendor = 1 << iota - // getTestDeps is for download (part of "go get") and indicates + // GetTestDeps is for download (part of "go get") and indicates // that test dependencies should be fetched too. GetTestDeps ) -// loadImport scans the directory named by path, which must be an import path, +// LoadImport scans the directory named by path, which must be an import path, // but possibly a local import path (an absolute file system path or one beginning // with ./ or ../). A local relative path is interpreted relative to srcDir. // It returns a *Package describing the package found in that directory. @@ -386,8 +387,14 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo importPath := path origPath := path isLocal := build.IsLocalImport(path) + var debugDeprecatedImportcfgDir string if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) + } else if DebugDeprecatedImportcfg.enabled { + if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" { + debugDeprecatedImportcfgDir = d + importPath = i + } } else if mode&UseVendor != 0 { // We do our own vendor resolution, because we want to // find out the key to use in packageCache without the @@ -409,20 +416,23 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo // Load package. // Import always returns bp != nil, even if an error occurs, // in order to return partial information. - // - // TODO: After Go 1, decide when to pass build.AllowBinary here. - // See issue 3268 for mistakes to avoid. - buildMode := build.ImportComment - if mode&UseVendor == 0 || path != origPath { - // Not vendoring, or we already found the vendored path. - buildMode |= build.IgnoreVendor - } - bp, err := cfg.BuildContext.Import(path, srcDir, buildMode) + var bp *build.Package + var err error + if debugDeprecatedImportcfgDir != "" { + bp, err = cfg.BuildContext.ImportDir(debugDeprecatedImportcfgDir, 0) + } else { + buildMode := build.ImportComment + if mode&UseVendor == 0 || path != origPath { + // Not vendoring, or we already found the vendored path. + buildMode |= build.IgnoreVendor + } + bp, err = cfg.BuildContext.Import(path, srcDir, buildMode) + } bp.ImportPath = importPath if cfg.GOBIN != "" { bp.BinDir = cfg.GOBIN } - if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && + if debugDeprecatedImportcfgDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } @@ -431,7 +441,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo p = setErrorPos(p, importPos) } - if origPath != cleanImport(origPath) { + if debugDeprecatedImportcfgDir == "" && origPath != cleanImport(origPath) { p.Error = &PackageError{ ImportStack: stk.Copy(), Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)), @@ -806,45 +816,27 @@ func FindVendor(path string) (index int, ok bool) { return 0, false } -type targetDir int +type TargetDir int const ( - ToRoot targetDir = iota // to bin dir inside package root (default) - ToTool // GOROOT/pkg/tool - StalePath // the old import path; fail to build + ToTool TargetDir = iota // to GOROOT/pkg/tool (default for cmd/*) + ToBin // to bin dir inside package root (default for non-cmd/*) + StalePath // an old import path; fail to build ) -// goTools is a map of Go program import path to install target directory. -var GoTools = map[string]targetDir{ - "cmd/addr2line": ToTool, - "cmd/api": ToTool, - "cmd/asm": ToTool, - "cmd/compile": ToTool, - "cmd/cgo": ToTool, - "cmd/cover": ToTool, - "cmd/dist": ToTool, - "cmd/doc": ToTool, - "cmd/fix": ToTool, - "cmd/link": ToTool, - "cmd/newlink": ToTool, - "cmd/nm": ToTool, - "cmd/objdump": ToTool, - "cmd/pack": ToTool, - "cmd/pprof": ToTool, - "cmd/trace": ToTool, - "cmd/vet": ToTool, - "code.google.com/p/go.tools/cmd/cover": StalePath, - "code.google.com/p/go.tools/cmd/godoc": StalePath, - "code.google.com/p/go.tools/cmd/vet": StalePath, -} - -var raceExclude = map[string]bool{ - "runtime/race": true, - "runtime/msan": true, - "runtime/cgo": true, - "cmd/cgo": true, - "syscall": true, - "errors": true, +// InstallTargetDir reports the target directory for installing the command p. +func InstallTargetDir(p *Package) TargetDir { + if strings.HasPrefix(p.ImportPath, "code.google.com/p/go.tools/cmd/") { + return StalePath + } + if p.Goroot && strings.HasPrefix(p.ImportPath, "cmd/") && p.Name == "main" { + switch p.ImportPath { + case "cmd/go", "cmd/gofmt": + return ToBin + } + return ToTool + } + return ToBin } var cgoExclude = map[string]bool{ @@ -861,7 +853,7 @@ var foldPath = make(map[string]string) // load populates p using information from bp, err, which should // be the result of calling build.Context.Import. -func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package { +func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { p.copyBuild(bp) // When using gccgo the go/build package will not be able to @@ -871,9 +863,31 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package err = nil } + // Decide whether p was listed on the command line. + // Given that load is called while processing the command line, + // you might think we could simply pass a flag down into load + // saying whether we are loading something named on the command + // line or something to satisfy an import. But the first load of a + // package named on the command line may be as a dependency + // of an earlier package named on the command line, not when we + // get to that package during command line processing. + // For example "go test fmt reflect" will load reflect as a dependency + // of fmt before it attempts to load as a command-line argument. + // Because loads are cached, the later load will be a no-op, + // so it is important that the first load can fill in CmdlinePkg correctly. + // Hence the call to an explicit matching check here. + p.Internal.CmdlinePkg = isCmdlinePkg(p) + + p.Internal.Asmflags = BuildAsmflags.For(p) + p.Internal.Gcflags = BuildGcflags.For(p) + p.Internal.Ldflags = BuildLdflags.For(p) + p.Internal.Gccgoflags = BuildGccgoflags.For(p) + // The localPrefix is the path we interpret ./ imports relative to. // Synthesized main packages sometimes override this. - p.Internal.LocalPrefix = dirToImportPath(p.Dir) + if p.Internal.Local { + p.Internal.LocalPrefix = dirToImportPath(p.Dir) + } if err != nil { if _, ok := err.(*build.NoGoError); ok { @@ -885,7 +899,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package ImportStack: stk.Copy(), Err: err.Error(), } - return p + return } useBindir := p.Name == "main" @@ -898,11 +912,11 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package if useBindir { // Report an error when the old code.google.com/p/go.tools paths are used. - if GoTools[p.ImportPath] == StalePath { + if InstallTargetDir(p) == StalePath { newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath) p.Error = &PackageError{Err: e} - return p + return } _, elem := filepath.Split(p.Dir) full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem @@ -912,128 +926,85 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package } if p.Internal.Build.BinDir != "" { // Install to GOBIN or bin of GOPATH entry. - p.Internal.Target = filepath.Join(p.Internal.Build.BinDir, elem) + p.Target = filepath.Join(p.Internal.Build.BinDir, elem) if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" { // Do not create $GOBIN/goos_goarch/elem. - p.Internal.Target = "" + p.Target = "" p.Internal.GobinSubdir = true } } - if GoTools[p.ImportPath] == ToTool { + if InstallTargetDir(p) == ToTool { // This is for 'go tool'. // Override all the usual logic and force it into the tool directory. if cfg.BuildToolchainName == "gccgo" { - p.Internal.Target = filepath.Join(runtime.GCCGOTOOLDIR, elem) + p.Target = filepath.Join(runtime.GCCGOTOOLDIR, elem) } else { - p.Internal.Target = filepath.Join(cfg.GOROOTpkg, "tool", full) + p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full) } } - if p.Internal.Target != "" && cfg.BuildContext.GOOS == "windows" { - p.Internal.Target += ".exe" + if p.Target != "" && cfg.BuildContext.GOOS == "windows" { + p.Target += ".exe" } } else if p.Internal.Local { // Local import turned into absolute path. // No permanent install target. - p.Internal.Target = "" + p.Target = "" } else { - p.Internal.Target = p.Internal.Build.PkgObj + p.Target = p.Internal.Build.PkgObj if cfg.BuildLinkshared { - shlibnamefile := p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname" + shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname" shlib, err := ioutil.ReadFile(shlibnamefile) + if err != nil && !os.IsNotExist(err) { + base.Fatalf("reading shlibname: %v", err) + } if err == nil { libname := strings.TrimSpace(string(shlib)) if cfg.BuildContext.Compiler == "gccgo" { p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname) } else { p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname) - } - } else if !os.IsNotExist(err) { - base.Fatalf("unexpected error reading %s: %v", shlibnamefile, err) } } } - ImportPaths := p.Imports - // Packages that use cgo import runtime/cgo implicitly. - // Packages that use cgo also import syscall implicitly, - // to wrap errno. - // Exclude certain packages to avoid circular dependencies. - if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) { - ImportPaths = append(ImportPaths, "runtime/cgo") - } - if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { - ImportPaths = append(ImportPaths, "syscall") - } - - if cfg.BuildContext.CgoEnabled && p.Name == "main" && !p.Goroot { - // Currently build modes c-shared, pie (on systems that do not - // support PIE with internal linking mode), plugin, and - // -linkshared force external linking mode, as of course does - // -ldflags=-linkmode=external. External linking mode forces - // an import of runtime/cgo. - pieCgo := cfg.BuildBuildmode == "pie" && (cfg.BuildContext.GOOS != "linux" || cfg.BuildContext.GOARCH != "amd64") - linkmodeExternal := false - for i, a := range cfg.BuildLdflags { - if a == "-linkmode=external" { - linkmodeExternal = true + // Build augmented import list to add implicit dependencies. + // Be careful not to add imports twice, just to avoid confusion. + importPaths := p.Imports + addImport := func(path string) { + for _, p := range importPaths { + if path == p { + return } - if a == "-linkmode" && i+1 < len(cfg.BuildLdflags) && cfg.BuildLdflags[i+1] == "external" { - linkmodeExternal = true - } - } - if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal { - ImportPaths = append(ImportPaths, "runtime/cgo") } + importPaths = append(importPaths, path) } - // Everything depends on runtime, except runtime, its internal - // subpackages, and unsafe. - if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") { - ImportPaths = append(ImportPaths, "runtime") - // When race detection enabled everything depends on runtime/race. - // Exclude certain packages to avoid circular dependencies. - if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) { - ImportPaths = append(ImportPaths, "runtime/race") - } - // MSan uses runtime/msan. - if cfg.BuildMSan && (!p.Standard || !raceExclude[p.ImportPath]) { - ImportPaths = append(ImportPaths, "runtime/msan") - } - // On ARM with GOARM=5, everything depends on math for the link. - if p.Name == "main" && cfg.Goarch == "arm" { - ImportPaths = append(ImportPaths, "math") - } + // Cgo translation adds imports of "runtime/cgo" and "syscall", + // except for certain packages, to avoid circular dependencies. + if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) { + addImport("runtime/cgo") } - - // Runtime and its internal packages depend on runtime/internal/sys, - // so that they pick up the generated zversion.go file. - // This can be an issue particularly for runtime/internal/atomic; - // see issue 13655. - if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" { - ImportPaths = append(ImportPaths, "runtime/internal/sys") + if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { + addImport("syscall") } - // Build list of full paths to all Go files in the package, - // for use by commands like go fmt. - p.Internal.GoFiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles) - for i := range p.Internal.GoFiles { - p.Internal.GoFiles[i] = filepath.Join(p.Dir, p.Internal.GoFiles[i]) - } - sort.Strings(p.Internal.GoFiles) + // SWIG adds imports of some standard packages. + if p.UsesSwig() { + addImport("runtime/cgo") + addImport("syscall") + addImport("sync") - p.Internal.SFiles = str.StringList(p.SFiles) - for i := range p.Internal.SFiles { - p.Internal.SFiles[i] = filepath.Join(p.Dir, p.Internal.SFiles[i]) + // TODO: The .swig and .swigcxx files can use + // %go_import directives to import other packages. } - sort.Strings(p.Internal.SFiles) - p.Internal.AllGoFiles = str.StringList(p.IgnoredGoFiles) - for i := range p.Internal.AllGoFiles { - p.Internal.AllGoFiles[i] = filepath.Join(p.Dir, p.Internal.AllGoFiles[i]) + // The linker loads implicit dependencies. + if p.Name == "main" && !p.Internal.ForceLibrary { + for _, dep := range LinkerDeps(p) { + addImport(dep) + } } - p.Internal.AllGoFiles = append(p.Internal.AllGoFiles, p.Internal.GoFiles...) - sort.Strings(p.Internal.AllGoFiles) // Check for case-insensitive collision of input files. // To avoid problems on case-insensitive files, we reject any package @@ -1060,23 +1031,12 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package ImportStack: stk.Copy(), Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2), } - return p + return } // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) - deps := make(map[string]*Package) - save := func(path string, p1 *Package) { - // The same import path could produce an error or not, - // depending on what tries to import it. - // Prefer to record entries with errors, so we can report them. - p0 := deps[path] - if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) { - deps[path] = p1 - } - } - - for i, path := range ImportPaths { + for i, path := range importPaths { if path == "C" { continue } @@ -1096,22 +1056,38 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package } path = p1.ImportPath - ImportPaths[i] = path + importPaths[i] = path if i < len(p.Imports) { p.Imports[i] = path } - save(path, p1) imports = append(imports, p1) - for _, dep := range p1.Internal.Deps { - save(dep.ImportPath, dep) - } if p1.Incomplete { p.Incomplete = true } } p.Internal.Imports = imports + deps := make(map[string]*Package) + var q []*Package + q = append(q, imports...) + for i := 0; i < len(q); i++ { + p1 := q[i] + path := p1.ImportPath + // The same import path could produce an error or not, + // depending on what tries to import it. + // Prefer to record entries with errors, so we can report them. + p0 := deps[path] + if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) { + deps[path] = p1 + for _, p2 := range p1.Internal.Imports { + if deps[p2.ImportPath] != p2 { + q = append(q, p2) + } + } + } + } + p.Deps = make([]string, 0, len(deps)) for dep := range deps { p.Deps = append(p.Deps, dep) @@ -1122,7 +1098,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package if p1 == nil { panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) } - p.Internal.Deps = append(p.Internal.Deps, p1) if p1.Error != nil { p.DepsErrors = append(p.DepsErrors, p1.Error) } @@ -1130,9 +1105,8 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package // unsafe is a fake package. if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") { - p.Internal.Target = "" + p.Target = "" } - p.Target = p.Internal.Target // If cgo is not enabled, ignore cgo supporting sources // just as we ignore go files containing import "C". @@ -1148,13 +1122,32 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package // code; see issue #16050). } - // The gc toolchain only permits C source files with cgo. - if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" { + setError := func(msg string) { p.Error = &PackageError{ ImportStack: stk.Copy(), - Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")), + Err: msg, } - return p + } + + // The gc toolchain only permits C source files with cgo or SWIG. + if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" { + setError(fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " "))) + return + } + + // C++, Objective-C, and Fortran source files are permitted only with cgo or SWIG, + // regardless of toolchain. + if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Sprintf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " "))) + return + } + if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Sprintf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " "))) + return + } + if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Sprintf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " "))) + return } // Check for case-insensitive collisions of import paths. @@ -1162,23 +1155,104 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package if other := foldPath[fold]; other == "" { foldPath[fold] = p.ImportPath } else if other != p.ImportPath { - p.Error = &PackageError{ - ImportStack: stk.Copy(), - Err: fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other), + setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other)) + return + } +} + +// LinkerDeps returns the list of linker-induced dependencies for main package p. +func LinkerDeps(p *Package) []string { + // Everything links runtime. + deps := []string{"runtime"} + + // External linking mode forces an import of runtime/cgo. + if externalLinkingForced(p) { + deps = append(deps, "runtime/cgo") + } + // On ARM with GOARM=5, it forces an import of math, for soft floating point. + if cfg.Goarch == "arm" { + deps = append(deps, "math") + } + // Using the race detector forces an import of runtime/race. + if cfg.BuildRace { + deps = append(deps, "runtime/race") + } + // Using memory sanitizer forces an import of runtime/msan. + if cfg.BuildMSan { + deps = append(deps, "runtime/msan") + } + + return deps +} + +// externalLinkingForced reports whether external linking is being +// forced even for programs that do not use cgo. +func externalLinkingForced(p *Package) bool { + // Some targets must use external linking even inside GOROOT. + switch cfg.BuildContext.GOOS { + case "android": + return true + case "darwin": + switch cfg.BuildContext.GOARCH { + case "arm", "arm64": + return true } - return p } - if p.BinaryOnly { - // For binary-only package, use build ID from supplied package binary. - buildID, err := buildid.ReadBuildID(p.Name, p.Target) - if err == nil { - p.Internal.BuildID = buildID + if !cfg.BuildContext.CgoEnabled { + return false + } + // Currently build modes c-shared, pie (on systems that do not + // support PIE with internal linking mode (currently all + // systems: issue #18968)), plugin, and -linkshared force + // external linking mode, as of course does + // -ldflags=-linkmode=external. External linking mode forces + // an import of runtime/cgo. + pieCgo := cfg.BuildBuildmode == "pie" + linkmodeExternal := false + if p != nil { + ldflags := BuildLdflags.For(p) + for i, a := range ldflags { + if a == "-linkmode=external" { + linkmodeExternal = true + } + if a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" { + linkmodeExternal = true + } } - } else { - computeBuildID(p) } - return p + + return cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal +} + +// mkAbs rewrites list, which must be paths relative to p.Dir, +// into a sorted list of absolute paths. It edits list in place but for +// convenience also returns list back to its caller. +func (p *Package) mkAbs(list []string) []string { + for i, f := range list { + list[i] = filepath.Join(p.Dir, f) + } + sort.Strings(list) + return list +} + +// InternalGoFiles returns the list of Go files being built for the package, +// using absolute paths. +func (p *Package) InternalGoFiles() []string { + return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)) +} + +// InternalGoFiles returns the list of all Go files possibly relevant for the package, +// using absolute paths. "Possibly relevant" means that files are not excluded +// due to build tags, but files with names beginning with . or _ are still excluded. +func (p *Package) InternalAllGoFiles() []string { + var extra []string + for _, f := range p.IgnoredGoFiles { + if f != "" && f[0] != '.' || f[0] != '_' { + extra = append(extra, f) + } + } + return p.mkAbs(str.StringList(extra, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)) } // usesSwig reports whether the package needs to run SWIG. @@ -1213,517 +1287,6 @@ func PackageList(roots []*Package) []*Package { return all } -// computeStale computes the Stale flag in the package dag that starts -// at the named pkgs (command-line arguments). -func ComputeStale(pkgs ...*Package) { - for _, p := range PackageList(pkgs) { - p.Stale, p.StaleReason = isStale(p) - } -} - -// The runtime version string takes one of two forms: -// "go1.X[.Y]" for Go releases, and "devel +hash" at tip. -// Determine whether we are in a released copy by -// inspecting the version. -var isGoRelease = strings.HasPrefix(runtime.Version(), "go1") - -// isStale and computeBuildID -// -// Theory of Operation -// -// There is an installed copy of the package (or binary). -// Can we reuse the installed copy, or do we need to build a new one? -// -// We can use the installed copy if it matches what we'd get -// by building a new one. The hard part is predicting that without -// actually running a build. -// -// To start, we must know the set of inputs to the build process that can -// affect the generated output. At a minimum, that includes the source -// files for the package and also any compiled packages imported by those -// source files. The *Package has these, and we use them. One might also -// argue for including in the input set: the build tags, whether the race -// detector is in use, the target operating system and architecture, the -// compiler and linker binaries being used, the additional flags being -// passed to those, the cgo binary being used, the additional flags cgo -// passes to the host C compiler, the host C compiler being used, the set -// of host C include files and installed C libraries, and so on. -// We include some but not all of this information. -// -// Once we have decided on a set of inputs, we must next decide how to -// tell whether the content of that set has changed since the last build -// of p. If there have been no changes, then we assume a new build would -// produce the same result and reuse the installed package or binary. -// But if there have been changes, then we assume a new build might not -// produce the same result, so we rebuild. -// -// There are two common ways to decide whether the content of the set has -// changed: modification times and content hashes. We use a mixture of both. -// -// The use of modification times (mtimes) was pioneered by make: -// assuming that a file's mtime is an accurate record of when that file was last written, -// and assuming that the modification time of an installed package or -// binary is the time that it was built, if the mtimes of the inputs -// predate the mtime of the installed object, then the build of that -// object saw those versions of the files, and therefore a rebuild using -// those same versions would produce the same object. In contrast, if any -// mtime of an input is newer than the mtime of the installed object, a -// change has occurred since the build, and the build should be redone. -// -// Modification times are attractive because the logic is easy to -// understand and the file system maintains the mtimes automatically -// (less work for us). Unfortunately, there are a variety of ways in -// which the mtime approach fails to detect a change and reuses a stale -// object file incorrectly. (Making the opposite mistake, rebuilding -// unnecessarily, is only a performance problem and not a correctness -// problem, so we ignore that one.) -// -// As a warmup, one problem is that to be perfectly precise, we need to -// compare the input mtimes against the time at the beginning of the -// build, but the object file time is the time at the end of the build. -// If an input file changes after being read but before the object is -// written, the next build will see an object newer than the input and -// will incorrectly decide that the object is up to date. We make no -// attempt to detect or solve this problem. -// -// Another problem is that due to file system imprecision, an input and -// output that are actually ordered in time have the same mtime. -// This typically happens on file systems with 1-second (or, worse, -// 2-second) mtime granularity and with automated scripts that write an -// input and then immediately run a build, or vice versa. If an input and -// an output have the same mtime, the conservative behavior is to treat -// the output as out-of-date and rebuild. This can cause one or more -// spurious rebuilds, but only for 1 second, until the object finally has -// an mtime later than the input. -// -// Another problem is that binary distributions often set the mtime on -// all files to the same time. If the distribution includes both inputs -// and cached build outputs, the conservative solution to the previous -// problem will cause unnecessary rebuilds. Worse, in such a binary -// distribution, those rebuilds might not even have permission to update -// the cached build output. To avoid these write errors, if an input and -// output have the same mtime, we assume the output is up-to-date. -// This is the opposite of what the previous problem would have us do, -// but binary distributions are more common than instances of the -// previous problem. -// -// A variant of the last problem is that some binary distributions do not -// set the mtime on all files to the same time. Instead they let the file -// system record mtimes as the distribution is unpacked. If the outputs -// are unpacked before the inputs, they'll be older and a build will try -// to rebuild them. That rebuild might hit the same write errors as in -// the last scenario. We don't make any attempt to solve this, and we -// haven't had many reports of it. Perhaps the only time this happens is -// when people manually unpack the distribution, and most of the time -// that's done as the same user who will be using it, so an initial -// rebuild on first use succeeds quietly. -// -// More generally, people and programs change mtimes on files. The last -// few problems were specific examples of this, but it's a general problem. -// For example, instead of a binary distribution, copying a home -// directory from one directory or machine to another might copy files -// but not preserve mtimes. If the inputs are new than the outputs on the -// first machine but copied first, they end up older than the outputs on -// the second machine. -// -// Because many other build systems have the same sensitivity to mtimes, -// most programs manipulating source code take pains not to break the -// mtime assumptions. For example, Git does not set the mtime of files -// during a checkout operation, even when checking out an old version of -// the code. This decision was made specifically to work well with -// mtime-based build systems. -// -// The killer problem, though, for mtime-based build systems is that the -// build only has access to the mtimes of the inputs that still exist. -// If it is possible to remove an input without changing any other inputs, -// a later build will think the object is up-to-date when it is not. -// This happens for Go because a package is made up of all source -// files in a directory. If a source file is removed, there is no newer -// mtime available recording that fact. The mtime on the directory could -// be used, but it also changes when unrelated files are added to or -// removed from the directory, so including the directory mtime would -// cause unnecessary rebuilds, possibly many. It would also exacerbate -// the problems mentioned earlier, since even programs that are careful -// to maintain mtimes on files rarely maintain mtimes on directories. -// -// A variant of the last problem is when the inputs change for other -// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg -// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a. -// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must -// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date. -// If Go 1.5 has just been installed, perhaps the compiler will have a -// newer mtime; since the compiler is considered an input, that would -// trigger a rebuild. But only once, and only the last Go 1.4 build of -// mypkg.a happened before Go 1.5 was installed. If a user has the two -// versions installed in different locations and flips back and forth, -// mtimes alone cannot tell what to do. Changing the toolchain is -// changing the set of inputs, without affecting any mtimes. -// -// To detect the set of inputs changing, we turn away from mtimes and to -// an explicit data comparison. Specifically, we build a list of the -// inputs to the build, compute its SHA1 hash, and record that as the -// ``build ID'' in the generated object. At the next build, we can -// recompute the build ID and compare it to the one in the generated -// object. If they differ, the list of inputs has changed, so the object -// is out of date and must be rebuilt. -// -// Because this build ID is computed before the build begins, the -// comparison does not have the race that mtime comparison does. -// -// Making the build sensitive to changes in other state is -// straightforward: include the state in the build ID hash, and if it -// changes, so does the build ID, triggering a rebuild. -// -// To detect changes in toolchain, we include the toolchain version in -// the build ID hash for package runtime, and then we include the build -// IDs of all imported packages in the build ID for p. -// -// It is natural to think about including build tags in the build ID, but -// the naive approach of just dumping the tags into the hash would cause -// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag' -// produce the same binaries (assuming neverusedtag is never used). -// A more precise approach would be to include only tags that have an -// effect on the build. But the effect of a tag on the build is to -// include or exclude a file from the compilation, and that file list is -// already in the build ID hash. So the build ID is already tag-sensitive -// in a perfectly precise way. So we do NOT explicitly add build tags to -// the build ID hash. -// -// We do not include as part of the build ID the operating system, -// architecture, or whether the race detector is enabled, even though all -// three have an effect on the output, because that information is used -// to decide the install location. Binaries for linux and binaries for -// darwin are written to different directory trees; including that -// information in the build ID is unnecessary (although it would be -// harmless). -// -// TODO(rsc): Investigate the cost of putting source file content into -// the build ID hash as a replacement for the use of mtimes. Using the -// file content would avoid all the mtime problems, but it does require -// reading all the source files, something we avoid today (we read the -// beginning to find the build tags and the imports, but we stop as soon -// as we see the import block is over). If the package is stale, the compiler -// is going to read the files anyway. But if the package is up-to-date, the -// read is overhead. -// -// TODO(rsc): Investigate the complexity of making the build more -// precise about when individual results are needed. To be fully precise, -// there are two results of a compilation: the entire .a file used by the link -// and the subpiece used by later compilations (__.PKGDEF only). -// If a rebuild is needed but produces the previous __.PKGDEF, then -// no more recompilation due to the rebuilt package is needed, only -// relinking. To date, there is nothing in the Go command to express this. -// -// Special Cases -// -// When the go command makes the wrong build decision and does not -// rebuild something it should, users fall back to adding the -a flag. -// Any common use of the -a flag should be considered prima facie evidence -// that isStale is returning an incorrect false result in some important case. -// Bugs reported in the behavior of -a itself should prompt the question -// ``Why is -a being used at all? What bug does that indicate?'' -// -// There is a long history of changes to isStale to try to make -a into a -// suitable workaround for bugs in the mtime-based decisions. -// It is worth recording that history to inform (and, as much as possible, deter) future changes. -// -// (1) Before the build IDs were introduced, building with alternate tags -// would happily reuse installed objects built without those tags. -// For example, "go build -tags netgo myprog.go" would use the installed -// copy of package net, even if that copy had been built without netgo. -// (The netgo tag controls whether package net uses cgo or pure Go for -// functionality such as name resolution.) -// Using the installed non-netgo package defeats the purpose. -// -// Users worked around this with "go build -tags netgo -a myprog.go". -// -// Build IDs have made that workaround unnecessary: -// "go build -tags netgo myprog.go" -// cannot use a non-netgo copy of package net. -// -// (2) Before the build IDs were introduced, building with different toolchains, -// especially changing between toolchains, tried to reuse objects stored in -// $GOPATH/pkg, resulting in link-time errors about object file mismatches. -// -// Users worked around this with "go install -a ./...". -// -// Build IDs have made that workaround unnecessary: -// "go install ./..." will rebuild any objects it finds that were built against -// a different toolchain. -// -// (3) The common use of "go install -a ./..." led to reports of problems -// when the -a forced the rebuild of the standard library, which for some -// users was not writable. Because we didn't understand that the real -// problem was the bug -a was working around, we changed -a not to -// apply to the standard library. -// -// (4) The common use of "go build -tags netgo -a myprog.go" broke -// when we changed -a not to apply to the standard library, because -// if go build doesn't rebuild package net, it uses the non-netgo version. -// -// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go". -// The -installsuffix here is making the go command look for packages -// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH. -// Since the former presumably doesn't exist, go build decides to rebuild -// everything, including the standard library. Since go build doesn't -// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf, -// so repeated invocations continue to work. -// -// If the use of -a wasn't a red flag, the use of -installsuffix to point to -// a non-existent directory in a command that installs nothing should -// have been. -// -// (5) Now that (1) and (2) no longer need -a, we have removed the kludge -// introduced in (3): once again, -a means ``rebuild everything,'' not -// ``rebuild everything except the standard library.'' Only Go 1.4 had -// the restricted meaning. -// -// In addition to these cases trying to trigger rebuilds, there are -// special cases trying NOT to trigger rebuilds. The main one is that for -// a variety of reasons (see above), the install process for a Go release -// cannot be relied upon to set the mtimes such that the go command will -// think the standard library is up to date. So the mtime evidence is -// ignored for the standard library if we find ourselves in a release -// version of Go. Build ID-based staleness checks still apply to the -// standard library, even in release versions. This makes -// 'go build -tags netgo' work, among other things. - -// isStale reports whether package p needs to be rebuilt, -// along with the reason why. -func isStale(p *Package) (bool, string) { - if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") { - // fake, builtin package - return false, "builtin package" - } - if p.Error != nil { - return true, "errors loading package" - } - if p.Stale { - return true, p.StaleReason - } - - // If this is a package with no source code, it cannot be rebuilt. - // If the binary is missing, we mark the package stale so that - // if a rebuild is needed, that rebuild attempt will produce a useful error. - // (Some commands, such as 'go list', do not attempt to rebuild.) - if p.BinaryOnly { - if p.Internal.Target == "" { - // Fail if a build is attempted. - return true, "no source code for package, but no install target" - } - if _, err := os.Stat(p.Internal.Target); err != nil { - // Fail if a build is attempted. - return true, "no source code for package, but cannot access install target: " + err.Error() - } - return false, "no source code for package" - } - - // If the -a flag is given, rebuild everything. - if cfg.BuildA { - return true, "build -a flag in use" - } - - // If there's no install target, we have to rebuild. - if p.Internal.Target == "" { - return true, "no install target" - } - - // Package is stale if completely unbuilt. - fi, err := os.Stat(p.Internal.Target) - if err != nil { - return true, "cannot stat install target" - } - - // Package is stale if the expected build ID differs from the - // recorded build ID. This catches changes like a source file - // being removed from a package directory. See issue 3895. - // It also catches changes in build tags that affect the set of - // files being compiled. See issue 9369. - // It also catches changes in toolchain, like when flipping between - // two versions of Go compiling a single GOPATH. - // See issue 8290 and issue 10702. - targetBuildID, err := buildid.ReadBuildID(p.Name, p.Target) - if err == nil && targetBuildID != p.Internal.BuildID { - return true, "build ID mismatch" - } - - // Package is stale if a dependency is. - for _, p1 := range p.Internal.Deps { - if p1.Stale { - return true, "stale dependency" - } - } - - // The checks above are content-based staleness. - // We assume they are always accurate. - // - // The checks below are mtime-based staleness. - // We hope they are accurate, but we know that they fail in the case of - // prebuilt Go installations that don't preserve the build mtimes - // (for example, if the pkg/ mtimes are before the src/ mtimes). - // See the large comment above isStale for details. - - // If we are running a release copy of Go and didn't find a content-based - // reason to rebuild the standard packages, do not rebuild them. - // They may not be writable anyway, but they are certainly not changing. - // This makes 'go build' skip the standard packages when - // using an official release, even when the mtimes have been changed. - // See issue 3036, issue 3149, issue 4106, issue 8290. - // (If a change to a release tree must be made by hand, the way to force the - // install is to run make.bash, which will remove the old package archives - // before rebuilding.) - if p.Standard && isGoRelease { - return false, "standard package in Go release distribution" - } - - // Time-based staleness. - - built := fi.ModTime() - - olderThan := func(file string) bool { - fi, err := os.Stat(file) - return err != nil || fi.ModTime().After(built) - } - - // Package is stale if a dependency is, or if a dependency is newer. - for _, p1 := range p.Internal.Deps { - if p1.Internal.Target != "" && olderThan(p1.Internal.Target) { - return true, "newer dependency" - } - } - - // As a courtesy to developers installing new versions of the compiler - // frequently, define that packages are stale if they are - // older than the compiler, and commands if they are older than - // the linker. This heuristic will not work if the binaries are - // back-dated, as some binary distributions may do, but it does handle - // a very common case. - // See issue 3036. - // Exclude $GOROOT, under the assumption that people working on - // the compiler may want to control when everything gets rebuilt, - // and people updating the Go repository will run make.bash or all.bash - // and get a full rebuild anyway. - // Excluding $GOROOT used to also fix issue 4106, but that's now - // taken care of above (at least when the installed Go is a released version). - if p.Root != cfg.GOROOT { - if olderThan(cfg.BuildToolchainCompiler()) { - return true, "newer compiler" - } - if p.Internal.Build.IsCommand() && olderThan(cfg.BuildToolchainLinker()) { - return true, "newer linker" - } - } - - // Note: Until Go 1.5, we had an additional shortcut here. - // We built a list of the workspace roots ($GOROOT, each $GOPATH) - // containing targets directly named on the command line, - // and if p were not in any of those, it would be treated as up-to-date - // as long as it is built. The goal was to avoid rebuilding a system-installed - // $GOROOT, unless something from $GOROOT were explicitly named - // on the command line (like go install math). - // That's now handled by the isGoRelease clause above. - // The other effect of the shortcut was to isolate different entries in - // $GOPATH from each other. This had the unfortunate effect that - // if you had (say), GOPATH listing two entries, one for commands - // and one for libraries, and you did a 'git pull' in the library one - // and then tried 'go install commands/...', it would build the new libraries - // during the first build (because they wouldn't have been installed at all) - // but then subsequent builds would not rebuild the libraries, even if the - // mtimes indicate they are stale, because the different GOPATH entries - // were treated differently. This behavior was confusing when using - // non-trivial GOPATHs, which were particularly common with some - // code management conventions, like the original godep. - // Since the $GOROOT case (the original motivation) is handled separately, - // we no longer put a barrier between the different $GOPATH entries. - // - // One implication of this is that if there is a system directory for - // non-standard Go packages that is included in $GOPATH, the mtimes - // on those compiled packages must be no earlier than the mtimes - // on the source files. Since most distributions use the same mtime - // for all files in a tree, they will be unaffected. People using plain - // tar x to extract system-installed packages will need to adjust mtimes, - // but it's better to force them to get the mtimes right than to ignore - // the mtimes and thereby do the wrong thing in common use cases. - // - // So there is no GOPATH vs GOPATH shortcut here anymore. - // - // If something needs to come back here, we could try writing a dummy - // file with a random name to the $GOPATH/pkg directory (and removing it) - // to test for write access, and then skip GOPATH roots we don't have write - // access to. But hopefully we can just use the mtimes always. - - srcs := str.StringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles) - for _, src := range srcs { - if olderThan(filepath.Join(p.Dir, src)) { - return true, "newer source file" - } - } - - return false, "" -} - -// computeBuildID computes the build ID for p, leaving it in p.Internal.BuildID. -// Build ID is a hash of the information we want to detect changes in. -// See the long comment in isStale for details. -func computeBuildID(p *Package) { - h := sha1.New() - - // Include the list of files compiled as part of the package. - // This lets us detect removed files. See issue 3895. - inputFiles := str.StringList( - p.GoFiles, - p.CgoFiles, - p.CFiles, - p.CXXFiles, - p.FFiles, - p.MFiles, - p.HFiles, - p.SFiles, - p.SysoFiles, - p.SwigFiles, - p.SwigCXXFiles, - ) - for _, file := range inputFiles { - fmt.Fprintf(h, "file %s\n", file) - } - - // Include the content of runtime/internal/sys/zversion.go in the hash - // for package runtime. This will give package runtime a - // different build ID in each Go release. - if p.Standard && p.ImportPath == "runtime/internal/sys" && cfg.BuildContext.Compiler != "gccgo" { - data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go")) - if os.IsNotExist(err) { - p.Stale = true - p.StaleReason = fmt.Sprintf("missing zversion.go") - } else if err != nil { - base.Fatalf("go: %s", err) - } - fmt.Fprintf(h, "zversion %q\n", string(data)) - - // Add environment variables that affect code generation. - switch cfg.BuildContext.GOARCH { - case "arm": - fmt.Fprintf(h, "GOARM=%s\n", cfg.GOARM) - case "386": - fmt.Fprintf(h, "GO386=%s\n", cfg.GO386) - } - } - - // Include the build IDs of any dependencies in the hash. - // This, combined with the runtime/zversion content, - // will cause packages to have different build IDs when - // compiled with different Go releases. - // This helps the go command know to recompile when - // people use the same GOPATH but switch between - // different Go releases. See issue 10702. - // This is also a better fix for issue 8290. - for _, p1 := range p.Internal.Deps { - fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.Internal.BuildID) - } - - p.Internal.BuildID = fmt.Sprintf("%x", h.Sum(nil)) -} - var cmdCache = map[string]*Package{} func ClearCmdCache() { @@ -1842,7 +1405,6 @@ func PackagesAndErrors(args []string) []*Package { seenPkg[pkg] = true pkgs = append(pkgs, pkg) } - ComputeStale(pkgs...) return pkgs } @@ -1943,13 +1505,13 @@ func GoFilesPackage(gofiles []string) *Package { bp, err := ctxt.ImportDir(dir, 0) pkg := new(Package) pkg.Internal.Local = true - pkg.Internal.Cmdline = true + pkg.Internal.CmdlineFiles = true stk.Push("main") pkg.load(&stk, bp, err) stk.Pop() pkg.Internal.LocalPrefix = dirToImportPath(dir) pkg.ImportPath = "command-line-arguments" - pkg.Internal.Target = "" + pkg.Target = "" if pkg.Name == "main" { _, elem := filepath.Split(gofiles[0]) @@ -1958,14 +1520,9 @@ func GoFilesPackage(gofiles []string) *Package { cfg.BuildO = exe } if cfg.GOBIN != "" { - pkg.Internal.Target = filepath.Join(cfg.GOBIN, exe) + pkg.Target = filepath.Join(cfg.GOBIN, exe) } } - pkg.Target = pkg.Internal.Target - pkg.Stale = true - pkg.StaleReason = "files named on command line" - - ComputeStale(pkg) return pkg } diff --git a/libgo/go/cmd/go/internal/load/search.go b/libgo/go/cmd/go/internal/load/search.go index 0c7d9ce0e6c..595de079046 100644 --- a/libgo/go/cmd/go/internal/load/search.go +++ b/libgo/go/cmd/go/internal/load/search.go @@ -266,6 +266,50 @@ func matchPattern(pattern string) func(name string) bool { } } +// MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd. +func MatchPackage(pattern, cwd string) func(*Package) bool { + switch { + case strings.HasPrefix(pattern, "./") || strings.HasPrefix(pattern, "../") || pattern == "." || pattern == "..": + // Split pattern into leading pattern-free directory path + // (including all . and .. elements) and the final pattern. + var dir string + i := strings.Index(pattern, "...") + if i < 0 { + dir, pattern = pattern, "" + } else { + j := strings.LastIndex(pattern[:i], "/") + dir, pattern = pattern[:j], pattern[j+1:] + } + dir = filepath.Join(cwd, dir) + if pattern == "" { + return func(p *Package) bool { return p.Dir == dir } + } + matchPath := matchPattern(pattern) + return func(p *Package) bool { + // Compute relative path to dir and see if it matches the pattern. + rel, err := filepath.Rel(dir, p.Dir) + if err != nil { + // Cannot make relative - e.g. different drive letters on Windows. + return false + } + rel = filepath.ToSlash(rel) + if rel == ".." || strings.HasPrefix(rel, "../") { + return false + } + return matchPath(rel) + } + case pattern == "all": + return func(p *Package) bool { return true } + case pattern == "std": + return func(p *Package) bool { return p.Standard } + case pattern == "cmd": + return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") } + default: + matchPath := matchPattern(pattern) + return func(p *Package) bool { return matchPath(p.ImportPath) } + } +} + // replaceVendor returns the result of replacing // non-trailing vendor path elements in x with repl. func replaceVendor(x, repl string) string { @@ -302,6 +346,9 @@ func ImportPaths(args []string) []string { // ImportPathsNoDotExpansion returns the import paths to use for the given // command line, but it does no ... expansion. func ImportPathsNoDotExpansion(args []string) []string { + if cmdlineMatchers == nil { + SetCmdlinePatterns(args) + } if len(args) == 0 { return []string{"."} } @@ -332,7 +379,7 @@ func ImportPathsNoDotExpansion(args []string) []string { return out } -// isMetaPackage checks if name is a reserved package name that expands to multiple packages. +// IsMetaPackage checks if name is a reserved package name that expands to multiple packages. func IsMetaPackage(name string) bool { return name == "std" || name == "cmd" || name == "all" } diff --git a/libgo/go/cmd/go/internal/load/testgo.go b/libgo/go/cmd/go/internal/load/testgo.go deleted file mode 100644 index 7734048f5c9..00000000000 --- a/libgo/go/cmd/go/internal/load/testgo.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file contains extra hooks for testing the go command. -// It is compiled into the Go binary only when building the -// test copy; it does not get compiled into the standard go -// command, so these testing hooks are not present in the -// go command that everyone uses. - -// +build testgo - -package load - -import "os" - -func init() { - if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" { - isGoRelease = v == "1" - } -} diff --git a/libgo/go/cmd/go/internal/run/run.go b/libgo/go/cmd/go/internal/run/run.go index 6e276c28ec1..ce24748f4e3 100644 --- a/libgo/go/cmd/go/internal/run/run.go +++ b/libgo/go/cmd/go/internal/run/run.go @@ -52,8 +52,7 @@ func printStderr(args ...interface{}) (int, error) { } func runRun(cmd *base.Command, args []string) { - work.InstrumentInit() - work.BuildModeInit() + work.BuildInit() var b work.Builder b.Init() b.Print = printStderr @@ -94,7 +93,7 @@ func runRun(cmd *base.Command, args []string) { if p.Name != "main" { base.Fatalf("go run: cannot run non-main package") } - p.Internal.Target = "" // must build - not up to date + p.Target = "" // must build - not up to date var src string if len(p.GoFiles) > 0 { src = p.GoFiles[0] @@ -110,8 +109,8 @@ func runRun(cmd *base.Command, args []string) { base.Fatalf("go run: no suitable source files%s", hint) } p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file - a1 := b.Action(work.ModeBuild, work.ModeBuild, p) - a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}} + a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p) + a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}} b.Do(a) } diff --git a/libgo/go/cmd/go/internal/test/cover.go b/libgo/go/cmd/go/internal/test/cover.go new file mode 100644 index 00000000000..12538b46564 --- /dev/null +++ b/libgo/go/cmd/go/internal/test/cover.go @@ -0,0 +1,84 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package test + +import ( + "cmd/go/internal/base" + "fmt" + "io" + "os" + "path/filepath" + "sync" +) + +var coverMerge struct { + f *os.File + sync.Mutex // for f.Write +} + +// initCoverProfile initializes the test coverage profile. +// It must be run before any calls to mergeCoverProfile or closeCoverProfile. +// Using this function clears the profile in case it existed from a previous run, +// or in case it doesn't exist and the test is going to fail to create it (or not run). +func initCoverProfile() { + if testCoverProfile == "" { + return + } + if !filepath.IsAbs(testCoverProfile) && testOutputDir != "" { + testCoverProfile = filepath.Join(testOutputDir, testCoverProfile) + } + + // No mutex - caller's responsibility to call with no racing goroutines. + f, err := os.Create(testCoverProfile) + if err != nil { + base.Fatalf("%v", err) + } + _, err = fmt.Fprintf(f, "mode: %s\n", testCoverMode) + if err != nil { + base.Fatalf("%v", err) + } + coverMerge.f = f +} + +// mergeCoverProfile merges file into the profile stored in testCoverProfile. +// It prints any errors it encounters to ew. +func mergeCoverProfile(ew io.Writer, file string) { + if coverMerge.f == nil { + return + } + coverMerge.Lock() + defer coverMerge.Unlock() + + expect := fmt.Sprintf("mode: %s\n", testCoverMode) + buf := make([]byte, len(expect)) + r, err := os.Open(file) + if err != nil { + // Test did not create profile, which is OK. + return + } + defer r.Close() + + n, err := io.ReadFull(r, buf) + if n == 0 { + return + } + if err != nil || string(buf) != expect { + fmt.Fprintf(ew, "error: test wrote malformed coverage profile.\n") + return + } + _, err = io.Copy(coverMerge.f, r) + if err != nil { + fmt.Fprintf(ew, "error: saving coverage profile: %v\n", err) + } +} + +func closeCoverProfile() { + if coverMerge.f == nil { + return + } + if err := coverMerge.f.Close(); err != nil { + base.Errorf("closing coverage profile: %v", err) + } +} diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go index c1e66f9e889..3e08a721545 100644 --- a/libgo/go/cmd/go/internal/test/test.go +++ b/libgo/go/cmd/go/internal/test/test.go @@ -13,24 +13,29 @@ import ( "go/doc" "go/parser" "go/token" + "io" + "io/ioutil" "os" "os/exec" "path" "path/filepath" "regexp" - "runtime" "sort" + "strconv" "strings" + "sync" "text/template" "time" "unicode" "unicode/utf8" "cmd/go/internal/base" + "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" "cmd/go/internal/work" + "cmd/internal/test2json" ) // Break init loop. @@ -57,10 +62,10 @@ followed by detailed output for each failed package. 'Go test' recompiles each package along with any files with names matching the file pattern "*_test.go". -Files whose names begin with "_" (including "_test.go") or "." are ignored. These additional files can contain test functions, benchmark functions, and example functions. See 'go help testfunc' for more. Each listed package causes the execution of a separate test binary. +Files whose names begin with "_" (including "_test.go") or "." are ignored. Test files that declare a package with the suffix "_test" will be compiled as a separate package, and then linked and run with the main test binary. @@ -68,11 +73,46 @@ separate package, and then linked and run with the main test binary. The go tool will ignore a directory named "testdata", making it available to hold ancillary data needed by the tests. -By default, go test needs no arguments. It compiles and tests the package -with source in the current directory, including tests, and runs the tests. - -The package is built in a temporary directory so it does not interfere with the -non-test installation. +As part of building a test binary, go test runs go vet on the package +and its test source files to identify significant problems. If go vet +finds any problems, go test reports those and does not run the test binary. +Only a high-confidence subset of the default go vet checks are used. +To disable the running of go vet, use the -vet=off flag. + +Go test runs in two different modes: local directory mode when invoked with +no package arguments (for example, 'go test'), and package list mode when +invoked with package arguments (for example 'go test math', 'go test ./...', +and even 'go test .'). + +In local directory mode, go test compiles and tests the package sources +found in the current directory and then runs the resulting test binary. +In this mode, caching (discussed below) is disabled. After the package test +finishes, go test prints a summary line showing the test status ('ok' or 'FAIL'), +package name, and elapsed time. + +In package list mode, go test compiles and tests each of the packages +listed on the command line. If a package test passes, go test prints only +the final 'ok' summary line. If a package test fails, go test prints the +full test output. If invoked with the -bench or -v flag, go test prints +the full output even for passing package tests, in order to display the +requested benchmark results or verbose logging. + +All test output and summary lines are printed to the go command's standard +output, even if the test printed them to its own standard error. +(The go command's standard error is reserved for printing errors building +the tests.) + +In package list mode, go test also caches successful package test results. +If go test has cached a previous test run using the same test binary and +the same command line consisting entirely of cacheable test flags +(defined as -cpu, -list, -parallel, -run, -short, and -v), +go test will redisplay the previous output instead of running the test +binary again. In the summary line, go test prints '(cached)' in place of +the elapsed time. To disable test caching, use any test flag or argument +other than the cacheable flags. The idiomatic way to disable test caching +explicitly is to use -count=1. A cached result is treated as executing in +no time at all, so a successful package test result will be cached and reused +regardless of -timeout setting. ` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details. @@ -105,6 +145,10 @@ In addition to the build flags, the flags handled by 'go test' itself are: Install packages that are dependencies of the test. Do not run the test. + -json + Convert test output to JSON suitable for automated processing. + See 'go doc test2json' for the encoding details. + -o file Compile the test binary to the named file. The test still runs (unless -c or -i is specified). @@ -143,7 +187,7 @@ control the execution of any test: const testFlag2 = ` -bench regexp Run only those benchmarks matching a regular expression. - By default, no benchmarks are run. + By default, no benchmarks are run. To run all benchmarks, use '-bench .' or '-bench=.'. The regular expression is split by unbracketed slash (/) characters into a sequence of regular expressions, and each @@ -182,10 +226,10 @@ const testFlag2 = ` significantly more expensive. Sets -cover. - -coverpkg pkg1,pkg2,pkg3 - Apply coverage analysis in each test to the given list of packages. + -coverpkg pattern1,pattern2,pattern3 + Apply coverage analysis in each test to packages matching the patterns. The default is for each test to analyze only the package being tested. - Packages are specified as import paths. + See 'go help packages' for a description of package patterns. Sets -cover. -cpu 1,2,4 @@ -193,6 +237,9 @@ const testFlag2 = ` benchmarks should be executed. The default is the current value of GOMAXPROCS. + -failfast + Do not start new tests after the first test failure. + -list regexp List tests, benchmarks, or examples matching the regular expression. No tests, benchmarks or examples will be run. This will only @@ -225,12 +272,20 @@ const testFlag2 = ` -timeout d If a test binary runs longer than duration d, panic. + If d is 0, the timeout is disabled. The default is 10 minutes (10m). -v Verbose output: log all tests as they are run. Also print all text from Log and Logf calls even if the test succeeds. + -vet list + Configure the invocation of "go vet" during "go test" + to use the comma-separated list of vet checks. + If list is empty, "go test" runs "go vet" with a curated list of + checks believed to be always worth addressing. + If list is "off", "go test" does not run "go vet" at all. + The following flags are also recognized by 'go test' and can be used to profile the tests during execution: @@ -411,36 +466,68 @@ var ( testCoverMode string // -covermode flag testCoverPaths []string // -coverpkg flag testCoverPkgs []*load.Package // -coverpkg flag + testCoverProfile string // -coverprofile flag + testOutputDir string // -outputdir flag testO string // -o flag - testProfile bool // some profiling flag + testProfile string // profiling flag that limits test to one package testNeedBinary bool // profile needs to keep binary around + testJSON bool // -json flag testV bool // -v flag testTimeout string // -timeout flag testArgs []string testBench bool testList bool - testStreamOutput bool // show output as it is generated - testShowPass bool // show passing output + testShowPass bool // show passing output + testVetList string // -vet flag + pkgArgs []string + pkgs []*load.Package testKillTimeout = 10 * time.Minute + testCacheExpire time.Time // ignore cached test results before this time ) -var testMainDeps = map[string]bool{ +var testMainDeps = []string{ // Dependencies for testmain. - "testing": true, - "testing/internal/testdeps": true, - "os": true, + "os", + "testing", + "testing/internal/testdeps", +} + +// testVetFlags is the list of flags to pass to vet when invoked automatically during go test. +var testVetFlags = []string{ + // TODO(rsc): Decide which tests are enabled by default. + // See golang.org/issue/18085. + // "-asmdecl", + // "-assign", + "-atomic", + "-bool", + "-buildtags", + // "-cgocall", + // "-composites", + // "-copylocks", + // "-httpresponse", + // "-lostcancel", + // "-methods", + "-nilfunc", + "-printf", + // "-rangeloops", + // "-shift", + // "-structtags", + // "-tests", + // "-unreachable", + // "-unsafeptr", + // "-unusedresult", } func runTest(cmd *base.Command, args []string) { - var pkgArgs []string pkgArgs, testArgs = testFlags(args) work.FindExecCmd() // initialize cached result - work.InstrumentInit() - work.BuildModeInit() - pkgs := load.PackagesForBuild(pkgArgs) + work.BuildInit() + work.VetFlags = testVetFlags + + pkgs = load.PackagesForBuild(pkgArgs) if len(pkgs) == 0 { base.Fatalf("no packages to test") } @@ -451,9 +538,11 @@ func runTest(cmd *base.Command, args []string) { if testO != "" && len(pkgs) != 1 { base.Fatalf("cannot use -o flag with multiple packages") } - if testProfile && len(pkgs) != 1 { - base.Fatalf("cannot use test profile flag with multiple packages") + if testProfile != "" && len(pkgs) != 1 { + base.Fatalf("cannot use %s flag with multiple packages", testProfile) } + initCoverProfile() + defer closeCoverProfile() // If a test timeout was given and is parseable, set our kill timeout // to that timeout plus one minute. This is a backup alarm in case @@ -461,6 +550,10 @@ func runTest(cmd *base.Command, args []string) { // timer does not get a chance to fire. if dt, err := time.ParseDuration(testTimeout); err == nil && dt > 0 { testKillTimeout = dt + 1*time.Minute + } else if err == nil && dt == 0 { + // An explicit zero disables the test timeout. + // Let it have one century (almost) before we kill it. + testKillTimeout = 100 * 365 * 24 * time.Hour } // show passing test output (after buffering) with -v flag. @@ -468,21 +561,22 @@ func runTest(cmd *base.Command, args []string) { // otherwise the output will get mixed. testShowPass = testV || testList - // stream test output (no buffering) when no package has - // been given on the command line (implicit current directory) - // or when benchmarking. - // Also stream if we're showing output anyway with a - // single package under test or if parallelism is set to 1. - // In these cases, streaming the output produces the same result - // as not streaming, just more immediately. - testStreamOutput = len(pkgArgs) == 0 || testBench || - (testShowPass && (len(pkgs) == 1 || cfg.BuildP == 1)) - // For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier. if cfg.BuildI && testO != "" { testC = true } + // Read testcache expiration time, if present. + // (We implement go clean -testcache by writing an expiration date + // instead of searching out and deleting test result cache entries.) + if dir := cache.DefaultDir(); dir != "off" { + if data, _ := ioutil.ReadFile(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' { + if t, err := strconv.ParseInt(string(data[:len(data)-1]), 10, 64); err == nil { + testCacheExpire = time.Unix(0, t) + } + } + } + var b work.Builder b.Init() @@ -490,7 +584,7 @@ func runTest(cmd *base.Command, args []string) { cfg.BuildV = testV deps := make(map[string]bool) - for dep := range testMainDeps { + for _, dep := range testMainDeps { deps[dep] = true } @@ -511,9 +605,6 @@ func runTest(cmd *base.Command, args []string) { if deps["C"] { delete(deps, "C") deps["runtime/cgo"] = true - if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan { - deps["cmd/cgo"] = true - } } // Ignore pseudo-packages. delete(deps, "unsafe") @@ -526,12 +617,12 @@ func runTest(cmd *base.Command, args []string) { } sort.Strings(all) - a := &work.Action{} + a := &work.Action{Mode: "go test -i"} for _, p := range load.PackagesForBuild(all) { if cfg.BuildToolchainName == "gccgo" && p.Standard { continue } - a.Deps = append(a.Deps, b.Action(work.ModeInstall, work.ModeInstall, p)) + a.Deps = append(a.Deps, b.CompileAction(work.ModeInstall, work.ModeInstall, p)) } b.Do(a) if !testC || a.Failed { @@ -543,21 +634,30 @@ func runTest(cmd *base.Command, args []string) { var builds, runs, prints []*work.Action if testCoverPaths != nil { - // Load packages that were asked about for coverage. - // packagesForBuild exits if the packages cannot be loaded. - testCoverPkgs = load.PackagesForBuild(testCoverPaths) - - // Warn about -coverpkg arguments that are not actually used. - used := make(map[string]bool) - for _, p := range pkgs { - used[p.ImportPath] = true - for _, dep := range p.Deps { - used[dep] = true + match := make([]func(*load.Package) bool, len(testCoverPaths)) + matched := make([]bool, len(testCoverPaths)) + for i := range testCoverPaths { + match[i] = load.MatchPackage(testCoverPaths[i], base.Cwd) + } + + // Select for coverage all dependencies matching the testCoverPaths patterns. + for _, p := range load.PackageList(pkgs) { + haveMatch := false + for i := range testCoverPaths { + if match[i](p) { + matched[i] = true + haveMatch = true + } + } + if haveMatch { + testCoverPkgs = append(testCoverPkgs, p) } } - for _, p := range testCoverPkgs { - if !used[p.ImportPath] { - fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on %s\n", p.ImportPath) + + // Warn about -coverpkg arguments that are not actually used. + for i := range testCoverPaths { + if !matched[i] { + fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on matches for pattern %s\n", testCoverPaths[i]) } } @@ -567,15 +667,15 @@ func runTest(cmd *base.Command, args []string) { if p.ImportPath == "unsafe" { continue } - p.Stale = true // rebuild - p.StaleReason = "rebuild for coverage" - p.Internal.Fake = true // do not warn about rebuild p.Internal.CoverMode = testCoverMode var coverFiles []string coverFiles = append(coverFiles, p.GoFiles...) coverFiles = append(coverFiles, p.CgoFiles...) coverFiles = append(coverFiles, p.TestGoFiles...) p.Internal.CoverVars = declareCoverVars(p.ImportPath, coverFiles...) + if testCover && testCoverMode == "atomic" { + ensureImport(p, "sync/atomic") + } } } @@ -607,7 +707,7 @@ func runTest(cmd *base.Command, args []string) { } // Ultimately the goal is to print the output. - root := &work.Action{Deps: prints} + root := &work.Action{Mode: "go test", Deps: prints} // Force the printing of results to happen in order, // one at a time. @@ -630,68 +730,23 @@ func runTest(cmd *base.Command, args []string) { } } - // If we are building any out-of-date packages other - // than those under test, warn. - okBuild := map[*load.Package]bool{} - for _, p := range pkgs { - okBuild[p] = true - } - warned := false - for _, a := range work.ActionList(root) { - if a.Package == nil || okBuild[a.Package] { - continue - } - okBuild[a.Package] = true // warn at most once - - // Don't warn about packages being rebuilt because of - // things like coverage analysis. - for _, p1 := range a.Package.Internal.Imports { - if p1.Internal.Fake { - a.Package.Internal.Fake = true - } - } - - if a.Func != nil && !okBuild[a.Package] && !a.Package.Internal.Fake && !a.Package.Internal.Local { - if !warned { - fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n") - warned = true - } - fmt.Fprintf(os.Stderr, "\t%s\n", a.Package.ImportPath) - } - } - if warned { - args := strings.Join(pkgArgs, " ") - if args != "" { - args = " " + args - } - extraOpts := "" - if cfg.BuildRace { - extraOpts = "-race " - } - if cfg.BuildMSan { - extraOpts = "-msan " - } - fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args) - } - b.Do(root) } // ensures that package p imports the named package func ensureImport(p *load.Package, pkg string) { - for _, d := range p.Internal.Deps { + for _, d := range p.Internal.Imports { if d.Name == pkg { return } } - a := load.LoadPackage(pkg, &load.ImportStack{}) - if a.Error != nil { - base.Fatalf("load %s: %v", pkg, a.Error) + p1 := load.LoadPackage(pkg, &load.ImportStack{}) + if p1.Error != nil { + base.Fatalf("load %s: %v", pkg, p1.Error) } - load.ComputeStale(a) - p.Internal.Imports = append(p.Internal.Imports, a) + p.Internal.Imports = append(p.Internal.Imports, p1) } var windowsBadWords = []string{ @@ -703,9 +758,10 @@ var windowsBadWords = []string{ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := b.Action(work.ModeBuild, work.ModeBuild, p) - run := &work.Action{Package: p, Deps: []*work.Action{build}} - print := &work.Action{Func: builderNoTest, Package: p, Deps: []*work.Action{run}} + build := b.CompileAction(work.ModeBuild, work.ModeBuild, p) + run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}} + addTestVet(b, p, run, nil) + print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}} return build, run, print, nil } @@ -718,6 +774,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin var imports, ximports []*load.Package var stk load.ImportStack stk.Push(p.ImportPath + " (test)") + rawTestImports := str.StringList(p.TestImports) for i, path := range p.TestImports { p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor) if cfg.BuildToolchainName == "gccgo" && p1.Standard { @@ -748,6 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin stk.Pop() stk.Push(p.ImportPath + "_test") pxtestNeedsPtest := false + rawXTestImports := str.StringList(p.XTestImports) for i, path := range p.XTestImports { p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor) if cfg.BuildToolchainName == "gccgo" && p1.Standard { @@ -782,29 +840,6 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin } testBinary := elem + ".test" - // The ptest package needs to be importable under the - // same import path that p has, but we cannot put it in - // the usual place in the temporary tree, because then - // other tests will see it as the real package. - // Instead we make a _test directory under the import path - // and then repeat the import path there. We tell the - // compiler and linker to look in that _test directory first. - // - // That is, if the package under test is unicode/utf8, - // then the normal place to write the package archive is - // $WORK/unicode/utf8.a, but we write the test package archive to - // $WORK/unicode/utf8/_test/unicode/utf8.a. - // We write the external test package archive to - // $WORK/unicode/utf8/_test/unicode/utf8_test.a. - testDir := filepath.Join(b.WorkDir, filepath.FromSlash(p.ImportPath+"/_test")) - ptestObj := work.BuildToolchain.Pkgpath(testDir, p) - - // Create the directory for the .a files. - ptestDir, _ := filepath.Split(ptestObj) - if err := b.Mkdir(ptestDir); err != nil { - return nil, nil, nil, err - } - // Should we apply coverage analysis locally, // only for this package and only for this test? // Yes, if -cover is on but -coverpkg has not specified @@ -818,14 +853,22 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin ptest.GoFiles = nil ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...) - ptest.Internal.Target = "" - ptest.Imports = str.StringList(p.Imports, p.TestImports) - ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...) - ptest.Internal.Pkgdir = testDir - ptest.Internal.Fake = true + ptest.Target = "" + // Note: The preparation of the vet config requires that common + // indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports + // all line up (but RawImports can be shorter than the others). + // That is, for 0 ≤ i < len(RawImports), + // RawImports[i] is the import string in the program text, + // Imports[i] is the expanded import string (vendoring applied or relative path expanded away), + // and Internal.Imports[i] is the corresponding *Package. + // Any implicitly added imports appear in Imports and Internal.Imports + // but not RawImports (because they were not in the source code). + // We insert TestImports, imports, and rawTestImports at the start of + // these lists to preserve the alignment. + ptest.Imports = str.StringList(p.TestImports, p.Imports) + ptest.Internal.Imports = append(imports, p.Internal.Imports...) + ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports) ptest.Internal.ForceLibrary = true - ptest.Stale = true - ptest.StaleReason = "rebuild for test" ptest.Internal.Build = new(build.Package) *ptest.Internal.Build = *p.Internal.Build m := map[string][]token.Position{} @@ -858,17 +901,19 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin Dir: p.Dir, GoFiles: p.XTestGoFiles, Imports: p.XTestImports, - Stale: true, }, Internal: load.PackageInternal{ LocalPrefix: p.Internal.LocalPrefix, Build: &build.Package{ ImportPos: p.Internal.Build.XTestImportPos, }, - Imports: ximports, - Pkgdir: testDir, - Fake: true, - External: true, + Imports: ximports, + RawImports: rawXTestImports, + + Asmflags: p.Internal.Asmflags, + Gcflags: p.Internal.Gcflags, + Ldflags: p.Internal.Ldflags, + Gccgoflags: p.Internal.Gccgoflags, }, } if pxtestNeedsPtest { @@ -876,27 +921,34 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin } } + testDir := b.NewObjdir() + if err := b.Mkdir(testDir); err != nil { + return nil, nil, nil, err + } + // Action for building pkg.test. pmain = &load.Package{ PackagePublic: load.PackagePublic{ Name: "main", Dir: testDir, GoFiles: []string{"_testmain.go"}, - ImportPath: "testmain", + ImportPath: p.ImportPath + " (testmain)", Root: p.Root, - Stale: true, }, Internal: load.PackageInternal{ Build: &build.Package{Name: "main"}, - Pkgdir: testDir, - Fake: true, OmitDebug: !testC && !testNeedBinary, }, } // The generated main also imports testing, regexp, and os. + // Also the linker introduces implicit dependencies reported by LinkerDeps. stk.Push("testmain") - for dep := range testMainDeps { + deps := testMainDeps // cap==len, so safe for append + for _, d := range load.LinkerDeps(p) { + deps = append(deps, d) + } + for _, dep := range deps { if dep == ptest.ImportPath { pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) } else { @@ -944,24 +996,21 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin if ptest != p && localCover { // We have made modifications to the package p being tested - // and are rebuilding p (as ptest), writing it to the testDir tree. - // Arrange to rebuild, writing to that same tree, all packages q - // such that the test depends on q, and q depends on p. + // and are rebuilding p (as ptest). + // Arrange to rebuild all packages q such that + // the test depends on q and q depends on p. // This makes sure that q sees the modifications to p. // Strictly speaking, the rebuild is only necessary if the // modifications to p change its export metadata, but // determining that is a bit tricky, so we rebuild always. + // TODO(rsc): Once we get export metadata changes + // handled properly, look into the expense of dropping + // "&& localCover" above. // // This will cause extra compilation, so for now we only do it // when testCover is set. The conditions are more general, though, // and we may find that we need to do it always in the future. - recompileForTest(pmain, p, ptest, testDir) - } - - if cfg.BuildContext.GOOS == "darwin" { - if cfg.BuildContext.GOARCH == "arm" || cfg.BuildContext.GOARCH == "arm64" { - t.NeedCgo = true - } + recompileForTest(pmain, p, ptest) } for _, cp := range pmain.Internal.Imports { @@ -971,34 +1020,19 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin } if !cfg.BuildN { - // writeTestmain writes _testmain.go. This must happen after recompileForTest, - // because recompileForTest modifies XXX. - if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil { + // writeTestmain writes _testmain.go, + // using the test description gathered in t. + if err := writeTestmain(testDir+"_testmain.go", t); err != nil { return nil, nil, nil, err } } - load.ComputeStale(pmain) - - if ptest != p { - a := b.Action(work.ModeBuild, work.ModeBuild, ptest) - a.Objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator) - a.Objpkg = ptestObj - a.Target = ptestObj - a.Link = false - } + // Set compile objdir to testDir we've already created, + // so that the default file path stripping applies to _testmain.go. + b.CompileAction(work.ModeBuild, work.ModeBuild, pmain).Objdir = testDir - if pxtest != nil { - a := b.Action(work.ModeBuild, work.ModeBuild, pxtest) - a.Objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator) - a.Objpkg = work.BuildToolchain.Pkgpath(testDir, pxtest) - a.Target = a.Objpkg - } - - a := b.Action(work.ModeBuild, work.ModeBuild, pmain) - a.Objdir = testDir + string(filepath.Separator) - a.Objpkg = filepath.Join(testDir, "main.a") - a.Target = filepath.Join(testDir, testBinary) + cfg.ExeSuffix + a := b.LinkAction(work.ModeBuild, work.ModeBuild, pmain) + a.Target = testDir + testBinary + cfg.ExeSuffix if cfg.Goos == "windows" { // There are many reserved words on Windows that, // if used in the name of an executable, cause Windows @@ -1024,12 +1058,13 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin // we could just do this always on Windows. for _, bad := range windowsBadWords { if strings.Contains(testBinary, bad) { - a.Target = filepath.Join(testDir, "test.test") + cfg.ExeSuffix + a.Target = testDir + "test.test" + cfg.ExeSuffix break } } } buildAction = a + var installAction *work.Action if testC || testNeedBinary { // -c or profiling flag: create action to copy binary to ./test.out. @@ -1040,30 +1075,46 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin target = filepath.Join(base.Cwd, target) } } - buildAction = &work.Action{ + pmain.Target = target + installAction = &work.Action{ + Mode: "test build", Func: work.BuildInstallFunc, Deps: []*work.Action{buildAction}, Package: pmain, Target: target, } - runAction = buildAction // make sure runAction != nil even if not running test + buildAction = installAction + runAction = installAction // make sure runAction != nil even if not running test } if testC { - printAction = &work.Action{Package: p, Deps: []*work.Action{runAction}} // nop + printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop } else { // run test + c := new(runCache) runAction = &work.Action{ - Func: builderRunTest, + Mode: "test run", + Func: c.builderRunTest, Deps: []*work.Action{buildAction}, Package: p, IgnoreFail: true, + TryCache: c.tryCache, + Objdir: testDir, + } + if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { + addTestVet(b, ptest, runAction, installAction) + } + if pxtest != nil { + addTestVet(b, pxtest, runAction, installAction) } cleanAction := &work.Action{ + Mode: "test clean", Func: builderCleanTest, Deps: []*work.Action{runAction}, Package: p, + Objdir: testDir, } printAction = &work.Action{ + Mode: "test print", Func: builderPrintTest, Deps: []*work.Action{cleanAction}, Package: p, @@ -1073,6 +1124,22 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin return buildAction, runAction, printAction, nil } +func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work.Action) { + if testVetList == "off" { + return + } + + vet := b.VetAction(work.ModeBuild, work.ModeBuild, p) + runAction.Deps = append(runAction.Deps, vet) + // Install will clean the build directory. + // Make sure vet runs first. + // The install ordering in b.VetAction does not apply here + // because we are using a custom installAction (created above). + if installAction != nil { + installAction.Deps = append(installAction.Deps, vet) + } +} + func testImportStack(top string, p *load.Package, target string) []string { stk := []string{top, p.ImportPath} Search: @@ -1091,7 +1158,7 @@ Search: return stk } -func recompileForTest(pmain, preal, ptest *load.Package, testDir string) { +func recompileForTest(pmain, preal, ptest *load.Package) { // The "test copy" of preal is ptest. // For each package that depends on preal, make a "test copy" // that depends on ptest. And so on, up the dependency tree. @@ -1104,28 +1171,19 @@ func recompileForTest(pmain, preal, ptest *load.Package, testDir string) { return } didSplit = true - if p.Internal.Pkgdir != testDir { - p1 := new(load.Package) - testCopy[p] = p1 - *p1 = *p - p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports)) - copy(p1.Internal.Imports, p.Internal.Imports) - p = p1 - p.Internal.Pkgdir = testDir - p.Internal.Target = "" - p.Internal.Fake = true - p.Stale = true - p.StaleReason = "depends on package being tested" + if testCopy[p] != nil { + panic("recompileForTest loop") } + p1 := new(load.Package) + testCopy[p] = p1 + *p1 = *p + p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports)) + copy(p1.Internal.Imports, p.Internal.Imports) + p = p1 + p.Target = "" } - // Update p.Deps and p.Internal.Imports to use at test copies. - for i, dep := range p.Internal.Deps { - if p1 := testCopy[dep]; p1 != nil && p1 != dep { - split() - p.Internal.Deps[i] = p1 - } - } + // Update p.Internal.Imports to use test copies. for i, imp := range p.Internal.Imports { if p1 := testCopy[imp]; p1 != nil && p1 != imp { split() @@ -1135,8 +1193,6 @@ func recompileForTest(pmain, preal, ptest *load.Package, testDir string) { } } -var coverIndex = 0 - // isTestFile reports whether the source file is a set of tests and should therefore // be excluded from coverage analysis. func isTestFile(file string) bool { @@ -1148,6 +1204,7 @@ func isTestFile(file string) bool { // to the files, to be used when annotating the files. func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar { coverVars := make(map[string]*load.CoverVar) + coverIndex := 0 for _, file := range files { if isTestFile(file) { continue @@ -1163,37 +1220,114 @@ func declareCoverVars(importPath string, files ...string) map[string]*load.Cover var noTestsToRun = []byte("\ntesting: warning: no tests to run\n") -// builderRunTest is the action for running a test binary. -func builderRunTest(b *work.Builder, a *work.Action) error { - args := str.StringList(work.FindExecCmd(), a.Deps[0].Target, testArgs) - a.TestOutput = new(bytes.Buffer) +type runCache struct { + disableCache bool // cache should be disabled for this run - if cfg.BuildN || cfg.BuildX { - b.Showcmd("", "%s", strings.Join(args, " ")) - if cfg.BuildN { - return nil - } + buf *bytes.Buffer + id1 cache.ActionID + id2 cache.ActionID +} + +// stdoutMu and lockedStdout provide a locked standard output +// that guarantees never to interlace writes from multiple +// goroutines, so that we can have multiple JSON streams writing +// to a lockedStdout simultaneously and know that events will +// still be intelligible. +var stdoutMu sync.Mutex + +type lockedStdout struct{} + +func (lockedStdout) Write(b []byte) (int, error) { + stdoutMu.Lock() + defer stdoutMu.Unlock() + return os.Stdout.Write(b) +} + +// builderRunTest is the action for running a test binary. +func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error { + if c.buf == nil { + // We did not find a cached result using the link step action ID, + // so we ran the link step. Try again now with the link output + // content ID. The attempt using the action ID makes sure that + // if the link inputs don't change, we reuse the cached test + // result without even rerunning the linker. The attempt using + // the link output (test binary) content ID makes sure that if + // we have different link inputs but the same final binary, + // we still reuse the cached test result. + // c.saveOutput will store the result under both IDs. + c.tryCacheWithID(b, a, a.Deps[0].BuildContentID()) + } + if c.buf != nil { + a.TestOutput = c.buf + return nil } if a.Failed { // We were unable to build the binary. a.Failed = false + a.TestOutput = new(bytes.Buffer) fmt.Fprintf(a.TestOutput, "FAIL\t%s [build failed]\n", a.Package.ImportPath) base.SetExitStatus(1) return nil } + args := str.StringList(work.FindExecCmd(), a.Deps[0].Target, testArgs) + + if testCoverProfile != "" { + // Write coverage to temporary profile, for merging later. + for i, arg := range args { + if strings.HasPrefix(arg, "-test.coverprofile=") { + args[i] = "-test.coverprofile=" + a.Objdir + "_cover_.out" + } + } + } + + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "%s", strings.Join(args, " ")) + if cfg.BuildN { + return nil + } + } + cmd := exec.Command(args[0], args[1:]...) cmd.Dir = a.Package.Dir cmd.Env = base.EnvForDir(cmd.Dir, cfg.OrigEnv) var buf bytes.Buffer - if testStreamOutput { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + var stdout io.Writer = os.Stdout + if testJSON { + json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) + defer json.Close() + stdout = json + } + if len(pkgArgs) == 0 || testBench { + // Stream test output (no buffering) when no package has + // been given on the command line (implicit current directory) + // or when benchmarking. + cmd.Stdout = stdout } else { - cmd.Stdout = &buf - cmd.Stderr = &buf + // If we're only running a single package under test or if parallelism is + // set to 1, and if we're displaying all output (testShowPass), we can + // hurry the output along, echoing it as soon as it comes in. + // We still have to copy to &buf for caching the result. This special + // case was introduced in Go 1.5 and is intentionally undocumented: + // the exact details of output buffering are up to the go command and + // subject to change. It would be nice to remove this special case + // entirely, but it is surely very helpful to see progress being made + // when tests are run on slow single-CPU ARM systems. + // + // If we're showing JSON output, then display output as soon as + // possible even when multiple tests are being run: the JSON output + // events are attributed to specific package tests, so interlacing them + // is OK. + if testShowPass && (len(pkgs) == 1 || cfg.BuildP == 1) || testJSON { + // Write both to stdout and buf, for possible saving + // to cache, and for looking for the "no tests to run" message. + cmd.Stdout = io.MultiWriter(stdout, &buf) + } else { + cmd.Stdout = &buf + } } + cmd.Stderr = cmd.Stdout // If there are any local SWIG dependencies, we want to load // the shared library from the build directory. @@ -1239,41 +1373,154 @@ func builderRunTest(b *work.Builder, a *work.Action) error { cmd.Process.Signal(base.SignalTrace) select { case err = <-done: - fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout) + fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout) break Outer case <-time.After(5 * time.Second): } } cmd.Process.Kill() err = <-done - fmt.Fprintf(&buf, "*** Test killed: ran too long (%v).\n", testKillTimeout) + fmt.Fprintf(cmd.Stdout, "*** Test killed: ran too long (%v).\n", testKillTimeout) } tick.Stop() } out := buf.Bytes() + a.TestOutput = &buf t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds()) + + mergeCoverProfile(cmd.Stdout, a.Objdir+"_cover_.out") + if err == nil { norun := "" - if testShowPass { - a.TestOutput.Write(out) + if !testShowPass { + buf.Reset() } if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { norun = " [no tests to run]" } - fmt.Fprintf(a.TestOutput, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) - return nil + fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) + c.saveOutput(a) + } else { + base.SetExitStatus(1) + // If there was test output, assume we don't need to print the exit status. + // Buf there's no test output, do print the exit status. + if len(out) == 0 { + fmt.Fprintf(cmd.Stdout, "%s\n", err) + } + fmt.Fprintf(cmd.Stdout, "FAIL\t%s\t%s\n", a.Package.ImportPath, t) + } + + if cmd.Stdout != &buf { + buf.Reset() // cmd.Stdout was going to os.Stdout already + } + return nil +} + +// tryCache is called just before the link attempt, +// to see if the test result is cached and therefore the link is unneeded. +// It reports whether the result can be satisfied from cache. +func (c *runCache) tryCache(b *work.Builder, a *work.Action) bool { + return c.tryCacheWithID(b, a, a.Deps[0].BuildActionID()) +} + +func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bool { + if len(pkgArgs) == 0 { + // Caching does not apply to "go test", + // only to "go test foo" (including "go test ."). + c.disableCache = true + return false + } + + var cacheArgs []string + for _, arg := range testArgs { + i := strings.Index(arg, "=") + if i < 0 || !strings.HasPrefix(arg, "-test.") { + c.disableCache = true + return false + } + switch arg[:i] { + case "-test.cpu", + "-test.list", + "-test.parallel", + "-test.run", + "-test.short", + "-test.v": + // These are cacheable. + // Note that this list is documented above, + // so if you add to this list, update the docs too. + cacheArgs = append(cacheArgs, arg) + + case "-test.timeout": + // Special case: this is cacheable but ignored during the hash. + // Do not add to cacheArgs. + + default: + // nothing else is cacheable + c.disableCache = true + return false + } } - base.SetExitStatus(1) - if len(out) > 0 { - a.TestOutput.Write(out) - // assume printing the test binary's exit status is superfluous + if cache.Default() == nil { + c.disableCache = true + return false + } + + h := cache.NewHash("testResult") + fmt.Fprintf(h, "test binary %s args %q execcmd %q", id, cacheArgs, work.ExecCmd) + // TODO(rsc): How to handle other test dependencies like environment variables or input files? + // We could potentially add new API like testing.UsedEnv(envName string) + // or testing.UsedFile(inputFile string) to let tests declare what external inputs + // they consulted. These could be recorded and rechecked. + // The lookup here would become a two-step lookup: first use the binary+args + // to fetch the list of other inputs, then add the other inputs to produce a + // second key for fetching the results. + // For now, we'll assume that users will use -count=1 (or "go test") to bypass the test result + // cache when modifying those things. + testID := h.Sum() + if c.id1 == (cache.ActionID{}) { + c.id1 = testID } else { - fmt.Fprintf(a.TestOutput, "%s\n", err) + c.id2 = testID } - fmt.Fprintf(a.TestOutput, "FAIL\t%s\t%s\n", a.Package.ImportPath, t) - return nil + // Parse cached result in preparation for changing run time to "(cached)". + // If we can't parse the cached result, don't use it. + data, entry, _ := cache.Default().GetBytes(testID) + if len(data) == 0 || data[len(data)-1] != '\n' { + return false + } + if entry.Time.Before(testCacheExpire) { + return false + } + i := bytes.LastIndexByte(data[:len(data)-1], '\n') + 1 + if !bytes.HasPrefix(data[i:], []byte("ok \t")) { + return false + } + j := bytes.IndexByte(data[i+len("ok \t"):], '\t') + if j < 0 { + return false + } + j += i + len("ok \t") + 1 + + // Committed to printing. + c.buf = new(bytes.Buffer) + c.buf.Write(data[:j]) + c.buf.WriteString("(cached)") + for j < len(data) && ('0' <= data[j] && data[j] <= '9' || data[j] == '.' || data[j] == 's') { + j++ + } + c.buf.Write(data[j:]) + return true +} + +func (c *runCache) saveOutput(a *work.Action) { + if c.id1 != (cache.ActionID{}) { + cache.Default().PutNoVerify(c.id1, bytes.NewReader(a.TestOutput.Bytes())) + } + if c.id2 != (cache.ActionID{}) { + cache.Default().PutNoVerify(c.id2, bytes.NewReader(a.TestOutput.Bytes())) + } } // coveragePercentage returns the coverage results (if enabled) for the @@ -1300,9 +1547,10 @@ func builderCleanTest(b *work.Builder, a *work.Action) error { if cfg.BuildWork { return nil } - run := a.Deps[0] - testDir := filepath.Join(b.WorkDir, filepath.FromSlash(run.Package.ImportPath+"/_test")) - os.RemoveAll(testDir) + if cfg.BuildX { + b.Showcmd("", "rm -r %s", a.Objdir) + } + os.RemoveAll(a.Objdir) return nil } @@ -1310,14 +1558,22 @@ func builderCleanTest(b *work.Builder, a *work.Action) error { func builderPrintTest(b *work.Builder, a *work.Action) error { clean := a.Deps[0] run := clean.Deps[0] - os.Stdout.Write(run.TestOutput.Bytes()) - run.TestOutput = nil + if run.TestOutput != nil { + os.Stdout.Write(run.TestOutput.Bytes()) + run.TestOutput = nil + } return nil } // builderNoTest is the action for testing a package with no test files. func builderNoTest(b *work.Builder, a *work.Action) error { - fmt.Printf("? \t%s\t[no test files]\n", a.Package.ImportPath) + var stdout io.Writer = os.Stdout + if testJSON { + json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) + defer json.Close() + stdout = json + } + fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath) return nil } @@ -1409,7 +1665,6 @@ type testFuncs struct { NeedTest bool ImportXtest bool NeedXtest bool - NeedCgo bool Cover []coverInfo } @@ -1474,7 +1729,16 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { } name := n.Name.String() switch { - case name == "TestMain" && isTestFunc(n, "M"): + case name == "TestMain": + if isTestFunc(n, "T") { + t.Tests = append(t.Tests, testFunc{pkg, name, "", false}) + *doImport, *seen = true, true + continue + } + err := checkTestFunc(n, "M") + if err != nil { + return err + } if t.TestMain != nil { return errors.New("multiple definitions of TestMain") } @@ -1538,10 +1802,6 @@ import ( {{range $i, $p := .Cover}} _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} {{end}} - -{{if .NeedCgo}} - _ "runtime/cgo" -{{end}} ) var tests = []testing.InternalTest{ diff --git a/libgo/go/cmd/go/internal/test/testflag.go b/libgo/go/cmd/go/internal/test/testflag.go index bff8656a4c1..8a908f7e215 100644 --- a/libgo/go/cmd/go/internal/test/testflag.go +++ b/libgo/go/cmd/go/internal/test/testflag.go @@ -33,20 +33,23 @@ var testFlagDefn = []*cmdflag.Defn{ {Name: "covermode"}, {Name: "coverpkg"}, {Name: "exec"}, + {Name: "json", BoolVar: &testJSON}, + {Name: "vet"}, // Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v. {Name: "bench", PassToTest: true}, {Name: "benchmem", BoolVar: new(bool), PassToTest: true}, {Name: "benchtime", PassToTest: true}, + {Name: "blockprofile", PassToTest: true}, + {Name: "blockprofilerate", PassToTest: true}, {Name: "count", PassToTest: true}, {Name: "coverprofile", PassToTest: true}, {Name: "cpu", PassToTest: true}, {Name: "cpuprofile", PassToTest: true}, + {Name: "failfast", BoolVar: new(bool), PassToTest: true}, {Name: "list", PassToTest: true}, {Name: "memprofile", PassToTest: true}, {Name: "memprofilerate", PassToTest: true}, - {Name: "blockprofile", PassToTest: true}, - {Name: "blockprofilerate", PassToTest: true}, {Name: "mutexprofile", PassToTest: true}, {Name: "mutexprofilefraction", PassToTest: true}, {Name: "outputdir", PassToTest: true}, @@ -85,7 +88,6 @@ func init() { // go test -x math func testFlags(args []string) (packageNames, passToTest []string) { inPkg := false - outputDir := "" var explicitArgs []string for i := 0; i < len(args); i++ { if !strings.HasPrefix(args[i], "-") { @@ -132,8 +134,11 @@ func testFlags(args []string) (packageNames, passToTest []string) { // Arguably should be handled by f.Value, but aren't. switch f.Name { // bool flags. - case "c", "i", "v", "cover": + case "c", "i", "v", "cover", "json": cmdflag.SetBool(cmd, f.BoolVar, value) + if f.Name == "json" && testJSON { + passToTest = append(passToTest, "-test.v") + } case "o": testO = value testNeedBinary = true @@ -151,10 +156,10 @@ func testFlags(args []string) (packageNames, passToTest []string) { case "timeout": testTimeout = value case "blockprofile", "cpuprofile", "memprofile", "mutexprofile": - testProfile = true + testProfile = "-" + f.Name testNeedBinary = true case "trace": - testProfile = true + testProfile = "-trace" case "coverpkg": testCover = true if value == "" { @@ -164,7 +169,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { } case "coverprofile": testCover = true - testProfile = true + testCoverProfile = value case "covermode": switch value { case "set", "count", "atomic": @@ -174,7 +179,9 @@ func testFlags(args []string) (packageNames, passToTest []string) { } testCover = true case "outputdir": - outputDir = value + testOutputDir = value + case "vet": + testVetList = value } } if extraWord { @@ -193,12 +200,26 @@ func testFlags(args []string) (packageNames, passToTest []string) { } } + if testVetList != "" && testVetList != "off" { + if strings.Contains(testVetList, "=") { + base.Fatalf("-vet argument cannot contain equal signs") + } + if strings.Contains(testVetList, " ") { + base.Fatalf("-vet argument is comma-separated list, cannot contain spaces") + } + list := strings.Split(testVetList, ",") + for i, arg := range list { + list[i] = "-" + arg + } + testVetFlags = list + } + if cfg.BuildRace && testCoverMode != "atomic" { base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode) } // Tell the test what directory we're running in, so it can write the profiles there. - if testProfile && outputDir == "" { + if testProfile != "" && testOutputDir == "" { dir, err := os.Getwd() if err != nil { base.Fatalf("error from os.Getwd: %s", err) diff --git a/libgo/go/cmd/go/internal/tool/tool.go b/libgo/go/cmd/go/internal/tool/tool.go index 7dd5510328c..4c7d0897e05 100644 --- a/libgo/go/cmd/go/internal/tool/tool.go +++ b/libgo/go/cmd/go/internal/tool/tool.go @@ -27,7 +27,7 @@ With no arguments it prints the list of known tools. The -n flag causes tool to print the command that would be executed but not execute it. -For more about each tool command, see 'go tool command -h'. +For more about each tool command, see 'go doc cmd/'. `, } diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go index ddacd085b06..db734c9d846 100644 --- a/libgo/go/cmd/go/internal/vet/vet.go +++ b/libgo/go/cmd/go/internal/vet/vet.go @@ -6,19 +6,16 @@ package vet import ( - "path/filepath" - "cmd/go/internal/base" - "cmd/go/internal/cfg" "cmd/go/internal/load" - "cmd/go/internal/str" + "cmd/go/internal/work" ) var CmdVet = &base.Command{ Run: runVet, CustomFlags: true, UsageLine: "vet [-n] [-x] [build flags] [vet flags] [packages]", - Short: "run go tool vet on packages", + Short: "report likely mistakes in packages", Long: ` Vet runs the Go vet command on the packages named by the import paths. @@ -28,29 +25,31 @@ For more about specifying packages, see 'go help packages'. The -n flag prints commands that would be executed. The -x flag prints commands as they are executed. -For more about build flags, see 'go help build'. +The build flags supported by go vet are those that control package resolution +and execution, such as -n, -x, -v, -tags, and -toolexec. +For more about these flags, see 'go help build'. See also: go fmt, go fix. `, } func runVet(cmd *base.Command, args []string) { - vetFlags, packages := vetFlags(args) - for _, p := range load.Packages(packages) { - // Vet expects to be given a set of files all from the same package. - // Run once for package p and once for package p_test. - if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 { - runVetFiles(p, vetFlags, str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles)) - } - if len(p.XTestGoFiles) > 0 { - runVetFiles(p, vetFlags, str.StringList(p.XTestGoFiles)) - } + vetFlags, pkgArgs := vetFlags(args) + + work.BuildInit() + work.VetFlags = vetFlags + + pkgs := load.PackagesForBuild(pkgArgs) + if len(pkgs) == 0 { + base.Fatalf("no packages to vet") } -} -func runVetFiles(p *load.Package, flags, files []string) { - for i := range files { - files[i] = filepath.Join(p.Dir, files[i]) + var b work.Builder + b.Init() + + root := &work.Action{Mode: "go vet"} + for _, p := range pkgs { + root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, p)) } - base.Run(cfg.BuildToolexec, base.Tool("vet"), flags, base.RelPaths(files)) + b.Do(root) } diff --git a/libgo/go/cmd/go/internal/vet/vetflag.go b/libgo/go/cmd/go/internal/vet/vetflag.go index 8cd21bb72b7..36ee04ede77 100644 --- a/libgo/go/cmd/go/internal/vet/vetflag.go +++ b/libgo/go/cmd/go/internal/vet/vetflag.go @@ -44,6 +44,7 @@ var vetFlagDefn = []*cmdflag.Defn{ {Name: "rangeloops", BoolVar: new(bool)}, {Name: "shadow", BoolVar: new(bool)}, {Name: "shadowstrict", BoolVar: new(bool)}, + {Name: "shift", BoolVar: new(bool)}, {Name: "source", BoolVar: new(bool)}, {Name: "structtags", BoolVar: new(bool)}, {Name: "tests", BoolVar: new(bool)}, diff --git a/libgo/go/cmd/go/internal/work/action.go b/libgo/go/cmd/go/internal/work/action.go new file mode 100644 index 00000000000..fa7fd0c2e4a --- /dev/null +++ b/libgo/go/cmd/go/internal/work/action.go @@ -0,0 +1,752 @@ +// 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. + +// Action graph creation (planning). + +package work + +import ( + "bufio" + "bytes" + "container/heap" + "debug/elf" + "debug/xcoff" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/internal/buildid" +) + +// A Builder holds global state about a build. +// It does not hold per-package state, because we +// build packages in parallel, and the builder is shared. +type Builder struct { + WorkDir string // the temporary work directory (ends in filepath.Separator) + actionCache map[cacheKey]*Action // a cache of already-constructed actions + mkdirCache map[string]bool // a cache of created directories + flagCache map[[2]string]bool // a cache of supported compiler flags + Print func(args ...interface{}) (int, error) + + ComputeStaleOnly bool // compute staleness for go list; no actual build + + objdirSeq int // counter for NewObjdir + pkgSeq int + + output sync.Mutex + scriptDir string // current directory in printed script + + exec sync.Mutex + readySema chan bool + ready actionQueue + + id sync.Mutex + toolIDCache map[string]string // tool name -> tool ID + buildIDCache map[string]string // file name -> build ID +} + +// NOTE: Much of Action would not need to be exported if not for test. +// Maybe test functionality should move into this package too? + +// An Action represents a single action in the action graph. +type Action struct { + Mode string // description of action operation + Package *load.Package // the package this action works on + Deps []*Action // actions that must happen before this one + Func func(*Builder, *Action) error // the action itself (nil = no-op) + IgnoreFail bool // whether to run f even if dependencies fail + TestOutput *bytes.Buffer // test output buffer + Args []string // additional args for runProgram + + triggers []*Action // inverse of deps + + buggyInstall bool // is this a buggy install (see -linkshared)? + + TryCache func(*Builder, *Action) bool // callback for cache bypass + + // Generated files, directories. + Objdir string // directory for intermediate objects + Target string // goal of the action: the created package or executable + built string // the actual created package or executable + actionID cache.ActionID // cache ID of action input + buildID string // build ID of action output + + needVet bool // Mode=="build": need to fill in vet config + vetCfg *vetConfig // vet config + output []byte // output redirect buffer (nil means use b.Print) + + // Execution state. + pending int // number of deps yet to complete + priority int // relative execution priority + Failed bool // whether the action failed +} + +// BuildActionID returns the action ID section of a's build ID. +func (a *Action) BuildActionID() string { return actionID(a.buildID) } + +// BuildContentID returns the content ID section of a's build ID. +func (a *Action) BuildContentID() string { return contentID(a.buildID) } + +// BuildID returns a's build ID. +func (a *Action) BuildID() string { return a.buildID } + +// An actionQueue is a priority queue of actions. +type actionQueue []*Action + +// Implement heap.Interface +func (q *actionQueue) Len() int { return len(*q) } +func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } +func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority } +func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*Action)) } +func (q *actionQueue) Pop() interface{} { + n := len(*q) - 1 + x := (*q)[n] + *q = (*q)[:n] + return x +} + +func (q *actionQueue) push(a *Action) { + heap.Push(q, a) +} + +func (q *actionQueue) pop() *Action { + return heap.Pop(q).(*Action) +} + +type actionJSON struct { + ID int + Mode string + Package string + Deps []int `json:",omitempty"` + IgnoreFail bool `json:",omitempty"` + Args []string `json:",omitempty"` + Link bool `json:",omitempty"` + Objdir string `json:",omitempty"` + Target string `json:",omitempty"` + Priority int `json:",omitempty"` + Failed bool `json:",omitempty"` + Built string `json:",omitempty"` +} + +// cacheKey is the key for the action cache. +type cacheKey struct { + mode string + p *load.Package +} + +func actionGraphJSON(a *Action) string { + var workq []*Action + var inWorkq = make(map[*Action]int) + + add := func(a *Action) { + if _, ok := inWorkq[a]; ok { + return + } + inWorkq[a] = len(workq) + workq = append(workq, a) + } + add(a) + + for i := 0; i < len(workq); i++ { + for _, dep := range workq[i].Deps { + add(dep) + } + } + + var list []*actionJSON + for id, a := range workq { + aj := &actionJSON{ + Mode: a.Mode, + ID: id, + IgnoreFail: a.IgnoreFail, + Args: a.Args, + Objdir: a.Objdir, + Target: a.Target, + Failed: a.Failed, + Priority: a.priority, + Built: a.built, + } + if a.Package != nil { + // TODO(rsc): Make this a unique key for a.Package somehow. + aj.Package = a.Package.ImportPath + } + for _, a1 := range a.Deps { + aj.Deps = append(aj.Deps, inWorkq[a1]) + } + list = append(list, aj) + } + + js, err := json.MarshalIndent(list, "", "\t") + if err != nil { + fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err) + return "" + } + return string(js) +} + +// BuildMode specifies the build mode: +// are we just building things or also installing the results? +type BuildMode int + +const ( + ModeBuild BuildMode = iota + ModeInstall + ModeBuggyInstall +) + +func (b *Builder) Init() { + var err error + b.Print = func(a ...interface{}) (int, error) { + return fmt.Fprint(os.Stderr, a...) + } + b.actionCache = make(map[cacheKey]*Action) + b.mkdirCache = make(map[string]bool) + b.toolIDCache = make(map[string]string) + b.buildIDCache = make(map[string]string) + + if cfg.BuildN { + b.WorkDir = "$WORK" + } else { + b.WorkDir, err = ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build") + if err != nil { + base.Fatalf("%s", err) + } + if cfg.BuildX || cfg.BuildWork { + fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir) + } + if !cfg.BuildWork { + workdir := b.WorkDir + base.AtExit(func() { os.RemoveAll(workdir) }) + } + } + + if _, ok := cfg.OSArchSupportsCgo[cfg.Goos+"/"+cfg.Goarch]; !ok && cfg.BuildContext.Compiler == "gc" { + fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", cfg.Goos, cfg.Goarch) + os.Exit(2) + } + for _, tag := range cfg.BuildContext.BuildTags { + if strings.Contains(tag, ",") { + fmt.Fprintf(os.Stderr, "cmd/go: -tags space-separated list contains comma\n") + os.Exit(2) + } + } +} + +// NewObjdir returns the name of a fresh object directory under b.WorkDir. +// It is up to the caller to call b.Mkdir on the result at an appropriate time. +// The result ends in a slash, so that file names in that directory +// can be constructed with direct string addition. +// +// NewObjdir must be called only from a single goroutine at a time, +// so it is safe to call during action graph construction, but it must not +// be called during action graph execution. +func (b *Builder) NewObjdir() string { + b.objdirSeq++ + return filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)) + string(filepath.Separator) +} + +// readpkglist returns the list of packages that were built into the shared library +// at shlibpath. For the native toolchain this list is stored, newline separated, in +// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the +// .go_export section. +func readpkglist(shlibpath string) (pkgs []*load.Package) { + var stk load.ImportStack + if cfg.BuildToolchainName == "gccgo" { + var data []byte + if f, err := elf.Open(shlibpath); err == nil { + sect := f.Section(".go_export") + data, _ = sect.Data() + } else if f, err := xcoff.Open(shlibpath); err == nil { + data = f.CSect(".go_export") + } + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + for scanner.Scan() { + t := scanner.Text() + if strings.HasPrefix(t, "pkgpath ") { + t = strings.TrimPrefix(t, "pkgpath ") + t = strings.TrimSuffix(t, ";") + pkgs = append(pkgs, load.LoadPackage(t, &stk)) + } + } + } else { + pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1) + if err != nil { + base.Fatalf("readELFNote failed: %v", err) + } + scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) + for scanner.Scan() { + t := scanner.Text() + pkgs = append(pkgs, load.LoadPackage(t, &stk)) + } + } + return +} + +// cacheAction looks up {mode, p} in the cache and returns the resulting action. +// If the cache has no such action, f() is recorded and returned. +// TODO(rsc): Change the second key from *load.Package to interface{}, +// to make the caching in linkShared less awkward? +func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action { + a := b.actionCache[cacheKey{mode, p}] + if a == nil { + a = f() + b.actionCache[cacheKey{mode, p}] = a + } + return a +} + +// AutoAction returns the "right" action for go build or go install of p. +func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action { + if p.Name == "main" { + return b.LinkAction(mode, depMode, p) + } + return b.CompileAction(mode, depMode, p) +} + +// CompileAction returns the action for compiling and possibly installing +// (according to mode) the given package. The resulting action is only +// for building packages (archives), never for linking executables. +// depMode is the action (build or install) to use when building dependencies. +// To turn package main into an executable, call b.Link instead. +func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action { + if mode != ModeBuild && p.Internal.Local && p.Target == "" { + // Imported via local path. No permanent target. + mode = ModeBuild + } + if mode != ModeBuild && p.Name == "main" { + // We never install the .a file for a main package. + mode = ModeBuild + } + + // Construct package build action. + a := b.cacheAction("build", p, func() *Action { + a := &Action{ + Mode: "build", + Package: p, + Func: (*Builder).build, + Objdir: b.NewObjdir(), + } + + for _, p1 := range p.Internal.Imports { + a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1)) + } + + if p.Standard { + switch p.ImportPath { + case "builtin", "unsafe": + // Fake packages - nothing to build. + a.Mode = "built-in package" + a.Func = nil + return a + } + + // gccgo standard library is "fake" too. + if cfg.BuildToolchainName == "gccgo" { + // the target name is needed for cgo. + a.Mode = "gccgo stdlib" + a.Target = p.Target + a.Func = nil + return a + } + } + + return a + }) + + // Construct install action. + if mode == ModeInstall || mode == ModeBuggyInstall { + a = b.installAction(a, mode) + } + + return a +} + +// VetAction returns the action for running go vet on package p. +// It depends on the action for compiling p. +// If the caller may be causing p to be installed, it is up to the caller +// to make sure that the install depends on (runs after) vet. +func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { + // Construct vet action. + a := b.cacheAction("vet", p, func() *Action { + a1 := b.CompileAction(mode, depMode, p) + + // vet expects to be able to import "fmt". + var stk load.ImportStack + stk.Push("vet") + p1 := load.LoadPackage("fmt", &stk) + stk.Pop() + aFmt := b.CompileAction(ModeBuild, depMode, p1) + + a := &Action{ + Mode: "vet", + Package: p, + Deps: []*Action{a1, aFmt}, + Objdir: a1.Objdir, + } + if a1.Func == nil { + // Built-in packages like unsafe. + return a + } + a1.needVet = true + a.Func = (*Builder).vet + + return a + }) + return a +} + +// LinkAction returns the action for linking p into an executable +// and possibly installing the result (according to mode). +// depMode is the action (build or install) to use when compiling dependencies. +func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action { + // Construct link action. + a := b.cacheAction("link", p, func() *Action { + a := &Action{ + Mode: "link", + Package: p, + } + + a1 := b.CompileAction(ModeBuild, depMode, p) + a.Func = (*Builder).link + a.Deps = []*Action{a1} + a.Objdir = a1.Objdir + + // An executable file. (This is the name of a temporary file.) + // Because we run the temporary file in 'go run' and 'go test', + // the name will show up in ps listings. If the caller has specified + // a name, use that instead of a.out. The binary is generated + // in an otherwise empty subdirectory named exe to avoid + // naming conflicts. The only possible conflict is if we were + // to create a top-level package named exe. + name := "a.out" + if p.Internal.ExeName != "" { + name = p.Internal.ExeName + } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" { + // On OS X, the linker output name gets recorded in the + // shared library's LC_ID_DYLIB load command. + // The code invoking the linker knows to pass only the final + // path element. Arrange that the path element matches what + // we'll install it as; otherwise the library is only loadable as "a.out". + // On Windows, DLL file name is recorded in PE file + // export section, so do like on OS X. + _, name = filepath.Split(p.Target) + } + a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix + a.built = a.Target + b.addTransitiveLinkDeps(a, a1, "") + + // Sequence the build of the main package (a1) strictly after the build + // of all other dependencies that go into the link. It is likely to be after + // them anyway, but just make sure. This is required by the build ID-based + // shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a). + // In order for that linkActionID call to compute the right action ID, all the + // dependencies of a (except a1) must have completed building and have + // recorded their build IDs. + a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]}) + return a + }) + + if mode == ModeInstall || mode == ModeBuggyInstall { + a = b.installAction(a, mode) + } + + return a +} + +// installAction returns the action for installing the result of a1. +func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action { + // Because we overwrite the build action with the install action below, + // a1 may already be an install action fetched from the "build" cache key, + // and the caller just doesn't realize. + if strings.HasSuffix(a1.Mode, "-install") { + if a1.buggyInstall && mode == ModeInstall { + // Congratulations! The buggy install is now a proper install. + a1.buggyInstall = false + } + return a1 + } + + // If there's no actual action to build a1, + // there's nothing to install either. + // This happens if a1 corresponds to reusing an already-built object. + if a1.Func == nil { + return a1 + } + + p := a1.Package + return b.cacheAction(a1.Mode+"-install", p, func() *Action { + // The install deletes the temporary build result, + // so we need all other actions, both past and future, + // that attempt to depend on the build to depend instead + // on the install. + + // Make a private copy of a1 (the build action), + // no longer accessible to any other rules. + buildAction := new(Action) + *buildAction = *a1 + + // Overwrite a1 with the install action. + // This takes care of updating past actions that + // point at a1 for the build action; now they will + // point at a1 and get the install action. + // We also leave a1 in the action cache as the result + // for "build", so that actions not yet created that + // try to depend on the build will instead depend + // on the install. + *a1 = Action{ + Mode: buildAction.Mode + "-install", + Func: BuildInstallFunc, + Package: p, + Objdir: buildAction.Objdir, + Deps: []*Action{buildAction}, + Target: p.Target, + built: p.Target, + + buggyInstall: mode == ModeBuggyInstall, + } + + b.addInstallHeaderAction(a1) + return a1 + }) +} + +// addTransitiveLinkDeps adds to the link action a all packages +// that are transitive dependencies of a1.Deps. +// That is, if a is a link of package main, a1 is the compile of package main +// and a1.Deps is the actions for building packages directly imported by +// package main (what the compiler needs). The linker needs all packages +// transitively imported by the whole program; addTransitiveLinkDeps +// makes sure those are present in a.Deps. +// If shlib is non-empty, then a corresponds to the build and installation of shlib, +// so any rebuild of shlib should not be added as a dependency. +func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) { + // Expand Deps to include all built packages, for the linker. + // Use breadth-first search to find rebuilt-for-test packages + // before the standard ones. + // TODO(rsc): Eliminate the standard ones from the action graph, + // which will require doing a little bit more rebuilding. + workq := []*Action{a1} + haveDep := map[string]bool{} + if a1.Package != nil { + haveDep[a1.Package.ImportPath] = true + } + for i := 0; i < len(workq); i++ { + a1 := workq[i] + for _, a2 := range a1.Deps { + // TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles. + if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] { + continue + } + haveDep[a2.Package.ImportPath] = true + a.Deps = append(a.Deps, a2) + if a2.Mode == "build-install" { + a2 = a2.Deps[0] // walk children of "build" action + } + workq = append(workq, a2) + } + } + + // If this is go build -linkshared, then the link depends on the shared libraries + // in addition to the packages themselves. (The compile steps do not.) + if cfg.BuildLinkshared { + haveShlib := map[string]bool{shlib: true} + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] { + continue + } + haveShlib[filepath.Base(p1.Shlib)] = true + // TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild, + // we'll end up building an overall library or executable that depends at runtime + // on other libraries that are out-of-date, which is clearly not good either. + // We call it ModeBuggyInstall to make clear that this is not right. + a.Deps = append(a.Deps, b.linkSharedAction(ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil)) + } + } +} + +// addInstallHeaderAction adds an install header action to a, if needed. +// The action a should be an install action as generated by either +// b.CompileAction or b.LinkAction with mode=ModeInstall, +// and so a.Deps[0] is the corresponding build action. +func (b *Builder) addInstallHeaderAction(a *Action) { + // Install header for cgo in c-archive and c-shared modes. + p := a.Package + if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { + hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h" + if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" { + // For the header file, remove the "lib" + // added by go/build, so we generate pkg.h + // rather than libpkg.h. + dir, file := filepath.Split(hdrTarget) + file = strings.TrimPrefix(file, "lib") + hdrTarget = filepath.Join(dir, file) + } + ah := &Action{ + Mode: "install header", + Package: a.Package, + Deps: []*Action{a.Deps[0]}, + Func: (*Builder).installHeader, + Objdir: a.Deps[0].Objdir, + Target: hdrTarget, + } + a.Deps = append(a.Deps, ah) + } +} + +// buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps. +// That is, the input a1 represents "go build pkgs" and the result represents "go build -buidmode=shared pkgs". +func (b *Builder) buildmodeShared(mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action { + name, err := libname(args, pkgs) + if err != nil { + base.Fatalf("%v", err) + } + return b.linkSharedAction(mode, depMode, name, a1) +} + +// linkSharedAction takes a grouping action a1 corresponding to a list of built packages +// and returns an action that links them together into a shared library with the name shlib. +// If a1 is nil, shlib should be an absolute path to an existing shared library, +// and then linkSharedAction reads that library to find out the package list. +func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Action) *Action { + fullShlib := shlib + shlib = filepath.Base(shlib) + a := b.cacheAction("build-shlib "+shlib, nil, func() *Action { + if a1 == nil { + // TODO(rsc): Need to find some other place to store config, + // not in pkg directory. See golang.org/issue/22196. + pkgs := readpkglist(fullShlib) + a1 = &Action{ + Mode: "shlib packages", + } + for _, p := range pkgs { + a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p)) + } + } + + // Fake package to hold ldflags. + // As usual shared libraries are a kludgy, abstraction-violating special case: + // we let them use the flags specified for the command-line arguments. + p := &load.Package{} + p.Internal.CmdlinePkg = true + p.Internal.Ldflags = load.BuildLdflags.For(p) + p.Internal.Gccgoflags = load.BuildGccgoflags.For(p) + + // Add implicit dependencies to pkgs list. + // Currently buildmode=shared forces external linking mode, and + // external linking mode forces an import of runtime/cgo (and + // math on arm). So if it was not passed on the command line and + // it is not present in another shared library, add it here. + // TODO(rsc): Maybe this should only happen if "runtime" is in the original package set. + // TODO(rsc): This should probably be changed to use load.LinkerDeps(p). + // TODO(rsc): Find out and explain here why gccgo is excluded. + // If the answer is that gccgo is different in implicit linker deps, maybe + // load.LinkerDeps should be used and updated. + // Link packages into a shared library. + + a := &Action{ + Mode: "go build -buildmode=shared", + Package: p, + Objdir: b.NewObjdir(), + Func: (*Builder).linkShared, + Deps: []*Action{a1}, + } + a.Target = filepath.Join(a.Objdir, shlib) + if cfg.BuildToolchainName != "gccgo" { + add := func(a1 *Action, pkg string, force bool) { + for _, a2 := range a1.Deps { + if a2.Package != nil && a2.Package.ImportPath == pkg { + return + } + } + var stk load.ImportStack + p := load.LoadPackage(pkg, &stk) + if p.Error != nil { + base.Fatalf("load %s: %v", pkg, p.Error) + } + // Assume that if pkg (runtime/cgo or math) + // is already accounted for in a different shared library, + // then that shared library also contains runtime, + // so that anything we do will depend on that library, + // so we don't need to include pkg in our shared library. + if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg { + a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p)) + } + } + add(a1, "runtime/cgo", false) + if cfg.Goarch == "arm" { + add(a1, "math", false) + } + + // The linker step still needs all the usual linker deps. + // (For example, the linker always opens runtime.a.) + for _, dep := range load.LinkerDeps(nil) { + add(a, dep, true) + } + } + b.addTransitiveLinkDeps(a, a1, shlib) + return a + }) + + // Install result. + if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Func != nil { + buildAction := a + + a = b.cacheAction("install-shlib "+shlib, nil, func() *Action { + // Determine the eventual install target. + // The install target is root/pkg/shlib, where root is the source root + // in which all the packages lie. + // TODO(rsc): Perhaps this cross-root check should apply to the full + // transitive package dependency list, not just the ones named + // on the command line? + pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot + for _, a2 := range a1.Deps { + if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir { + base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s", + a1.Deps[0].Package.ImportPath, + a2.Package.ImportPath, + pkgDir, + dir) + } + } + // TODO(rsc): Find out and explain here why gccgo is different. + if cfg.BuildToolchainName == "gccgo" { + pkgDir = filepath.Join(pkgDir, "shlibs") + } + target := filepath.Join(pkgDir, shlib) + + a := &Action{ + Mode: "go install -buildmode=shared", + Objdir: buildAction.Objdir, + Func: BuildInstallFunc, + Deps: []*Action{buildAction}, + Target: target, + } + for _, a2 := range buildAction.Deps[0].Deps { + p := a2.Package + if p.Target == "" { + continue + } + a.Deps = append(a.Deps, &Action{ + Mode: "shlibname", + Package: p, + Func: (*Builder).installShlibname, + Target: strings.TrimSuffix(p.Target, ".a") + ".shlibname", + Deps: []*Action{a.Deps[0]}, + }) + } + return a + }) + } + + return a +} diff --git a/libgo/go/cmd/go/internal/work/build.go b/libgo/go/cmd/go/internal/work/build.go index 75f3c1a5058..57b7b008791 100644 --- a/libgo/go/cmd/go/internal/work/build.go +++ b/libgo/go/cmd/go/internal/work/build.go @@ -5,34 +5,19 @@ package work import ( - "bufio" - "bytes" - "container/heap" - "debug/elf" - "debug/xcoff" "errors" - "flag" "fmt" "go/build" - "io" - "io/ioutil" - "log" "os" "os/exec" "path" "path/filepath" - "regexp" "runtime" - "strconv" "strings" - "sync" - "time" "cmd/go/internal/base" - "cmd/go/internal/buildid" "cmd/go/internal/cfg" "cmd/go/internal/load" - "cmd/go/internal/str" ) var CmdBuild = &base.Command{ @@ -90,15 +75,15 @@ and test commands: -x print the commands. - -asmflags 'flag list' + -asmflags '[pattern=]arg list' arguments to pass on each go tool asm invocation. -buildmode mode build mode to use. See 'go help buildmode' for more. -compiler name name of compiler to use, as in runtime.Compiler (gccgo or gc). - -gccgoflags 'arg list' + -gccgoflags '[pattern=]arg list' arguments to pass on each gccgo compiler/linker invocation. - -gcflags 'arg list' + -gcflags '[pattern=]arg list' arguments to pass on each go tool compile invocation. -installsuffix suffix a suffix to use in the name of the package installation directory, @@ -107,7 +92,7 @@ and test commands: or, if set explicitly, has _race appended to it. Likewise for the -msan flag. Using a -buildmode option that requires non-default compile flags has a similar effect. - -ldflags 'flag list' + -ldflags '[pattern=]arg list' arguments to pass on each go tool link invocation. -linkshared link against shared libraries previously created with @@ -125,9 +110,21 @@ and test commands: For example, instead of running asm, the go command will run 'cmd args /path/to/asm '. -All the flags that take a list of arguments accept a space-separated -list of strings. To embed spaces in an element in the list, surround -it with either single or double quotes. +The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a +space-separated list of arguments to pass to an underlying tool +during the build. To embed spaces in an element in the list, surround +it with either single or double quotes. The argument list may be +preceded by a package pattern and an equal sign, which restricts +the use of that argument list to the building of packages matching +that pattern (see 'go help packages' for a description of package +patterns). Without a pattern, the argument list applies only to the +packages named on the command line. The flags may be repeated +with different patterns in order to specify different arguments for +different sets of packages. If a package matches patterns given in +multiple flags, the latest match on the command line wins. +For example, 'go build -gcflags=-S fmt' prints the disassembly +only for package fmt, while 'go build -gcflags=all=-S fmt' +prints the disassembly for fmt and all its dependencies. For more about specifying packages, see 'go help packages'. For more about where packages and binaries are installed, @@ -155,6 +152,8 @@ func init() { CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "") CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file") + CmdInstall.Flag.BoolVar(&cfg.BuildI, "i", false, "") + AddBuildFlags(CmdBuild) AddBuildFlags(CmdInstall) } @@ -162,9 +161,12 @@ func init() { // Note that flags consulted by other parts of the code // (for example, buildV) are in cmd/go/internal/cfg. -var buildAsmflags []string // -asmflags flag -var buildGcflags []string // -gcflags flag -var buildGccgoflags []string // -gccgoflags flag +var ( + forcedAsmflags []string // internally-forced flags for cmd/asm + forcedGcflags []string // internally-forced flags for cmd/compile + forcedLdflags []string // internally-forced flags for cmd/link + forcedGccgoflags []string // internally-forced flags for gccgo +) var BuildToolchain toolchain = noToolchain{} var ldBuildmode string @@ -210,13 +212,13 @@ func AddBuildFlags(cmd *base.Command) { cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "") cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "") - cmd.Flag.Var((*base.StringsFlag)(&buildAsmflags), "asmflags", "") + cmd.Flag.Var(&load.BuildAsmflags, "asmflags", "") cmd.Flag.Var(buildCompiler{}, "compiler", "") cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "") - cmd.Flag.Var((*base.StringsFlag)(&buildGcflags), "gcflags", "") - cmd.Flag.Var((*base.StringsFlag)(&buildGccgoflags), "gccgoflags", "") + cmd.Flag.Var(&load.BuildGcflags, "gcflags", "") + cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "") cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") - cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildLdflags), "ldflags", "") + cmd.Flag.Var(&load.BuildLdflags, "ldflags", "") cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "") cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "") @@ -224,6 +226,10 @@ func AddBuildFlags(cmd *base.Command) { cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "") cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "") cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "") + + // Undocumented, unstable debugging flags. + cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "") + cmd.Flag.Var(&load.DebugDeprecatedImportcfg, "debug-deprecated-importcfg", "") } // fileExtSplit expects a filename and returns the name @@ -265,156 +271,10 @@ func oneMainPkg(pkgs []*load.Package) []*load.Package { var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } -func BuildModeInit() { - gccgo := cfg.BuildToolchainName == "gccgo" - var codegenArg string - platform := cfg.Goos + "/" + cfg.Goarch - switch cfg.BuildBuildmode { - case "archive": - pkgsFilter = pkgsNotMain - case "c-archive": - pkgsFilter = oneMainPkg - if gccgo { - codegenArg = "-fPIC" - } else { - switch platform { - case "darwin/arm", "darwin/arm64": - codegenArg = "-shared" - default: - switch cfg.Goos { - case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": - // Use -shared so that the result is - // suitable for inclusion in a PIE or - // shared library. - codegenArg = "-shared" - } - } - } - cfg.ExeSuffix = ".a" - ldBuildmode = "c-archive" - case "c-shared": - pkgsFilter = oneMainPkg - if gccgo { - codegenArg = "-fPIC" - } else { - switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", - "android/amd64", "android/arm", "android/arm64", "android/386": - codegenArg = "-shared" - case "darwin/amd64", "darwin/386": - default: - base.Fatalf("-buildmode=c-shared not supported on %s\n", platform) - } - } - ldBuildmode = "c-shared" - case "default": - switch platform { - case "android/arm", "android/arm64", "android/amd64", "android/386": - if !gccgo { - codegenArg = "-shared" - } - ldBuildmode = "pie" - case "darwin/arm", "darwin/arm64": - if !gccgo { - codegenArg = "-shared" - } - fallthrough - default: - ldBuildmode = "exe" - } - case "exe": - pkgsFilter = pkgsMain - ldBuildmode = "exe" - case "pie": - if cfg.BuildRace { - base.Fatalf("-buildmode=pie not supported when -race is enabled") - } - if gccgo { - codegenArg = "-fPIE" - } else { - switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", - "android/amd64", "android/arm", "android/arm64", "android/386": - codegenArg = "-shared" - default: - base.Fatalf("-buildmode=pie not supported on %s\n", platform) - } - } - ldBuildmode = "pie" - case "shared": - pkgsFilter = pkgsNotMain - if gccgo { - codegenArg = "-fPIC" - } else { - switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": - default: - base.Fatalf("-buildmode=shared not supported on %s\n", platform) - } - codegenArg = "-dynlink" - } - if cfg.BuildO != "" { - base.Fatalf("-buildmode=shared and -o not supported together") - } - ldBuildmode = "shared" - case "plugin": - pkgsFilter = oneMainPkg - if gccgo { - codegenArg = "-fPIC" - } else { - switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", - "android/amd64", "android/arm", "android/arm64", "android/386": - default: - base.Fatalf("-buildmode=plugin not supported on %s\n", platform) - } - codegenArg = "-dynlink" - } - cfg.ExeSuffix = ".so" - ldBuildmode = "plugin" - default: - base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode) - } - if cfg.BuildLinkshared { - if gccgo { - codegenArg = "-fPIC" - } else { - switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": - buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1") - default: - base.Fatalf("-linkshared not supported on %s\n", platform) - } - codegenArg = "-dynlink" - // TODO(mwhudson): remove -w when that gets fixed in linker. - cfg.BuildLdflags = append(cfg.BuildLdflags, "-linkshared", "-w") - } - } - if codegenArg != "" { - if gccgo { - buildGccgoflags = append([]string{codegenArg}, buildGccgoflags...) - } else { - buildAsmflags = append([]string{codegenArg}, buildAsmflags...) - buildGcflags = append([]string{codegenArg}, buildGcflags...) - } - // Don't alter InstallSuffix when modifying default codegen args. - if cfg.BuildBuildmode != "default" || cfg.BuildLinkshared { - if cfg.BuildContext.InstallSuffix != "" { - cfg.BuildContext.InstallSuffix += "_" - } - cfg.BuildContext.InstallSuffix += codegenArg[1:] - } - } - if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") && !gccgo { - buildGcflags = append(buildGcflags, "-goversion", runtimeVersion) - } -} - var runtimeVersion = runtime.Version() func runBuild(cmd *base.Command, args []string) { - InstrumentInit() - BuildModeInit() + BuildInit() var b Builder b.Init() @@ -433,14 +293,14 @@ func runBuild(cmd *base.Command, args []string) { // sanity check some often mis-used options switch cfg.BuildContext.Compiler { case "gccgo": - if len(buildGcflags) != 0 { + if load.BuildGcflags.Present() { fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags") } - if len(cfg.BuildLdflags) != 0 { + if load.BuildLdflags.Present() { fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags") } case "gc": - if len(buildGccgoflags) != 0 { + if load.BuildGccgoflags.Present() { fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags") } } @@ -450,6 +310,8 @@ func runBuild(cmd *base.Command, args []string) { depMode = ModeInstall } + pkgs = pkgsFilter(load.Packages(args)) + if cfg.BuildO != "" { if len(pkgs) > 1 { base.Fatalf("go build: cannot use -o with multiple packages") @@ -457,38 +319,31 @@ func runBuild(cmd *base.Command, args []string) { base.Fatalf("no packages to build") } p := pkgs[0] - p.Internal.Target = cfg.BuildO + p.Target = cfg.BuildO p.Stale = true // must build - not up to date p.StaleReason = "build -o flag in use" - a := b.Action(ModeInstall, depMode, p) + a := b.AutoAction(ModeInstall, depMode, p) b.Do(a) return } - pkgs = pkgsFilter(load.Packages(args)) - - var a *Action + a := &Action{Mode: "go build"} + for _, p := range pkgs { + a.Deps = append(a.Deps, b.AutoAction(ModeBuild, depMode, p)) + } if cfg.BuildBuildmode == "shared" { - if libName, err := libname(args, pkgs); err != nil { - base.Fatalf("%s", err.Error()) - } else { - a = b.libaction(libName, pkgs, ModeBuild, depMode) - } - } else { - a = &Action{} - for _, p := range pkgs { - a.Deps = append(a.Deps, b.Action(ModeBuild, depMode, p)) - } + a = b.buildmodeShared(ModeBuild, depMode, args, pkgs, a) } b.Do(a) } var CmdInstall = &base.Command{ - UsageLine: "install [build flags] [packages]", + UsageLine: "install [-i] [build flags] [packages]", Short: "compile and install packages and dependencies", Long: ` -Install compiles and installs the packages named by the import paths, -along with their dependencies. +Install compiles and installs the packages named by the import paths. + +The -i flag installs the dependencies of the named packages as well. For more about the build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. @@ -554,8 +409,7 @@ func libname(args []string, pkgs []*load.Package) (string, error) { } func runInstall(cmd *base.Command, args []string) { - InstrumentInit() - BuildModeInit() + BuildInit() InstallPackages(args, false) } @@ -570,14 +424,14 @@ func InstallPackages(args []string, forGet bool) { if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") { switch { case p.Internal.GobinSubdir: - base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set") - case p.Internal.Cmdline: - base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)") + base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName) + case p.Internal.CmdlineFiles: + base.Errorf("go %s: no install location for .go files listed on command line (GOBIN not set)", cfg.CmdName) case p.ConflictDir != "": - base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir) + base.Errorf("go %s: no install location for %s: hidden by %s", cfg.CmdName, p.Dir, p.ConflictDir) default: - base.Errorf("go install: no install location for directory %s outside GOPATH\n"+ - "\tFor more details see: 'go help gopath'", p.Dir) + base.Errorf("go %s: no install location for directory %s outside GOPATH\n"+ + "\tFor more details see: 'go help gopath'", cfg.CmdName, p.Dir) } } } @@ -585,42 +439,46 @@ func InstallPackages(args []string, forGet bool) { var b Builder b.Init() - var a *Action - if cfg.BuildBuildmode == "shared" { - if libName, err := libname(args, pkgs); err != nil { - base.Fatalf("%s", err.Error()) - } else { - a = b.libaction(libName, pkgs, ModeInstall, ModeInstall) + depMode := ModeBuild + if cfg.BuildI { + depMode = ModeInstall + } + a := &Action{Mode: "go install"} + var tools []*Action + for _, p := range pkgs { + // During 'go get', don't attempt (and fail) to install packages with only tests. + // TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760. + if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { + continue } - } else { - a = &Action{} - var tools []*Action - for _, p := range pkgs { - // During 'go get', don't attempt (and fail) to install packages with only tests. - // TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760. - if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { - continue - } - // If p is a tool, delay the installation until the end of the build. - // This avoids installing assemblers/compilers that are being executed - // by other steps in the build. - // cmd/cgo is handled specially in b.Action, so that we can - // both build and use it in the same 'go install'. - Action := b.Action(ModeInstall, ModeInstall, p) - if load.GoTools[p.ImportPath] == load.ToTool && p.ImportPath != "cmd/cgo" { - a.Deps = append(a.Deps, Action.Deps...) - Action.Deps = append(Action.Deps, a) - tools = append(tools, Action) - continue - } - a.Deps = append(a.Deps, Action) + // If p is a tool, delay the installation until the end of the build. + // This avoids installing assemblers/compilers that are being executed + // by other steps in the build. + a1 := b.AutoAction(ModeInstall, depMode, p) + if load.InstallTargetDir(p) == load.ToTool { + a.Deps = append(a.Deps, a1.Deps...) + a1.Deps = append(a1.Deps, a) + tools = append(tools, a1) + continue } - if len(tools) > 0 { - a = &Action{ - Deps: tools, - } + a.Deps = append(a.Deps, a1) + } + if len(tools) > 0 { + a = &Action{ + Mode: "go install (tools)", + Deps: tools, } } + + if cfg.BuildBuildmode == "shared" { + // Note: If buildmode=shared then only non-main packages + // are present in the pkgs list, so all the special case code about + // tools above did not apply, and a is just a simple Action + // with a list of Deps, one per package named in pkgs, + // the same as in runBuild. + a = b.buildmodeShared(ModeInstall, ModeInstall, args, pkgs, a) + } + b.Do(a) base.ExitIfErrors() @@ -652,3270 +510,6 @@ func InstallPackages(args []string, forGet bool) { } } -// A Builder holds global state about a build. -// It does not hold per-package state, because we -// build packages in parallel, and the builder is shared. -type Builder struct { - WorkDir string // the temporary work directory (ends in filepath.Separator) - actionCache map[cacheKey]*Action // a cache of already-constructed actions - mkdirCache map[string]bool // a cache of created directories - flagCache map[string]bool // a cache of supported compiler flags - Print func(args ...interface{}) (int, error) - - output sync.Mutex - scriptDir string // current directory in printed script - - exec sync.Mutex - readySema chan bool - ready actionQueue -} - -// NOTE: Much of Action would not need to be exported if not for test. -// Maybe test functionality should move into this package too? - -// An Action represents a single action in the action graph. -type Action struct { - Package *load.Package // the package this action works on - Deps []*Action // actions that must happen before this one - Func func(*Builder, *Action) error // the action itself (nil = no-op) - IgnoreFail bool // whether to run f even if dependencies fail - TestOutput *bytes.Buffer // test output buffer - Args []string // additional args for runProgram - - triggers []*Action // inverse of deps - cgo *Action // action for cgo binary if needed - - // Generated files, directories. - Link bool // target is executable, not just package - Pkgdir string // the -I or -L argument to use when importing this package - Objdir string // directory for intermediate objects - Objpkg string // the intermediate package .a file created during the action - Target string // goal of the action: the created package or executable - - // Execution state. - pending int // number of deps yet to complete - priority int // relative execution priority - Failed bool // whether the action failed -} - -// cacheKey is the key for the action cache. -type cacheKey struct { - mode BuildMode - p *load.Package - shlib string -} - -// BuildMode specifies the build mode: -// are we just building things or also installing the results? -type BuildMode int - -const ( - ModeBuild BuildMode = iota - ModeInstall -) - -func (b *Builder) Init() { - var err error - b.Print = func(a ...interface{}) (int, error) { - return fmt.Fprint(os.Stderr, a...) - } - b.actionCache = make(map[cacheKey]*Action) - b.mkdirCache = make(map[string]bool) - - if cfg.BuildN { - b.WorkDir = "$WORK" - } else { - b.WorkDir, err = ioutil.TempDir("", "go-build") - if err != nil { - base.Fatalf("%s", err) - } - if cfg.BuildX || cfg.BuildWork { - fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir) - } - if !cfg.BuildWork { - workdir := b.WorkDir - base.AtExit(func() { os.RemoveAll(workdir) }) - } - } -} - -// readpkglist returns the list of packages that were built into the shared library -// at shlibpath. For the native toolchain this list is stored, newline separated, in -// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the -// .go_export section. -func readpkglist(shlibpath string) (pkgs []*load.Package) { - var stk load.ImportStack - if cfg.BuildToolchainName == "gccgo" { - var data []byte - if f, err := elf.Open(shlibpath); err == nil { - sect := f.Section(".go_export") - data, _ = sect.Data() - } else if f, err := xcoff.Open(shlibpath); err == nil { - data = f.CSect(".go_export") - } - scanner := bufio.NewScanner(bytes.NewBuffer(data)) - for scanner.Scan() { - t := scanner.Text() - if strings.HasPrefix(t, "pkgpath ") { - t = strings.TrimPrefix(t, "pkgpath ") - t = strings.TrimSuffix(t, ";") - pkgs = append(pkgs, load.LoadPackage(t, &stk)) - } - } - } else { - pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1) - if err != nil { - base.Fatalf("readELFNote failed: %v", err) - } - scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) - for scanner.Scan() { - t := scanner.Text() - pkgs = append(pkgs, load.LoadPackage(t, &stk)) - } - } - return -} - -// Action returns the action for applying the given operation (mode) to the package. -// depMode is the action to use when building dependencies. -// action never looks for p in a shared library, but may find p's dependencies in a -// shared library if buildLinkshared is true. -func (b *Builder) Action(mode BuildMode, depMode BuildMode, p *load.Package) *Action { - return b.action1(mode, depMode, p, false, "") -} - -// action1 returns the action for applying the given operation (mode) to the package. -// depMode is the action to use when building dependencies. -// action1 will look for p in a shared library if lookshared is true. -// forShlib is the shared library that p will become part of, if any. -func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lookshared bool, forShlib string) *Action { - shlib := "" - if lookshared { - shlib = p.Shlib - } - key := cacheKey{mode, p, shlib} - - a := b.actionCache[key] - if a != nil { - return a - } - if shlib != "" { - key2 := cacheKey{ModeInstall, nil, shlib} - a = b.actionCache[key2] - if a != nil { - b.actionCache[key] = a - return a - } - pkgs := readpkglist(shlib) - a = b.libaction(filepath.Base(shlib), pkgs, ModeInstall, depMode) - b.actionCache[key2] = a - b.actionCache[key] = a - return a - } - - a = &Action{Package: p, Pkgdir: p.Internal.Build.PkgRoot} - if p.Internal.Pkgdir != "" { // overrides p.t - a.Pkgdir = p.Internal.Pkgdir - } - b.actionCache[key] = a - - for _, p1 := range p.Internal.Imports { - if forShlib != "" { - // p is part of a shared library. - if p1.Shlib != "" && p1.Shlib != forShlib { - // p1 is explicitly part of a different shared library. - // Put the action for that shared library into a.Deps. - a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, true, p1.Shlib)) - } else { - // p1 is (implicitly or not) part of this shared library. - // Put the action for p1 into a.Deps. - a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, false, forShlib)) - } - } else { - // p is not part of a shared library. - // If p1 is in a shared library, put the action for that into - // a.Deps, otherwise put the action for p1 into a.Deps. - a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, cfg.BuildLinkshared, p1.Shlib)) - } - } - - // If we are not doing a cross-build, then record the binary we'll - // generate for cgo as a dependency of the build of any package - // using cgo, to make sure we do not overwrite the binary while - // a package is using it. If this is a cross-build, then the cgo we - // are writing is not the cgo we need to use. - if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan && cfg.BuildToolchainName != "gccgo" { - if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !cfg.BuildLinkshared && cfg.BuildBuildmode != "shared" { - var stk load.ImportStack - p1 := load.LoadPackage("cmd/cgo", &stk) - if p1.Error != nil { - base.Fatalf("load cmd/cgo: %v", p1.Error) - } - a.cgo = b.Action(depMode, depMode, p1) - a.Deps = append(a.Deps, a.cgo) - } - } - - if p.Standard { - switch p.ImportPath { - case "builtin", "unsafe": - // Fake packages - nothing to build. - return a - } - // gccgo standard library is "fake" too. - if cfg.BuildToolchainName == "gccgo" { - // the target name is needed for cgo. - a.Target = p.Internal.Target - return a - } - } - - if !p.Stale && p.Internal.Target != "" { - // p.Stale==false implies that p.Internal.Target is up-to-date. - // Record target name for use by actions depending on this one. - a.Target = p.Internal.Target - return a - } - - if p.Internal.Local && p.Internal.Target == "" { - // Imported via local path. No permanent target. - mode = ModeBuild - } - work := p.Internal.Pkgdir - if work == "" { - work = b.WorkDir - } - a.Objdir = filepath.Join(work, a.Package.ImportPath, "_obj") + string(filepath.Separator) - a.Objpkg = BuildToolchain.Pkgpath(work, a.Package) - a.Link = p.Name == "main" - - switch mode { - case ModeInstall: - a.Func = BuildInstallFunc - a.Deps = []*Action{b.action1(ModeBuild, depMode, p, lookshared, forShlib)} - a.Target = a.Package.Internal.Target - - // Install header for cgo in c-archive and c-shared modes. - if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { - hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h" - if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" { - // For the header file, remove the "lib" - // added by go/build, so we generate pkg.h - // rather than libpkg.h. - dir, file := filepath.Split(hdrTarget) - file = strings.TrimPrefix(file, "lib") - hdrTarget = filepath.Join(dir, file) - } - ah := &Action{ - Package: a.Package, - Deps: []*Action{a.Deps[0]}, - Func: (*Builder).installHeader, - Pkgdir: a.Pkgdir, - Objdir: a.Objdir, - Target: hdrTarget, - } - a.Deps = append(a.Deps, ah) - } - - case ModeBuild: - a.Func = (*Builder).build - a.Target = a.Objpkg - if a.Link { - // An executable file. (This is the name of a temporary file.) - // Because we run the temporary file in 'go run' and 'go test', - // the name will show up in ps listings. If the caller has specified - // a name, use that instead of a.out. The binary is generated - // in an otherwise empty subdirectory named exe to avoid - // naming conflicts. The only possible conflict is if we were - // to create a top-level package named exe. - name := "a.out" - if p.Internal.ExeName != "" { - name = p.Internal.ExeName - } else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.Internal.Target != "" { - // On OS X, the linker output name gets recorded in the - // shared library's LC_ID_DYLIB load command. - // The code invoking the linker knows to pass only the final - // path element. Arrange that the path element matches what - // we'll install it as; otherwise the library is only loadable as "a.out". - _, name = filepath.Split(p.Internal.Target) - } - a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix - } - } - - return a -} - -func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode BuildMode) *Action { - a := &Action{} - switch mode { - default: - base.Fatalf("unrecognized mode %v", mode) - - case ModeBuild: - a.Func = (*Builder).linkShared - a.Target = filepath.Join(b.WorkDir, libname) - for _, p := range pkgs { - if p.Internal.Target == "" { - continue - } - a.Deps = append(a.Deps, b.Action(depMode, depMode, p)) - } - - case ModeInstall: - // Currently build mode shared forces external linking mode, and - // external linking mode forces an import of runtime/cgo (and - // math on arm). So if it was not passed on the command line and - // it is not present in another shared library, add it here. - gccgo := cfg.BuildToolchainName == "gccgo" - if !gccgo { - seencgo := false - for _, p := range pkgs { - seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo") - } - if !seencgo { - var stk load.ImportStack - p := load.LoadPackage("runtime/cgo", &stk) - if p.Error != nil { - base.Fatalf("load runtime/cgo: %v", p.Error) - } - load.ComputeStale(p) - // If runtime/cgo is in another shared library, then that's - // also the shared library that contains runtime, so - // something will depend on it and so runtime/cgo's staleness - // will be checked when processing that library. - if p.Shlib == "" || p.Shlib == libname { - pkgs = append([]*load.Package{}, pkgs...) - pkgs = append(pkgs, p) - } - } - if cfg.Goarch == "arm" { - seenmath := false - for _, p := range pkgs { - seenmath = seenmath || (p.Standard && p.ImportPath == "math") - } - if !seenmath { - var stk load.ImportStack - p := load.LoadPackage("math", &stk) - if p.Error != nil { - base.Fatalf("load math: %v", p.Error) - } - load.ComputeStale(p) - // If math is in another shared library, then that's - // also the shared library that contains runtime, so - // something will depend on it and so math's staleness - // will be checked when processing that library. - if p.Shlib == "" || p.Shlib == libname { - pkgs = append([]*load.Package{}, pkgs...) - pkgs = append(pkgs, p) - } - } - } - } - - // Figure out where the library will go. - var libdir string - for _, p := range pkgs { - plibdir := p.Internal.Build.PkgTargetRoot - if gccgo { - plibdir = filepath.Join(plibdir, "shlibs") - } - if libdir == "" { - libdir = plibdir - } else if libdir != plibdir { - base.Fatalf("multiple roots %s & %s", libdir, plibdir) - } - } - a.Target = filepath.Join(libdir, libname) - - // Now we can check whether we need to rebuild it. - stale := false - var built time.Time - if fi, err := os.Stat(a.Target); err == nil { - built = fi.ModTime() - } - for _, p := range pkgs { - if p.Internal.Target == "" { - continue - } - stale = stale || p.Stale - lstat, err := os.Stat(p.Internal.Target) - if err != nil || lstat.ModTime().After(built) { - stale = true - } - a.Deps = append(a.Deps, b.action1(depMode, depMode, p, false, a.Target)) - } - - if stale { - a.Func = BuildInstallFunc - buildAction := b.libaction(libname, pkgs, ModeBuild, depMode) - a.Deps = []*Action{buildAction} - for _, p := range pkgs { - if p.Internal.Target == "" { - continue - } - shlibnameaction := &Action{} - shlibnameaction.Func = (*Builder).installShlibname - shlibnameaction.Target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname" - a.Deps = append(a.Deps, shlibnameaction) - shlibnameaction.Deps = append(shlibnameaction.Deps, buildAction) - } - } - } - return a -} - -// ActionList returns the list of actions in the dag rooted at root -// as visited in a depth-first post-order traversal. -func ActionList(root *Action) []*Action { - seen := map[*Action]bool{} - all := []*Action{} - var walk func(*Action) - walk = func(a *Action) { - if seen[a] { - return - } - seen[a] = true - for _, a1 := range a.Deps { - walk(a1) - } - all = append(all, a) - } - walk(root) - return all -} - -// allArchiveActions returns a list of the archive dependencies of root. -// This is needed because if package p depends on package q that is in libr.so, the -// action graph looks like p->libr.so->q and so just scanning through p's -// dependencies does not find the import dir for q. -func allArchiveActions(root *Action) []*Action { - seen := map[*Action]bool{} - r := []*Action{} - var walk func(*Action) - walk = func(a *Action) { - if seen[a] { - return - } - seen[a] = true - if strings.HasSuffix(a.Target, ".so") || a == root { - for _, a1 := range a.Deps { - walk(a1) - } - } else if strings.HasSuffix(a.Target, ".a") { - r = append(r, a) - } - } - walk(root) - return r -} - -// do runs the action graph rooted at root. -func (b *Builder) Do(root *Action) { - /* Commented for gccgo, which does not have OSArchSupportsCgo. - - if _, ok := cfg.OSArchSupportsCgo[cfg.Goos+"/"+cfg.Goarch]; !ok && cfg.BuildContext.Compiler == "gc" { - fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", cfg.Goos, cfg.Goarch) - os.Exit(2) - } - */ - - for _, tag := range cfg.BuildContext.BuildTags { - if strings.Contains(tag, ",") { - fmt.Fprintf(os.Stderr, "cmd/go: -tags space-separated list contains comma\n") - os.Exit(2) - } - } - - // Build list of all actions, assigning depth-first post-order priority. - // The original implementation here was a true queue - // (using a channel) but it had the effect of getting - // distracted by low-level leaf actions to the detriment - // of completing higher-level actions. The order of - // work does not matter much to overall execution time, - // but when running "go test std" it is nice to see each test - // results as soon as possible. The priorities assigned - // ensure that, all else being equal, the execution prefers - // to do what it would have done first in a simple depth-first - // dependency order traversal. - all := ActionList(root) - for i, a := range all { - a.priority = i - } - - b.readySema = make(chan bool, len(all)) - - // Initialize per-action execution state. - for _, a := range all { - for _, a1 := range a.Deps { - a1.triggers = append(a1.triggers, a) - } - a.pending = len(a.Deps) - if a.pending == 0 { - b.ready.push(a) - b.readySema <- true - } - } - - // Handle runs a single action and takes care of triggering - // any actions that are runnable as a result. - handle := func(a *Action) { - var err error - if a.Func != nil && (!a.Failed || a.IgnoreFail) { - err = a.Func(b, a) - } - - // The actions run in parallel but all the updates to the - // shared work state are serialized through b.exec. - b.exec.Lock() - defer b.exec.Unlock() - - if err != nil { - if err == errPrintedOutput { - base.SetExitStatus(2) - } else { - base.Errorf("%s", err) - } - a.Failed = true - } - - for _, a0 := range a.triggers { - if a.Failed { - a0.Failed = true - } - if a0.pending--; a0.pending == 0 { - b.ready.push(a0) - b.readySema <- true - } - } - - if a == root { - close(b.readySema) - } - } - - var wg sync.WaitGroup - - // Kick off goroutines according to parallelism. - // If we are using the -n flag (just printing commands) - // drop the parallelism to 1, both to make the output - // deterministic and because there is no real work anyway. - par := cfg.BuildP - if cfg.BuildN { - par = 1 - } - for i := 0; i < par; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case _, ok := <-b.readySema: - if !ok { - return - } - // Receiving a value from b.readySema entitles - // us to take from the ready queue. - b.exec.Lock() - a := b.ready.pop() - b.exec.Unlock() - handle(a) - case <-base.Interrupted: - base.SetExitStatus(1) - return - } - } - }() - } - - wg.Wait() -} - -// build is the action for building a single package or command. -func (b *Builder) build(a *Action) (err error) { - // Return an error for binary-only package. - // We only reach this if isStale believes the binary form is - // either not present or not usable. - if a.Package.BinaryOnly { - return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.Package.ImportPath) - } - - // Return an error if the package has CXX files but it's not using - // cgo nor SWIG, since the CXX files can only be processed by cgo - // and SWIG. - if len(a.Package.CXXFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { - return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG", - a.Package.ImportPath, strings.Join(a.Package.CXXFiles, ",")) - } - // Same as above for Objective-C files - if len(a.Package.MFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { - return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG", - a.Package.ImportPath, strings.Join(a.Package.MFiles, ",")) - } - // Same as above for Fortran files - if len(a.Package.FFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { - return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG", - a.Package.ImportPath, strings.Join(a.Package.FFiles, ",")) - } - - defer func() { - if err != nil && err != errPrintedOutput { - err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err) - } - }() - if cfg.BuildN { - // In -n mode, print a banner between packages. - // The banner is five lines so that when changes to - // different sections of the bootstrap script have to - // be merged, the banners give patch something - // to use to find its context. - b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n") - } - - if cfg.BuildV { - b.Print(a.Package.ImportPath + "\n") - } - - // Make build directory. - obj := a.Objdir - if err := b.Mkdir(obj); err != nil { - return err - } - - // make target directory - dir, _ := filepath.Split(a.Target) - if dir != "" { - if err := b.Mkdir(dir); err != nil { - return err - } - } - - var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string - - gofiles = append(gofiles, a.Package.GoFiles...) - cgofiles = append(cgofiles, a.Package.CgoFiles...) - cfiles = append(cfiles, a.Package.CFiles...) - sfiles = append(sfiles, a.Package.SFiles...) - cxxfiles = append(cxxfiles, a.Package.CXXFiles...) - - if a.Package.UsesCgo() || a.Package.UsesSwig() { - if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil { - return - } - } - - // Run SWIG on each .swig and .swigcxx file. - // Each run will generate two files, a .go file and a .c or .cxx file. - // The .go file will use import "C" and is to be processed by cgo. - if a.Package.UsesSwig() { - outGo, outC, outCXX, err := b.swig(a.Package, obj, pcCFLAGS) - if err != nil { - return err - } - objdirCgofiles = append(objdirCgofiles, outGo...) - cfiles = append(cfiles, outC...) - cxxfiles = append(cxxfiles, outCXX...) - } - - // Run cgo. - if a.Package.UsesCgo() || a.Package.UsesSwig() { - // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. - // There is one exception: runtime/cgo's job is to bridge the - // cgo and non-cgo worlds, so it necessarily has files in both. - // In that case gcc only gets the gcc_* files. - var gccfiles []string - gccfiles = append(gccfiles, cfiles...) - cfiles = nil - if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" { - filter := func(files, nongcc, gcc []string) ([]string, []string) { - for _, f := range files { - if strings.HasPrefix(f, "gcc_") { - gcc = append(gcc, f) - } else { - nongcc = append(nongcc, f) - } - } - return nongcc, gcc - } - sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles) - } else { - for _, sfile := range sfiles { - data, err := ioutil.ReadFile(filepath.Join(a.Package.Dir, sfile)) - if err == nil { - if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) || - bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) || - bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) { - return fmt.Errorf("package using cgo has Go assembly file %s", sfile) - } - } - } - gccfiles = append(gccfiles, sfiles...) - sfiles = nil - } - - var cgoExe string - if a.cgo != nil && a.cgo.Target != "" { - cgoExe = a.cgo.Target - } else { - cgoExe = base.Tool("cgo") - } - outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles) - if err != nil { - return err - } - if cfg.BuildToolchainName == "gccgo" { - cgoObjects = append(cgoObjects, filepath.Join(a.Objdir, "_cgo_flags")) - } - cgoObjects = append(cgoObjects, outObj...) - gofiles = append(gofiles, outGo...) - } - - if len(gofiles) == 0 { - return &load.NoGoError{Package: a.Package} - } - - // If we're doing coverage, preprocess the .go files and put them in the work directory - if a.Package.Internal.CoverMode != "" { - for i, file := range gofiles { - var sourceFile string - var coverFile string - var key string - if strings.HasSuffix(file, ".cgo1.go") { - // cgo files have absolute paths - base := filepath.Base(file) - sourceFile = file - coverFile = filepath.Join(obj, base) - key = strings.TrimSuffix(base, ".cgo1.go") + ".go" - } else { - sourceFile = filepath.Join(a.Package.Dir, file) - coverFile = filepath.Join(obj, file) - key = file - } - cover := a.Package.Internal.CoverVars[key] - if cover == nil || base.IsTestFile(file) { - // Not covering this file. - continue - } - if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil { - return err - } - gofiles[i] = coverFile - } - } - - // Prepare Go import path list. - inc := b.includeArgs("-I", allArchiveActions(a)) - - // Compile Go. - ofile, out, err := BuildToolchain.gc(b, a.Package, a.Objpkg, obj, len(sfiles) > 0, inc, gofiles) - if len(out) > 0 { - b.showOutput(a.Package.Dir, a.Package.ImportPath, b.processOutput(out)) - if err != nil { - return errPrintedOutput - } - } - if err != nil { - return err - } - if ofile != a.Objpkg { - objects = append(objects, ofile) - } - - // Copy .h files named for goos or goarch or goos_goarch - // to names using GOOS and GOARCH. - // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. - _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch - _goos := "_" + cfg.Goos - _goarch := "_" + cfg.Goarch - for _, file := range a.Package.HFiles { - name, ext := fileExtSplit(file) - switch { - case strings.HasSuffix(name, _goos_goarch): - targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { - return err - } - case strings.HasSuffix(name, _goarch): - targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { - return err - } - case strings.HasSuffix(name, _goos): - targ := file[:len(name)-len(_goos)] + "_GOOS." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { - return err - } - } - } - - for _, file := range cfiles { - out := file[:len(file)-len(".c")] + ".o" - if err := BuildToolchain.cc(b, a.Package, obj, obj+out, file); err != nil { - return err - } - objects = append(objects, out) - } - - // Assemble .s files. - if len(sfiles) > 0 { - ofiles, err := BuildToolchain.asm(b, a.Package, obj, sfiles) - if err != nil { - return err - } - objects = append(objects, ofiles...) - } - - // NOTE(rsc): On Windows, it is critically important that the - // gcc-compiled objects (cgoObjects) be listed after the ordinary - // objects in the archive. I do not know why this is. - // https://golang.org/issue/2601 - objects = append(objects, cgoObjects...) - - // Add system object files. - for _, syso := range a.Package.SysoFiles { - objects = append(objects, filepath.Join(a.Package.Dir, syso)) - } - - // Pack into archive in obj directory. - // If the Go compiler wrote an archive, we only need to add the - // object files for non-Go sources to the archive. - // If the Go compiler wrote an archive and the package is entirely - // Go sources, there is no pack to execute at all. - if len(objects) > 0 { - if err := BuildToolchain.pack(b, a.Package, obj, a.Objpkg, objects); err != nil { - return err - } - } - - // Link if needed. - if a.Link { - // The compiler only cares about direct imports, but the - // linker needs the whole dependency tree. - all := ActionList(a) - all = all[:len(all)-1] // drop a - if err := BuildToolchain.ld(b, a, a.Target, all, a.Objpkg, objects); err != nil { - return err - } - } - - return nil -} - -// PkgconfigCmd returns a pkg-config binary name -// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. -func (b *Builder) PkgconfigCmd() string { - return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0] -} - -// splitPkgConfigOutput parses the pkg-config output into a slice of -// flags. pkg-config always uses \ to escape special characters. -func splitPkgConfigOutput(out []byte) []string { - if len(out) == 0 { - return nil - } - var flags []string - flag := make([]byte, len(out)) - r, w := 0, 0 - for r < len(out) { - switch out[r] { - case ' ', '\t', '\r', '\n': - if w > 0 { - flags = append(flags, string(flag[:w])) - } - w = 0 - case '\\': - r++ - fallthrough - default: - if r < len(out) { - flag[w] = out[r] - w++ - } - } - r++ - } - if w > 0 { - flags = append(flags, string(flag[:w])) - } - return flags -} - -// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. -func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { - if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { - var out []byte - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pkgs) - if err != nil { - b.showOutput(p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) - b.Print(err.Error() + "\n") - err = errPrintedOutput - return - } - if len(out) > 0 { - cflags = splitPkgConfigOutput(out) - } - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pkgs) - if err != nil { - b.showOutput(p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) - b.Print(err.Error() + "\n") - err = errPrintedOutput - return - } - if len(out) > 0 { - ldflags = strings.Fields(string(out)) - } - } - return -} - -func (b *Builder) installShlibname(a *Action) error { - a1 := a.Deps[0] - err := ioutil.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666) - if err != nil { - return err - } - if cfg.BuildX { - b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target) - } - return nil -} - -func (b *Builder) linkShared(a *Action) (err error) { - allactions := ActionList(a) - allactions = allactions[:len(allactions)-1] - return BuildToolchain.ldShared(b, a.Deps, a.Target, allactions) -} - -// BuildInstallFunc is the action for installing a single package or executable. -func BuildInstallFunc(b *Builder, a *Action) (err error) { - defer func() { - if err != nil && err != errPrintedOutput { - err = fmt.Errorf("go install %s: %v", a.Package.ImportPath, err) - } - }() - a1 := a.Deps[0] - perm := os.FileMode(0666) - if a1.Link { - switch cfg.BuildBuildmode { - case "c-archive", "c-shared", "plugin": - default: - perm = 0777 - } - } - - // make target directory - dir, _ := filepath.Split(a.Target) - if dir != "" { - if err := b.Mkdir(dir); err != nil { - return err - } - } - - // remove object dir to keep the amount of - // garbage down in a large build. On an operating system - // with aggressive buffering, cleaning incrementally like - // this keeps the intermediate objects from hitting the disk. - if !cfg.BuildWork { - defer os.RemoveAll(a1.Objdir) - defer os.Remove(a1.Target) - } - - return b.moveOrCopyFile(a, a.Target, a1.Target, perm, false) -} - -// includeArgs returns the -I or -L directory list for access -// to the results of the list of actions. -func (b *Builder) includeArgs(flag string, all []*Action) []string { - inc := []string{} - incMap := map[string]bool{ - b.WorkDir: true, // handled later - cfg.GOROOTpkg: true, - "": true, // ignore empty strings - } - - // Look in the temporary space for results of test-specific actions. - // This is the $WORK/my/package/_test directory for the - // package being built, so there are few of these. - for _, a1 := range all { - if a1.Package == nil { - continue - } - if dir := a1.Pkgdir; dir != a1.Package.Internal.Build.PkgRoot && !incMap[dir] { - incMap[dir] = true - inc = append(inc, flag, dir) - } - } - - // Also look in $WORK for any non-test packages that have - // been built but not installed. - inc = append(inc, flag, b.WorkDir) - - // Finally, look in the installed package directories for each action. - // First add the package dirs corresponding to GOPATH entries - // in the original GOPATH order. - need := map[string]*build.Package{} - for _, a1 := range all { - if a1.Package != nil && a1.Pkgdir == a1.Package.Internal.Build.PkgRoot { - need[a1.Package.Internal.Build.Root] = a1.Package.Internal.Build - } - } - for _, root := range cfg.Gopath { - if p := need[root]; p != nil && !incMap[p.PkgRoot] { - incMap[p.PkgRoot] = true - inc = append(inc, flag, p.PkgTargetRoot) - } - } - - // Then add anything that's left. - for _, a1 := range all { - if a1.Package == nil { - continue - } - if dir := a1.Pkgdir; dir == a1.Package.Internal.Build.PkgRoot && !incMap[dir] { - incMap[dir] = true - inc = append(inc, flag, a1.Package.Internal.Build.PkgTargetRoot) - } - } - - return inc -} - -// moveOrCopyFile is like 'mv src dst' or 'cp src dst'. -func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { - if cfg.BuildN { - b.Showcmd("", "mv %s %s", src, dst) - return nil - } - - // If we can update the mode and rename to the dst, do it. - // Otherwise fall back to standard copy. - - // If the destination directory has the group sticky bit set, - // we have to copy the file to retain the correct permissions. - // https://golang.org/issue/18878 - if fi, err := os.Stat(filepath.Dir(dst)); err == nil { - if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 { - return b.copyFile(a, dst, src, perm, force) - } - } - - // The perm argument is meant to be adjusted according to umask, - // but we don't know what the umask is. - // Create a dummy file to find out. - // This avoids build tags and works even on systems like Plan 9 - // where the file mask computation incorporates other information. - mode := perm - f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) - if err == nil { - fi, err := f.Stat() - if err == nil { - mode = fi.Mode() & 0777 - } - name := f.Name() - f.Close() - os.Remove(name) - } - - if err := os.Chmod(src, mode); err == nil { - if err := os.Rename(src, dst); err == nil { - if cfg.BuildX { - b.Showcmd("", "mv %s %s", src, dst) - } - return nil - } - } - - return b.copyFile(a, dst, src, perm, force) -} - -// copyFile is like 'cp src dst'. -func (b *Builder) copyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { - if cfg.BuildN || cfg.BuildX { - b.Showcmd("", "cp %s %s", src, dst) - if cfg.BuildN { - return nil - } - } - - sf, err := os.Open(src) - if err != nil { - return err - } - defer sf.Close() - - // Be careful about removing/overwriting dst. - // Do not remove/overwrite if dst exists and is a directory - // or a non-object file. - if fi, err := os.Stat(dst); err == nil { - if fi.IsDir() { - return fmt.Errorf("build output %q already exists and is a directory", dst) - } - if !force && fi.Mode().IsRegular() && !isObject(dst) { - return fmt.Errorf("build output %q already exists and is not an object file", dst) - } - } - - // On Windows, remove lingering ~ file from last attempt. - if base.ToolIsWindows { - if _, err := os.Stat(dst + "~"); err == nil { - os.Remove(dst + "~") - } - } - - mayberemovefile(dst) - df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil && base.ToolIsWindows { - // Windows does not allow deletion of a binary file - // while it is executing. Try to move it out of the way. - // If the move fails, which is likely, we'll try again the - // next time we do an install of this binary. - if err := os.Rename(dst, dst+"~"); err == nil { - os.Remove(dst + "~") - } - df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - } - if err != nil { - return err - } - - _, err = io.Copy(df, sf) - df.Close() - if err != nil { - mayberemovefile(dst) - return fmt.Errorf("copying %s to %s: %v", src, dst, err) - } - return nil -} - -// Install the cgo export header file, if there is one. -func (b *Builder) installHeader(a *Action) error { - src := a.Objdir + "_cgo_install.h" - if _, err := os.Stat(src); os.IsNotExist(err) { - // If the file does not exist, there are no exported - // functions, and we do not install anything. - return nil - } - - dir, _ := filepath.Split(a.Target) - if dir != "" { - if err := b.Mkdir(dir); err != nil { - return err - } - } - - return b.moveOrCopyFile(a, a.Target, src, 0666, true) -} - -// cover runs, in effect, -// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go -func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName string) error { - return b.run(a.Objdir, "cover "+a.Package.ImportPath, nil, - cfg.BuildToolexec, - base.Tool("cover"), - "-mode", a.Package.Internal.CoverMode, - "-var", varName, - "-o", dst, - src) -} - -var objectMagic = [][]byte{ - {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive - {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package archive (AIX format) - {'\x7F', 'E', 'L', 'F'}, // ELF - {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit - {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit - {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit - {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit - {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc - {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 - {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 - {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm - {0x01, 0xDF}, // XCOFF32 - {0x01, 0xF7}, // XCOFF64 -} - -func isObject(s string) bool { - f, err := os.Open(s) - if err != nil { - return false - } - defer f.Close() - buf := make([]byte, 64) - io.ReadFull(f, buf) - for _, magic := range objectMagic { - if bytes.HasPrefix(buf, magic) { - return true - } - } - return false -} - -// mayberemovefile removes a file only if it is a regular file -// When running as a user with sufficient privileges, we may delete -// even device files, for example, which is not intended. -func mayberemovefile(s string) { - if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() { - return - } - os.Remove(s) -} - -// fmtcmd formats a command in the manner of fmt.Sprintf but also: -// -// If dir is non-empty and the script is not in dir right now, -// fmtcmd inserts "cd dir\n" before the command. -// -// fmtcmd replaces the value of b.WorkDir with $WORK. -// fmtcmd replaces the value of goroot with $GOROOT. -// fmtcmd replaces the value of b.gobin with $GOBIN. -// -// fmtcmd replaces the name of the current directory with dot (.) -// but only when it is at the beginning of a space-separated token. -// -func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string { - cmd := fmt.Sprintf(format, args...) - if dir != "" && dir != "/" { - cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:] - if b.scriptDir != dir { - b.scriptDir = dir - cmd = "cd " + dir + "\n" + cmd - } - } - if b.WorkDir != "" { - cmd = strings.Replace(cmd, b.WorkDir, "$WORK", -1) - } - return cmd -} - -// showcmd prints the given command to standard output -// for the implementation of -n or -x. -func (b *Builder) Showcmd(dir string, format string, args ...interface{}) { - b.output.Lock() - defer b.output.Unlock() - b.Print(b.fmtcmd(dir, format, args...) + "\n") -} - -// showOutput prints "# desc" followed by the given output. -// The output is expected to contain references to 'dir', usually -// the source directory for the package that has failed to build. -// showOutput rewrites mentions of dir with a relative path to dir -// when the relative path is shorter. This is usually more pleasant. -// For example, if fmt doesn't compile and we are in src/html, -// the output is -// -// $ go build -// # fmt -// ../fmt/print.go:1090: undefined: asdf -// $ -// -// instead of -// -// $ go build -// # fmt -// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf -// $ -// -// showOutput also replaces references to the work directory with $WORK. -// -func (b *Builder) showOutput(dir, desc, out string) { - prefix := "# " + desc - suffix := "\n" + out - if reldir := base.ShortPath(dir); reldir != dir { - suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1) - suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1) - } - suffix = strings.Replace(suffix, " "+b.WorkDir, " $WORK", -1) - - b.output.Lock() - defer b.output.Unlock() - b.Print(prefix, suffix) -} - -// errPrintedOutput is a special error indicating that a command failed -// but that it generated output as well, and that output has already -// been printed, so there's no point showing 'exit status 1' or whatever -// the wait status was. The main executor, builder.do, knows not to -// print this error. -var errPrintedOutput = errors.New("already printed output - no need to show error") - -var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+(:[0-9]+)?\]`) -var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`) - -// run runs the command given by cmdline in the directory dir. -// If the command fails, run prints information about the failure -// and returns a non-nil error. -func (b *Builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error { - out, err := b.runOut(dir, desc, env, cmdargs...) - if len(out) > 0 { - if desc == "" { - desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " ")) - } - b.showOutput(dir, desc, b.processOutput(out)) - if err != nil { - err = errPrintedOutput - } - } - return err -} - -// processOutput prepares the output of runOut to be output to the console. -func (b *Builder) processOutput(out []byte) string { - if out[len(out)-1] != '\n' { - out = append(out, '\n') - } - messages := string(out) - // Fix up output referring to cgo-generated code to be more readable. - // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19. - // Replace *[100]_Ctype_foo with *[100]C.foo. - // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite. - if !cfg.BuildX && cgoLine.MatchString(messages) { - messages = cgoLine.ReplaceAllString(messages, "") - messages = cgoTypeSigRe.ReplaceAllString(messages, "C.") - } - return messages -} - -// runOut runs the command given by cmdline in the directory dir. -// It returns the command output and any errors that occurred. -func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { - cmdline := str.StringList(cmdargs...) - if cfg.BuildN || cfg.BuildX { - var envcmdline string - for i := range env { - envcmdline += env[i] - envcmdline += " " - } - envcmdline += joinUnambiguously(cmdline) - b.Showcmd(dir, "%s", envcmdline) - if cfg.BuildN { - return nil, nil - } - } - - nbusy := 0 - for { - var buf bytes.Buffer - cmd := exec.Command(cmdline[0], cmdline[1:]...) - cmd.Stdout = &buf - cmd.Stderr = &buf - cmd.Dir = dir - cmd.Env = base.MergeEnvLists(env, base.EnvForDir(cmd.Dir, os.Environ())) - err := cmd.Run() - - // cmd.Run will fail on Unix if some other process has the binary - // we want to run open for writing. This can happen here because - // we build and install the cgo command and then run it. - // If another command was kicked off while we were writing the - // cgo binary, the child process for that command may be holding - // a reference to the fd, keeping us from running exec. - // - // But, you might reasonably wonder, how can this happen? - // The cgo fd, like all our fds, is close-on-exec, so that we need - // not worry about other processes inheriting the fd accidentally. - // The answer is that running a command is fork and exec. - // A child forked while the cgo fd is open inherits that fd. - // Until the child has called exec, it holds the fd open and the - // kernel will not let us run cgo. Even if the child were to close - // the fd explicitly, it would still be open from the time of the fork - // until the time of the explicit close, and the race would remain. - // - // On Unix systems, this results in ETXTBSY, which formats - // as "text file busy". Rather than hard-code specific error cases, - // we just look for that string. If this happens, sleep a little - // and try again. We let this happen three times, with increasing - // sleep lengths: 100+200+400 ms = 0.7 seconds. - // - // An alternate solution might be to split the cmd.Run into - // separate cmd.Start and cmd.Wait, and then use an RWLock - // to make sure that copyFile only executes when no cmd.Start - // call is in progress. However, cmd.Start (really syscall.forkExec) - // only guarantees that when it returns, the exec is committed to - // happen and succeed. It uses a close-on-exec file descriptor - // itself to determine this, so we know that when cmd.Start returns, - // at least one close-on-exec file descriptor has been closed. - // However, we cannot be sure that all of them have been closed, - // so the program might still encounter ETXTBSY even with such - // an RWLock. The race window would be smaller, perhaps, but not - // guaranteed to be gone. - // - // Sleeping when we observe the race seems to be the most reliable - // option we have. - // - // https://golang.org/issue/3001 - // - if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") { - time.Sleep(100 * time.Millisecond << uint(nbusy)) - nbusy++ - continue - } - - // err can be something like 'exit status 1'. - // Add information about what program was running. - // Note that if buf.Bytes() is non-empty, the caller usually - // shows buf.Bytes() and does not print err at all, so the - // prefix here does not make most output any more verbose. - if err != nil { - err = errors.New(cmdline[0] + ": " + err.Error()) - } - return buf.Bytes(), err - } -} - -// joinUnambiguously prints the slice, quoting where necessary to make the -// output unambiguous. -// TODO: See issue 5279. The printing of commands needs a complete redo. -func joinUnambiguously(a []string) string { - var buf bytes.Buffer - for i, s := range a { - if i > 0 { - buf.WriteByte(' ') - } - q := strconv.Quote(s) - if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 { - buf.WriteString(q) - } else { - buf.WriteString(s) - } - } - return buf.String() -} - -// mkdir makes the named directory. -func (b *Builder) Mkdir(dir string) error { - b.exec.Lock() - defer b.exec.Unlock() - // We can be a little aggressive about being - // sure directories exist. Skip repeated calls. - if b.mkdirCache[dir] { - return nil - } - b.mkdirCache[dir] = true - - if cfg.BuildN || cfg.BuildX { - b.Showcmd("", "mkdir -p %s", dir) - if cfg.BuildN { - return nil - } - } - - if err := os.MkdirAll(dir, 0777); err != nil { - return err - } - return nil -} - -// mkAbs returns an absolute path corresponding to -// evaluating f in the directory dir. -// We always pass absolute paths of source files so that -// the error messages will include the full path to a file -// in need of attention. -func mkAbs(dir, f string) string { - // Leave absolute paths alone. - // Also, during -n mode we use the pseudo-directory $WORK - // instead of creating an actual work directory that won't be used. - // Leave paths beginning with $WORK alone too. - if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") { - return f - } - return filepath.Join(dir, f) -} - -type toolchain interface { - // gc runs the compiler in a specific directory on a set of files - // and returns the name of the generated output file. - gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) - // cc runs the toolchain's C compiler in a directory on a C file - // to produce an output file. - cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error - // asm runs the assembler in a specific directory on specific files - // and returns a list of named output files. - asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) - // pkgpath builds an appropriate path for a temporary package file. - Pkgpath(basedir string, p *load.Package) string - // pack runs the archive packer in a specific directory to create - // an archive from a set of object files. - // typically it is run in the object directory. - pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error - // ld runs the linker to create an executable starting at mainpkg. - ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error - // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions - ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error - - compiler() string - linker() string -} - -type noToolchain struct{} - -func noCompiler() error { - log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler) - return nil -} - -func (noToolchain) compiler() string { - noCompiler() - return "" -} - -func (noToolchain) linker() string { - noCompiler() - return "" -} - -func (noToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { - return "", nil, noCompiler() -} - -func (noToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { - return nil, noCompiler() -} - -func (noToolchain) Pkgpath(basedir string, p *load.Package) string { - noCompiler() - return "" -} - -func (noToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { - return noCompiler() -} - -func (noToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { - return noCompiler() -} - -func (noToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { - return noCompiler() -} - -func (noToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { - return noCompiler() -} - -// The Go toolchain. -type gcToolchain struct{} - -func (gcToolchain) compiler() string { - return base.Tool("compile") -} - -func (gcToolchain) linker() string { - return base.Tool("link") -} - -func (gcToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - if archive != "" { - ofile = archive - } else { - out := "_go_.o" - ofile = obj + out - } - - gcargs := []string{"-p", p.ImportPath} - if p.Name == "main" { - gcargs[1] = "main" - } - if p.Standard { - gcargs = append(gcargs, "-std") - } - compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) - if compilingRuntime { - // runtime compiles with a special gc flag to emit - // additional reflect type data. - gcargs = append(gcargs, "-+") - } - - // If we're giving the compiler the entire package (no C etc files), tell it that, - // so that it can give good error messages about forward declarations. - // Exceptions: a few standard packages have forward declarations for - // pieces supplied behind-the-scenes by package runtime. - extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) - if p.Standard { - switch p.ImportPath { - case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "syscall", "time": - extFiles++ - } - } - if extFiles == 0 { - gcargs = append(gcargs, "-complete") - } - if cfg.BuildContext.InstallSuffix != "" { - gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix) - } - if p.Internal.BuildID != "" { - gcargs = append(gcargs, "-buildid", p.Internal.BuildID) - } - platform := cfg.Goos + "/" + cfg.Goarch - if p.Internal.OmitDebug || platform == "nacl/amd64p32" || platform == "darwin/arm" || platform == "darwin/arm64" || cfg.Goos == "plan9" { - gcargs = append(gcargs, "-dwarf=false") - } - - for _, path := range p.Imports { - if i := strings.LastIndex(path, "/vendor/"); i >= 0 { - gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path) - } else if strings.HasPrefix(path, "vendor/") { - gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path) - } - } - - gcflags := buildGcflags - if compilingRuntime { - // Remove -N, if present. - // It is not possible to build the runtime with no optimizations, - // because the compiler cannot eliminate enough write barriers. - gcflags = make([]string, len(buildGcflags)) - copy(gcflags, buildGcflags) - for i := 0; i < len(gcflags); i++ { - if gcflags[i] == "-N" { - copy(gcflags[i:], gcflags[i+1:]) - gcflags = gcflags[:len(gcflags)-1] - i-- - } - } - } - args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.WorkDir, gcflags, gcargs, "-D", p.Internal.LocalPrefix, importArgs} - if ofile == archive { - args = append(args, "-pack") - } - if asmhdr { - args = append(args, "-asmhdr", obj+"go_asm.h") - } - - // Add -c=N to use concurrent backend compilation, if possible. - if c := gcBackendConcurrency(gcflags); c > 1 { - args = append(args, fmt.Sprintf("-c=%d", c)) - } - - for _, f := range gofiles { - args = append(args, mkAbs(p.Dir, f)) - } - - output, err = b.runOut(p.Dir, p.ImportPath, nil, args...) - return ofile, output, err -} - -// gcBackendConcurrency returns the backend compiler concurrency level for a package compilation. -func gcBackendConcurrency(gcflags []string) int { - // First, check whether we can use -c at all for this compilation. - canDashC := concurrentGCBackendCompilationEnabledByDefault - - switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e { - case "0": - canDashC = false - case "1": - canDashC = true - case "": - // Not set. Use default. - default: - log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e) - } - - if os.Getenv("GOEXPERIMENT") != "" { - // Concurrent compilation is presumed incompatible with GOEXPERIMENTs. - canDashC = false - } - -CheckFlags: - for _, flag := range gcflags { - // Concurrent compilation is presumed incompatible with any gcflags, - // except for a small whitelist of commonly used flags. - // If the user knows better, they can manually add their own -c to the gcflags. - switch flag { - case "-N", "-l", "-S", "-B", "-C", "-I": - // OK - default: - canDashC = false - break CheckFlags - } - } - - if !canDashC { - return 1 - } - - // Decide how many concurrent backend compilations to allow. - // - // If we allow too many, in theory we might end up with p concurrent processes, - // each with c concurrent backend compiles, all fighting over the same resources. - // However, in practice, that seems not to happen too much. - // Most build graphs are surprisingly serial, so p==1 for much of the build. - // Furthermore, concurrent backend compilation is only enabled for a part - // of the overall compiler execution, so c==1 for much of the build. - // So don't worry too much about that interaction for now. - // - // However, in practice, setting c above 4 tends not to help very much. - // See the analysis in CL 41192. - // - // TODO(josharian): attempt to detect whether this particular compilation - // is likely to be a bottleneck, e.g. when: - // - it has no successor packages to compile (usually package main) - // - all paths through the build graph pass through it - // - critical path scheduling says it is high priority - // and in such a case, set c to runtime.NumCPU. - // We do this now when p==1. - if cfg.BuildP == 1 { - // No process parallelism. Max out c. - return runtime.NumCPU() - } - // Some process parallelism. Set c to min(4, numcpu). - c := 4 - if ncpu := runtime.NumCPU(); ncpu < c { - c = ncpu - } - return c -} - -func (gcToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { - // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. - inc := filepath.Join(cfg.GOROOT, "pkg", "include") - args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.WorkDir, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags} - if p.ImportPath == "runtime" && cfg.Goarch == "386" { - for _, arg := range buildAsmflags { - if arg == "-dynlink" { - args = append(args, "-D=GOBUILDMODE_shared=1") - } - } - } - var ofiles []string - for _, sfile := range sfiles { - ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" - ofiles = append(ofiles, ofile) - a := append(args, "-o", ofile, mkAbs(p.Dir, sfile)) - if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil { - return nil, err - } - } - return ofiles, nil -} - -// toolVerify checks that the command line args writes the same output file -// if run using newTool instead. -// Unused now but kept around for future use. -func toolVerify(b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error { - newArgs := make([]interface{}, len(args)) - copy(newArgs, args) - newArgs[1] = base.Tool(newTool) - newArgs[3] = ofile + ".new" // x.6 becomes x.6.new - if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil { - return err - } - data1, err := ioutil.ReadFile(ofile) - if err != nil { - return err - } - data2, err := ioutil.ReadFile(ofile + ".new") - if err != nil { - return err - } - if !bytes.Equal(data1, data2) { - return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " ")) - } - os.Remove(ofile + ".new") - return nil -} - -func (gcToolchain) Pkgpath(basedir string, p *load.Package) string { - end := filepath.FromSlash(p.ImportPath + ".a") - return filepath.Join(basedir, end) -} - -func (gcToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { - var absOfiles []string - for _, f := range ofiles { - absOfiles = append(absOfiles, mkAbs(objDir, f)) - } - absAfile := mkAbs(objDir, afile) - - // The archive file should have been created by the compiler. - // Since it used to not work that way, verify. - if !cfg.BuildN { - if _, err := os.Stat(absAfile); err != nil { - base.Fatalf("os.Stat of archive file failed: %v", err) - } - } - - if cfg.BuildN || cfg.BuildX { - cmdline := str.StringList("pack", "r", absAfile, absOfiles) - b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) - } - if cfg.BuildN { - return nil - } - if err := packInternal(b, absAfile, absOfiles); err != nil { - b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n") - return errPrintedOutput - } - return nil -} - -func packInternal(b *Builder, afile string, ofiles []string) error { - dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0) - if err != nil { - return err - } - defer dst.Close() // only for error returns or panics - w := bufio.NewWriter(dst) - - for _, ofile := range ofiles { - src, err := os.Open(ofile) - if err != nil { - return err - } - fi, err := src.Stat() - if err != nil { - src.Close() - return err - } - // Note: Not using %-16.16s format because we care - // about bytes, not runes. - name := fi.Name() - if len(name) > 16 { - name = name[:16] - } else { - name += strings.Repeat(" ", 16-len(name)) - } - size := fi.Size() - fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n", - name, 0, 0, 0, 0644, size) - n, err := io.Copy(w, src) - src.Close() - if err == nil && n < size { - err = io.ErrUnexpectedEOF - } else if err == nil && n > size { - err = fmt.Errorf("file larger than size reported by stat") - } - if err != nil { - return fmt.Errorf("copying %s to %s: %v", ofile, afile, err) - } - if size&1 != 0 { - w.WriteByte(0) - } - } - - if err := w.Flush(); err != nil { - return err - } - return dst.Close() -} - -// setextld sets the appropriate linker flags for the specified compiler. -func setextld(ldflags []string, compiler []string) []string { - for _, f := range ldflags { - if f == "-extld" || strings.HasPrefix(f, "-extld=") { - // don't override -extld if supplied - return ldflags - } - } - ldflags = append(ldflags, "-extld="+compiler[0]) - if len(compiler) > 1 { - extldflags := false - add := strings.Join(compiler[1:], " ") - for i, f := range ldflags { - if f == "-extldflags" && i+1 < len(ldflags) { - ldflags[i+1] = add + " " + ldflags[i+1] - extldflags = true - break - } else if strings.HasPrefix(f, "-extldflags=") { - ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] - extldflags = true - break - } - } - if !extldflags { - ldflags = append(ldflags, "-extldflags="+add) - } - } - return ldflags -} - -func (gcToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { - importArgs := b.includeArgs("-L", allactions) - cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 - for _, a := range allactions { - if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { - cxx = true - } - } - var ldflags []string - if cfg.BuildContext.InstallSuffix != "" { - ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix) - } - if root.Package.Internal.OmitDebug { - ldflags = append(ldflags, "-s", "-w") - } - if cfg.BuildBuildmode == "plugin" { - pluginpath := root.Package.ImportPath - if pluginpath == "command-line-arguments" { - pluginpath = "plugin/unnamed-" + root.Package.Internal.BuildID - } - ldflags = append(ldflags, "-pluginpath", pluginpath) - } - - // If the user has not specified the -extld option, then specify the - // appropriate linker. In case of C++ code, use the compiler named - // by the CXX environment variable or defaultCXX if CXX is not set. - // Else, use the CC environment variable and defaultCC as fallback. - var compiler []string - if cxx { - compiler = envList("CXX", cfg.DefaultCXX) - } else { - compiler = envList("CC", cfg.DefaultCC) - } - ldflags = setextld(ldflags, compiler) - ldflags = append(ldflags, "-buildmode="+ldBuildmode) - if root.Package.Internal.BuildID != "" { - ldflags = append(ldflags, "-buildid="+root.Package.Internal.BuildID) - } - ldflags = append(ldflags, cfg.BuildLdflags...) - - // On OS X when using external linking to build a shared library, - // the argument passed here to -o ends up recorded in the final - // shared library in the LC_ID_DYLIB load command. - // To avoid putting the temporary output directory name there - // (and making the resulting shared library useless), - // run the link in the output directory so that -o can name - // just the final path element. - dir := "." - if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" { - dir, out = filepath.Split(out) - } - - return b.run(dir, root.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags, mainpkg) -} - -func (gcToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { - importArgs := b.includeArgs("-L", allactions) - ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix} - ldflags = append(ldflags, "-buildmode=shared") - ldflags = append(ldflags, cfg.BuildLdflags...) - cxx := false - for _, a := range allactions { - if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { - cxx = true - } - } - // If the user has not specified the -extld option, then specify the - // appropriate linker. In case of C++ code, use the compiler named - // by the CXX environment variable or defaultCXX if CXX is not set. - // Else, use the CC environment variable and defaultCC as fallback. - var compiler []string - if cxx { - compiler = envList("CXX", cfg.DefaultCXX) - } else { - compiler = envList("CC", cfg.DefaultCC) - } - ldflags = setextld(ldflags, compiler) - for _, d := range toplevelactions { - if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries - continue - } - ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target) - } - return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags) -} - -func (gcToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { - return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile)) -} - -// The Gccgo toolchain. -type gccgoToolchain struct{} - -var GccgoName, GccgoBin string -var gccgoErr error - -func init() { - GccgoName = os.Getenv("GCCGO") - if GccgoName == "" { - GccgoName = cfg.DefaultGCCGO - } - GccgoBin, gccgoErr = exec.LookPath(GccgoName) -} - -func (gccgoToolchain) compiler() string { - checkGccgoBin() - return GccgoBin -} - -func (gccgoToolchain) linker() string { - checkGccgoBin() - return GccgoBin -} - -func checkGccgoBin() { - if gccgoErr == nil { - return - } - fmt.Fprintf(os.Stderr, "cmd/go: gccgo: %s\n", gccgoErr) - os.Exit(2) -} - -func (tools gccgoToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - out := "_go_.o" - ofile = obj + out - gcargs := []string{"-g"} - gcargs = append(gcargs, b.gccArchArgs()...) - gcargs = append(gcargs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") - gcargs = append(gcargs, "-gno-record-gcc-switches") - if pkgpath := gccgoPkgpath(p); pkgpath != "" { - gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath) - } - if p.Internal.LocalPrefix != "" { - gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix) - } - - // Handle vendor directories - savedirs := []string{} - for _, incdir := range importArgs { - if incdir != "-I" { - savedirs = append(savedirs, incdir) - } - } - - for _, path := range p.Imports { - // If this is a new vendor path, add it to the list of importArgs - if i := strings.LastIndex(path, "/vendor/"); i >= 0 { - for _, dir := range savedirs { - // Check if the vendor path is already included in dir - if strings.HasSuffix(dir, path[:i+len("/vendor")]) { - continue - } - // Make sure this vendor path is not already in the list for importArgs - vendorPath := dir + "/" + path[:i+len("/vendor/")] - for _, imp := range importArgs { - if imp == "-I" { - continue - } - // This vendorPath is already in the list - if imp == vendorPath { - goto nextSuffixPath - } - } - // New vendorPath not yet in the importArgs list, so add it - importArgs = append(importArgs, "-I", vendorPath) - nextSuffixPath: - } - } else if strings.HasPrefix(path, "vendor/") { - for _, dir := range savedirs { - // Make sure this vendor path is not already in the list for importArgs - vendorPath := dir + "/" + path[len("/vendor"):] - for _, imp := range importArgs { - if imp == "-I" { - continue - } - if imp == vendorPath { - goto nextPrefixPath - } - } - // This vendor path is needed and not already in the list, so add it - importArgs = append(importArgs, "-I", vendorPath) - nextPrefixPath: - } - } - } - - args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) - for _, f := range gofiles { - args = append(args, mkAbs(p.Dir, f)) - } - - output, err = b.runOut(p.Dir, p.ImportPath, nil, args) - return ofile, output, err -} - -func (tools gccgoToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { - var ofiles []string - for _, sfile := range sfiles { - ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" - ofiles = append(ofiles, ofile) - sfile = mkAbs(p.Dir, sfile) - defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} - if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { - defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath) - } - defs = tools.maybePIC(defs) - defs = append(defs, b.gccArchArgs()...) - err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile) - if err != nil { - return nil, err - } - } - return ofiles, nil -} - -func (gccgoToolchain) Pkgpath(basedir string, p *load.Package) string { - end := filepath.FromSlash(p.ImportPath + ".a") - afile := filepath.Join(basedir, end) - // add "lib" to the final element - return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile)) -} - -func (gccgoToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { - var absOfiles []string - for _, f := range ofiles { - absOfiles = append(absOfiles, mkAbs(objDir, f)) - } - absAfile := mkAbs(objDir, afile) - // Try with D modifier first, then without if that fails. - if b.run(p.Dir, p.ImportPath, nil, "ar", "rcD", absAfile, absOfiles) != nil { - if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { - // AIX puts both 32-bit and 64-bit objects in the same archive. - // Tell the AIX "ar" command to only care about 64-bit objects. - // AIX "ar" command does not know D option. - return b.run(p.Dir, p.ImportPath, nil, "ar", "-X64", "rc", absAfile, absOfiles) - } else { - return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", absAfile, absOfiles) - } - } - return nil -} - -func (tools gccgoToolchain) link(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string, buildmode, desc string) error { - // gccgo needs explicit linking with all package dependencies, - // and all LDFLAGS from cgo dependencies. - apackagePathsSeen := make(map[string]bool) - afiles := []string{} - shlibs := []string{} - ldflags := b.gccArchArgs() - cgoldflags := []string{} - usesCgo := false - cxx := false - objc := false - fortran := false - if root.Package != nil { - cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 - objc = len(root.Package.MFiles) > 0 - fortran = len(root.Package.FFiles) > 0 - } - - readCgoFlags := func(flagsFile string) error { - flags, err := ioutil.ReadFile(flagsFile) - if err != nil { - return err - } - const ldflagsPrefix = "_CGO_LDFLAGS=" - for _, line := range strings.Split(string(flags), "\n") { - if strings.HasPrefix(line, ldflagsPrefix) { - line = line[len(ldflagsPrefix):] - quote := byte(0) - start := true - var nl []byte - for len(line) > 0 { - b := line[0] - line = line[1:] - if quote == 0 && (b == ' ' || b == '\t') { - if len(nl) > 0 { - cgoldflags = append(cgoldflags, string(nl)) - nl = nil - } - start = true - continue - } else if b == '"' || b == '\'' { - quote = b - } else if b == quote { - quote = 0 - } else if quote == 0 && start && b == '-' && strings.HasPrefix(line, "g") { - line = line[1:] - continue - } else if quote == 0 && start && b == '-' && strings.HasPrefix(line, "O") { - for len(line) > 0 && line[0] != ' ' && line[0] != '\t' { - line = line[1:] - } - continue - } - nl = append(nl, b) - start = false - } - } - } - return nil - } - - readAndRemoveCgoFlags := func(archive string) (string, error) { - newa, err := ioutil.TempFile(b.WorkDir, filepath.Base(archive)) - if err != nil { - return "", err - } - olda, err := os.Open(archive) - if err != nil { - return "", err - } - _, err = io.Copy(newa, olda) - if err != nil { - return "", err - } - err = olda.Close() - if err != nil { - return "", err - } - err = newa.Close() - if err != nil { - return "", err - } - - newarchive := newa.Name() - err = b.run(b.WorkDir, desc, nil, "ar", "x", newarchive, "_cgo_flags") - if err != nil { - return "", err - } - err = b.run(".", desc, nil, "ar", "d", newarchive, "_cgo_flags") - if err != nil { - return "", err - } - err = readCgoFlags(filepath.Join(b.WorkDir, "_cgo_flags")) - if err != nil { - return "", err - } - return newarchive, nil - } - - actionsSeen := make(map[*Action]bool) - // Make a pre-order depth-first traversal of the action graph, taking note of - // whether a shared library action has been seen on the way to an action (the - // construction of the graph means that if any path to a node passes through - // a shared library action, they all do). - var walk func(a *Action, seenShlib bool) - var err error - walk = func(a *Action, seenShlib bool) { - if actionsSeen[a] { - return - } - actionsSeen[a] = true - if a.Package != nil && !seenShlib { - if a.Package.Standard { - return - } - // We record the target of the first time we see a .a file - // for a package to make sure that we prefer the 'install' - // rather than the 'build' location (which may not exist any - // more). We still need to traverse the dependencies of the - // build action though so saying - // if apackagePathsSeen[a.Package.ImportPath] { return } - // doesn't work. - if !apackagePathsSeen[a.Package.ImportPath] { - apackagePathsSeen[a.Package.ImportPath] = true - target := a.Target - if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() { - target, err = readAndRemoveCgoFlags(target) - if err != nil { - return - } - } - afiles = append(afiles, target) - } - } - if strings.HasSuffix(a.Target, ".so") { - shlibs = append(shlibs, a.Target) - seenShlib = true - } - for _, a1 := range a.Deps { - walk(a1, seenShlib) - if err != nil { - return - } - } - } - for _, a1 := range root.Deps { - walk(a1, false) - if err != nil { - return err - } - } - - for _, a := range allactions { - // Gather CgoLDFLAGS, but not from standard packages. - // The go tool can dig up runtime/cgo from GOROOT and - // think that it should use its CgoLDFLAGS, but gccgo - // doesn't use runtime/cgo. - if a.Package == nil { - continue - } - if !a.Package.Standard { - cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...) - } - if len(a.Package.CgoFiles) > 0 { - usesCgo = true - } - if a.Package.UsesSwig() { - usesCgo = true - } - if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 { - cxx = true - } - if len(a.Package.MFiles) > 0 { - objc = true - } - if len(a.Package.FFiles) > 0 { - fortran = true - } - } - - for i, o := range ofiles { - if filepath.Base(o) == "_cgo_flags" { - readCgoFlags(o) - ofiles = append(ofiles[:i], ofiles[i+1:]...) - break - } - } - - ldflags = append(ldflags, "-Wl,--whole-archive") - ldflags = append(ldflags, afiles...) - ldflags = append(ldflags, "-Wl,--no-whole-archive") - - ldflags = append(ldflags, cgoldflags...) - ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) - if root.Package != nil { - ldflags = append(ldflags, root.Package.CgoLDFLAGS...) - } - - ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)") - - for _, shlib := range shlibs { - ldflags = append( - ldflags, - "-L"+filepath.Dir(shlib), - "-Wl,-rpath="+filepath.Dir(shlib), - "-l"+strings.TrimSuffix( - strings.TrimPrefix(filepath.Base(shlib), "lib"), - ".so")) - } - - var realOut string - switch buildmode { - case "exe": - if usesCgo && cfg.Goos == "linux" { - ldflags = append(ldflags, "-Wl,-E") - } - - case "c-archive": - // Link the Go files into a single .o, and also link - // in -lgolibbegin. - // - // We need to use --whole-archive with -lgolibbegin - // because it doesn't define any symbols that will - // cause the contents to be pulled in; it's just - // initialization code. - // - // The user remains responsible for linking against - // -lgo -lpthread -lm in the final link. We can't use - // -r to pick them up because we can't combine - // split-stack and non-split-stack code in a single -r - // link, and libgo picks up non-split-stack code from - // libffi. - ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive") - - if nopie := b.gccNoPie(); nopie != "" { - ldflags = append(ldflags, nopie) - } - - // We are creating an object file, so we don't want a build ID. - ldflags = b.disableBuildID(ldflags) - - realOut = out - out = out + ".o" - - case "c-shared": - ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc") - case "shared": - ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") - case "pie": - ldflags = append(ldflags, "-pie") - - default: - base.Fatalf("-buildmode=%s not supported for gccgo", buildmode) - } - - switch buildmode { - case "exe", "c-shared": - if cxx { - ldflags = append(ldflags, "-lstdc++") - } - if objc { - ldflags = append(ldflags, "-lobjc") - } - if fortran { - fc := os.Getenv("FC") - if fc == "" { - fc = "gfortran" - } - // support gfortran out of the box and let others pass the correct link options - // via CGO_LDFLAGS - if strings.Contains(fc, "gfortran") { - ldflags = append(ldflags, "-lgfortran") - } - } - } - - if err := b.run(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil { - return err - } - - switch buildmode { - case "c-archive": - if err := b.run(".", desc, nil, "ar", "rc", realOut, out); err != nil { - return err - } - } - return nil -} - -func (tools gccgoToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { - return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.Package.ImportPath) -} - -func (tools gccgoToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { - fakeRoot := &Action{} - fakeRoot.Deps = toplevelactions - return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out) -} - -func (tools gccgoToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { - inc := filepath.Join(cfg.GOROOT, "pkg", "include") - cfile = mkAbs(p.Dir, cfile) - defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} - defs = append(defs, b.gccArchArgs()...) - if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { - defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) - } - if b.gccSupportsFlag("-fsplit-stack") { - defs = append(defs, "-fsplit-stack") - } - defs = tools.maybePIC(defs) - if b.gccSupportsFlag("-fdebug-prefix-map=a=b") { - defs = append(defs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") - } - if b.gccSupportsFlag("-gno-record-gcc-switches") { - defs = append(defs, "-gno-record-gcc-switches") - } - return b.run(p.Dir, p.ImportPath, nil, envList("CC", cfg.DefaultCC), "-Wall", "-g", - "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) -} - -// maybePIC adds -fPIC to the list of arguments if needed. -func (tools gccgoToolchain) maybePIC(args []string) []string { - switch cfg.BuildBuildmode { - case "c-archive", "c-shared", "shared", "plugin": - args = append(args, "-fPIC") - } - return args -} - -func gccgoPkgpath(p *load.Package) string { - if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary { - return "" - } - return p.ImportPath -} - -func gccgoCleanPkgpath(p *load.Package) string { - clean := func(r rune) rune { - switch { - case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', - '0' <= r && r <= '9': - return r - } - return '_' - } - return strings.Map(clean, gccgoPkgpath(p)) -} - -// gcc runs the gcc C compiler to create an object from a single C file. -func (b *Builder) gcc(p *load.Package, out string, flags []string, cfile string) error { - return b.ccompile(p, out, flags, cfile, b.GccCmd(p.Dir)) -} - -// gxx runs the g++ C++ compiler to create an object from a single C++ file. -func (b *Builder) gxx(p *load.Package, out string, flags []string, cxxfile string) error { - return b.ccompile(p, out, flags, cxxfile, b.GxxCmd(p.Dir)) -} - -// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. -func (b *Builder) gfortran(p *load.Package, out string, flags []string, ffile string) error { - return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir)) -} - -// ccompile runs the given C or C++ compiler and creates an object from a single source file. -func (b *Builder) ccompile(p *load.Package, outfile string, flags []string, file string, compiler []string) error { - file = mkAbs(p.Dir, file) - desc := p.ImportPath - if !filepath.IsAbs(outfile) { - outfile = filepath.Join(p.Dir, outfile) - } - output, err := b.runOut(filepath.Dir(file), desc, nil, compiler, flags, "-o", outfile, "-c", filepath.Base(file)) - if len(output) > 0 { - // On FreeBSD 11, when we pass -g to clang 3.8 it - // invokes its internal assembler with -dwarf-version=2. - // When it sees .section .note.GNU-stack, it warns - // "DWARF2 only supports one section per compilation unit". - // This warning makes no sense, since the section is empty, - // but it confuses people. - // We work around the problem by detecting the warning - // and dropping -g and trying again. - if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) { - newFlags := make([]string, 0, len(flags)) - for _, f := range flags { - if !strings.HasPrefix(f, "-g") { - newFlags = append(newFlags, f) - } - } - if len(newFlags) < len(flags) { - return b.ccompile(p, outfile, newFlags, file, compiler) - } - } - - b.showOutput(p.Dir, desc, b.processOutput(output)) - if err != nil { - err = errPrintedOutput - } else if os.Getenv("GO_BUILDER_NAME") != "" { - return errors.New("C compiler warning promoted to error on Go builders") - } - } - return err -} - -// gccld runs the gcc linker to create an executable from a set of object files. -func (b *Builder) gccld(p *load.Package, out string, flags []string, obj []string) error { - var cmd []string - if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { - cmd = b.GxxCmd(p.Dir) - } else { - cmd = b.GccCmd(p.Dir) - } - return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags) -} - -// gccCmd returns a gcc command line prefix -// defaultCC is defined in zdefaultcc.go, written by cmd/dist. -func (b *Builder) GccCmd(objdir string) []string { - return b.ccompilerCmd("CC", cfg.DefaultCC, objdir) -} - -// gxxCmd returns a g++ command line prefix -// defaultCXX is defined in zdefaultcc.go, written by cmd/dist. -func (b *Builder) GxxCmd(objdir string) []string { - return b.ccompilerCmd("CXX", cfg.DefaultCXX, objdir) -} - -// gfortranCmd returns a gfortran command line prefix. -func (b *Builder) gfortranCmd(objdir string) []string { - return b.ccompilerCmd("FC", "gfortran", objdir) -} - -// ccompilerCmd returns a command line prefix for the given environment -// variable and using the default command when the variable is empty. -func (b *Builder) ccompilerCmd(envvar, defcmd, objdir string) []string { - // NOTE: env.go's mkEnv knows that the first three - // strings returned are "gcc", "-I", objdir (and cuts them off). - - compiler := envList(envvar, defcmd) - a := []string{compiler[0], "-I", objdir} - a = append(a, compiler[1:]...) - - // Definitely want -fPIC but on Windows gcc complains - // "-fPIC ignored for target (all code is position independent)" - if cfg.Goos != "windows" { - a = append(a, "-fPIC") - } - a = append(a, b.gccArchArgs()...) - // gcc-4.5 and beyond require explicit "-pthread" flag - // for multithreading with pthread library. - if cfg.BuildContext.CgoEnabled { - switch cfg.Goos { - case "windows": - a = append(a, "-mthreads") - default: - a = append(a, "-pthread") - } - } - - if strings.Contains(a[0], "clang") { - // disable ASCII art in clang errors, if possible - a = append(a, "-fno-caret-diagnostics") - // clang is too smart about command-line arguments - a = append(a, "-Qunused-arguments") - } - - // disable word wrapping in error messages - a = append(a, "-fmessage-length=0") - - // Tell gcc not to include the work directory in object files. - if b.gccSupportsFlag("-fdebug-prefix-map=a=b") { - a = append(a, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") - } - - // Tell gcc not to include flags in object files, which defeats the - // point of -fdebug-prefix-map above. - if b.gccSupportsFlag("-gno-record-gcc-switches") { - a = append(a, "-gno-record-gcc-switches") - } - - // On OS X, some of the compilers behave as if -fno-common - // is always set, and the Mach-O linker in 6l/8l assumes this. - // See https://golang.org/issue/3253. - if cfg.Goos == "darwin" { - a = append(a, "-fno-common") - } - - // gccgo uses the language-independent exception mechanism to - // handle panics, so it always needs unwind tables. - if cfg.BuildToolchainName == "gccgo" { - a = append(a, "-funwind-tables") - } - - return a -} - -// gccNoPie returns the flag to use to request non-PIE. On systems -// with PIE (position independent executables) enabled by default, -// -no-pie must be passed when doing a partial link with -Wl,-r. -// But -no-pie is not supported by all compilers, and clang spells it -nopie. -func (b *Builder) gccNoPie() string { - if b.gccSupportsFlag("-no-pie") { - return "-no-pie" - } - if b.gccSupportsFlag("-nopie") { - return "-nopie" - } - return "" -} - -// gccSupportsFlag checks to see if the compiler supports a flag. -func (b *Builder) gccSupportsFlag(flag string) bool { - b.exec.Lock() - defer b.exec.Unlock() - if b, ok := b.flagCache[flag]; ok { - return b - } - if b.flagCache == nil { - src := filepath.Join(b.WorkDir, "trivial.c") - if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { - return false - } - b.flagCache = make(map[string]bool) - } - cmdArgs := append(envList("CC", cfg.DefaultCC), flag, "-c", "trivial.c") - if cfg.BuildN || cfg.BuildX { - b.Showcmd(b.WorkDir, "%s", joinUnambiguously(cmdArgs)) - if cfg.BuildN { - return false - } - } - cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) - cmd.Dir = b.WorkDir - cmd.Env = base.MergeEnvLists([]string{"LC_ALL=C"}, base.EnvForDir(cmd.Dir, os.Environ())) - out, err := cmd.CombinedOutput() - supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) - b.flagCache[flag] = supported - return supported -} - -// gccArchArgs returns arguments to pass to gcc based on the architecture. -func (b *Builder) gccArchArgs() []string { - switch cfg.Goarch { - case "386": - return []string{"-m32"} - case "amd64", "amd64p32": - return []string{"-m64"} - case "arm": - return []string{"-marm"} // not thumb - case "s390x": - return []string{"-m64", "-march=z196"} - case "mips64", "mips64le": - return []string{"-mabi=64"} - case "mips", "mipsle": - return []string{"-mabi=32", "-march=mips32"} - case "ppc64": - if cfg.Goos == "aix" { - return []string{"-maix64"} - } - } - return nil -} - -// envList returns the value of the given environment variable broken -// into fields, using the default value when the variable is empty. -func envList(key, def string) []string { - v := os.Getenv(key) - if v == "" { - v = def - } - return strings.Fields(v) -} - -// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. -func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { - defaults := "-g -O2" - - cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) - cflags = str.StringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) - cxxflags = str.StringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) - fflags = str.StringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS) - ldflags = str.StringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) - return -} - -var cgoRe = regexp.MustCompile(`[/\\:]`) - -func (b *Builder) cgo(a *Action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { - p := a.Package - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.CFlags(p) - cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) - cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) - // If we are compiling Objective-C code, then we need to link against libobjc - if len(mfiles) > 0 { - cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") - } - - // Likewise for Fortran, except there are many Fortran compilers. - // Support gfortran out of the box and let others pass the correct link options - // via CGO_LDFLAGS - if len(ffiles) > 0 { - fc := os.Getenv("FC") - if fc == "" { - fc = "gfortran" - } - if strings.Contains(fc, "gfortran") { - cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran") - } - } - - if cfg.BuildMSan { - cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) - cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) - } - - // Allows including _cgo_export.h from .[ch] files in the package. - cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) - - // If we have cgo files in the object directory, then copy any - // other cgo files into the object directory, and pass a - // -srcdir option to cgo. - var srcdirarg []string - if len(objdirCgofiles) > 0 { - for _, fn := range cgofiles { - if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil { - return nil, nil, err - } - } - cgofiles = append(cgofiles, objdirCgofiles...) - srcdirarg = []string{"-srcdir", obj} - } - - // cgo - // TODO: CGO_FLAGS? - gofiles := []string{obj + "_cgo_gotypes.go"} - cfiles := []string{"_cgo_export.c"} - for _, fn := range cgofiles { - f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_") - gofiles = append(gofiles, obj+f+"cgo1.go") - cfiles = append(cfiles, f+"cgo2.c") - } - - // TODO: make cgo not depend on $GOARCH? - - cgoflags := []string{} - if p.Standard && p.ImportPath == "runtime/cgo" { - cgoflags = append(cgoflags, "-import_runtime_cgo=false") - } - if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") { - cgoflags = append(cgoflags, "-import_syscall=false") - } - - // Update $CGO_LDFLAGS with p.CgoLDFLAGS. - var cgoenv []string - if len(cgoLDFLAGS) > 0 { - flags := make([]string, len(cgoLDFLAGS)) - for i, f := range cgoLDFLAGS { - flags[i] = strconv.Quote(f) - } - cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")} - } - - if cfg.BuildToolchainName == "gccgo" { - if b.gccSupportsFlag("-fsplit-stack") { - cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") - } - cgoflags = append(cgoflags, "-gccgo") - if pkgpath := gccgoPkgpath(p); pkgpath != "" { - cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath) - } - } - - switch cfg.BuildBuildmode { - case "c-archive", "c-shared": - // Tell cgo that if there are any exported functions - // it should generate a header file that C code can - // #include. - cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h") - } - - if err := b.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil { - return nil, nil, err - } - outGo = append(outGo, gofiles...) - - // gcc - cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS) - for _, cfile := range cfiles { - ofile := obj + cfile[:len(cfile)-1] + "o" - if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - for _, file := range gccfiles { - base := filepath.Base(file) - ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o" - if err := b.gcc(p, ofile, cflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS) - for _, file := range gxxfiles { - // Append .o to the file, just in case the pkg has file.c and file.cpp - ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" - if err := b.gxx(p, ofile, cxxflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - for _, file := range mfiles { - // Append .o to the file, just in case the pkg has file.c and file.m - ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" - if err := b.gcc(p, ofile, cflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS) - for _, file := range ffiles { - // Append .o to the file, just in case the pkg has file.c and file.f - ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o" - if err := b.gfortran(p, ofile, fflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - switch cfg.BuildToolchainName { - case "gc": - importGo := obj + "_cgo_import.go" - if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil { - return nil, nil, err - } - outGo = append(outGo, importGo) - - ofile := obj + "_all.o" - if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil { - return nil, nil, err - } - outObj = []string{ofile} - - case "gccgo": - defunC := obj + "_cgo_defun.c" - defunObj := obj + "_cgo_defun.o" - if err := BuildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { - return nil, nil, err - } - outObj = append(outObj, defunObj) - - default: - noCompiler() - } - - return outGo, outObj, nil -} - -// dynimport creates a Go source file named importGo containing -// //go:cgo_import_dynamic directives for each symbol or library -// dynamically imported by the object files outObj. -func (b *Builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { - cfile := obj + "_cgo_main.c" - ofile := obj + "_cgo_main.o" - if err := b.gcc(p, ofile, cflags, cfile); err != nil { - return err - } - - linkobj := str.StringList(ofile, outObj, p.SysoFiles) - dynobj := obj + "_cgo_.o" - - // we need to use -pie for Linux/ARM to get accurate imported sym - ldflags := cgoLDFLAGS - if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" { - ldflags = append(ldflags, "-pie") - } - if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil { - return err - } - - // cgo -dynimport - var cgoflags []string - if p.Standard && p.ImportPath == "runtime/cgo" { - cgoflags = []string{"-dynlinker"} // record path to dynamic linker - } - return b.run(p.Dir, p.ImportPath, nil, cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) -} - -// collect partially links the object files outObj into a single -// relocatable object file named ofile. -func (b *Builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj []string) error { - // When linking relocatable objects, various flags need to be - // filtered out as they are inapplicable and can cause some linkers - // to fail. - var ldflags []string - for i := 0; i < len(cgoLDFLAGS); i++ { - f := cgoLDFLAGS[i] - switch { - // skip "-lc" or "-l somelib" - case strings.HasPrefix(f, "-l"): - if f == "-l" { - i++ - } - // skip "-framework X" on Darwin - case cfg.Goos == "darwin" && f == "-framework": - i++ - // skip "*.{dylib,so,dll,o,a}" - case strings.HasSuffix(f, ".dylib"), - strings.HasSuffix(f, ".so"), - strings.HasSuffix(f, ".dll"), - strings.HasSuffix(f, ".o"), - strings.HasSuffix(f, ".a"): - // Remove any -fsanitize=foo flags. - // Otherwise the compiler driver thinks that we are doing final link - // and links sanitizer runtime into the object file. But we are not doing - // the final link, we will link the resulting object file again. And - // so the program ends up with two copies of sanitizer runtime. - // See issue 8788 for details. - case strings.HasPrefix(f, "-fsanitize="): - continue - // runpath flags not applicable unless building a shared - // object or executable; see issue 12115 for details. This - // is necessary as Go currently does not offer a way to - // specify the set of LDFLAGS that only apply to shared - // objects. - case strings.HasPrefix(f, "-Wl,-rpath"): - if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" { - // Skip following argument to -rpath* too. - i++ - } - default: - ldflags = append(ldflags, f) - } - } - - ldflags = append(ldflags, "-Wl,-r", "-nostdlib") - - if flag := b.gccNoPie(); flag != "" { - ldflags = append(ldflags, flag) - } - - // We are creating an object file, so we don't want a build ID. - ldflags = b.disableBuildID(ldflags) - - return b.gccld(p, ofile, ldflags, outObj) -} - -// Run SWIG on all SWIG input files. -// TODO: Don't build a shared library, once SWIG emits the necessary -// pragmas for external linking. -func (b *Builder) swig(p *load.Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { - if err := b.swigVersionCheck(); err != nil { - return nil, nil, nil, err - } - - intgosize, err := b.swigIntSize(obj) - if err != nil { - return nil, nil, nil, err - } - - for _, f := range p.SwigFiles { - goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) - if err != nil { - return nil, nil, nil, err - } - if goFile != "" { - outGo = append(outGo, goFile) - } - if cFile != "" { - outC = append(outC, cFile) - } - } - for _, f := range p.SwigCXXFiles { - goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) - if err != nil { - return nil, nil, nil, err - } - if goFile != "" { - outGo = append(outGo, goFile) - } - if cxxFile != "" { - outCXX = append(outCXX, cxxFile) - } - } - return outGo, outC, outCXX, nil -} - -// Make sure SWIG is new enough. -var ( - swigCheckOnce sync.Once - swigCheck error -) - -func (b *Builder) swigDoVersionCheck() error { - out, err := b.runOut("", "", nil, "swig", "-version") - if err != nil { - return err - } - re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) - matches := re.FindSubmatch(out) - if matches == nil { - // Can't find version number; hope for the best. - return nil - } - - major, err := strconv.Atoi(string(matches[1])) - if err != nil { - // Can't find version number; hope for the best. - return nil - } - const errmsg = "must have SWIG version >= 3.0.6" - if major < 3 { - return errors.New(errmsg) - } - if major > 3 { - // 4.0 or later - return nil - } - - // We have SWIG version 3.x. - if len(matches[2]) > 0 { - minor, err := strconv.Atoi(string(matches[2][1:])) - if err != nil { - return nil - } - if minor > 0 { - // 3.1 or later - return nil - } - } - - // We have SWIG version 3.0.x. - if len(matches[3]) > 0 { - patch, err := strconv.Atoi(string(matches[3][1:])) - if err != nil { - return nil - } - if patch < 6 { - // Before 3.0.6. - return errors.New(errmsg) - } - } - - return nil -} - -func (b *Builder) swigVersionCheck() error { - swigCheckOnce.Do(func() { - swigCheck = b.swigDoVersionCheck() - }) - return swigCheck -} - -// Find the value to pass for the -intgosize option to swig. -var ( - swigIntSizeOnce sync.Once - swigIntSize string - swigIntSizeError error -) - -// This code fails to build if sizeof(int) <= 32 -const swigIntSizeCode = ` -package main -const i int = 1 << 32 -` - -// Determine the size of int on the target system for the -intgosize option -// of swig >= 2.0.9. Run only once. -func (b *Builder) swigDoIntSize(obj string) (intsize string, err error) { - if cfg.BuildN { - return "$INTBITS", nil - } - src := filepath.Join(b.WorkDir, "swig_intsize.go") - if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil { - return - } - srcs := []string{src} - - p := load.GoFilesPackage(srcs) - - if _, _, e := BuildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil { - return "32", nil - } - return "64", nil -} - -// Determine the size of int on the target system for the -intgosize option -// of swig >= 2.0.9. -func (b *Builder) swigIntSize(obj string) (intsize string, err error) { - swigIntSizeOnce.Do(func() { - swigIntSize, swigIntSizeError = b.swigDoIntSize(obj) - }) - return swigIntSize, swigIntSizeError -} - -// Run SWIG on one SWIG input file. -func (b *Builder) swigOne(p *load.Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.CFlags(p) - var cflags []string - if cxx { - cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) - } else { - cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) - } - - n := 5 // length of ".swig" - if cxx { - n = 8 // length of ".swigcxx" - } - base := file[:len(file)-n] - goFile := base + ".go" - gccBase := base + "_wrap." - gccExt := "c" - if cxx { - gccExt = "cxx" - } - - gccgo := cfg.BuildToolchainName == "gccgo" - - // swig - args := []string{ - "-go", - "-cgo", - "-intgosize", intgosize, - "-module", base, - "-o", obj + gccBase + gccExt, - "-outdir", obj, - } - - for _, f := range cflags { - if len(f) > 3 && f[:2] == "-I" { - args = append(args, f) - } - } - - if gccgo { - args = append(args, "-gccgo") - if pkgpath := gccgoPkgpath(p); pkgpath != "" { - args = append(args, "-go-pkgpath", pkgpath) - } - } - if cxx { - args = append(args, "-c++") - } - - out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file) - if err != nil { - if len(out) > 0 { - if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) { - return "", "", errors.New("must have SWIG version >= 3.0.6") - } - b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error - return "", "", errPrintedOutput - } - return "", "", err - } - if len(out) > 0 { - b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning - } - - return goFile, obj + gccBase + gccExt, nil -} - -// disableBuildID adjusts a linker command line to avoid creating a -// build ID when creating an object file rather than an executable or -// shared library. Some systems, such as Ubuntu, always add -// --build-id to every link, but we don't want a build ID when we are -// producing an object file. On some of those system a plain -r (not -// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a -// plain -r. I don't know how to turn off --build-id when using clang -// other than passing a trailing --build-id=none. So that is what we -// do, but only on systems likely to support it, which is to say, -// systems that normally use gold or the GNU linker. -func (b *Builder) disableBuildID(ldflags []string) []string { - switch cfg.Goos { - case "android", "dragonfly", "linux", "netbsd": - ldflags = append(ldflags, "-Wl,--build-id=none") - } - return ldflags -} - -// An actionQueue is a priority queue of actions. -type actionQueue []*Action - -// Implement heap.Interface -func (q *actionQueue) Len() int { return len(*q) } -func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } -func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority } -func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*Action)) } -func (q *actionQueue) Pop() interface{} { - n := len(*q) - 1 - x := (*q)[n] - *q = (*q)[:n] - return x -} - -func (q *actionQueue) push(a *Action) { - heap.Push(q, a) -} - -func (q *actionQueue) pop() *Action { - return heap.Pop(q).(*Action) -} - -func InstrumentInit() { - if !cfg.BuildRace && !cfg.BuildMSan { - return - } - if cfg.BuildRace && cfg.BuildMSan { - fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) - os.Exit(2) - } - if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64") { - fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) - os.Exit(2) - } - if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" { - fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) - os.Exit(2) - } - if !cfg.BuildContext.CgoEnabled { - fmt.Fprintf(os.Stderr, "go %s: -race requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0]) - os.Exit(2) - } - if cfg.BuildRace { - buildGcflags = append(buildGcflags, "-race") - cfg.BuildLdflags = append(cfg.BuildLdflags, "-race") - } else { - buildGcflags = append(buildGcflags, "-msan") - cfg.BuildLdflags = append(cfg.BuildLdflags, "-msan") - } - if cfg.BuildContext.InstallSuffix != "" { - cfg.BuildContext.InstallSuffix += "_" - } - - if cfg.BuildRace { - cfg.BuildContext.InstallSuffix += "race" - cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "race") - } else { - cfg.BuildContext.InstallSuffix += "msan" - cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "msan") - } -} - // ExecCmd is the command to use to run user binaries. // Normally it is empty, meaning run the binaries directly. // If cross-compiling and running on a remote system or diff --git a/libgo/go/cmd/go/internal/work/build_test.go b/libgo/go/cmd/go/internal/work/build_test.go index 294b83c6b2a..3f5ba37c641 100644 --- a/libgo/go/cmd/go/internal/work/build_test.go +++ b/libgo/go/cmd/go/internal/work/build_test.go @@ -175,8 +175,13 @@ func pkgImportPath(pkgpath string) *load.Package { // directory. // See https://golang.org/issue/18878. func TestRespectSetgidDir(t *testing.T) { - if runtime.GOOS == "nacl" { + switch runtime.GOOS { + case "nacl": t.Skip("can't set SetGID bit with chmod on nacl") + case "darwin": + if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { + t.Skip("can't set SetGID bit with chmod on iOS") + } } var b Builder diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go new file mode 100644 index 00000000000..878dbeada2c --- /dev/null +++ b/libgo/go/cmd/go/internal/work/buildid.go @@ -0,0 +1,614 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package work + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/internal/buildid" +) + +// Build IDs +// +// Go packages and binaries are stamped with build IDs that record both +// the action ID, which is a hash of the inputs to the action that produced +// the packages or binary, and the content ID, which is a hash of the action +// output, namely the archive or binary itself. The hash is the same one +// used by the build artifact cache (see cmd/go/internal/cache), but +// truncated when stored in packages and binaries, as the full length is not +// needed and is a bit unwieldy. The precise form is +// +// actionID/[.../]contentID +// +// where the actionID and contentID are prepared by hashToString below. +// and are found by looking for the first or last slash. +// Usually the buildID is simply actionID/contentID, but see below for an +// exception. +// +// The build ID serves two primary purposes. +// +// 1. The action ID half allows installed packages and binaries to serve as +// one-element cache entries. If we intend to build math.a with a given +// set of inputs summarized in the action ID, and the installed math.a already +// has that action ID, we can reuse the installed math.a instead of rebuilding it. +// +// 2. The content ID half allows the easy preparation of action IDs for steps +// that consume a particular package or binary. The content hash of every +// input file for a given action must be included in the action ID hash. +// Storing the content ID in the build ID lets us read it from the file with +// minimal I/O, instead of reading and hashing the entire file. +// This is especially effective since packages and binaries are typically +// the largest inputs to an action. +// +// Separating action ID from content ID is important for reproducible builds. +// The compiler is compiled with itself. If an output were represented by its +// own action ID (instead of content ID) when computing the action ID of +// the next step in the build process, then the compiler could never have its +// own input action ID as its output action ID (short of a miraculous hash collision). +// Instead we use the content IDs to compute the next action ID, and because +// the content IDs converge, so too do the action IDs and therefore the +// build IDs and the overall compiler binary. See cmd/dist's cmdbootstrap +// for the actual convergence sequence. +// +// The “one-element cache” purpose is a bit more complex for installed +// binaries. For a binary, like cmd/gofmt, there are two steps: compile +// cmd/gofmt/*.go into main.a, and then link main.a into the gofmt binary. +// We do not install gofmt's main.a, only the gofmt binary. Being able to +// decide that the gofmt binary is up-to-date means computing the action ID +// for the final link of the gofmt binary and comparing it against the +// already-installed gofmt binary. But computing the action ID for the link +// means knowing the content ID of main.a, which we did not keep. +// To sidestep this problem, each binary actually stores an expanded build ID: +// +// actionID(binary)/actionID(main.a)/contentID(main.a)/contentID(binary) +// +// (Note that this can be viewed equivalently as: +// +// actionID(binary)/buildID(main.a)/contentID(binary) +// +// Storing the buildID(main.a) in the middle lets the computations that care +// about the prefix or suffix halves ignore the middle and preserves the +// original build ID as a contiguous string.) +// +// During the build, when it's time to build main.a, the gofmt binary has the +// information needed to decide whether the eventual link would produce +// the same binary: if the action ID for main.a's inputs matches and then +// the action ID for the link step matches when assuming the given main.a +// content ID, then the binary as a whole is up-to-date and need not be rebuilt. +// +// This is all a bit complex and may be simplified once we can rely on the +// main cache, but at least at the start we will be using the content-based +// staleness determination without a cache beyond the usual installed +// package and binary locations. + +const buildIDSeparator = "/" + +// actionID returns the action ID half of a build ID. +func actionID(buildID string) string { + i := strings.Index(buildID, buildIDSeparator) + if i < 0 { + return buildID + } + return buildID[:i] +} + +// contentID returns the content ID half of a build ID. +func contentID(buildID string) string { + return buildID[strings.LastIndex(buildID, buildIDSeparator)+1:] +} + +// hashToString converts the hash h to a string to be recorded +// in package archives and binaries as part of the build ID. +// We use the first 96 bits of the hash and encode it in base64, +// resulting in a 16-byte string. Because this is only used for +// detecting the need to rebuild installed files (not for lookups +// in the object file cache), 96 bits are sufficient to drive the +// probability of a false "do not need to rebuild" decision to effectively zero. +// We embed two different hashes in archives and four in binaries, +// so cutting to 16 bytes is a significant savings when build IDs are displayed. +// (16*4+3 = 67 bytes compared to 64*4+3 = 259 bytes for the +// more straightforward option of printing the entire h in hex). +func hashToString(h [cache.HashSize]byte) string { + const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" + const chunks = 5 + var dst [chunks * 4]byte + for i := 0; i < chunks; i++ { + v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2]) + dst[4*i+0] = b64[(v>>18)&0x3F] + dst[4*i+1] = b64[(v>>12)&0x3F] + dst[4*i+2] = b64[(v>>6)&0x3F] + dst[4*i+3] = b64[v&0x3F] + } + return string(dst[:]) +} + +// toolID returns the unique ID to use for the current copy of the +// named tool (asm, compile, cover, link). +// +// It is important that if the tool changes (for example a compiler bug is fixed +// and the compiler reinstalled), toolID returns a different string, so that old +// package archives look stale and are rebuilt (with the fixed compiler). +// This suggests using a content hash of the tool binary, as stored in the build ID. +// +// Unfortunately, we can't just open the tool binary, because the tool might be +// invoked via a wrapper program specified by -toolexec and we don't know +// what the wrapper program does. In particular, we want "-toolexec toolstash" +// to continue working: it does no good if "-toolexec toolstash" is executing a +// stashed copy of the compiler but the go command is acting as if it will run +// the standard copy of the compiler. The solution is to ask the tool binary to tell +// us its own build ID using the "-V=full" flag now supported by all tools. +// Then we know we're getting the build ID of the compiler that will actually run +// during the build. (How does the compiler binary know its own content hash? +// We store it there using updateBuildID after the standard link step.) +// +// A final twist is that we'd prefer to have reproducible builds for release toolchains. +// It should be possible to cross-compile for Windows from either Linux or Mac +// or Windows itself and produce the same binaries, bit for bit. If the tool ID, +// which influences the action ID half of the build ID, is based on the content ID, +// then the Linux compiler binary and Mac compiler binary will have different tool IDs +// and therefore produce executables with different action IDs. +// To avoids this problem, for releases we use the release version string instead +// of the compiler binary's content hash. This assumes that all compilers built +// on all different systems are semantically equivalent, which is of course only true +// modulo bugs. (Producing the exact same executables also requires that the different +// build setups agree on details like $GOROOT and file name paths, but at least the +// tool IDs do not make it impossible.) +func (b *Builder) toolID(name string) string { + b.id.Lock() + id := b.toolIDCache[name] + b.id.Unlock() + + if id != "" { + return id + } + + cmdline := str.StringList(cfg.BuildToolexec, base.Tool(name), "-V=full") + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + base.Fatalf("go tool %s: %v\n%s%s", name, err, stdout.Bytes(), stderr.Bytes()) + } + + line := stdout.String() + f := strings.Fields(line) + if len(f) < 3 || f[0] != name || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { + base.Fatalf("go tool %s -V=full: unexpected output:\n\t%s", name, line) + } + if f[2] == "devel" { + // On the development branch, use the content ID part of the build ID. + id = contentID(f[len(f)-1]) + } else { + // For a release, the output is like: "compile version go1.9.1". Use the whole line. + id = f[2] + } + + b.id.Lock() + b.toolIDCache[name] = id + b.id.Unlock() + + return id +} + +// gccToolID returns the unique ID to use for a tool that is invoked +// by the GCC driver. This is in particular gccgo, but this can also +// be used for gcc, g++, gfortran, etc.; those tools all use the GCC +// driver under different names. The approach used here should also +// work for sufficiently new versions of clang. Unlike toolID, the +// name argument is the program to run. The language argument is the +// type of input file as passed to the GCC driver's -x option. +// +// For these tools we have no -V=full option to dump the build ID, +// but we can run the tool with -v -### to reliably get the compiler proper +// and hash that. That will work in the presence of -toolexec. +// +// In order to get reproducible builds for released compilers, we +// detect a released compiler by the absence of "experimental" in the +// --version output, and in that case we just use the version string. +func (b *Builder) gccgoToolID(name, language string) (string, error) { + key := name + "." + language + b.id.Lock() + id := b.toolIDCache[key] + b.id.Unlock() + + if id != "" { + return id, nil + } + + // Invoke the driver with -### to see the subcommands and the + // version strings. Use -x to set the language. Pretend to + // compile an empty file on standard input. + cmdline := str.StringList(cfg.BuildToolexec, name, "-###", "-x", language, "-c", "-") + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) + out, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("%s: %v; output: %q", name, err, out) + } + + version := "" + lines := strings.Split(string(out), "\n") + for _, line := range lines { + if fields := strings.Fields(line); len(fields) > 1 && fields[1] == "version" { + version = line + break + } + } + if version == "" { + return "", fmt.Errorf("%s: can not find version number in %q", name, out) + } + + if !strings.Contains(version, "experimental") { + // This is a release. Use this line as the tool ID. + id = version + } else { + // This is a development version. The first line with + // a leading space is the compiler proper. + compiler := "" + for _, line := range lines { + if len(line) > 1 && line[0] == ' ' { + compiler = line + break + } + } + if compiler == "" { + return "", fmt.Errorf("%s: can not find compilation command in %q", name, out) + } + + fields := strings.Fields(compiler) + if len(fields) == 0 { + return "", fmt.Errorf("%s: compilation command confusion %q", name, out) + } + exe := fields[0] + if !strings.ContainsAny(exe, `/\`) { + if lp, err := exec.LookPath(exe); err == nil { + exe = lp + } + } + if _, err := os.Stat(exe); err != nil { + return "", fmt.Errorf("%s: can not find compiler %q: %v; output %q", name, exe, err, out) + } + id = b.fileHash(exe) + } + + b.id.Lock() + b.toolIDCache[name] = id + b.id.Unlock() + + return id, nil +} + +// gccgoBuildIDELFFile creates an assembler file that records the +// action's build ID in an SHF_EXCLUDE section. +func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { + sfile := a.Objdir + "_buildid.s" + + var buf bytes.Buffer + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + fmt.Fprintf(&buf, "\t.byte ") + for i := 0; i < len(a.buildID); i++ { + if i > 0 { + if i%8 == 0 { + fmt.Fprintf(&buf, "\n\t.byte ") + } else { + fmt.Fprintf(&buf, ",") + } + } + fmt.Fprintf(&buf, "%#02x", a.buildID[i]) + } + fmt.Fprintf(&buf, "\n") + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + + if cfg.BuildN || cfg.BuildX { + for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { + b.Showcmd("", "echo '%s' >> %s", line, sfile) + } + if cfg.BuildN { + return sfile, nil + } + } + + if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil { + return "", err + } + + return sfile, nil +} + +// buildID returns the build ID found in the given file. +// If no build ID is found, buildID returns the content hash of the file. +func (b *Builder) buildID(file string) string { + b.id.Lock() + id := b.buildIDCache[file] + b.id.Unlock() + + if id != "" { + return id + } + + id, err := buildid.ReadFile(file) + if err != nil { + id = b.fileHash(file) + } + + b.id.Lock() + b.buildIDCache[file] = id + b.id.Unlock() + + return id +} + +// fileHash returns the content hash of the named file. +func (b *Builder) fileHash(file string) string { + sum, err := cache.FileHash(file) + if err != nil { + return "" + } + return hashToString(sum) +} + +// useCache tries to satisfy the action a, which has action ID actionHash, +// by using a cached result from an earlier build. At the moment, the only +// cached result is the installed package or binary at target. +// If useCache decides that the cache can be used, it sets a.buildID +// and a.built for use by parent actions and then returns true. +// Otherwise it sets a.buildID to a temporary build ID for use in the build +// and returns false. When useCache returns false the expectation is that +// the caller will build the target and then call updateBuildID to finish the +// build ID computation. +// When useCache returns false, it may have initiated buffering of output +// during a's work. The caller should defer b.flushOutput(a), to make sure +// that flushOutput is eventually called regardless of whether the action +// succeeds. The flushOutput call must happen after updateBuildID. +func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID, target string) bool { + // The second half of the build ID here is a placeholder for the content hash. + // It's important that the overall buildID be unlikely verging on impossible + // to appear in the output by chance, but that should be taken care of by + // the actionID half; if it also appeared in the input that would be like an + // engineered 96-bit partial SHA256 collision. + a.actionID = actionHash + actionID := hashToString(actionHash) + contentID := actionID // temporary placeholder, likely unique + a.buildID = actionID + buildIDSeparator + contentID + + // Executable binaries also record the main build ID in the middle. + // See "Build IDs" comment above. + if a.Mode == "link" { + mainpkg := a.Deps[0] + a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID + } + + // Check to see if target exists and matches the expected action ID. + // If so, it's up to date and we can reuse it instead of rebuilding it. + var buildID string + if target != "" && !cfg.BuildA { + var err error + buildID, err = buildid.ReadFile(target) + if err != nil && b.ComputeStaleOnly { + if p != nil && !p.Stale { + p.Stale = true + p.StaleReason = "target missing" + } + return true + } + if strings.HasPrefix(buildID, actionID+buildIDSeparator) { + a.buildID = buildID + a.built = target + // Poison a.Target to catch uses later in the build. + a.Target = "DO NOT USE - " + a.Mode + return true + } + } + + // Special case for building a main package: if the only thing we + // want the package for is to link a binary, and the binary is + // already up-to-date, then to avoid a rebuild, report the package + // as up-to-date as well. See "Build IDs" comment above. + // TODO(rsc): Rewrite this code to use a TryCache func on the link action. + if target != "" && !cfg.BuildA && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { + buildID, err := buildid.ReadFile(target) + if err == nil { + id := strings.Split(buildID, buildIDSeparator) + if len(id) == 4 && id[1] == actionID { + // Temporarily assume a.buildID is the package build ID + // stored in the installed binary, and see if that makes + // the upcoming link action ID a match. If so, report that + // we built the package, safe in the knowledge that the + // link step will not ask us for the actual package file. + // Note that (*Builder).LinkAction arranged that all of + // a.triggers[0]'s dependencies other than a are also + // dependencies of a, so that we can be sure that, + // other than a.buildID, b.linkActionID is only accessing + // build IDs of completed actions. + oldBuildID := a.buildID + a.buildID = id[1] + buildIDSeparator + id[2] + linkID := hashToString(b.linkActionID(a.triggers[0])) + if id[0] == linkID { + // Poison a.Target to catch uses later in the build. + a.Target = "DO NOT USE - main build pseudo-cache Target" + a.built = "DO NOT USE - main build pseudo-cache built" + return true + } + // Otherwise restore old build ID for main build. + a.buildID = oldBuildID + } + } + } + + // Special case for linking a test binary: if the only thing we + // want the binary for is to run the test, and the test result is cached, + // then to avoid the link step, report the link as up-to-date. + // We avoid the nested build ID problem in the previous special case + // by recording the test results in the cache under the action ID half. + if !cfg.BuildA && len(a.triggers) == 1 && a.triggers[0].TryCache != nil && a.triggers[0].TryCache(b, a.triggers[0]) { + a.Target = "DO NOT USE - pseudo-cache Target" + a.built = "DO NOT USE - pseudo-cache built" + return true + } + + if b.ComputeStaleOnly { + // Invoked during go list only to compute and record staleness. + if p := a.Package; p != nil && !p.Stale { + p.Stale = true + if cfg.BuildA { + p.StaleReason = "build -a flag in use" + } else { + p.StaleReason = "build ID mismatch" + for _, p1 := range p.Internal.Imports { + if p1.Stale && p1.StaleReason != "" { + if strings.HasPrefix(p1.StaleReason, "stale dependency: ") { + p.StaleReason = p1.StaleReason + break + } + if strings.HasPrefix(p.StaleReason, "build ID mismatch") { + p.StaleReason = "stale dependency: " + p1.ImportPath + } + } + } + } + } + return true + } + + // Check the build artifact cache. + // We treat hits in this cache as being "stale" for the purposes of go list + // (in effect, "stale" means whether p.Target is up-to-date), + // but we're still happy to use results from the build artifact cache. + if c := cache.Default(); c != nil { + if !cfg.BuildA { + entry, err := c.Get(actionHash) + if err == nil { + file := c.OutputFile(entry.OutputID) + info, err1 := os.Stat(file) + buildID, err2 := buildid.ReadFile(file) + if err1 == nil && err2 == nil && info.Size() == entry.Size { + stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")) + if err == nil { + if len(stdout) > 0 { + if cfg.BuildX || cfg.BuildN { + b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) + } + if !cfg.BuildN { + b.Print(string(stdout)) + } + } + a.built = file + a.Target = "DO NOT USE - using cache" + a.buildID = buildID + return true + } + } + } + } + + // Begin saving output for later writing to cache. + a.output = []byte{} + } + + return false +} + +// flushOutput flushes the output being queued in a. +func (b *Builder) flushOutput(a *Action) { + b.Print(string(a.output)) + a.output = nil +} + +// updateBuildID updates the build ID in the target written by action a. +// It requires that useCache was called for action a and returned false, +// and that the build was then carried out and given the temporary +// a.buildID to record as the build ID in the resulting package or binary. +// updateBuildID computes the final content ID and updates the build IDs +// in the binary. +func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { + if cfg.BuildX || cfg.BuildN { + if rewrite { + b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList(base.Tool("buildid"), "-w", target))) + } + if cfg.BuildN { + return nil + } + } + + // Find occurrences of old ID and compute new content-based ID. + r, err := os.Open(target) + if err != nil { + return err + } + matches, hash, err := buildid.FindAndHash(r, a.buildID, 0) + r.Close() + if err != nil { + return err + } + newID := a.buildID[:strings.LastIndex(a.buildID, buildIDSeparator)] + buildIDSeparator + hashToString(hash) + if len(newID) != len(a.buildID) { + return fmt.Errorf("internal error: build ID length mismatch %q vs %q", a.buildID, newID) + } + + // Replace with new content-based ID. + a.buildID = newID + if len(matches) == 0 { + // Assume the user specified -buildid= to override what we were going to choose. + return nil + } + + if rewrite { + w, err := os.OpenFile(target, os.O_WRONLY, 0) + if err != nil { + return err + } + err = buildid.Rewrite(w, matches, newID) + if err != nil { + w.Close() + return err + } + if err := w.Close(); err != nil { + return err + } + } + + // Cache package builds, but not binaries (link steps). + // The expectation is that binaries are not reused + // nearly as often as individual packages, and they're + // much larger, so the cache-footprint-to-utility ratio + // of binaries is much lower for binaries. + // Not caching the link step also makes sure that repeated "go run" at least + // always rerun the linker, so that they don't get too fast. + // (We don't want people thinking go is a scripting language.) + // Note also that if we start caching binaries, then we will + // copy the binaries out of the cache to run them, and then + // that will mean the go process is itself writing a binary + // and then executing it, so we will need to defend against + // ETXTBSY problems as discussed in exec.go and golang.org/issue/22220. + if c := cache.Default(); c != nil && a.Mode == "build" { + r, err := os.Open(target) + if err == nil { + if a.output == nil { + panic("internal error: a.output not set") + } + outputID, _, err := c.Put(a.actionID, r) + if err == nil && cfg.BuildX { + b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID)))) + } + c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) + r.Close() + } + } + + return nil +} diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go new file mode 100644 index 00000000000..f955573e297 --- /dev/null +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -0,0 +1,2366 @@ +// 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. + +// Action graph execution. + +package work + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" +) + +// actionList returns the list of actions in the dag rooted at root +// as visited in a depth-first post-order traversal. +func actionList(root *Action) []*Action { + seen := map[*Action]bool{} + all := []*Action{} + var walk func(*Action) + walk = func(a *Action) { + if seen[a] { + return + } + seen[a] = true + for _, a1 := range a.Deps { + walk(a1) + } + all = append(all, a) + } + walk(root) + return all +} + +// do runs the action graph rooted at root. +func (b *Builder) Do(root *Action) { + if c := cache.Default(); c != nil && !b.ComputeStaleOnly { + // If we're doing real work, take time at the end to trim the cache. + defer c.Trim() + } + + // Build list of all actions, assigning depth-first post-order priority. + // The original implementation here was a true queue + // (using a channel) but it had the effect of getting + // distracted by low-level leaf actions to the detriment + // of completing higher-level actions. The order of + // work does not matter much to overall execution time, + // but when running "go test std" it is nice to see each test + // results as soon as possible. The priorities assigned + // ensure that, all else being equal, the execution prefers + // to do what it would have done first in a simple depth-first + // dependency order traversal. + all := actionList(root) + for i, a := range all { + a.priority = i + } + + if cfg.DebugActiongraph != "" { + js := actionGraphJSON(root) + if err := ioutil.WriteFile(cfg.DebugActiongraph, []byte(js), 0666); err != nil { + fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err) + base.SetExitStatus(1) + } + } + + b.readySema = make(chan bool, len(all)) + + // Initialize per-action execution state. + for _, a := range all { + for _, a1 := range a.Deps { + a1.triggers = append(a1.triggers, a) + } + a.pending = len(a.Deps) + if a.pending == 0 { + b.ready.push(a) + b.readySema <- true + } + } + + // Handle runs a single action and takes care of triggering + // any actions that are runnable as a result. + handle := func(a *Action) { + var err error + + if a.Func != nil && (!a.Failed || a.IgnoreFail) { + if err == nil { + err = a.Func(b, a) + } + } + + // The actions run in parallel but all the updates to the + // shared work state are serialized through b.exec. + b.exec.Lock() + defer b.exec.Unlock() + + if err != nil { + if err == errPrintedOutput { + base.SetExitStatus(2) + } else { + base.Errorf("%s", err) + } + a.Failed = true + } + + for _, a0 := range a.triggers { + if a.Failed { + a0.Failed = true + } + if a0.pending--; a0.pending == 0 { + b.ready.push(a0) + b.readySema <- true + } + } + + if a == root { + close(b.readySema) + } + } + + var wg sync.WaitGroup + + // Kick off goroutines according to parallelism. + // If we are using the -n flag (just printing commands) + // drop the parallelism to 1, both to make the output + // deterministic and because there is no real work anyway. + par := cfg.BuildP + if cfg.BuildN { + par = 1 + } + for i := 0; i < par; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case _, ok := <-b.readySema: + if !ok { + return + } + // Receiving a value from b.readySema entitles + // us to take from the ready queue. + b.exec.Lock() + a := b.ready.pop() + b.exec.Unlock() + handle(a) + case <-base.Interrupted: + base.SetExitStatus(1) + return + } + } + }() + } + + wg.Wait() +} + +// buildActionID computes the action ID for a build action. +func (b *Builder) buildActionID(a *Action) cache.ActionID { + p := a.Package + h := cache.NewHash("build " + p.ImportPath) + + // Configuration independent of compiler toolchain. + // Note: buildmode has already been accounted for in buildGcflags + // and should not be inserted explicitly. Most buildmodes use the + // same compiler settings and can reuse each other's results. + // If not, the reason is already recorded in buildGcflags. + fmt.Fprintf(h, "compile\n") + // The compiler hides the exact value of $GOROOT + // when building things in GOROOT, + // but it does not hide the exact value of $GOPATH. + // Include the full dir in that case. + // Assume b.WorkDir is being trimmed properly. + if !p.Goroot && !strings.HasPrefix(p.Dir, b.WorkDir) { + fmt.Fprintf(h, "dir %s\n", p.Dir) + } + fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) + fmt.Fprintf(h, "import %q\n", p.ImportPath) + fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) + if len(p.CgoFiles)+len(p.SwigFiles) > 0 { + fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo")) + cppflags, cflags, cxxflags, fflags, _ := b.CFlags(p) + fmt.Fprintf(h, "CC=%q %q %q\n", b.ccExe(), cppflags, cflags) + if len(p.CXXFiles)+len(p.SwigFiles) > 0 { + fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags) + } + if len(p.FFiles) > 0 { + fmt.Fprintf(h, "FC=%q %q\n", b.fcExe(), fflags) + } + // TODO(rsc): Should we include the SWIG version or Fortran/GCC/G++/Objective-C compiler versions? + } + if p.Internal.CoverMode != "" { + fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover")) + } + + // Configuration specific to compiler toolchain. + switch cfg.BuildToolchainName { + default: + base.Fatalf("buildActionID: unknown build toolchain %q", cfg.BuildToolchainName) + case "gc": + fmt.Fprintf(h, "compile %s %q %q\n", b.toolID("compile"), forcedGcflags, p.Internal.Gcflags) + if len(p.SFiles) > 0 { + fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags) + } + fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc + + // TODO(rsc): Convince compiler team not to add more magic environment variables, + // or perhaps restrict the environment variables passed to subprocesses. + magic := []string{ + "GOCLOBBERDEADHASH", + "GOSSAFUNC", + "GO_SSA_PHI_LOC_CUTOFF", + "GOSSAHASH", + } + for _, env := range magic { + if x := os.Getenv(env); x != "" { + fmt.Fprintf(h, "magic %s=%s\n", env, x) + } + } + if os.Getenv("GOSSAHASH") != "" { + for i := 0; ; i++ { + env := fmt.Sprintf("GOSSAHASH%d", i) + x := os.Getenv(env) + if x == "" { + break + } + fmt.Fprintf(h, "magic %s=%s\n", env, x) + } + } + if os.Getenv("GSHS_LOGFILE") != "" { + // Clumsy hack. Compiler writes to this log file, + // so do not allow use of cache at all. + // We will still write to the cache but it will be + // essentially unfindable. + fmt.Fprintf(h, "nocache %d\n", time.Now().UnixNano()) + } + + case "gccgo": + id, err := b.gccgoToolID(BuildToolchain.compiler(), "go") + if err != nil { + base.Fatalf("%v", err) + } + fmt.Fprintf(h, "compile %s %q %q\n", id, forcedGccgoflags, p.Internal.Gccgoflags) + fmt.Fprintf(h, "pkgpath %s\n", gccgoPkgpath(p)) + if len(p.SFiles) > 0 { + id, err = b.gccgoToolID(BuildToolchain.compiler(), "assembler-with-cpp") + // Ignore error; different assembler versions + // are unlikely to make any difference anyhow. + fmt.Fprintf(h, "asm %q\n", id) + } + } + + // Input files. + inputFiles := str.StringList( + p.GoFiles, + p.CgoFiles, + p.CFiles, + p.CXXFiles, + p.FFiles, + p.MFiles, + p.HFiles, + p.SFiles, + p.SysoFiles, + p.SwigFiles, + p.SwigCXXFiles, + ) + for _, file := range inputFiles { + fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file))) + } + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 != nil { + fmt.Fprintf(h, "import %s %s\n", p1.ImportPath, contentID(a1.buildID)) + } + } + + return h.Sum() +} + +// build is the action for building a single package. +// Note that any new influence on this logic must be reported in b.buildActionID above as well. +func (b *Builder) build(a *Action) (err error) { + p := a.Package + cached := false + if !p.BinaryOnly { + if b.useCache(a, p, b.buildActionID(a), p.Target) { + // If this build triggers a header install, run cgo to get the header. + // TODO(rsc): Once we can cache multiple file outputs from an action, + // the header should be cached, and then this awful test can be deleted. + // Need to look for install header actions depending on this action, + // or depending on a link that depends on this action. + needHeader := false + if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-header") { + for _, t1 := range a.triggers { + if t1.Mode == "install header" { + needHeader = true + goto CheckedHeader + } + } + for _, t1 := range a.triggers { + for _, t2 := range t1.triggers { + if t2.Mode == "install header" { + needHeader = true + goto CheckedHeader + } + } + } + } + CheckedHeader: + if b.ComputeStaleOnly || !a.needVet && !needHeader { + return nil + } + cached = true + } + defer b.flushOutput(a) + } + + defer func() { + if err != nil && err != errPrintedOutput { + err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err) + } + }() + if cfg.BuildN { + // In -n mode, print a banner between packages. + // The banner is five lines so that when changes to + // different sections of the bootstrap script have to + // be merged, the banners give patch something + // to use to find its context. + b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n") + } + + if cfg.BuildV { + b.Print(a.Package.ImportPath + "\n") + } + + if a.Package.BinaryOnly { + _, err := os.Stat(a.Package.Target) + if err == nil { + a.built = a.Package.Target + a.Target = a.Package.Target + a.buildID = b.fileHash(a.Package.Target) + a.Package.Stale = false + a.Package.StaleReason = "binary-only package" + return nil + } + if b.ComputeStaleOnly { + a.Package.Stale = true + a.Package.StaleReason = "missing or invalid binary-only package" + return nil + } + return fmt.Errorf("missing or invalid binary-only package") + } + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + objdir := a.Objdir + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string + + gofiles = append(gofiles, a.Package.GoFiles...) + cgofiles = append(cgofiles, a.Package.CgoFiles...) + cfiles = append(cfiles, a.Package.CFiles...) + sfiles = append(sfiles, a.Package.SFiles...) + cxxfiles = append(cxxfiles, a.Package.CXXFiles...) + + if a.Package.UsesCgo() || a.Package.UsesSwig() { + if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil { + return + } + } + + // Run SWIG on each .swig and .swigcxx file. + // Each run will generate two files, a .go file and a .c or .cxx file. + // The .go file will use import "C" and is to be processed by cgo. + if a.Package.UsesSwig() { + outGo, outC, outCXX, err := b.swig(a, a.Package, objdir, pcCFLAGS) + if err != nil { + return err + } + cgofiles = append(cgofiles, outGo...) + cfiles = append(cfiles, outC...) + cxxfiles = append(cxxfiles, outCXX...) + } + + // If we're doing coverage, preprocess the .go files and put them in the work directory + if a.Package.Internal.CoverMode != "" { + for i, file := range str.StringList(gofiles, cgofiles) { + var sourceFile string + var coverFile string + var key string + if strings.HasSuffix(file, ".cgo1.go") { + // cgo files have absolute paths + base := filepath.Base(file) + sourceFile = file + coverFile = objdir + base + key = strings.TrimSuffix(base, ".cgo1.go") + ".go" + } else { + sourceFile = filepath.Join(a.Package.Dir, file) + coverFile = objdir + file + key = file + } + coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go" + cover := a.Package.Internal.CoverVars[key] + if cover == nil || base.IsTestFile(file) { + // Not covering this file. + continue + } + if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil { + return err + } + if i < len(gofiles) { + gofiles[i] = coverFile + } else { + cgofiles[i-len(gofiles)] = coverFile + } + } + } + + // Run cgo. + if a.Package.UsesCgo() || a.Package.UsesSwig() { + // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. + // There is one exception: runtime/cgo's job is to bridge the + // cgo and non-cgo worlds, so it necessarily has files in both. + // In that case gcc only gets the gcc_* files. + var gccfiles []string + gccfiles = append(gccfiles, cfiles...) + cfiles = nil + if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" { + filter := func(files, nongcc, gcc []string) ([]string, []string) { + for _, f := range files { + if strings.HasPrefix(f, "gcc_") { + gcc = append(gcc, f) + } else { + nongcc = append(nongcc, f) + } + } + return nongcc, gcc + } + sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles) + } else { + for _, sfile := range sfiles { + data, err := ioutil.ReadFile(filepath.Join(a.Package.Dir, sfile)) + if err == nil { + if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) || + bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) || + bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) { + return fmt.Errorf("package using cgo has Go assembly file %s", sfile) + } + } + } + gccfiles = append(gccfiles, sfiles...) + sfiles = nil + } + + outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcLDFLAGS, mkAbsFiles(a.Package.Dir, cgofiles), gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles) + if err != nil { + return err + } + if cfg.BuildToolchainName == "gccgo" { + cgoObjects = append(cgoObjects, a.Objdir+"_cgo_flags") + } + cgoObjects = append(cgoObjects, outObj...) + gofiles = append(gofiles, outGo...) + } + if cached && !a.needVet { + return nil + } + + // Sanity check only, since Package.load already checked as well. + if len(gofiles) == 0 { + return &load.NoGoError{Package: a.Package} + } + + // Prepare Go vet config if needed. + var vcfg *vetConfig + if a.needVet { + // Pass list of absolute paths to vet, + // so that vet's error messages will use absolute paths, + // so that we can reformat them relative to the directory + // in which the go command is invoked. + vcfg = &vetConfig{ + Compiler: cfg.BuildToolchainName, + Dir: a.Package.Dir, + GoFiles: mkAbsFiles(a.Package.Dir, gofiles), + ImportMap: make(map[string]string), + PackageFile: make(map[string]string), + } + a.vetCfg = vcfg + for i, raw := range a.Package.Internal.RawImports { + final := a.Package.Imports[i] + vcfg.ImportMap[raw] = final + } + } + + // Prepare Go import config. + var icfg bytes.Buffer + for i, raw := range a.Package.Internal.RawImports { + final := a.Package.Imports[i] + if final != raw { + fmt.Fprintf(&icfg, "importmap %s=%s\n", raw, final) + } + } + + // Compute the list of mapped imports in the vet config + // so that we can add any missing mappings below. + var vcfgMapped map[string]bool + if vcfg != nil { + vcfgMapped = make(map[string]bool) + for _, p := range vcfg.ImportMap { + vcfgMapped[p] = true + } + } + + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil || p1.ImportPath == "" || a1.built == "" { + continue + } + fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + if vcfg != nil { + // Add import mapping if needed + // (for imports like "runtime/cgo" that appear only in generated code). + if !vcfgMapped[p1.ImportPath] { + vcfg.ImportMap[p1.ImportPath] = p1.ImportPath + } + vcfg.PackageFile[p1.ImportPath] = a1.built + } + } + + if cached { + // The cached package file is OK, so we don't need to run the compile. + // We've only going through the motions to prepare the vet configuration, + // which is now complete. + return nil + } + + // Compile Go. + objpkg := objdir + "_pkg_.a" + ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles) + if len(out) > 0 { + b.showOutput(a, a.Package.Dir, a.Package.ImportPath, b.processOutput(out)) + if err != nil { + return errPrintedOutput + } + } + if err != nil { + return err + } + if ofile != objpkg { + objects = append(objects, ofile) + } + + // Copy .h files named for goos or goarch or goos_goarch + // to names using GOOS and GOARCH. + // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. + _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch + _goos := "_" + cfg.Goos + _goarch := "_" + cfg.Goarch + for _, file := range a.Package.HFiles { + name, ext := fileExtSplit(file) + switch { + case strings.HasSuffix(name, _goos_goarch): + targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext + if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { + return err + } + case strings.HasSuffix(name, _goarch): + targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext + if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { + return err + } + case strings.HasSuffix(name, _goos): + targ := file[:len(name)-len(_goos)] + "_GOOS." + ext + if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { + return err + } + } + } + + for _, file := range cfiles { + out := file[:len(file)-len(".c")] + ".o" + if err := BuildToolchain.cc(b, a, objdir+out, file); err != nil { + return err + } + objects = append(objects, out) + } + + // Assemble .s files. + if len(sfiles) > 0 { + ofiles, err := BuildToolchain.asm(b, a, sfiles) + if err != nil { + return err + } + objects = append(objects, ofiles...) + } + + // For gccgo on ELF systems, we write the build ID as an assembler file. + // This lets us set the the SHF_EXCLUDE flag. + // This is read by readGccgoArchive in cmd/internal/buildid/buildid.go. + if a.buildID != "" && cfg.BuildToolchainName == "gccgo" { + switch cfg.Goos { + case "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + asmfile, err := b.gccgoBuildIDELFFile(a) + if err != nil { + return err + } + ofiles, err := BuildToolchain.asm(b, a, []string{asmfile}) + if err != nil { + return err + } + objects = append(objects, ofiles...) + } + } + + // NOTE(rsc): On Windows, it is critically important that the + // gcc-compiled objects (cgoObjects) be listed after the ordinary + // objects in the archive. I do not know why this is. + // https://golang.org/issue/2601 + objects = append(objects, cgoObjects...) + + // Add system object files. + for _, syso := range a.Package.SysoFiles { + objects = append(objects, filepath.Join(a.Package.Dir, syso)) + } + + // Pack into archive in objdir directory. + // If the Go compiler wrote an archive, we only need to add the + // object files for non-Go sources to the archive. + // If the Go compiler wrote an archive and the package is entirely + // Go sources, there is no pack to execute at all. + if len(objects) > 0 { + if err := BuildToolchain.pack(b, a, objpkg, objects); err != nil { + return err + } + } + + if err := b.updateBuildID(a, objpkg, true); err != nil { + return err + } + + a.built = objpkg + return nil +} + +type vetConfig struct { + Compiler string + Dir string + GoFiles []string + ImportMap map[string]string + PackageFile map[string]string + + SucceedOnTypecheckFailure bool +} + +// VetFlags are the flags to pass to vet. +// The caller is expected to set them before executing any vet actions. +var VetFlags []string + +func (b *Builder) vet(a *Action) error { + // a.Deps[0] is the build of the package being vetted. + // a.Deps[1] is the build of the "fmt" package. + + vcfg := a.Deps[0].vetCfg + if vcfg == nil { + // Vet config should only be missing if the build failed. + if !a.Deps[0].Failed { + return fmt.Errorf("vet config not found") + } + return nil + } + + if vcfg.ImportMap["fmt"] == "" { + a1 := a.Deps[1] + vcfg.ImportMap["fmt"] = "fmt" + vcfg.PackageFile["fmt"] = a1.built + } + + // During go test, ignore type-checking failures during vet. + // We only run vet if the compilation has succeeded, + // so at least for now assume the bug is in vet. + // We know of at least #18395. + // TODO(rsc,gri): Try to remove this for Go 1.11. + vcfg.SucceedOnTypecheckFailure = cfg.CmdName == "test" + + js, err := json.MarshalIndent(vcfg, "", "\t") + if err != nil { + return fmt.Errorf("internal error marshaling vet config: %v", err) + } + js = append(js, '\n') + if err := b.writeFile(a.Objdir+"vet.cfg", js); err != nil { + return err + } + + var env []string + if cfg.BuildToolchainName == "gccgo" { + env = append(env, "GCCGO="+BuildToolchain.compiler()) + } + + p := a.Package + return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, base.Tool("vet"), VetFlags, a.Objdir+"vet.cfg") +} + +// linkActionID computes the action ID for a link action. +func (b *Builder) linkActionID(a *Action) cache.ActionID { + p := a.Package + h := cache.NewHash("link " + p.ImportPath) + + // Toolchain-independent configuration. + fmt.Fprintf(h, "link\n") + fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) + fmt.Fprintf(h, "import %q\n", p.ImportPath) + fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) + + // Toolchain-dependent configuration, shared with b.linkSharedActionID. + b.printLinkerConfig(h, p) + + // Input files. + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 != nil { + if a1.built != "" || a1.buildID != "" { + buildID := a1.buildID + if buildID == "" { + buildID = b.buildID(a1.built) + } + fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(buildID)) + } + // Because we put package main's full action ID into the binary's build ID, + // we must also put the full action ID into the binary's action ID hash. + if p1.Name == "main" { + fmt.Fprintf(h, "packagemain %s\n", a1.buildID) + } + if p1.Shlib != "" { + fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) + } + } + } + + return h.Sum() +} + +// printLinkerConfig prints the linker config into the hash h, +// as part of the computation of a linker-related action ID. +func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { + switch cfg.BuildToolchainName { + default: + base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName) + + case "gc": + fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode) + if p != nil { + fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags) + } + fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc + + /* + // TODO(rsc): Enable this code. + // golang.org/issue/22475. + goroot := cfg.BuildContext.GOROOT + if final := os.Getenv("GOROOT_FINAL"); final != "" { + goroot = final + } + fmt.Fprintf(h, "GOROOT=%s\n", goroot) + */ + + // TODO(rsc): Convince linker team not to add more magic environment variables, + // or perhaps restrict the environment variables passed to subprocesses. + magic := []string{ + "GO_EXTLINK_ENABLED", + } + for _, env := range magic { + if x := os.Getenv(env); x != "" { + fmt.Fprintf(h, "magic %s=%s\n", env, x) + } + } + + // TODO(rsc): Do cgo settings and flags need to be included? + // Or external linker settings and flags? + + case "gccgo": + id, err := b.gccgoToolID(BuildToolchain.linker(), "go") + if err != nil { + base.Fatalf("%v", err) + } + fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode) + // TODO(iant): Should probably include cgo flags here. + } +} + +// link is the action for linking a single command. +// Note that any new influence on this logic must be reported in b.linkActionID above as well. +func (b *Builder) link(a *Action) (err error) { + if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) { + return nil + } + defer b.flushOutput(a) + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + importcfg := a.Objdir + "importcfg.link" + if err := b.writeLinkImportcfg(a, importcfg); err != nil { + return err + } + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil { + return err + } + + // Update the binary with the final build ID. + // But if OmitDebug is set, don't rewrite the binary, because we set OmitDebug + // on binaries that we are going to run and then delete. + // There's no point in doing work on such a binary. + // Worse, opening the binary for write here makes it + // essentially impossible to safely fork+exec due to a fundamental + // incompatibility between ETXTBSY and threads on modern Unix systems. + // See golang.org/issue/22220. + // We still call updateBuildID to update a.buildID, which is important + // for test result caching, but passing rewrite=false (final arg) + // means we don't actually rewrite the binary, nor store the + // result into the cache. + // Not calling updateBuildID means we also don't insert these + // binaries into the build object cache. That's probably a net win: + // less cache space wasted on large binaries we are not likely to + // need again. (On the other hand it does make repeated go test slower.) + if err := b.updateBuildID(a, a.Target, !a.Package.Internal.OmitDebug); err != nil { + return err + } + + a.built = a.Target + return nil +} + +func (b *Builder) writeLinkImportcfg(a *Action, file string) error { + // Prepare Go import cfg. + var icfg bytes.Buffer + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil { + continue + } + fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + if p1.Shlib != "" { + fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib) + } + } + return b.writeFile(file, icfg.Bytes()) +} + +// PkgconfigCmd returns a pkg-config binary name +// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) PkgconfigCmd() string { + return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0] +} + +// splitPkgConfigOutput parses the pkg-config output into a slice of +// flags. pkg-config always uses \ to escape special characters. +func splitPkgConfigOutput(out []byte) []string { + if len(out) == 0 { + return nil + } + var flags []string + flag := make([]byte, len(out)) + r, w := 0, 0 + for r < len(out) { + switch out[r] { + case ' ', '\t', '\r', '\n': + if w > 0 { + flags = append(flags, string(flag[:w])) + } + w = 0 + case '\\': + r++ + fallthrough + default: + if r < len(out) { + flag[w] = out[r] + w++ + } + } + r++ + } + if w > 0 { + flags = append(flags, string(flag[:w])) + } + return flags +} + +// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. +func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { + if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { + var out []byte + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pkgs) + if err != nil { + b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) + b.Print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + cflags = splitPkgConfigOutput(out) + } + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pkgs) + if err != nil { + b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) + b.Print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + ldflags = strings.Fields(string(out)) + } + } + return +} + +func (b *Builder) installShlibname(a *Action) error { + // TODO: BuildN + a1 := a.Deps[0] + err := ioutil.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666) + if err != nil { + return err + } + if cfg.BuildX { + b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target) + } + return nil +} + +func (b *Builder) linkSharedActionID(a *Action) cache.ActionID { + h := cache.NewHash("linkShared") + + // Toolchain-independent configuration. + fmt.Fprintf(h, "linkShared\n") + fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) + + // Toolchain-dependent configuration, shared with b.linkActionID. + b.printLinkerConfig(h, nil) + + // Input files. + for _, a1 := range a.Deps { + p1 := a1.Package + if a1.built == "" { + continue + } + if p1 != nil { + fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) + if p1.Shlib != "" { + fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) + } + } + } + // Files named on command line are special. + for _, a1 := range a.Deps[0].Deps { + p1 := a1.Package + fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) + } + + return h.Sum() +} + +func (b *Builder) linkShared(a *Action) (err error) { + if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) { + return nil + } + defer b.flushOutput(a) + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + importcfg := a.Objdir + "importcfg.link" + if err := b.writeLinkImportcfg(a, importcfg); err != nil { + return err + } + + // TODO(rsc): There is a missing updateBuildID here, + // but we have to decide where to store the build ID in these files. + a.built = a.Target + return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps) +} + +// BuildInstallFunc is the action for installing a single package or executable. +func BuildInstallFunc(b *Builder, a *Action) (err error) { + defer func() { + if err != nil && err != errPrintedOutput { + // a.Package == nil is possible for the go install -buildmode=shared + // action that installs libmangledname.so, which corresponds to + // a list of packages, not just one. + sep, path := "", "" + if a.Package != nil { + sep, path = " ", a.Package.ImportPath + } + err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err) + } + }() + + a1 := a.Deps[0] + a.buildID = a1.buildID + + // If we are using the eventual install target as an up-to-date + // cached copy of the thing we built, then there's no need to + // copy it into itself (and that would probably fail anyway). + // In this case a1.built == a.Target because a1.built == p.Target, + // so the built target is not in the a1.Objdir tree that b.cleanup(a1) removes. + if a1.built == a.Target { + a.built = a.Target + b.cleanup(a1) + // Whether we're smart enough to avoid a complete rebuild + // depends on exactly what the staleness and rebuild algorithms + // are, as well as potentially the state of the Go build cache. + // We don't really want users to be able to infer (or worse start depending on) + // those details from whether the modification time changes during + // "go install", so do a best-effort update of the file times to make it + // look like we rewrote a.Target even if we did not. Updating the mtime + // may also help other mtime-based systems that depend on our + // previous mtime updates that happened more often. + // This is still not perfect - we ignore the error result, and if the file was + // unwritable for some reason then pretending to have written it is also + // confusing - but it's probably better than not doing the mtime update. + // + // But don't do that for the special case where building an executable + // with -linkshared implicitly installs all its dependent libraries. + // We want to hide that awful detail as much as possible, so don't + // advertise it by touching the mtimes (usually the libraries are up + // to date). + if !a.buggyInstall { + now := time.Now() + os.Chtimes(a.Target, now, now) + } + return nil + } + if b.ComputeStaleOnly { + return nil + } + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + perm := os.FileMode(0666) + if a1.Mode == "link" { + switch cfg.BuildBuildmode { + case "c-archive", "c-shared", "plugin": + default: + perm = 0777 + } + } + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + defer b.cleanup(a1) + + return b.moveOrCopyFile(a, a.Target, a1.built, perm, false) +} + +// cleanup removes a's object dir to keep the amount of +// on-disk garbage down in a large build. On an operating system +// with aggressive buffering, cleaning incrementally like +// this keeps the intermediate objects from hitting the disk. +func (b *Builder) cleanup(a *Action) { + if !cfg.BuildWork { + if cfg.BuildX { + b.Showcmd("", "rm -r %s", a.Objdir) + } + os.RemoveAll(a.Objdir) + } +} + +// moveOrCopyFile is like 'mv src dst' or 'cp src dst'. +func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { + if cfg.BuildN { + b.Showcmd("", "mv %s %s", src, dst) + return nil + } + + // If we can update the mode and rename to the dst, do it. + // Otherwise fall back to standard copy. + + // If the source is in the build cache, we need to copy it. + if strings.HasPrefix(src, cache.DefaultDir()) { + return b.copyFile(a, dst, src, perm, force) + } + + // On Windows, always copy the file, so that we respect the NTFS + // permissions of the parent folder. https://golang.org/issue/22343. + // What matters here is not cfg.Goos (the system we are building + // for) but runtime.GOOS (the system we are building on). + if runtime.GOOS == "windows" { + return b.copyFile(a, dst, src, perm, force) + } + + // If the destination directory has the group sticky bit set, + // we have to copy the file to retain the correct permissions. + // https://golang.org/issue/18878 + if fi, err := os.Stat(filepath.Dir(dst)); err == nil { + if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 { + return b.copyFile(a, dst, src, perm, force) + } + } + + // The perm argument is meant to be adjusted according to umask, + // but we don't know what the umask is. + // Create a dummy file to find out. + // This avoids build tags and works even on systems like Plan 9 + // where the file mask computation incorporates other information. + mode := perm + f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err == nil { + fi, err := f.Stat() + if err == nil { + mode = fi.Mode() & 0777 + } + name := f.Name() + f.Close() + os.Remove(name) + } + + if err := os.Chmod(src, mode); err == nil { + if err := os.Rename(src, dst); err == nil { + if cfg.BuildX { + b.Showcmd("", "mv %s %s", src, dst) + } + return nil + } + } + + return b.copyFile(a, dst, src, perm, force) +} + +// copyFile is like 'cp src dst'. +func (b *Builder) copyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "cp %s %s", src, dst) + if cfg.BuildN { + return nil + } + } + + sf, err := os.Open(src) + if err != nil { + return err + } + defer sf.Close() + + // Be careful about removing/overwriting dst. + // Do not remove/overwrite if dst exists and is a directory + // or a non-object file. + if fi, err := os.Stat(dst); err == nil { + if fi.IsDir() { + return fmt.Errorf("build output %q already exists and is a directory", dst) + } + if !force && fi.Mode().IsRegular() && !isObject(dst) { + return fmt.Errorf("build output %q already exists and is not an object file", dst) + } + } + + // On Windows, remove lingering ~ file from last attempt. + if base.ToolIsWindows { + if _, err := os.Stat(dst + "~"); err == nil { + os.Remove(dst + "~") + } + } + + mayberemovefile(dst) + df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil && base.ToolIsWindows { + // Windows does not allow deletion of a binary file + // while it is executing. Try to move it out of the way. + // If the move fails, which is likely, we'll try again the + // next time we do an install of this binary. + if err := os.Rename(dst, dst+"~"); err == nil { + os.Remove(dst + "~") + } + df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + } + if err != nil { + return err + } + + _, err = io.Copy(df, sf) + df.Close() + if err != nil { + mayberemovefile(dst) + return fmt.Errorf("copying %s to %s: %v", src, dst, err) + } + return nil +} + +// writeFile writes the text to file. +func (b *Builder) writeFile(file string, text []byte) error { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "cat >%s << 'EOF' # internal\n%sEOF", file, text) + } + if cfg.BuildN { + return nil + } + return ioutil.WriteFile(file, text, 0666) +} + +// Install the cgo export header file, if there is one. +func (b *Builder) installHeader(a *Action) error { + src := a.Objdir + "_cgo_install.h" + if _, err := os.Stat(src); os.IsNotExist(err) { + // If the file does not exist, there are no exported + // functions, and we do not install anything. + // TODO(rsc): Once we know that caching is rebuilding + // at the right times (not missing rebuilds), here we should + // probably delete the installed header, if any. + if cfg.BuildX { + b.Showcmd("", "# %s not created", src) + } + return nil + } + + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + return b.moveOrCopyFile(a, a.Target, src, 0666, true) +} + +// cover runs, in effect, +// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go +func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName string) error { + return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil, + cfg.BuildToolexec, + base.Tool("cover"), + "-mode", a.Package.Internal.CoverMode, + "-var", varName, + "-o", dst, + src) +} + +var objectMagic = [][]byte{ + {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive + {'\x7F', 'E', 'L', 'F'}, // ELF + {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit + {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit + {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit + {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit + {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc + {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 + {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 + {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm +} + +func isObject(s string) bool { + f, err := os.Open(s) + if err != nil { + return false + } + defer f.Close() + buf := make([]byte, 64) + io.ReadFull(f, buf) + for _, magic := range objectMagic { + if bytes.HasPrefix(buf, magic) { + return true + } + } + return false +} + +// mayberemovefile removes a file only if it is a regular file +// When running as a user with sufficient privileges, we may delete +// even device files, for example, which is not intended. +func mayberemovefile(s string) { + if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() { + return + } + os.Remove(s) +} + +// fmtcmd formats a command in the manner of fmt.Sprintf but also: +// +// If dir is non-empty and the script is not in dir right now, +// fmtcmd inserts "cd dir\n" before the command. +// +// fmtcmd replaces the value of b.WorkDir with $WORK. +// fmtcmd replaces the value of goroot with $GOROOT. +// fmtcmd replaces the value of b.gobin with $GOBIN. +// +// fmtcmd replaces the name of the current directory with dot (.) +// but only when it is at the beginning of a space-separated token. +// +func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string { + cmd := fmt.Sprintf(format, args...) + if dir != "" && dir != "/" { + to := "." + if dir[len(dir)-1] == filepath.Separator { + to += string(filepath.Separator) + } + cmd = strings.Replace(" "+cmd, " "+dir, " "+to, -1)[1:] + if b.scriptDir != dir { + b.scriptDir = dir + cmd = "cd " + dir + "\n" + cmd + } + } + if b.WorkDir != "" { + cmd = strings.Replace(cmd, b.WorkDir, "$WORK", -1) + } + return cmd +} + +// showcmd prints the given command to standard output +// for the implementation of -n or -x. +func (b *Builder) Showcmd(dir string, format string, args ...interface{}) { + b.output.Lock() + defer b.output.Unlock() + b.Print(b.fmtcmd(dir, format, args...) + "\n") +} + +// showOutput prints "# desc" followed by the given output. +// The output is expected to contain references to 'dir', usually +// the source directory for the package that has failed to build. +// showOutput rewrites mentions of dir with a relative path to dir +// when the relative path is shorter. This is usually more pleasant. +// For example, if fmt doesn't compile and we are in src/html, +// the output is +// +// $ go build +// # fmt +// ../fmt/print.go:1090: undefined: asdf +// $ +// +// instead of +// +// $ go build +// # fmt +// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf +// $ +// +// showOutput also replaces references to the work directory with $WORK. +// +// If a is not nil and a.output is not nil, showOutput appends to that slice instead of +// printing to b.Print. +// +func (b *Builder) showOutput(a *Action, dir, desc, out string) { + prefix := "# " + desc + suffix := "\n" + out + if reldir := base.ShortPath(dir); reldir != dir { + suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1) + suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1) + } + suffix = strings.Replace(suffix, " "+b.WorkDir, " $WORK", -1) + + if a != nil && a.output != nil { + a.output = append(a.output, prefix...) + a.output = append(a.output, suffix...) + return + } + + b.output.Lock() + defer b.output.Unlock() + b.Print(prefix, suffix) +} + +// errPrintedOutput is a special error indicating that a command failed +// but that it generated output as well, and that output has already +// been printed, so there's no point showing 'exit status 1' or whatever +// the wait status was. The main executor, builder.do, knows not to +// print this error. +var errPrintedOutput = errors.New("already printed output - no need to show error") + +var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.(cgo1|cover)\.go:[0-9]+(:[0-9]+)?\]`) +var cgoTypeSigRe = regexp.MustCompile(`\b_C2?(type|func|var|macro)_\B`) + +// run runs the command given by cmdline in the directory dir. +// If the command fails, run prints information about the failure +// and returns a non-nil error. +func (b *Builder) run(a *Action, dir string, desc string, env []string, cmdargs ...interface{}) error { + out, err := b.runOut(dir, desc, env, cmdargs...) + if len(out) > 0 { + if desc == "" { + desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " ")) + } + b.showOutput(a, dir, desc, b.processOutput(out)) + if err != nil { + err = errPrintedOutput + } + } + return err +} + +// processOutput prepares the output of runOut to be output to the console. +func (b *Builder) processOutput(out []byte) string { + if out[len(out)-1] != '\n' { + out = append(out, '\n') + } + messages := string(out) + // Fix up output referring to cgo-generated code to be more readable. + // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19. + // Replace *[100]_Ctype_foo with *[100]C.foo. + // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite. + if !cfg.BuildX && cgoLine.MatchString(messages) { + messages = cgoLine.ReplaceAllString(messages, "") + messages = cgoTypeSigRe.ReplaceAllString(messages, "C.") + } + return messages +} + +// runOut runs the command given by cmdline in the directory dir. +// It returns the command output and any errors that occurred. +func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { + cmdline := str.StringList(cmdargs...) + if cfg.BuildN || cfg.BuildX { + var envcmdline string + for _, e := range env { + if j := strings.IndexByte(e, '='); j != -1 { + if strings.ContainsRune(e[j+1:], '\'') { + envcmdline += fmt.Sprintf("%s=%q", e[:j], e[j+1:]) + } else { + envcmdline += fmt.Sprintf("%s='%s'", e[:j], e[j+1:]) + } + envcmdline += " " + } + } + envcmdline += joinUnambiguously(cmdline) + b.Showcmd(dir, "%s", envcmdline) + if cfg.BuildN { + return nil, nil + } + } + + var buf bytes.Buffer + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Stdout = &buf + cmd.Stderr = &buf + cmd.Dir = dir + cmd.Env = base.MergeEnvLists(env, base.EnvForDir(cmd.Dir, os.Environ())) + err := cmd.Run() + + // err can be something like 'exit status 1'. + // Add information about what program was running. + // Note that if buf.Bytes() is non-empty, the caller usually + // shows buf.Bytes() and does not print err at all, so the + // prefix here does not make most output any more verbose. + if err != nil { + err = errors.New(cmdline[0] + ": " + err.Error()) + } + return buf.Bytes(), err +} + +// joinUnambiguously prints the slice, quoting where necessary to make the +// output unambiguous. +// TODO: See issue 5279. The printing of commands needs a complete redo. +func joinUnambiguously(a []string) string { + var buf bytes.Buffer + for i, s := range a { + if i > 0 { + buf.WriteByte(' ') + } + q := strconv.Quote(s) + if s == "" || strings.ContainsAny(s, " ()") || len(q) > len(s)+2 { + buf.WriteString(q) + } else { + buf.WriteString(s) + } + } + return buf.String() +} + +// mkdir makes the named directory. +func (b *Builder) Mkdir(dir string) error { + // Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "". + if dir == "" { + return nil + } + + b.exec.Lock() + defer b.exec.Unlock() + // We can be a little aggressive about being + // sure directories exist. Skip repeated calls. + if b.mkdirCache[dir] { + return nil + } + b.mkdirCache[dir] = true + + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "mkdir -p %s", dir) + if cfg.BuildN { + return nil + } + } + + if err := os.MkdirAll(dir, 0777); err != nil { + return err + } + return nil +} + +// symlink creates a symlink newname -> oldname. +func (b *Builder) Symlink(oldname, newname string) error { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "ln -sf %s %s", oldname, newname) + if cfg.BuildN { + return nil + } + } + os.Remove(newname) + return os.Symlink(oldname, newname) +} + +// mkAbs returns an absolute path corresponding to +// evaluating f in the directory dir. +// We always pass absolute paths of source files so that +// the error messages will include the full path to a file +// in need of attention. +func mkAbs(dir, f string) string { + // Leave absolute paths alone. + // Also, during -n mode we use the pseudo-directory $WORK + // instead of creating an actual work directory that won't be used. + // Leave paths beginning with $WORK alone too. + if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") { + return f + } + return filepath.Join(dir, f) +} + +type toolchain interface { + // gc runs the compiler in a specific directory on a set of files + // and returns the name of the generated output file. + gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) + // cc runs the toolchain's C compiler in a directory on a C file + // to produce an output file. + cc(b *Builder, a *Action, ofile, cfile string) error + // asm runs the assembler in a specific directory on specific files + // and returns a list of named output files. + asm(b *Builder, a *Action, sfiles []string) ([]string, error) + // pack runs the archive packer in a specific directory to create + // an archive from a set of object files. + // typically it is run in the object directory. + pack(b *Builder, a *Action, afile string, ofiles []string) error + // ld runs the linker to create an executable starting at mainpkg. + ld(b *Builder, root *Action, out, importcfg, mainpkg string) error + // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions + ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error + + compiler() string + linker() string +} + +type noToolchain struct{} + +func noCompiler() error { + log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler) + return nil +} + +func (noToolchain) compiler() string { + noCompiler() + return "" +} + +func (noToolchain) linker() string { + noCompiler() + return "" +} + +func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) { + return "", nil, noCompiler() +} + +func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + return nil, noCompiler() +} + +func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + return noCompiler() +} + +func (noToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + return noCompiler() +} + +func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + return noCompiler() +} + +func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + return noCompiler() +} + +// gcc runs the gcc C compiler to create an object from a single C file. +func (b *Builder) gcc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error { + return b.ccompile(a, p, out, flags, cfile, b.GccCmd(p.Dir, workdir)) +} + +// gxx runs the g++ C++ compiler to create an object from a single C++ file. +func (b *Builder) gxx(a *Action, p *load.Package, workdir, out string, flags []string, cxxfile string) error { + return b.ccompile(a, p, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir)) +} + +// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. +func (b *Builder) gfortran(a *Action, p *load.Package, workdir, out string, flags []string, ffile string) error { + return b.ccompile(a, p, out, flags, ffile, b.gfortranCmd(p.Dir, workdir)) +} + +// ccompile runs the given C or C++ compiler and creates an object from a single source file. +func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error { + file = mkAbs(p.Dir, file) + desc := p.ImportPath + if !filepath.IsAbs(outfile) { + outfile = filepath.Join(p.Dir, outfile) + } + output, err := b.runOut(filepath.Dir(file), desc, nil, compiler, flags, "-o", outfile, "-c", filepath.Base(file)) + if len(output) > 0 { + // On FreeBSD 11, when we pass -g to clang 3.8 it + // invokes its internal assembler with -dwarf-version=2. + // When it sees .section .note.GNU-stack, it warns + // "DWARF2 only supports one section per compilation unit". + // This warning makes no sense, since the section is empty, + // but it confuses people. + // We work around the problem by detecting the warning + // and dropping -g and trying again. + if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) { + newFlags := make([]string, 0, len(flags)) + for _, f := range flags { + if !strings.HasPrefix(f, "-g") { + newFlags = append(newFlags, f) + } + } + if len(newFlags) < len(flags) { + return b.ccompile(a, p, outfile, newFlags, file, compiler) + } + } + + b.showOutput(a, p.Dir, desc, b.processOutput(output)) + if err != nil { + err = errPrintedOutput + } else if os.Getenv("GO_BUILDER_NAME") != "" { + return errors.New("C compiler warning promoted to error on Go builders") + } + } + return err +} + +// gccld runs the gcc linker to create an executable from a set of object files. +func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, objs []string) error { + var cmd []string + if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { + cmd = b.GxxCmd(p.Dir, objdir) + } else { + cmd = b.GccCmd(p.Dir, objdir) + } + return b.run(nil, p.Dir, p.ImportPath, nil, cmd, "-o", out, objs, flags) +} + +// Grab these before main helpfully overwrites them. +var ( + origCC = os.Getenv("CC") + origCXX = os.Getenv("CXX") +) + +// gccCmd returns a gcc command line prefix +// defaultCC is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) GccCmd(incdir, workdir string) []string { + return b.compilerCmd(b.ccExe(), incdir, workdir) +} + +// gxxCmd returns a g++ command line prefix +// defaultCXX is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) GxxCmd(incdir, workdir string) []string { + return b.compilerCmd(b.cxxExe(), incdir, workdir) +} + +// gfortranCmd returns a gfortran command line prefix. +func (b *Builder) gfortranCmd(incdir, workdir string) []string { + return b.compilerCmd(b.fcExe(), incdir, workdir) +} + +// ccExe returns the CC compiler setting without all the extra flags we add implicitly. +func (b *Builder) ccExe() []string { + return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch)) +} + +// cxxExe returns the CXX compiler setting without all the extra flags we add implicitly. +func (b *Builder) cxxExe() []string { + return b.compilerExe(origCXX, cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) +} + +// fcExe returns the FC compiler setting without all the extra flags we add implicitly. +func (b *Builder) fcExe() []string { + return b.compilerExe(os.Getenv("FC"), "gfortran") +} + +// compilerExe returns the compiler to use given an +// environment variable setting (the value not the name) +// and a default. The resulting slice is usually just the name +// of the compiler but can have additional arguments if they +// were present in the environment value. +// For example if CC="gcc -DGOPHER" then the result is ["gcc", "-DGOPHER"]. +func (b *Builder) compilerExe(envValue string, def string) []string { + compiler := strings.Fields(envValue) + if len(compiler) == 0 { + compiler = []string{def} + } + return compiler +} + +// compilerCmd returns a command line prefix for the given environment +// variable and using the default command when the variable is empty. +func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string { + // NOTE: env.go's mkEnv knows that the first three + // strings returned are "gcc", "-I", incdir (and cuts them off). + a := []string{compiler[0], "-I", incdir} + a = append(a, compiler[1:]...) + + // Definitely want -fPIC but on Windows gcc complains + // "-fPIC ignored for target (all code is position independent)" + if cfg.Goos != "windows" { + a = append(a, "-fPIC") + } + a = append(a, b.gccArchArgs()...) + // gcc-4.5 and beyond require explicit "-pthread" flag + // for multithreading with pthread library. + if cfg.BuildContext.CgoEnabled { + switch cfg.Goos { + case "windows": + a = append(a, "-mthreads") + default: + a = append(a, "-pthread") + } + } + + // disable ASCII art in clang errors, if possible + if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") { + a = append(a, "-fno-caret-diagnostics") + } + // clang is too smart about command-line arguments + if b.gccSupportsFlag(compiler, "-Qunused-arguments") { + a = append(a, "-Qunused-arguments") + } + + // disable word wrapping in error messages + a = append(a, "-fmessage-length=0") + + // Tell gcc not to include the work directory in object files. + if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { + if workdir == "" { + workdir = b.WorkDir + } + workdir = strings.TrimSuffix(workdir, string(filepath.Separator)) + a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build") + } + + // Tell gcc not to include flags in object files, which defeats the + // point of -fdebug-prefix-map above. + if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") { + a = append(a, "-gno-record-gcc-switches") + } + + // On OS X, some of the compilers behave as if -fno-common + // is always set, and the Mach-O linker in 6l/8l assumes this. + // See https://golang.org/issue/3253. + if cfg.Goos == "darwin" { + a = append(a, "-fno-common") + } + + // gccgo uses the language-independent exception mechanism to + // handle panics, so it always needs unwind tables. + if cfg.BuildToolchainName == "gccgo" { + a = append(a, "-funwind-tables") + } + + return a +} + +// gccNoPie returns the flag to use to request non-PIE. On systems +// with PIE (position independent executables) enabled by default, +// -no-pie must be passed when doing a partial link with -Wl,-r. +// But -no-pie is not supported by all compilers, and clang spells it -nopie. +func (b *Builder) gccNoPie(linker []string) string { + if b.gccSupportsFlag(linker, "-no-pie") { + return "-no-pie" + } + if b.gccSupportsFlag(linker, "-nopie") { + return "-nopie" + } + return "" +} + +// gccSupportsFlag checks to see if the compiler supports a flag. +func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool { + key := [2]string{compiler[0], flag} + + b.exec.Lock() + defer b.exec.Unlock() + if b, ok := b.flagCache[key]; ok { + return b + } + if b.flagCache == nil { + b.flagCache = make(map[[2]string]bool) + } + // We used to write an empty C file, but that gets complicated with + // go build -n. We tried using a file that does not exist, but that + // fails on systems with GCC version 4.2.1; that is the last GPLv2 + // version of GCC, so some systems have frozen on it. + // Now we pass an empty file on stdin, which should work at least for + // GCC and clang. + cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-") + if cfg.BuildN || cfg.BuildX { + b.Showcmd(b.WorkDir, "%s", joinUnambiguously(cmdArgs)) + if cfg.BuildN { + return false + } + } + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + cmd.Dir = b.WorkDir + cmd.Env = base.MergeEnvLists([]string{"LC_ALL=C"}, base.EnvForDir(cmd.Dir, os.Environ())) + out, _ := cmd.CombinedOutput() + // GCC says "unrecognized command line option". + // clang says "unknown argument". + // Older versions of GCC say "unrecognised debug output level". + supported := !bytes.Contains(out, []byte("unrecognized")) && + !bytes.Contains(out, []byte("unknown")) && + !bytes.Contains(out, []byte("unrecognised")) + b.flagCache[key] = supported + return supported +} + +// gccArchArgs returns arguments to pass to gcc based on the architecture. +func (b *Builder) gccArchArgs() []string { + switch cfg.Goarch { + case "386": + return []string{"-m32"} + case "amd64", "amd64p32": + return []string{"-m64"} + case "arm": + return []string{"-marm"} // not thumb + case "s390x": + return []string{"-m64", "-march=z196"} + case "mips64", "mips64le": + return []string{"-mabi=64"} + case "mips", "mipsle": + return []string{"-mabi=32", "-march=mips32"} + case "ppc64": + if cfg.Goos == "aix" { + return []string{"-maix64"} + } + } + return nil +} + +// envList returns the value of the given environment variable broken +// into fields, using the default value when the variable is empty. +func envList(key, def string) []string { + v := os.Getenv(key) + if v == "" { + v = def + } + return strings.Fields(v) +} + +// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. +func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { + defaults := "-g -O2" + + cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) + cflags = str.StringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) + cxxflags = str.StringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) + fflags = str.StringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS) + ldflags = str.StringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) + return +} + +var cgoRe = regexp.MustCompile(`[/\\:]`) + +func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { + p := a.Package + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.CFlags(p) + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) + cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) + // If we are compiling Objective-C code, then we need to link against libobjc + if len(mfiles) > 0 { + cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") + } + + // Likewise for Fortran, except there are many Fortran compilers. + // Support gfortran out of the box and let others pass the correct link options + // via CGO_LDFLAGS + if len(ffiles) > 0 { + fc := os.Getenv("FC") + if fc == "" { + fc = "gfortran" + } + if strings.Contains(fc, "gfortran") { + cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran") + } + } + + if cfg.BuildMSan { + cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) + cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) + } + + // Allows including _cgo_export.h from .[ch] files in the package. + cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir) + + // cgo + // TODO: CGO_FLAGS? + gofiles := []string{objdir + "_cgo_gotypes.go"} + cfiles := []string{"_cgo_export.c"} + for _, fn := range cgofiles { + f := strings.TrimSuffix(filepath.Base(fn), ".go") + gofiles = append(gofiles, objdir+f+".cgo1.go") + cfiles = append(cfiles, f+".cgo2.c") + } + + // TODO: make cgo not depend on $GOARCH? + + cgoflags := []string{} + if p.Standard && p.ImportPath == "runtime/cgo" { + cgoflags = append(cgoflags, "-import_runtime_cgo=false") + } + if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") { + cgoflags = append(cgoflags, "-import_syscall=false") + } + + // Update $CGO_LDFLAGS with p.CgoLDFLAGS. + var cgoenv []string + if len(cgoLDFLAGS) > 0 { + flags := make([]string, len(cgoLDFLAGS)) + for i, f := range cgoLDFLAGS { + flags[i] = strconv.Quote(f) + } + cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")} + } + + if cfg.BuildToolchainName == "gccgo" { + if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") { + cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") + } + cgoflags = append(cgoflags, "-gccgo") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath) + } + } + + switch cfg.BuildBuildmode { + case "c-archive", "c-shared": + // Tell cgo that if there are any exported functions + // it should generate a header file that C code can + // #include. + cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h") + } + + if err := b.run(a, p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil { + return nil, nil, err + } + outGo = append(outGo, gofiles...) + + // Use sequential object file names to keep them distinct + // and short enough to fit in the .a header file name slots. + // We no longer collect them all into _all.o, and we'd like + // tools to see both the .o suffix and unique names, so + // we need to make them short enough not to be truncated + // in the final archive. + oseq := 0 + nextOfile := func() string { + oseq++ + return objdir + fmt.Sprintf("_x%03d.o", oseq) + } + + // gcc + cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS) + for _, cfile := range cfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + for _, file := range gccfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS) + for _, file := range gxxfiles { + ofile := nextOfile() + if err := b.gxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + for _, file := range mfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS) + for _, file := range ffiles { + ofile := nextOfile() + if err := b.gfortran(a, p, a.Objdir, ofile, fflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + switch cfg.BuildToolchainName { + case "gc": + importGo := objdir + "_cgo_import.go" + if err := b.dynimport(a, p, objdir, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil { + return nil, nil, err + } + outGo = append(outGo, importGo) + + case "gccgo": + defunC := objdir + "_cgo_defun.c" + defunObj := objdir + "_cgo_defun.o" + if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil { + return nil, nil, err + } + outObj = append(outObj, defunObj) + + default: + noCompiler() + } + + return outGo, outObj, nil +} + +// dynimport creates a Go source file named importGo containing +// //go:cgo_import_dynamic directives for each symbol or library +// dynamically imported by the object files outObj. +func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { + cfile := objdir + "_cgo_main.c" + ofile := objdir + "_cgo_main.o" + if err := b.gcc(a, p, objdir, ofile, cflags, cfile); err != nil { + return err + } + + linkobj := str.StringList(ofile, outObj, p.SysoFiles) + dynobj := objdir + "_cgo_.o" + + // we need to use -pie for Linux/ARM to get accurate imported sym + ldflags := cgoLDFLAGS + if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" { + ldflags = append(ldflags, "-pie") + } + if err := b.gccld(p, objdir, dynobj, ldflags, linkobj); err != nil { + return err + } + + // cgo -dynimport + var cgoflags []string + if p.Standard && p.ImportPath == "runtime/cgo" { + cgoflags = []string{"-dynlinker"} // record path to dynamic linker + } + return b.run(a, p.Dir, p.ImportPath, nil, cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) +} + +// Run SWIG on all SWIG input files. +// TODO: Don't build a shared library, once SWIG emits the necessary +// pragmas for external linking. +func (b *Builder) swig(a *Action, p *load.Package, objdir string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { + if err := b.swigVersionCheck(); err != nil { + return nil, nil, nil, err + } + + intgosize, err := b.swigIntSize(objdir) + if err != nil { + return nil, nil, nil, err + } + + for _, f := range p.SwigFiles { + goFile, cFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, false, intgosize) + if err != nil { + return nil, nil, nil, err + } + if goFile != "" { + outGo = append(outGo, goFile) + } + if cFile != "" { + outC = append(outC, cFile) + } + } + for _, f := range p.SwigCXXFiles { + goFile, cxxFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, true, intgosize) + if err != nil { + return nil, nil, nil, err + } + if goFile != "" { + outGo = append(outGo, goFile) + } + if cxxFile != "" { + outCXX = append(outCXX, cxxFile) + } + } + return outGo, outC, outCXX, nil +} + +// Make sure SWIG is new enough. +var ( + swigCheckOnce sync.Once + swigCheck error +) + +func (b *Builder) swigDoVersionCheck() error { + out, err := b.runOut("", "", nil, "swig", "-version") + if err != nil { + return err + } + re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) + matches := re.FindSubmatch(out) + if matches == nil { + // Can't find version number; hope for the best. + return nil + } + + major, err := strconv.Atoi(string(matches[1])) + if err != nil { + // Can't find version number; hope for the best. + return nil + } + const errmsg = "must have SWIG version >= 3.0.6" + if major < 3 { + return errors.New(errmsg) + } + if major > 3 { + // 4.0 or later + return nil + } + + // We have SWIG version 3.x. + if len(matches[2]) > 0 { + minor, err := strconv.Atoi(string(matches[2][1:])) + if err != nil { + return nil + } + if minor > 0 { + // 3.1 or later + return nil + } + } + + // We have SWIG version 3.0.x. + if len(matches[3]) > 0 { + patch, err := strconv.Atoi(string(matches[3][1:])) + if err != nil { + return nil + } + if patch < 6 { + // Before 3.0.6. + return errors.New(errmsg) + } + } + + return nil +} + +func (b *Builder) swigVersionCheck() error { + swigCheckOnce.Do(func() { + swigCheck = b.swigDoVersionCheck() + }) + return swigCheck +} + +// Find the value to pass for the -intgosize option to swig. +var ( + swigIntSizeOnce sync.Once + swigIntSize string + swigIntSizeError error +) + +// This code fails to build if sizeof(int) <= 32 +const swigIntSizeCode = ` +package main +const i int = 1 << 32 +` + +// Determine the size of int on the target system for the -intgosize option +// of swig >= 2.0.9. Run only once. +func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) { + if cfg.BuildN { + return "$INTBITS", nil + } + src := filepath.Join(b.WorkDir, "swig_intsize.go") + if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil { + return + } + srcs := []string{src} + + p := load.GoFilesPackage(srcs) + + if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil { + return "32", nil + } + return "64", nil +} + +// Determine the size of int on the target system for the -intgosize option +// of swig >= 2.0.9. +func (b *Builder) swigIntSize(objdir string) (intsize string, err error) { + swigIntSizeOnce.Do(func() { + swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir) + }) + return swigIntSize, swigIntSizeError +} + +// Run SWIG on one SWIG input file. +func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.CFlags(p) + var cflags []string + if cxx { + cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) + } else { + cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) + } + + n := 5 // length of ".swig" + if cxx { + n = 8 // length of ".swigcxx" + } + base := file[:len(file)-n] + goFile := base + ".go" + gccBase := base + "_wrap." + gccExt := "c" + if cxx { + gccExt = "cxx" + } + + gccgo := cfg.BuildToolchainName == "gccgo" + + // swig + args := []string{ + "-go", + "-cgo", + "-intgosize", intgosize, + "-module", base, + "-o", objdir + gccBase + gccExt, + "-outdir", objdir, + } + + for _, f := range cflags { + if len(f) > 3 && f[:2] == "-I" { + args = append(args, f) + } + } + + if gccgo { + args = append(args, "-gccgo") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + args = append(args, "-go-pkgpath", pkgpath) + } + } + if cxx { + args = append(args, "-c++") + } + + out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file) + if err != nil { + if len(out) > 0 { + if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) { + return "", "", errors.New("must have SWIG version >= 3.0.6") + } + b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(out)) // swig error + return "", "", errPrintedOutput + } + return "", "", err + } + if len(out) > 0 { + b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(out)) // swig warning + } + + // If the input was x.swig, the output is x.go in the objdir. + // But there might be an x.go in the original dir too, and if it + // uses cgo as well, cgo will be processing both and will + // translate both into x.cgo1.go in the objdir, overwriting one. + // Rename x.go to _x_swig.go to avoid this problem. + // We ignore files in the original dir that begin with underscore + // so _x_swig.go cannot conflict with an original file we were + // going to compile. + goFile = objdir + goFile + newGoFile := objdir + "_" + base + "_swig.go" + if err := os.Rename(goFile, newGoFile); err != nil { + return "", "", err + } + return newGoFile, objdir + gccBase + gccExt, nil +} + +// disableBuildID adjusts a linker command line to avoid creating a +// build ID when creating an object file rather than an executable or +// shared library. Some systems, such as Ubuntu, always add +// --build-id to every link, but we don't want a build ID when we are +// producing an object file. On some of those system a plain -r (not +// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a +// plain -r. I don't know how to turn off --build-id when using clang +// other than passing a trailing --build-id=none. So that is what we +// do, but only on systems likely to support it, which is to say, +// systems that normally use gold or the GNU linker. +func (b *Builder) disableBuildID(ldflags []string) []string { + switch cfg.Goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + return ldflags +} + +// mkAbsFiles converts files into a list of absolute files, +// assuming they were originally relative to dir, +// and returns that new list. +func mkAbsFiles(dir string, files []string) []string { + abs := make([]string, len(files)) + for i, f := range files { + if !filepath.IsAbs(f) { + f = filepath.Join(dir, f) + } + abs[i] = f + } + return abs +} diff --git a/libgo/go/cmd/go/internal/work/gc.go b/libgo/go/cmd/go/internal/work/gc.go new file mode 100644 index 00000000000..49258b30fd0 --- /dev/null +++ b/libgo/go/cmd/go/internal/work/gc.go @@ -0,0 +1,500 @@ +// 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 work + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/internal/objabi" + "crypto/sha1" +) + +// The Go toolchain. + +type gcToolchain struct{} + +func (gcToolchain) compiler() string { + return base.Tool("compile") +} + +func (gcToolchain) linker() string { + return base.Tool("link") +} + +func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) { + p := a.Package + objdir := a.Objdir + if archive != "" { + ofile = archive + } else { + out := "_go_.o" + ofile = objdir + out + } + + pkgpath := p.ImportPath + if cfg.BuildBuildmode == "plugin" { + pkgpath = pluginPath(a) + } else if p.Name == "main" { + pkgpath = "main" + } + gcargs := []string{"-p", pkgpath} + if p.Standard { + gcargs = append(gcargs, "-std") + } + compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) + if compilingRuntime { + // runtime compiles with a special gc flag to emit + // additional reflect type data. + gcargs = append(gcargs, "-+") + } + + // If we're giving the compiler the entire package (no C etc files), tell it that, + // so that it can give good error messages about forward declarations. + // Exceptions: a few standard packages have forward declarations for + // pieces supplied behind-the-scenes by package runtime. + extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) + if p.Standard { + switch p.ImportPath { + case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "syscall", "time": + extFiles++ + } + } + if extFiles == 0 { + gcargs = append(gcargs, "-complete") + } + if cfg.BuildContext.InstallSuffix != "" { + gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix) + } + if a.buildID != "" { + gcargs = append(gcargs, "-buildid", a.buildID) + } + platform := cfg.Goos + "/" + cfg.Goarch + if p.Internal.OmitDebug || platform == "nacl/amd64p32" || platform == "darwin/arm" || platform == "darwin/arm64" || cfg.Goos == "plan9" { + gcargs = append(gcargs, "-dwarf=false") + } + if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") { + gcargs = append(gcargs, "-goversion", runtimeVersion) + } + + gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags) + if compilingRuntime { + // Remove -N, if present. + // It is not possible to build the runtime with no optimizations, + // because the compiler cannot eliminate enough write barriers. + for i := 0; i < len(gcflags); i++ { + if gcflags[i] == "-N" { + copy(gcflags[i:], gcflags[i+1:]) + gcflags = gcflags[:len(gcflags)-1] + i-- + } + } + } + + args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", trimDir(a.Objdir), gcflags, gcargs, "-D", p.Internal.LocalPrefix} + if importcfg != nil { + if err := b.writeFile(objdir+"importcfg", importcfg); err != nil { + return "", nil, err + } + args = append(args, "-importcfg", objdir+"importcfg") + } + if ofile == archive { + args = append(args, "-pack") + } + if asmhdr { + args = append(args, "-asmhdr", objdir+"go_asm.h") + } + + // Add -c=N to use concurrent backend compilation, if possible. + if c := gcBackendConcurrency(gcflags); c > 1 { + args = append(args, fmt.Sprintf("-c=%d", c)) + } + + for _, f := range gofiles { + args = append(args, mkAbs(p.Dir, f)) + } + + output, err = b.runOut(p.Dir, p.ImportPath, nil, args...) + return ofile, output, err +} + +// gcBackendConcurrency returns the backend compiler concurrency level for a package compilation. +func gcBackendConcurrency(gcflags []string) int { + // First, check whether we can use -c at all for this compilation. + canDashC := concurrentGCBackendCompilationEnabledByDefault + + switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e { + case "0": + canDashC = false + case "1": + canDashC = true + case "": + // Not set. Use default. + default: + log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e) + } + +CheckFlags: + for _, flag := range gcflags { + // Concurrent compilation is presumed incompatible with any gcflags, + // except for a small whitelist of commonly used flags. + // If the user knows better, they can manually add their own -c to the gcflags. + switch flag { + case "-N", "-l", "-S", "-B", "-C", "-I": + // OK + default: + canDashC = false + break CheckFlags + } + } + + // TODO: Test and delete these conditions. + if objabi.Fieldtrack_enabled != 0 || objabi.Preemptibleloops_enabled != 0 || objabi.Clobberdead_enabled != 0 { + canDashC = false + } + + if !canDashC { + return 1 + } + + // Decide how many concurrent backend compilations to allow. + // + // If we allow too many, in theory we might end up with p concurrent processes, + // each with c concurrent backend compiles, all fighting over the same resources. + // However, in practice, that seems not to happen too much. + // Most build graphs are surprisingly serial, so p==1 for much of the build. + // Furthermore, concurrent backend compilation is only enabled for a part + // of the overall compiler execution, so c==1 for much of the build. + // So don't worry too much about that interaction for now. + // + // However, in practice, setting c above 4 tends not to help very much. + // See the analysis in CL 41192. + // + // TODO(josharian): attempt to detect whether this particular compilation + // is likely to be a bottleneck, e.g. when: + // - it has no successor packages to compile (usually package main) + // - all paths through the build graph pass through it + // - critical path scheduling says it is high priority + // and in such a case, set c to runtime.NumCPU. + // We do this now when p==1. + if cfg.BuildP == 1 { + // No process parallelism. Max out c. + return runtime.NumCPU() + } + // Some process parallelism. Set c to min(4, numcpu). + c := 4 + if ncpu := runtime.NumCPU(); ncpu < c { + c = ncpu + } + return c +} + +func trimDir(dir string) string { + if len(dir) > 1 && dir[len(dir)-1] == filepath.Separator { + dir = dir[:len(dir)-1] + } + return dir +} + +func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + p := a.Package + // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. + inc := filepath.Join(cfg.GOROOT, "pkg", "include") + args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", trimDir(a.Objdir), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags} + if p.ImportPath == "runtime" && cfg.Goarch == "386" { + for _, arg := range forcedAsmflags { + if arg == "-dynlink" { + args = append(args, "-D=GOBUILDMODE_shared=1") + } + } + } + + if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" { + // Define GOMIPS_value from cfg.GOMIPS. + args = append(args, "-D", "GOMIPS_"+cfg.GOMIPS) + } + + var ofiles []string + for _, sfile := range sfiles { + ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + args1 := append(args, "-o", ofile, mkAbs(p.Dir, sfile)) + if err := b.run(a, p.Dir, p.ImportPath, nil, args1...); err != nil { + return nil, err + } + } + return ofiles, nil +} + +// toolVerify checks that the command line args writes the same output file +// if run using newTool instead. +// Unused now but kept around for future use. +func toolVerify(a *Action, b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error { + newArgs := make([]interface{}, len(args)) + copy(newArgs, args) + newArgs[1] = base.Tool(newTool) + newArgs[3] = ofile + ".new" // x.6 becomes x.6.new + if err := b.run(a, p.Dir, p.ImportPath, nil, newArgs...); err != nil { + return err + } + data1, err := ioutil.ReadFile(ofile) + if err != nil { + return err + } + data2, err := ioutil.ReadFile(ofile + ".new") + if err != nil { + return err + } + if !bytes.Equal(data1, data2) { + return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " ")) + } + os.Remove(ofile + ".new") + return nil +} + +func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + var absOfiles []string + for _, f := range ofiles { + absOfiles = append(absOfiles, mkAbs(a.Objdir, f)) + } + absAfile := mkAbs(a.Objdir, afile) + + // The archive file should have been created by the compiler. + // Since it used to not work that way, verify. + if !cfg.BuildN { + if _, err := os.Stat(absAfile); err != nil { + base.Fatalf("os.Stat of archive file failed: %v", err) + } + } + + p := a.Package + if cfg.BuildN || cfg.BuildX { + cmdline := str.StringList(base.Tool("pack"), "r", absAfile, absOfiles) + b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) + } + if cfg.BuildN { + return nil + } + if err := packInternal(b, absAfile, absOfiles); err != nil { + b.showOutput(a, p.Dir, p.ImportPath, err.Error()+"\n") + return errPrintedOutput + } + return nil +} + +func packInternal(b *Builder, afile string, ofiles []string) error { + dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0) + if err != nil { + return err + } + defer dst.Close() // only for error returns or panics + w := bufio.NewWriter(dst) + + for _, ofile := range ofiles { + src, err := os.Open(ofile) + if err != nil { + return err + } + fi, err := src.Stat() + if err != nil { + src.Close() + return err + } + // Note: Not using %-16.16s format because we care + // about bytes, not runes. + name := fi.Name() + if len(name) > 16 { + name = name[:16] + } else { + name += strings.Repeat(" ", 16-len(name)) + } + size := fi.Size() + fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n", + name, 0, 0, 0, 0644, size) + n, err := io.Copy(w, src) + src.Close() + if err == nil && n < size { + err = io.ErrUnexpectedEOF + } else if err == nil && n > size { + err = fmt.Errorf("file larger than size reported by stat") + } + if err != nil { + return fmt.Errorf("copying %s to %s: %v", ofile, afile, err) + } + if size&1 != 0 { + w.WriteByte(0) + } + } + + if err := w.Flush(); err != nil { + return err + } + return dst.Close() +} + +// setextld sets the appropriate linker flags for the specified compiler. +func setextld(ldflags []string, compiler []string) []string { + for _, f := range ldflags { + if f == "-extld" || strings.HasPrefix(f, "-extld=") { + // don't override -extld if supplied + return ldflags + } + } + ldflags = append(ldflags, "-extld="+compiler[0]) + if len(compiler) > 1 { + extldflags := false + add := strings.Join(compiler[1:], " ") + for i, f := range ldflags { + if f == "-extldflags" && i+1 < len(ldflags) { + ldflags[i+1] = add + " " + ldflags[i+1] + extldflags = true + break + } else if strings.HasPrefix(f, "-extldflags=") { + ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] + extldflags = true + break + } + } + if !extldflags { + ldflags = append(ldflags, "-extldflags="+add) + } + } + return ldflags +} + +// pluginPath computes the package path for a plugin main package. +// +// This is typically the import path of the main package p, unless the +// plugin is being built directly from source files. In that case we +// combine the package build ID with the contents of the main package +// source files. This allows us to identify two different plugins +// built from two source files with the same name. +func pluginPath(a *Action) string { + p := a.Package + if p.ImportPath != "command-line-arguments" { + return p.ImportPath + } + h := sha1.New() + fmt.Fprintf(h, "build ID: %s\n", a.buildID) + for _, file := range str.StringList(p.GoFiles, p.CgoFiles, p.SFiles) { + data, err := ioutil.ReadFile(filepath.Join(p.Dir, file)) + if err != nil { + base.Fatalf("go: %s", err) + } + h.Write(data) + } + return fmt.Sprintf("plugin/unnamed-%x", h.Sum(nil)) +} + +func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 + for _, a := range root.Deps { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { + cxx = true + } + } + var ldflags []string + if cfg.BuildContext.InstallSuffix != "" { + ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix) + } + if root.Package.Internal.OmitDebug { + ldflags = append(ldflags, "-s", "-w") + } + if cfg.BuildBuildmode == "plugin" { + ldflags = append(ldflags, "-pluginpath", pluginPath(root)) + } + + // TODO(rsc): This is probably wrong - see golang.org/issue/22155. + if cfg.GOROOT != runtime.GOROOT() { + ldflags = append(ldflags, "-X=runtime/internal/sys.DefaultGoroot="+cfg.GOROOT) + } + + // Store BuildID inside toolchain binaries as a unique identifier of the + // tool being run, for use by content-based staleness determination. + if root.Package.Goroot && strings.HasPrefix(root.Package.ImportPath, "cmd/") { + ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID) + } + + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + var compiler []string + if cxx { + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) + } else { + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + } + ldflags = append(ldflags, "-buildmode="+ldBuildmode) + if root.buildID != "" { + ldflags = append(ldflags, "-buildid="+root.buildID) + } + ldflags = append(ldflags, forcedLdflags...) + ldflags = append(ldflags, root.Package.Internal.Ldflags...) + ldflags = setextld(ldflags, compiler) + + // On OS X when using external linking to build a shared library, + // the argument passed here to -o ends up recorded in the final + // shared library in the LC_ID_DYLIB load command. + // To avoid putting the temporary output directory name there + // (and making the resulting shared library useless), + // run the link in the output directory so that -o can name + // just the final path element. + // On Windows, DLL file name is recorded in PE file + // export section, so do like on OS X. + dir := "." + if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" { + dir, out = filepath.Split(out) + } + + return b.run(root, dir, root.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags, mainpkg) +} + +func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix} + ldflags = append(ldflags, "-buildmode=shared") + ldflags = append(ldflags, forcedLdflags...) + ldflags = append(ldflags, root.Package.Internal.Ldflags...) + cxx := false + for _, a := range allactions { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { + cxx = true + } + } + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + var compiler []string + if cxx { + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) + } else { + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + } + ldflags = setextld(ldflags, compiler) + for _, d := range toplevelactions { + if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries + continue + } + ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target) + } + return b.run(root, ".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags) +} + +func (gcToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(a.Package.Dir, cfile)) +} diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go new file mode 100644 index 00000000000..9e42842e3f7 --- /dev/null +++ b/libgo/go/cmd/go/internal/work/gccgo.go @@ -0,0 +1,554 @@ +// 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 work + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" +) + +// The Gccgo toolchain. + +type gccgoToolchain struct{} + +var GccgoName, GccgoBin string +var gccgoErr error + +func init() { + GccgoName = os.Getenv("GCCGO") + if GccgoName == "" { + GccgoName = cfg.DefaultGCCGO(cfg.Goos, cfg.Goarch) + } + GccgoBin, gccgoErr = exec.LookPath(GccgoName) +} + +func (gccgoToolchain) compiler() string { + checkGccgoBin() + return GccgoBin +} + +func (gccgoToolchain) linker() string { + checkGccgoBin() + return GccgoBin +} + +func checkGccgoBin() { + if gccgoErr == nil { + return + } + fmt.Fprintf(os.Stderr, "cmd/go: gccgo: %s\n", gccgoErr) + os.Exit(2) +} + +func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) { + p := a.Package + objdir := a.Objdir + out := "_go_.o" + ofile = objdir + out + gcargs := []string{"-g"} + gcargs = append(gcargs, b.gccArchArgs()...) + gcargs = append(gcargs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") + gcargs = append(gcargs, "-gno-record-gcc-switches") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath) + } + if p.Internal.LocalPrefix != "" { + gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix) + } + + args := str.StringList(tools.compiler(), "-c", gcargs, "-o", ofile, forcedGccgoflags) + if importcfg != nil { + if b.gccSupportsFlag(args[:1], "-fgo-importcfg=/dev/null") { + if err := b.writeFile(objdir+"importcfg", importcfg); err != nil { + return "", nil, err + } + args = append(args, "-fgo-importcfg="+objdir+"importcfg") + } else { + root := objdir + "_importcfgroot_" + if err := buildImportcfgSymlinks(b, root, importcfg); err != nil { + return "", nil, err + } + args = append(args, "-I", root) + } + } + args = append(args, a.Package.Internal.Gccgoflags...) + for _, f := range gofiles { + args = append(args, mkAbs(p.Dir, f)) + } + + output, err = b.runOut(p.Dir, p.ImportPath, nil, args) + return ofile, output, err +} + +// buildImportcfgSymlinks builds in root a tree of symlinks +// implementing the directives from importcfg. +// This serves as a temporary transition mechanism until +// we can depend on gccgo reading an importcfg directly. +// (The Go 1.9 and later gc compilers already do.) +func buildImportcfgSymlinks(b *Builder, root string, importcfg []byte) error { + for lineNum, line := range strings.Split(string(importcfg), "\n") { + lineNum++ // 1-based + line = strings.TrimSpace(line) + if line == "" { + continue + } + if line == "" || strings.HasPrefix(line, "#") { + continue + } + var verb, args string + if i := strings.Index(line, " "); i < 0 { + verb = line + } else { + verb, args = line[:i], strings.TrimSpace(line[i+1:]) + } + var before, after string + if i := strings.Index(args, "="); i >= 0 { + before, after = args[:i], args[i+1:] + } + switch verb { + default: + base.Fatalf("importcfg:%d: unknown directive %q", lineNum, verb) + case "packagefile": + if before == "" || after == "" { + return fmt.Errorf(`importcfg:%d: invalid packagefile: syntax is "packagefile path=filename": %s`, lineNum, line) + } + archive := gccgoArchive(root, before) + if err := b.Mkdir(filepath.Dir(archive)); err != nil { + return err + } + if err := b.Symlink(after, archive); err != nil { + return err + } + case "importmap": + if before == "" || after == "" { + return fmt.Errorf(`importcfg:%d: invalid importmap: syntax is "importmap old=new": %s`, lineNum, line) + } + beforeA := gccgoArchive(root, before) + afterA := gccgoArchive(root, after) + if err := b.Mkdir(filepath.Dir(beforeA)); err != nil { + return err + } + if err := b.Mkdir(filepath.Dir(afterA)); err != nil { + return err + } + if err := b.Symlink(afterA, beforeA); err != nil { + return err + } + case "packageshlib": + return fmt.Errorf("gccgo -importcfg does not support shared libraries") + } + } + return nil +} + +func (tools gccgoToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + p := a.Package + var ofiles []string + for _, sfile := range sfiles { + base := filepath.Base(sfile) + ofile := a.Objdir + base[:len(base)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + sfile = mkAbs(p.Dir, sfile) + defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} + if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { + defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath) + } + defs = tools.maybePIC(defs) + defs = append(defs, b.gccArchArgs()...) + err := b.run(a, p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", a.Objdir, "-c", "-o", ofile, defs, sfile) + if err != nil { + return nil, err + } + } + return ofiles, nil +} + +func gccgoArchive(basedir, imp string) string { + end := filepath.FromSlash(imp + ".a") + afile := filepath.Join(basedir, end) + // add "lib" to the final element + return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile)) +} + +func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + p := a.Package + objdir := a.Objdir + var absOfiles []string + for _, f := range ofiles { + absOfiles = append(absOfiles, mkAbs(objdir, f)) + } + absAfile := mkAbs(objdir, afile) + // Try with D modifier first, then without if that fails. + if b.run(a, p.Dir, p.ImportPath, nil, "ar", "rcD", absAfile, absOfiles) != nil { + if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { + // AIX puts both 32-bit and 64-bit objects in the same archive. + // Tell the AIX "ar" command to only care about 64-bit objects. + // AIX "ar" command does not know D option. + return b.run(a, p.Dir, p.ImportPath, nil, "ar", "-X64", "rc", absAfile, absOfiles) + } else { + return b.run(a, p.Dir, p.ImportPath, nil, "ar", "rc", absAfile, absOfiles) + } + } + return nil +} + +func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error { + // gccgo needs explicit linking with all package dependencies, + // and all LDFLAGS from cgo dependencies. + apackagePathsSeen := make(map[string]bool) + afiles := []string{} + shlibs := []string{} + ldflags := b.gccArchArgs() + cgoldflags := []string{} + usesCgo := false + cxx := false + objc := false + fortran := false + if root.Package != nil { + cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 + objc = len(root.Package.MFiles) > 0 + fortran = len(root.Package.FFiles) > 0 + } + + readCgoFlags := func(flagsFile string) error { + flags, err := ioutil.ReadFile(flagsFile) + if err != nil { + return err + } + const ldflagsPrefix = "_CGO_LDFLAGS=" + for _, line := range strings.Split(string(flags), "\n") { + if strings.HasPrefix(line, ldflagsPrefix) { + line = line[len(ldflagsPrefix):] + quote := byte(0) + start := true + var nl []byte + for len(line) > 0 { + b := line[0] + line = line[1:] + if quote == 0 && (b == ' ' || b == '\t') { + if len(nl) > 0 { + cgoldflags = append(cgoldflags, string(nl)) + nl = nil + } + start = true + continue + } else if b == '"' || b == '\'' { + quote = b + } else if b == quote { + quote = 0 + } else if quote == 0 && start && b == '-' && strings.HasPrefix(line, "g") { + line = line[1:] + continue + } else if quote == 0 && start && b == '-' && strings.HasPrefix(line, "O") { + for len(line) > 0 && line[0] != ' ' && line[0] != '\t' { + line = line[1:] + } + continue + } + nl = append(nl, b) + start = false + } + } + } + return nil + } + + newID := 0 + readAndRemoveCgoFlags := func(archive string) (string, error) { + newID++ + newArchive := root.Objdir + fmt.Sprintf("_pkg%d_.a", newID) + if err := b.copyFile(root, newArchive, archive, 0666, false); err != nil { + return "", err + } + if cfg.BuildN { + // TODO(rsc): We could do better about showing the right _cgo_flags even in -n mode. + // Either the archive is already built and we can read them out, + // or we're printing commands to build the archive and can + // forward the _cgo_flags directly to this step. + b.Showcmd("", "ar d %s _cgo_flags", newArchive) + return "", nil + } + err := b.run(root, root.Objdir, desc, nil, "ar", "x", newArchive, "_cgo_flags") + if err != nil { + return "", err + } + err = b.run(root, ".", desc, nil, "ar", "d", newArchive, "_cgo_flags") + if err != nil { + return "", err + } + err = readCgoFlags(filepath.Join(root.Objdir, "_cgo_flags")) + if err != nil { + return "", err + } + return newArchive, nil + } + + actionsSeen := make(map[*Action]bool) + // Make a pre-order depth-first traversal of the action graph, taking note of + // whether a shared library action has been seen on the way to an action (the + // construction of the graph means that if any path to a node passes through + // a shared library action, they all do). + var walk func(a *Action, seenShlib bool) + var err error + walk = func(a *Action, seenShlib bool) { + if actionsSeen[a] { + return + } + actionsSeen[a] = true + if a.Package != nil && !seenShlib { + if a.Package.Standard { + return + } + // We record the target of the first time we see a .a file + // for a package to make sure that we prefer the 'install' + // rather than the 'build' location (which may not exist any + // more). We still need to traverse the dependencies of the + // build action though so saying + // if apackagePathsSeen[a.Package.ImportPath] { return } + // doesn't work. + if !apackagePathsSeen[a.Package.ImportPath] { + apackagePathsSeen[a.Package.ImportPath] = true + target := a.built + if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() { + target, err = readAndRemoveCgoFlags(target) + if err != nil { + return + } + } + afiles = append(afiles, target) + } + } + if strings.HasSuffix(a.Target, ".so") { + shlibs = append(shlibs, a.Target) + seenShlib = true + } + for _, a1 := range a.Deps { + walk(a1, seenShlib) + if err != nil { + return + } + } + } + for _, a1 := range root.Deps { + walk(a1, false) + if err != nil { + return err + } + } + + for _, a := range allactions { + // Gather CgoLDFLAGS, but not from standard packages. + // The go tool can dig up runtime/cgo from GOROOT and + // think that it should use its CgoLDFLAGS, but gccgo + // doesn't use runtime/cgo. + if a.Package == nil { + continue + } + if !a.Package.Standard { + cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...) + } + if len(a.Package.CgoFiles) > 0 { + usesCgo = true + } + if a.Package.UsesSwig() { + usesCgo = true + } + if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 { + cxx = true + } + if len(a.Package.MFiles) > 0 { + objc = true + } + if len(a.Package.FFiles) > 0 { + fortran = true + } + } + + ldflags = append(ldflags, "-Wl,--whole-archive") + ldflags = append(ldflags, afiles...) + ldflags = append(ldflags, "-Wl,--no-whole-archive") + + ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) + if root.Package != nil { + ldflags = append(ldflags, root.Package.CgoLDFLAGS...) + } + + ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)") + + if root.buildID != "" { + // On systems that normally use gold or the GNU linker, + // use the --build-id option to write a GNU build ID note. + switch cfg.Goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, fmt.Sprintf("-Wl,--build-id=0x%x", root.buildID)) + } + } + + for _, shlib := range shlibs { + ldflags = append( + ldflags, + "-L"+filepath.Dir(shlib), + "-Wl,-rpath="+filepath.Dir(shlib), + "-l"+strings.TrimSuffix( + strings.TrimPrefix(filepath.Base(shlib), "lib"), + ".so")) + } + + var realOut string + switch buildmode { + case "exe": + if usesCgo && cfg.Goos == "linux" { + ldflags = append(ldflags, "-Wl,-E") + } + + case "c-archive": + // Link the Go files into a single .o, and also link + // in -lgolibbegin. + // + // We need to use --whole-archive with -lgolibbegin + // because it doesn't define any symbols that will + // cause the contents to be pulled in; it's just + // initialization code. + // + // The user remains responsible for linking against + // -lgo -lpthread -lm in the final link. We can't use + // -r to pick them up because we can't combine + // split-stack and non-split-stack code in a single -r + // link, and libgo picks up non-split-stack code from + // libffi. + ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive") + + if nopie := b.gccNoPie([]string{tools.linker()}); nopie != "" { + ldflags = append(ldflags, nopie) + } + + // We are creating an object file, so we don't want a build ID. + if root.buildID == "" { + ldflags = b.disableBuildID(ldflags) + } + + realOut = out + out = out + ".o" + + case "c-shared": + ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc") + case "shared": + ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") + + case "pie": + ldflags = append(ldflags, "-pie") + + default: + base.Fatalf("-buildmode=%s not supported for gccgo", buildmode) + } + + switch buildmode { + case "exe", "c-shared": + if cxx { + ldflags = append(ldflags, "-lstdc++") + } + if objc { + ldflags = append(ldflags, "-lobjc") + } + if fortran { + fc := os.Getenv("FC") + if fc == "" { + fc = "gfortran" + } + // support gfortran out of the box and let others pass the correct link options + // via CGO_LDFLAGS + if strings.Contains(fc, "gfortran") { + ldflags = append(ldflags, "-lgfortran") + } + } + } + + if err := b.run(root, ".", desc, nil, tools.linker(), "-o", out, ldflags, forcedGccgoflags, root.Package.Internal.Gccgoflags); err != nil { + return err + } + + switch buildmode { + case "c-archive": + if err := b.run(root, ".", desc, nil, "ar", "rc", realOut, out); err != nil { + return err + } + } + return nil +} + +func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + return tools.link(b, root, out, importcfg, root.Deps, ldBuildmode, root.Package.ImportPath) +} + +func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + fakeRoot := *root + fakeRoot.Deps = toplevelactions + return tools.link(b, &fakeRoot, out, importcfg, allactions, "shared", out) +} + +func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + p := a.Package + inc := filepath.Join(cfg.GOROOT, "pkg", "include") + cfile = mkAbs(p.Dir, cfile) + defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} + defs = append(defs, b.gccArchArgs()...) + if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { + defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) + } + compiler := envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + if b.gccSupportsFlag(compiler, "-fsplit-stack") { + defs = append(defs, "-fsplit-stack") + } + defs = tools.maybePIC(defs) + if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { + defs = append(defs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") + } + if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") { + defs = append(defs, "-gno-record-gcc-switches") + } + return b.run(a, p.Dir, p.ImportPath, nil, compiler, "-Wall", "-g", + "-I", a.Objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) +} + +// maybePIC adds -fPIC to the list of arguments if needed. +func (tools gccgoToolchain) maybePIC(args []string) []string { + switch cfg.BuildBuildmode { + case "c-archive", "c-shared", "shared", "plugin": + args = append(args, "-fPIC") + } + return args +} + +func gccgoPkgpath(p *load.Package) string { + if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary { + return "" + } + if p.ImportPath == "main" && p.Internal.ForceLibrary { + return "testmain" + } + return p.ImportPath +} + +func gccgoCleanPkgpath(p *load.Package) string { + clean := func(r rune) rune { + switch { + case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', + '0' <= r && r <= '9': + return r + } + return '_' + } + return strings.Map(clean, gccgoPkgpath(p)) +} diff --git a/libgo/go/cmd/go/internal/work/init.go b/libgo/go/cmd/go/internal/work/init.go new file mode 100644 index 00000000000..c2beb3be6e7 --- /dev/null +++ b/libgo/go/cmd/go/internal/work/init.go @@ -0,0 +1,223 @@ +// Copyright 2017 The Go 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 initialization (after flag parsing). + +package work + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "flag" + "fmt" + "os" + "path/filepath" +) + +func BuildInit() { + instrumentInit() + buildModeInit() + + // Make sure -pkgdir is absolute, because we run commands + // in different directories. + if cfg.BuildPkgdir != "" && !filepath.IsAbs(cfg.BuildPkgdir) { + p, err := filepath.Abs(cfg.BuildPkgdir) + if err != nil { + fmt.Fprintf(os.Stderr, "go %s: evaluating -pkgdir: %v\n", flag.Args()[0], err) + os.Exit(2) + } + cfg.BuildPkgdir = p + } +} + +func instrumentInit() { + if !cfg.BuildRace && !cfg.BuildMSan { + return + } + if cfg.BuildRace && cfg.BuildMSan { + fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) + os.Exit(2) + } + if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64") { + fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) + os.Exit(2) + } + if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" { + fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + os.Exit(2) + } + + mode := "race" + if cfg.BuildMSan { + mode = "msan" + } + modeFlag := "-" + mode + + if !cfg.BuildContext.CgoEnabled { + fmt.Fprintf(os.Stderr, "go %s: %s requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0], modeFlag) + os.Exit(2) + } + forcedGcflags = append(forcedGcflags, modeFlag) + forcedLdflags = append(forcedLdflags, modeFlag) + + if cfg.BuildContext.InstallSuffix != "" { + cfg.BuildContext.InstallSuffix += "_" + } + cfg.BuildContext.InstallSuffix += mode + cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, mode) +} + +func buildModeInit() { + gccgo := cfg.BuildToolchainName == "gccgo" + var codegenArg string + platform := cfg.Goos + "/" + cfg.Goarch + switch cfg.BuildBuildmode { + case "archive": + pkgsFilter = pkgsNotMain + case "c-archive": + pkgsFilter = oneMainPkg + switch platform { + case "darwin/arm", "darwin/arm64": + codegenArg = "-shared" + default: + switch cfg.Goos { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + // Use -shared so that the result is + // suitable for inclusion in a PIE or + // shared library. + codegenArg = "-shared" + } + } + if gccgo { + codegenArg = "-fPIC" + } + cfg.ExeSuffix = ".a" + ldBuildmode = "c-archive" + case "c-shared": + pkgsFilter = oneMainPkg + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386": + codegenArg = "-shared" + case "darwin/amd64", "darwin/386": + case "windows/amd64", "windows/386": + // Do not add usual .exe suffix to the .dll file. + cfg.ExeSuffix = "" + default: + base.Fatalf("-buildmode=c-shared not supported on %s\n", platform) + } + } + ldBuildmode = "c-shared" + case "default": + switch platform { + case "android/arm", "android/arm64", "android/amd64", "android/386": + codegenArg = "-shared" + ldBuildmode = "pie" + case "darwin/arm", "darwin/arm64": + codegenArg = "-shared" + fallthrough + default: + ldBuildmode = "exe" + } + if gccgo { + codegenArg = "" + } + case "exe": + pkgsFilter = pkgsMain + ldBuildmode = "exe" + // Set the pkgsFilter to oneMainPkg if the user passed a specific binary output + // and is using buildmode=exe for a better error message. + // See issue #20017. + if cfg.BuildO != "" { + pkgsFilter = oneMainPkg + } + case "pie": + if cfg.BuildRace { + base.Fatalf("-buildmode=pie not supported when -race is enabled") + } + if gccgo { + codegenArg = "-fPIE" + } else { + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386": + codegenArg = "-shared" + case "darwin/amd64": + codegenArg = "-shared" + default: + base.Fatalf("-buildmode=pie not supported on %s\n", platform) + } + } + ldBuildmode = "pie" + case "shared": + pkgsFilter = pkgsNotMain + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": + default: + base.Fatalf("-buildmode=shared not supported on %s\n", platform) + } + codegenArg = "-dynlink" + } + if cfg.BuildO != "" { + base.Fatalf("-buildmode=shared and -o not supported together") + } + ldBuildmode = "shared" + case "plugin": + pkgsFilter = oneMainPkg + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le", + "android/amd64", "android/arm", "android/arm64", "android/386": + case "darwin/amd64": + // Skip DWARF generation due to #21647 + forcedLdflags = append(forcedLdflags, "-w") + default: + base.Fatalf("-buildmode=plugin not supported on %s\n", platform) + } + codegenArg = "-dynlink" + } + cfg.ExeSuffix = ".so" + ldBuildmode = "plugin" + default: + base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode) + } + if cfg.BuildLinkshared { + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": + forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1") + default: + base.Fatalf("-linkshared not supported on %s\n", platform) + } + codegenArg = "-dynlink" + // TODO(mwhudson): remove -w when that gets fixed in linker. + forcedLdflags = append(forcedLdflags, "-linkshared", "-w") + } + } + if codegenArg != "" { + if gccgo { + forcedGccgoflags = append([]string{codegenArg}, forcedGccgoflags...) + } else { + forcedAsmflags = append([]string{codegenArg}, forcedAsmflags...) + forcedGcflags = append([]string{codegenArg}, forcedGcflags...) + } + // Don't alter InstallSuffix when modifying default codegen args. + if cfg.BuildBuildmode != "default" || cfg.BuildLinkshared { + if cfg.BuildContext.InstallSuffix != "" { + cfg.BuildContext.InstallSuffix += "_" + } + cfg.BuildContext.InstallSuffix += codegenArg[1:] + } + } +} diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go index 794ce08b769..09147ee5f91 100644 --- a/libgo/go/cmd/go/main.go +++ b/libgo/go/cmd/go/main.go @@ -77,6 +77,7 @@ func main() { base.Usage() } + cfg.CmdName = args[0] // for error messages if args[0] == "help" { help.Help(args[1:]) return @@ -89,6 +90,11 @@ func main() { fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) } else { for _, p := range filepath.SplitList(gopath) { + // Some GOPATHs have empty directory elements - ignore them. + // See issue 21928 for details. + if p == "" { + continue + } // Note: using HasPrefix instead of Contains because a ~ can appear // in the middle of directory elements, such as /tmp/git-1.8.2~rc3 // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell. diff --git a/libgo/go/cmd/go/note_test.go b/libgo/go/cmd/go/note_test.go index f33efdce226..7ef4c641d7d 100644 --- a/libgo/go/cmd/go/note_test.go +++ b/libgo/go/cmd/go/note_test.go @@ -11,33 +11,19 @@ import ( "runtime" "testing" - "cmd/go/internal/buildid" + "cmd/internal/buildid" ) func TestNoteReading(t *testing.T) { - testNoteReading(t) -} - -func TestNoteReading2K(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skipf("2kB is not enough on %s", runtime.GOOS) - } - // Set BuildIDReadSize to 2kB to exercise Mach-O parsing more strictly. - defer func(old int) { - buildid.BuildIDReadSize = old - }(buildid.BuildIDReadSize) - buildid.BuildIDReadSize = 2 * 1024 - - testNoteReading(t) -} - -func testNoteReading(t *testing.T) { + // cmd/internal/buildid already has tests that the basic reading works. + // This test is essentially checking that -ldflags=-buildid=XXX works, + // both in internal and external linking mode. tg := testgo(t) defer tg.cleanup() tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`) const buildID = "TestNoteReading-Build-ID" tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go")) - id, err := buildid.ReadBuildIDFromBinary(tg.path("hello.exe")) + id, err := buildid.ReadFile(tg.path("hello.exe")) if err != nil { t.Fatalf("reading build ID from hello binary: %v", err) } @@ -48,20 +34,41 @@ func testNoteReading(t *testing.T) { switch { case !build.Default.CgoEnabled: t.Skipf("skipping - no cgo, so assuming external linking not available") - case runtime.GOOS == "linux" && (runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"): - t.Skipf("skipping - external linking not supported, golang.org/issue/11184") case runtime.GOOS == "openbsd" && runtime.GOARCH == "arm": t.Skipf("skipping - external linking not supported, golang.org/issue/10619") case runtime.GOOS == "plan9": t.Skipf("skipping - external linking not supported") } - tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go")) - id, err = buildid.ReadBuildIDFromBinary(tg.path("hello.exe")) + tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello2.exe"), tg.path("hello.go")) + id, err = buildid.ReadFile(tg.path("hello2.exe")) if err != nil { t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err) } if id != buildID { t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID) } + + switch runtime.GOOS { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd": + // Test while forcing use of the gold linker, since in the past + // we've had trouble reading the notes generated by gold. + err := tg.doRun([]string{"build", "-ldflags", "-buildid=" + buildID + " -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello3.exe"), tg.path("hello.go")}) + if err != nil { + if tg.grepCountBoth("(invalid linker|gold|cannot find 'ld')") > 0 { + // It's not an error if gold isn't there. gcc claims it "cannot find 'ld'" if + // ld.gold is missing, see issue #22340. + t.Log("skipping gold test") + break + } + t.Fatalf("building hello binary: %v", err) + } + id, err = buildid.ReadFile(tg.path("hello3.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary (linkmode=external -extldflags=-fuse-ld=gold): %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external -extldflags=-fuse-ld=gold)", id, buildID) + } + } } diff --git a/libgo/go/cmd/go/testdata/print_goroot.go b/libgo/go/cmd/go/testdata/print_goroot.go new file mode 100644 index 00000000000..54772910609 --- /dev/null +++ b/libgo/go/cmd/go/testdata/print_goroot.go @@ -0,0 +1,11 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "runtime" + +func main() { + println(runtime.GOROOT()) +} diff --git a/libgo/go/cmd/go/testdata/src/complex/main.go b/libgo/go/cmd/go/testdata/src/complex/main.go new file mode 100644 index 00000000000..c38df019480 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/main.go @@ -0,0 +1,12 @@ +package main + +import ( + _ "complex/nest/sub/test12" + _ "complex/nest/sub/test23" + "complex/w" + "v" +) + +func main() { + println(v.Hello + " " + w.World) +} diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go new file mode 100644 index 00000000000..94943ec1bbe --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go @@ -0,0 +1,11 @@ +package test12 + +// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v1" + "v2" +) + +const x = v1.ComplexNestVendorV1 +const y = v2.ComplexNestSubVendorV2 diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go new file mode 100644 index 00000000000..8801a4812af --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go @@ -0,0 +1,11 @@ +package test23 + +// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v2" + "v3" +) + +const x = v3.ComplexNestVendorV3 +const y = v2.ComplexNestSubVendorV2 diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go new file mode 100644 index 00000000000..2991871710e --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go @@ -0,0 +1,3 @@ +package v2 + +const ComplexNestSubVendorV2 = true diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go new file mode 100644 index 00000000000..a55f5290a9a --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go @@ -0,0 +1,3 @@ +package v1 + +const ComplexNestVendorV1 = true diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go new file mode 100644 index 00000000000..ac94def4e3e --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go @@ -0,0 +1,3 @@ +package v2 + +const ComplexNestVendorV2 = true diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go new file mode 100644 index 00000000000..abf99b95745 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go @@ -0,0 +1,3 @@ +package v3 + +const ComplexNestVendorV3 = true diff --git a/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go b/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go new file mode 100644 index 00000000000..bb20d86f25a --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go @@ -0,0 +1,3 @@ +package v + +const Hello = "hello" diff --git a/libgo/go/cmd/go/testdata/src/complex/w/w.go b/libgo/go/cmd/go/testdata/src/complex/w/w.go new file mode 100644 index 00000000000..a9c7fbb3094 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/complex/w/w.go @@ -0,0 +1,3 @@ +package w + +const World = "world" diff --git a/libgo/go/cmd/go/testdata/src/coverasm/p.go b/libgo/go/cmd/go/testdata/src/coverasm/p.go new file mode 100644 index 00000000000..ab0c300d723 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverasm/p.go @@ -0,0 +1,7 @@ +package p + +func f() + +func g() { + println("g") +} diff --git a/libgo/go/cmd/go/testdata/src/coverasm/p.s b/libgo/go/cmd/go/testdata/src/coverasm/p.s new file mode 100644 index 00000000000..5e728f9946d --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverasm/p.s @@ -0,0 +1,2 @@ +// empty asm file, +// so go test doesn't complain about declaration of f in p.go. diff --git a/libgo/go/cmd/go/testdata/src/coverasm/p_test.go b/libgo/go/cmd/go/testdata/src/coverasm/p_test.go new file mode 100644 index 00000000000..3cb3bd5664b --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverasm/p_test.go @@ -0,0 +1,7 @@ +package p + +import "testing" + +func Test(t *testing.T) { + g() +} diff --git a/libgo/go/cmd/go/testdata/src/coverbad/p.go b/libgo/go/cmd/go/testdata/src/coverbad/p.go new file mode 100644 index 00000000000..16504a401eb --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverbad/p.go @@ -0,0 +1,5 @@ +package p + +func f() { + g() +} diff --git a/libgo/go/cmd/go/testdata/src/coverbad/p1.go b/libgo/go/cmd/go/testdata/src/coverbad/p1.go new file mode 100644 index 00000000000..2d25c8e1908 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverbad/p1.go @@ -0,0 +1,7 @@ +package p + +import "C" + +func h() { + j() +} diff --git a/libgo/go/cmd/go/testdata/src/coverbad/p_test.go b/libgo/go/cmd/go/testdata/src/coverbad/p_test.go new file mode 100644 index 00000000000..3a876d6296c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverbad/p_test.go @@ -0,0 +1,5 @@ +package p + +import "testing" + +func Test(t *testing.T) {} diff --git a/libgo/go/cmd/go/testdata/src/coverdep/p.go b/libgo/go/cmd/go/testdata/src/coverdep/p.go new file mode 100644 index 00000000000..6baf6d5f0c7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverdep/p.go @@ -0,0 +1,6 @@ +package p + +import _ "coverdep/p1" + +func F() { +} diff --git a/libgo/go/cmd/go/testdata/src/coverdep/p1/p1.go b/libgo/go/cmd/go/testdata/src/coverdep/p1/p1.go new file mode 100644 index 00000000000..8ae793d55d7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverdep/p1/p1.go @@ -0,0 +1,3 @@ +package p1 + +import _ "errors" diff --git a/libgo/go/cmd/go/testdata/src/coverdep/p_test.go b/libgo/go/cmd/go/testdata/src/coverdep/p_test.go new file mode 100644 index 00000000000..11a14343ea9 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/coverdep/p_test.go @@ -0,0 +1,7 @@ +package p + +import "testing" + +func Test(t *testing.T) { + F() +} diff --git a/libgo/go/cmd/go/testdata/src/failfast_test.go b/libgo/go/cmd/go/testdata/src/failfast_test.go new file mode 100644 index 00000000000..fef4d2a35e1 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/failfast_test.go @@ -0,0 +1,54 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package failfast + +import "testing" + +func TestA(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestFailingA(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) +} + +func TestB(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestParallelFailingA(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingB(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingSubtestsA(t *testing.T) { + t.Parallel() + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +func TestFailingSubtestsA(t *testing.T) { + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +func TestFailingB(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) +} diff --git a/libgo/go/cmd/go/testdata/src/multimain/multimain_test.go b/libgo/go/cmd/go/testdata/src/multimain/multimain_test.go new file mode 100644 index 00000000000..007a86a5da8 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/multimain/multimain_test.go @@ -0,0 +1,16 @@ +package multimain_test + +import "testing" + +func TestMain(m *testing.M) { + // Some users run m.Run multiple times, changing + // some kind of global state between runs. + // This used to work so I guess now it has to keep working. + // See golang.org/issue/23129. + m.Run() + m.Run() +} + +func Test(t *testing.T) { + t.Log("notwithstanding") +} diff --git a/libgo/go/cmd/go/testdata/src/not_main/not_main.go b/libgo/go/cmd/go/testdata/src/not_main/not_main.go new file mode 100644 index 00000000000..75a397c6cba --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/not_main/not_main.go @@ -0,0 +1,3 @@ +package not_main + +func F() {} diff --git a/libgo/go/cmd/go/testdata/src/skipper/skip_test.go b/libgo/go/cmd/go/testdata/src/skipper/skip_test.go new file mode 100644 index 00000000000..58e6dc505b7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/skipper/skip_test.go @@ -0,0 +1,7 @@ +package skipper + +import "testing" + +func Test(t *testing.T) { + t.Skip("skipping") +} diff --git a/libgo/go/cmd/go/testdata/src/sleepy1/p_test.go b/libgo/go/cmd/go/testdata/src/sleepy1/p_test.go new file mode 100644 index 00000000000..333be7d8e4c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/sleepy1/p_test.go @@ -0,0 +1,10 @@ +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} diff --git a/libgo/go/cmd/go/testdata/src/sleepy2/p_test.go b/libgo/go/cmd/go/testdata/src/sleepy2/p_test.go new file mode 100644 index 00000000000..333be7d8e4c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/sleepy2/p_test.go @@ -0,0 +1,10 @@ +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} diff --git a/libgo/go/cmd/go/testdata/src/sleepybad/p.go b/libgo/go/cmd/go/testdata/src/sleepybad/p.go new file mode 100644 index 00000000000..e05b403e392 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/sleepybad/p.go @@ -0,0 +1,5 @@ +package p + +// missing import + +var _ = io.DoesNotExist diff --git a/libgo/go/cmd/go/testdata/src/testcache/testcache_test.go b/libgo/go/cmd/go/testdata/src/testcache/testcache_test.go new file mode 100644 index 00000000000..9b2d1ea7824 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcache/testcache_test.go @@ -0,0 +1,91 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testcache + +import ( + "io/ioutil" + "os" + "runtime" + "testing" +) + +func TestChdir(t *testing.T) { + os.Chdir("..") + defer os.Chdir("testcache") + info, err := os.Stat("testcache/file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileContent(t *testing.T) { + f, err := os.Open("file.txt") + if err != nil { + t.Fatal(err) + } + data, err := ioutil.ReadAll(f) + f.Close() + if err != nil { + t.Fatal(err) + } + if len(data)%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileSize(t *testing.T) { + info, err := os.Stat("file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddGetenv(t *testing.T) { + val := os.Getenv("TESTKEY") + if len(val)%2 != 1 { + t.Fatal("even env value") + } +} + +func TestLookupEnv(t *testing.T) { + _, ok := os.LookupEnv("TESTKEY") + if !ok { + t.Fatal("env missing") + } +} + +func TestDirList(t *testing.T) { + f, err := os.Open(".") + if err != nil { + t.Fatal(err) + } + f.Readdirnames(-1) + f.Close() +} + +func TestExec(t *testing.T) { + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" || runtime.GOOS == "nacl" { + t.Skip("non-unix") + } + + // Note: not using os/exec to make sure there is no unexpected stat. + p, err := os.StartProcess("./script.sh", []string{"script"}, new(os.ProcAttr)) + if err != nil { + t.Fatal(err) + } + ps, err := p.Wait() + if err != nil { + t.Fatal(err) + } + if !ps.Success() { + t.Fatalf("script failed: %v", err) + } +} diff --git a/libgo/go/cmd/go/testdata/src/testrace/race_test.go b/libgo/go/cmd/go/testdata/src/testrace/race_test.go index 264dcf0d8a0..7ec0c6d17a3 100644 --- a/libgo/go/cmd/go/testdata/src/testrace/race_test.go +++ b/libgo/go/cmd/go/testdata/src/testrace/race_test.go @@ -12,6 +12,7 @@ func TestRace(t *testing.T) { }() x = 3 <-c + _ = x } } @@ -25,5 +26,6 @@ func BenchmarkRace(b *testing.B) { }() x = 3 <-c + _ = x } } diff --git a/libgo/go/cmd/go/testdata/src/vetcycle/p.go b/libgo/go/cmd/go/testdata/src/vetcycle/p.go new file mode 100644 index 00000000000..5b058e7806e --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vetcycle/p.go @@ -0,0 +1,13 @@ +package p + +type ( + _ interface{ m(B1) } + A1 interface{ a(D1) } + B1 interface{ A1 } + C1 interface { + B1 /* ERROR issue #18395 */ + } + D1 interface{ C1 } +) + +var _ A1 = C1 /* ERROR cannot use C1 */ (nil) diff --git a/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go b/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go new file mode 100644 index 00000000000..248317b779a --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import "fmt" + +func F() { + fmt.Printf("%d", "hello") // causes vet error +} diff --git a/libgo/go/cmd/go/testdata/src/vetfail/p2/p2.go b/libgo/go/cmd/go/testdata/src/vetfail/p2/p2.go new file mode 100644 index 00000000000..88b1cc23736 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vetfail/p2/p2.go @@ -0,0 +1,6 @@ +package p2 + +import _ "vetfail/p1" + +func F() { +} diff --git a/libgo/go/cmd/go/testdata/src/vetfail/p2/p2_test.go b/libgo/go/cmd/go/testdata/src/vetfail/p2/p2_test.go new file mode 100644 index 00000000000..fde0d1a73f3 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vetfail/p2/p2_test.go @@ -0,0 +1,7 @@ +package p2 + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/libgo/go/cmd/go/testdata/standalone_main_normal_test.go b/libgo/go/cmd/go/testdata/standalone_main_normal_test.go new file mode 100644 index 00000000000..018ce75b2e3 --- /dev/null +++ b/libgo/go/cmd/go/testdata/standalone_main_normal_test.go @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_main_normal_test + +import "testing" + +func TestMain(t *testing.T) { +} diff --git a/libgo/go/cmd/go/testdata/standalone_main_wrong_test.go b/libgo/go/cmd/go/testdata/standalone_main_wrong_test.go new file mode 100644 index 00000000000..59998873f94 --- /dev/null +++ b/libgo/go/cmd/go/testdata/standalone_main_wrong_test.go @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package standalone_main_wrong_test + +import "testing" + +func TestMain(m *testing.Main) { +} diff --git a/libgo/go/cmd/go/internal/buildid/buildid.go b/libgo/go/cmd/internal/buildid/buildid.go similarity index 62% rename from libgo/go/cmd/go/internal/buildid/buildid.go rename to libgo/go/cmd/internal/buildid/buildid.go index 091c9090c86..fa3d7f37ec6 100644 --- a/libgo/go/cmd/go/internal/buildid/buildid.go +++ b/libgo/go/cmd/internal/buildid/buildid.go @@ -6,7 +6,7 @@ package buildid import ( "bytes" - "cmd/go/internal/cfg" + "debug/elf" "fmt" "io" "os" @@ -27,23 +27,20 @@ var ( buildid = []byte("build id ") ) -// ReadBuildID reads the build ID from an archive or binary. -// It only supports the gc toolchain. -// Other toolchain maintainers should adjust this function. -func ReadBuildID(name, target string) (id string, err error) { - if cfg.BuildToolchainName != "gc" { - return "", errBuildIDToolchain +// ReadFile reads the build ID from an archive or executable file. +func ReadFile(name string) (id string, err error) { + f, err := os.Open(name) + if err != nil { + return "", err } + defer f.Close() - // For commands, read build ID directly from binary. - if name == "main" { - return ReadBuildIDFromBinary(target) + buf := make([]byte, 8) + if _, err := f.ReadAt(buf, 0); err != nil { + return "", err } - - // Otherwise, we expect to have an archive (.a) file, - // and we can read the build ID from the Go export data. - if !strings.HasSuffix(target, ".a") { - return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDUnknown} + if string(buf) != "!\n" { + return readBinary(name, f) } // Read just enough of the target to fetch the build ID. @@ -56,42 +53,36 @@ func ReadBuildID(name, target string) (id string, err error) { // // The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none). // Reading the first 1024 bytes should be plenty. - f, err := os.Open(target) - if err != nil { - return "", err - } data := make([]byte, 1024) n, err := io.ReadFull(f, data) - f.Close() - if err != nil && n == 0 { return "", err } - bad := func() (string, error) { - return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDMalformed} + tryGccgo := func() (string, error) { + return readGccgoArchive(name, f) } // Archive header. for i := 0; ; i++ { // returns during i==3 j := bytes.IndexByte(data, '\n') if j < 0 { - return bad() + return tryGccgo() } line := data[:j] data = data[j+1:] switch i { case 0: if !bytes.Equal(line, bangArch) { - return bad() + return tryGccgo() } case 1: if !bytes.HasPrefix(line, pkgdef) { - return bad() + return tryGccgo() } case 2: if !bytes.HasPrefix(line, goobject) { - return bad() + return tryGccgo() } case 3: if !bytes.HasPrefix(line, buildid) { @@ -101,13 +92,71 @@ func ReadBuildID(name, target string) (id string, err error) { } id, err := strconv.Unquote(string(line[len(buildid):])) if err != nil { - return bad() + return tryGccgo() } return id, nil } } } +// readGccgoArchive tries to parse the archive as a standard Unix +// archive file, and fetch the build ID from the _buildid.o entry. +// The _buildid.o entry is written by (*Builder).gccgoBuildIDELFFile +// in cmd/go/internal/work/exec.go. +func readGccgoArchive(name string, f *os.File) (string, error) { + bad := func() (string, error) { + return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed} + } + + off := int64(8) + for { + if _, err := f.Seek(off, io.SeekStart); err != nil { + return "", err + } + + // TODO(iant): Make a debug/ar package, and use it + // here and in cmd/link. + var hdr [60]byte + if _, err := io.ReadFull(f, hdr[:]); err != nil { + if err == io.EOF { + // No more entries, no build ID. + return "", nil + } + return "", err + } + off += 60 + + sizeStr := strings.TrimSpace(string(hdr[48:58])) + size, err := strconv.ParseInt(sizeStr, 0, 64) + if err != nil { + return bad() + } + + name := strings.TrimSpace(string(hdr[:16])) + if name == "_buildid.o/" { + sr := io.NewSectionReader(f, off, size) + e, err := elf.NewFile(sr) + if err != nil { + return bad() + } + s := e.Section(".go.buildid") + if s == nil { + return bad() + } + data, err := s.Data() + if err != nil { + return bad() + } + return string(data), nil + } + + off += size + if off&1 != 0 { + off++ + } + } +} + var ( goBuildPrefix = []byte("\xff Go build ID: \"") goBuildEnd = []byte("\"\n \xff") @@ -122,9 +171,9 @@ var ( } ) -var BuildIDReadSize = 32 * 1024 // changed for testing +var readSize = 32 * 1024 // changed for testing -// ReadBuildIDFromBinary reads the build ID from a binary. +// readBinary reads the build ID from a binary. // // ELF binaries store the build ID in a proper PT_NOTE section. // @@ -133,11 +182,7 @@ var BuildIDReadSize = 32 * 1024 // changed for testing // of the text segment, which should appear near the beginning // of the file. This is clumsy but fairly portable. Custom locations // can be added for other binary types as needed, like we did for ELF. -func ReadBuildIDFromBinary(filename string) (id string, err error) { - if filename == "" { - return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown} - } - +func readBinary(name string, f *os.File) (id string, err error) { // Read the first 32 kB of the binary file. // That should be enough to find the build ID. // In ELF files, the build ID is in the leading headers, @@ -151,13 +196,7 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) { // Plan 9: 0x20 // Windows: 0x600 // - f, err := os.Open(filename) - if err != nil { - return "", err - } - defer f.Close() - - data := make([]byte, BuildIDReadSize) + data := make([]byte, readSize) _, err = io.ReadFull(f, data) if err == io.ErrUnexpectedEOF { err = nil @@ -167,19 +206,18 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) { } if bytes.HasPrefix(data, elfPrefix) { - return readELFGoBuildID(filename, f, data) + return readELF(name, f, data) } for _, m := range machoPrefixes { if bytes.HasPrefix(data, m) { - return readMachoGoBuildID(filename, f, data) + return readMacho(name, f, data) } } - - return readRawGoBuildID(filename, data) + return readRaw(name, data) } -// readRawGoBuildID finds the raw build ID stored in text segment data. -func readRawGoBuildID(filename string, data []byte) (id string, err error) { +// readRaw finds the raw build ID stored in text segment data. +func readRaw(name string, data []byte) (id string, err error) { i := bytes.Index(data, goBuildPrefix) if i < 0 { // Missing. Treat as successful but build ID empty. @@ -188,14 +226,13 @@ func readRawGoBuildID(filename string, data []byte) (id string, err error) { j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd) if j < 0 { - return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} + return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed} } quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1] id, err = strconv.Unquote(string(quoted)) if err != nil { - return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} + return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed} } - return id, nil } diff --git a/libgo/go/cmd/internal/buildid/buildid_test.go b/libgo/go/cmd/internal/buildid/buildid_test.go new file mode 100644 index 00000000000..15481dd7623 --- /dev/null +++ b/libgo/go/cmd/internal/buildid/buildid_test.go @@ -0,0 +1,137 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buildid + +import ( + "bytes" + "crypto/sha256" + "io/ioutil" + "os" + "reflect" + "testing" +) + +const ( + expectedID = "abcdefghijklmnopqrstuvwxyz.1234567890123456789012345678901234567890123456789012345678901234" + newID = "bcdefghijklmnopqrstuvwxyza.2345678901234567890123456789012345678901234567890123456789012341" +) + +func TestReadFile(t *testing.T) { + var files = []string{ + "p.a", + "a.elf", + "a.macho", + "a.pe", + } + + f, err := ioutil.TempFile("", "buildid-test-") + if err != nil { + t.Fatal(err) + } + tmp := f.Name() + defer os.Remove(tmp) + f.Close() + + for _, f := range files { + id, err := ReadFile("testdata/" + f) + if id != expectedID || err != nil { + t.Errorf("ReadFile(testdata/%s) = %q, %v, want %q, nil", f, id, err, expectedID) + } + old := readSize + readSize = 2048 + id, err = ReadFile("testdata/" + f) + readSize = old + if id != expectedID || err != nil { + t.Errorf("ReadFile(testdata/%s) [readSize=2k] = %q, %v, want %q, nil", f, id, err, expectedID) + } + + data, err := ioutil.ReadFile("testdata/" + f) + if err != nil { + t.Fatal(err) + } + m, _, err := FindAndHash(bytes.NewReader(data), expectedID, 1024) + if err != nil { + t.Errorf("FindAndHash(testdata/%s): %v", f, err) + continue + } + if err := ioutil.WriteFile(tmp, data, 0666); err != nil { + t.Error(err) + continue + } + tf, err := os.OpenFile(tmp, os.O_WRONLY, 0) + if err != nil { + t.Error(err) + continue + } + err = Rewrite(tf, m, newID) + err2 := tf.Close() + if err != nil { + t.Errorf("Rewrite(testdata/%s): %v", f, err) + continue + } + if err2 != nil { + t.Fatal(err2) + } + + id, err = ReadFile(tmp) + if id != newID || err != nil { + t.Errorf("ReadFile(testdata/%s after Rewrite) = %q, %v, want %q, nil", f, id, err, newID) + } + } +} + +func TestFindAndHash(t *testing.T) { + buf := make([]byte, 64) + buf2 := make([]byte, 64) + id := make([]byte, 8) + zero := make([]byte, 8) + for i := range id { + id[i] = byte(i) + } + numError := 0 + errorf := func(msg string, args ...interface{}) { + t.Errorf(msg, args...) + if numError++; numError > 20 { + t.Logf("stopping after too many errors") + t.FailNow() + } + } + for bufSize := len(id); bufSize <= len(buf); bufSize++ { + for j := range buf { + for k := 0; k < 2*len(id) && j+k < len(buf); k++ { + for i := range buf { + buf[i] = 1 + } + copy(buf[j:], id) + copy(buf[j+k:], id) + var m []int64 + if j+len(id) <= j+k { + m = append(m, int64(j)) + } + if j+k+len(id) <= len(buf) { + m = append(m, int64(j+k)) + } + copy(buf2, buf) + for _, p := range m { + copy(buf2[p:], zero) + } + h := sha256.Sum256(buf2) + + matches, hash, err := FindAndHash(bytes.NewReader(buf), string(id), bufSize) + if err != nil { + errorf("bufSize=%d j=%d k=%d: findAndHash: %v", bufSize, j, k, err) + continue + } + if !reflect.DeepEqual(matches, m) { + errorf("bufSize=%d j=%d k=%d: findAndHash: matches=%v, want %v", bufSize, j, k, matches, m) + continue + } + if hash != h { + errorf("bufSize=%d j=%d k=%d: findAndHash: matches correct, but hash=%x, want %x", bufSize, j, k, hash, h) + } + } + } + } +} diff --git a/libgo/go/cmd/go/internal/buildid/note.go b/libgo/go/cmd/internal/buildid/note.go similarity index 80% rename from libgo/go/cmd/go/internal/buildid/note.go rename to libgo/go/cmd/internal/buildid/note.go index 68c91e27047..f0439fb0bfb 100644 --- a/libgo/go/cmd/go/internal/buildid/note.go +++ b/libgo/go/cmd/internal/buildid/note.go @@ -69,11 +69,12 @@ func ReadELFNote(filename, name string, typ int32) ([]byte, error) { } var elfGoNote = []byte("Go\x00\x00") +var elfGNUNote = []byte("GNU\x00") // The Go build ID is stored in a note described by an ELF PT_NOTE prog // header. The caller has already opened filename, to get f, and read // at least 4 kB out, in data. -func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) { +func readELF(name string, f *os.File, data []byte) (buildid string, err error) { // Assume the note content is in the data, already read. // Rewrite the ELF header to set shnum to 0, so that we can pass // the data to elf.NewFile and it will decode the Prog list but not @@ -90,11 +91,13 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, } const elfGoBuildIDTag = 4 + const gnuBuildIDTag = 3 ef, err := elf.NewFile(bytes.NewReader(data)) if err != nil { - return "", &os.PathError{Path: filename, Op: "parse", Err: err} + return "", &os.PathError{Path: name, Op: "parse", Err: err} } + var gnu string for _, p := range ef.Progs { if p.Type != elf.PT_NOTE || p.Filesz < 16 { continue @@ -123,26 +126,42 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, } filesz := p.Filesz + off := p.Off for filesz >= 16 { nameSize := ef.ByteOrder.Uint32(note) valSize := ef.ByteOrder.Uint32(note[4:]) tag := ef.ByteOrder.Uint32(note[8:]) - name := note[12:16] - if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == elfGoBuildIDTag && bytes.Equal(name, elfGoNote) { + nname := note[12:16] + if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == elfGoBuildIDTag && bytes.Equal(nname, elfGoNote) { return string(note[16 : 16+valSize]), nil } + if nameSize == 4 && 16+valSize <= uint32(len(note)) && tag == gnuBuildIDTag && bytes.Equal(nname, elfGNUNote) { + gnu = string(note[16 : 16+valSize]) + } + nameSize = (nameSize + 3) &^ 3 valSize = (valSize + 3) &^ 3 notesz := uint64(12 + nameSize + valSize) if filesz <= notesz { break } + off += notesz + align := uint64(p.Align) + alignedOff := (off + align - 1) &^ (align - 1) + notesz += alignedOff - off + off = alignedOff filesz -= notesz note = note[notesz:] } } + // If we didn't find a Go note, use a GNU note if available. + // This is what gccgo uses. + if gnu != "" { + return gnu, nil + } + // No note. Treat as successful but build ID empty. return "", nil } @@ -151,23 +170,23 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, // The caller has already opened filename, to get f, and read a few kB out, in data. // Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount // of other junk placed in the file ahead of the main text. -func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) { +func readMacho(name string, f *os.File, data []byte) (buildid string, err error) { // If the data we want has already been read, don't worry about Mach-O parsing. // This is both an optimization and a hedge against the Mach-O parsing failing // in the future due to, for example, the name of the __text section changing. - if b, err := readRawGoBuildID(filename, data); b != "" && err == nil { + if b, err := readRaw(name, data); b != "" && err == nil { return b, err } mf, err := macho.NewFile(f) if err != nil { - return "", &os.PathError{Path: filename, Op: "parse", Err: err} + return "", &os.PathError{Path: name, Op: "parse", Err: err} } sect := mf.Section("__text") if sect == nil { // Every binary has a __text section. Something is wrong. - return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")} + return "", &os.PathError{Path: name, Op: "parse", Err: fmt.Errorf("cannot find __text section")} } // It should be in the first few bytes, but read a lot just in case, @@ -175,13 +194,13 @@ func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid strin // There shouldn't be much difference between reading 4kB and 32kB: // the hard part is getting to the data, not transferring it. n := sect.Size - if n > uint64(BuildIDReadSize) { - n = uint64(BuildIDReadSize) + if n > uint64(readSize) { + n = uint64(readSize) } buf := make([]byte, n) if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil { return "", err } - return readRawGoBuildID(filename, buf) + return readRaw(name, buf) } diff --git a/libgo/go/cmd/internal/buildid/rewrite.go b/libgo/go/cmd/internal/buildid/rewrite.go new file mode 100644 index 00000000000..5be54552a6d --- /dev/null +++ b/libgo/go/cmd/internal/buildid/rewrite.go @@ -0,0 +1,91 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buildid + +import ( + "bytes" + "crypto/sha256" + "fmt" + "io" +) + +// FindAndHash reads all of r and returns the offsets of occurrences of id. +// While reading, findAndHash also computes and returns +// a hash of the content of r, but with occurrences of id replaced by zeros. +// FindAndHash reads bufSize bytes from r at a time. +// If bufSize == 0, FindAndHash uses a reasonable default. +func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32]byte, err error) { + if bufSize == 0 { + bufSize = 31 * 1024 // bufSize+little will likely fit in 32 kB + } + if len(id) > bufSize { + return nil, [32]byte{}, fmt.Errorf("buildid.FindAndHash: buffer too small") + } + zeros := make([]byte, len(id)) + idBytes := []byte(id) + + // The strategy is to read the file through buf, looking for id, + // but we need to worry about what happens if id is broken up + // and returned in parts by two different reads. + // We allocate a tiny buffer (at least len(id)) and a big buffer (bufSize bytes) + // next to each other in memory and then copy the tail of + // one read into the tiny buffer before reading new data into the big buffer. + // The search for id is over the entire tiny+big buffer. + tiny := (len(id) + 127) &^ 127 // round up to 128-aligned + buf := make([]byte, tiny+bufSize) + h := sha256.New() + start := tiny + for offset := int64(0); ; { + // The file offset maintained by the loop corresponds to &buf[tiny]. + // buf[start:tiny] is left over from previous iteration. + // After reading n bytes into buf[tiny:], we process buf[start:tiny+n]. + n, err := io.ReadFull(r, buf[tiny:]) + if err != io.ErrUnexpectedEOF && err != io.EOF && err != nil { + return nil, [32]byte{}, err + } + + // Process any matches. + for { + i := bytes.Index(buf[start:tiny+n], idBytes) + if i < 0 { + break + } + matches = append(matches, offset+int64(start+i-tiny)) + h.Write(buf[start : start+i]) + h.Write(zeros) + start += i + len(id) + } + if n < bufSize { + // Did not fill buffer, must be at end of file. + h.Write(buf[start : tiny+n]) + break + } + + // Process all but final tiny bytes of buf (bufSize = len(buf)-tiny). + // Note that start > len(buf)-tiny is possible, if the search above + // found an id ending in the final tiny fringe. That's OK. + if start < len(buf)-tiny { + h.Write(buf[start : len(buf)-tiny]) + start = len(buf) - tiny + } + + // Slide ending tiny-sized fringe to beginning of buffer. + copy(buf[0:], buf[bufSize:]) + start -= bufSize + offset += int64(bufSize) + } + h.Sum(hash[:0]) + return matches, hash, nil +} + +func Rewrite(w io.WriterAt, pos []int64, id string) error { + b := []byte(id) + for _, p := range pos { + if _, err := w.WriteAt(b, p); err != nil { + return err + } + } + return nil +} diff --git a/libgo/go/cmd/internal/buildid/testdata/a.elf b/libgo/go/cmd/internal/buildid/testdata/a.elf new file mode 100644 index 0000000000000000000000000000000000000000..f63128921aaee5027de1ae83995b183531c0a70f GIT binary patch literal 12768 zcmeHN&2G~`5FV$Y4HAe535g4m5eFm=cEWGCAaf`Pi3>uU5QijoT~jAc?QLlgf*$(- zJWhowapAy$N63Yz;1FiLGj?JDQCd~yFe~kTGvoPocE3cCHtSF8&!5yR3%J$b5#(Oe z%R^=a_*SNX2OU_$@gl6iDrVKObDl>Q;{ov)p^3@ZG)MQ(m$awRo5MKw02p}JVxfd_^JGyN3=!IpoIM^ z^#E=y$}XQXuZ$ee(%aCzSTlY8ydRRan7rygCVq`G3VltW!*RkYKgIY;B}coSZGs;R z6r*12YN^RN#b()7yz+Kk~r|;ti9S zCI;1b6vWYR3!F%Gd&UZrY&<{@kUHwe!`#d^GnHyfw_nrg6mLEo#p-E&En1&N{yzCY z{wDe1`VA{Xdl&ndV)-2+-M{kt0fTNdbo78%j26@_STz-O?g4i9RTiX~n`V7COx!H( zyZwRhMne^(!*1--wp|ruN^jR4;f|=BfG8jehytR3C?E=m0-}H@APR^AqJSuH>I&E` z@1HgJJ!F3WnDGalkMpxK&cNthH}kR2c)_MRbpGaZIiJUy6bD*Q`TnutE$g4BdJV2i Z*deqD`F{gOes3JNG}rzXpG*1=o!<)3veN(n literal 0 HcmV?d00001 diff --git a/libgo/go/cmd/internal/buildid/testdata/a.macho b/libgo/go/cmd/internal/buildid/testdata/a.macho new file mode 100644 index 0000000000000000000000000000000000000000..fbbd57c1fe370341514eda23e41eedb66f94c006 GIT binary patch literal 13472 zcmeHO&5smC6t9H^0d;{Ba%(_1kT|{I2Vi32COhIrqXgH)aH;fk_cZPHbPwGZ;#+)vxOP`Xl|i zs($pUGZgNPed9GvG0%$KyJSTU!i8;Or z**i}S0GlTG)S}cn8xML(q_cd~JG0&2TV#(<0^Cab=G6oRa0!Y8{*H%!6vk_e+y4HW zJu*`jT8FvQdzSWs1Uv?t&uV-@GIXPu4Vu?ui}>41cOBs3{-_)@DtO=h4sEqwURqsh zD6R57xleYKRq7by^MD!eJxp51a81igJIvFW_R7|9w94m+F<(!{U@rkX)vfn9s44`~^dxgK1(WkXnzn4B-`RIf0@(RCG7E3=j z`8i)KonVab5xlOPkkea`vH58h{*UF*ct6Y<3cjmfK_&Qi5{gS_A%pNmtfL$f$}wZ& zvP9dDc>Ydl0fZLhmmu4tEVZMsXM5ww1B~fa$nXfl3;IBru`Wp%5C((+VL%uV2801& z;JIaBYF$jM-YASbYi0Ru>$uZ%J-;7Z4L@It2Jp##Erme#i!ay5Uvf?w+Z=~8=J;6g zye!RE^1S7fmS0nU8&tA=o-f}dIS2b(vfkulmfUP7SQrongaKhd7!U@80bxKG5C((+ zVL%vo9vQ&+d;x=BiiclD3_^~Vj~Ms_wdeWo*AT;^Q;yFsAcm!&jNdc#pBQ=vG4#jr z`jGH-j@uFMfi=2>Zz6`psBHgR1LJ)B0&HSn{cXgs==T@;FL4hs^vCudAcn=+jQ>Im ze6as8N#AOJm@xm(IEfhgv*^FYJEZ6FUm?u@A=V5$Cd~eCAa3~k4PxAsLH55#-0=Tr zLw^r3_`5}XJwV*Jo_`{4_`3^q&Fg;oV-Lx|jSbwSAHwRILE?>~wr~B^8TiAbSoNX( z81`%U_1MAhFwcNTw$diT;9(mLk<;vQSXtS|NFiu(YVu*wVX)C613~7yd6>ilr|z`c P+rqw}AX9h*2QmEv%?9K9 literal 0 HcmV?d00001 diff --git a/libgo/go/cmd/internal/buildid/testdata/a.pe b/libgo/go/cmd/internal/buildid/testdata/a.pe new file mode 100644 index 0000000000000000000000000000000000000000..91202728c3f394c393a5546124f434166bac4ced GIT binary patch literal 3584 zcmeHJ&1w`u5U$yT5LXi-cu#NQc{=|8oCZk{K{23SJY{xfoE_cy$;_;7Jncy$dhii^ z1P>m9f2H{J)&+yL0HeYbScF;sB^RrO~UbwnJ1 zT{|*?dM~&q9oHNQLQ}^TTXE^OP5;oL>0%YlLdz@jXx^&YFV@D8q`AL4$+KwpZF&6Z^VIkhj_TQ{MSOl)Ye^!d=tod-;K=s zi1sJc&*W1z4Jbcj>_&;LK6ukwFm1t%Sx&_spvnhDkQXv9JQ=34$UW)BzKoJG$P>3K zsRmgFMX4@$nb~1V%S{AAIAiDSQvFmWmkS5vH*YMzwE)|vO+G#k#@7_j{pNFE&iw(Z yXV@}%CdHSu-ZmlU-y!~%kPn-Y#}7B len(b.old) { + panic("invalid edit position") + } + b.q = append(b.q, edit{pos, pos, new}) +} + +func (b *Buffer) Delete(start, end int) { + if end < start || start < 0 || end > len(b.old) { + panic("invalid edit position") + } + b.q = append(b.q, edit{start, end, ""}) +} + +func (b *Buffer) Replace(start, end int, new string) { + if end < start || start < 0 || end > len(b.old) { + panic("invalid edit position") + } + b.q = append(b.q, edit{start, end, new}) +} + +// Bytes returns a new byte slice containing the original data +// with the queued edits applied. +func (b *Buffer) Bytes() []byte { + // Sort edits by starting position and then by ending position. + // Breaking ties by ending position allows insertions at point x + // to be applied before a replacement of the text at [x, y). + sort.Stable(b.q) + + var new []byte + offset := 0 + for i, e := range b.q { + if e.start < offset { + e0 := b.q[i-1] + panic(fmt.Sprintf("overlapping edits: [%d,%d)->%q, [%d,%d)->%q", e0.start, e0.end, e0.new, e.start, e.end, e.new)) + } + new = append(new, b.old[offset:e.start]...) + offset = e.end + new = append(new, e.new...) + } + new = append(new, b.old[offset:]...) + return new +} + +// String returns a string containing the original data +// with the queued edits applied. +func (b *Buffer) String() string { + return string(b.Bytes()) +} diff --git a/libgo/go/cmd/internal/edit/edit_test.go b/libgo/go/cmd/internal/edit/edit_test.go new file mode 100644 index 00000000000..0e0c564d987 --- /dev/null +++ b/libgo/go/cmd/internal/edit/edit_test.go @@ -0,0 +1,28 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edit + +import "testing" + +func TestEdit(t *testing.T) { + b := NewBuffer([]byte("0123456789")) + b.Insert(8, ",7½,") + b.Replace(9, 10, "the-end") + b.Insert(10, "!") + b.Insert(4, "3.14,") + b.Insert(4, "π,") + b.Insert(4, "3.15,") + b.Replace(3, 4, "three,") + want := "012three,3.14,π,3.15,4567,7½,8the-end!" + + s := b.String() + if s != want { + t.Errorf("b.String() = %q, want %q", s, want) + } + sb := b.Bytes() + if string(sb) != want { + t.Errorf("b.Bytes() = %q, want %q", sb, want) + } +} diff --git a/libgo/go/cmd/internal/objabi/autotype.go b/libgo/go/cmd/internal/objabi/autotype.go index 17c42931310..1b46b0ffece 100644 --- a/libgo/go/cmd/internal/objabi/autotype.go +++ b/libgo/go/cmd/internal/objabi/autotype.go @@ -34,4 +34,5 @@ package objabi const ( A_AUTO = 1 + iota A_PARAM + A_DELETED_AUTO ) diff --git a/libgo/go/cmd/internal/objabi/flag.go b/libgo/go/cmd/internal/objabi/flag.go index e349b413249..1bd4bc9063a 100644 --- a/libgo/go/cmd/internal/objabi/flag.go +++ b/libgo/go/cmd/internal/objabi/flag.go @@ -9,30 +9,13 @@ import ( "fmt" "os" "strconv" + "strings" ) -func Flagfn2(string, string, func(string, string)) { panic("flag") } - func Flagcount(name, usage string, val *int) { flag.Var((*count)(val), name, usage) } -func Flagint32(name, usage string, val *int32) { - flag.Var((*int32Value)(val), name, usage) -} - -func Flagint64(name, usage string, val *int64) { - flag.Int64Var(val, name, *val, usage) -} - -func Flagstr(name, usage string, val *string) { - flag.StringVar(val, name, *val, usage) -} - -func Flagfn0(name, usage string, f func()) { - flag.Var(fn0(f), name, usage) -} - func Flagfn1(name, usage string, f func(string)) { flag.Var(fn1(f), name, usage) } @@ -49,6 +32,44 @@ func Flagparse(usage func()) { flag.Parse() } +func AddVersionFlag() { + flag.Var(versionFlag{}, "V", "print version and exit") +} + +var buildID string // filled in by linker + +type versionFlag struct{} + +func (versionFlag) IsBoolFlag() bool { return true } +func (versionFlag) Get() interface{} { return nil } +func (versionFlag) String() string { return "" } +func (versionFlag) Set(s string) error { + name := os.Args[0] + name = name[strings.LastIndex(name, `/`)+1:] + name = name[strings.LastIndex(name, `\`)+1:] + name = strings.TrimSuffix(name, ".exe") + p := Expstring() + if p == DefaultExpstring() { + p = "" + } + sep := "" + if p != "" { + sep = " " + } + + // The go command invokes -V=full to get a unique identifier + // for this tool. It is assumed that the release version is sufficient + // for releases, but during development we include the full + // build ID of the binary, so that if the compiler is changed and + // rebuilt, we notice and rebuild all packages. + if s == "full" && strings.HasPrefix(Version, "devel") { + p += " buildID=" + buildID + } + fmt.Printf("%s version %s%s%s\n", name, Version, sep, p) + os.Exit(0) + return nil +} + // count is a flag.Value that is like a flag.Bool and a flag.Int. // If used as -name, it increments the count, but -name=x sets the count. // Used for verbose flag -v. @@ -74,22 +95,18 @@ func (c *count) Set(s string) error { return nil } +func (c *count) Get() interface{} { + return int(*c) +} + func (c *count) IsBoolFlag() bool { return true } -type int32Value int32 - -func (i *int32Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = int32Value(v) - return err +func (c *count) IsCountFlag() bool { + return true } -func (i *int32Value) Get() interface{} { return int32(*i) } - -func (i *int32Value) String() string { return fmt.Sprint(*i) } - type fn0 func() func (f fn0) Set(s string) error { diff --git a/libgo/go/cmd/internal/objabi/line.go b/libgo/go/cmd/internal/objabi/line.go index ed509b70017..1c671b211f8 100644 --- a/libgo/go/cmd/internal/objabi/line.go +++ b/libgo/go/cmd/internal/objabi/line.go @@ -44,7 +44,7 @@ func AbsFile(dir, file, pathPrefix string) string { abs = "??" } - return filepath.Clean(abs) + return abs } // Does s have t as a path prefix? diff --git a/libgo/go/cmd/internal/objabi/reloctype.go b/libgo/go/cmd/internal/objabi/reloctype.go index 179f049de7d..2e0b916f7c1 100644 --- a/libgo/go/cmd/internal/objabi/reloctype.go +++ b/libgo/go/cmd/internal/objabi/reloctype.go @@ -99,8 +99,15 @@ const ( // of a JMP instruction, by encoding the address into the instruction. // The stack nosplit check ignores this since it is not a function call. R_JMPMIPS - // R_DWARFREF resolves to the offset of the symbol from its section. - R_DWARFREF + + // R_DWARFSECREF resolves to the offset of the symbol from its section. + // Target of relocation must be size 4 (in current implementation). + R_DWARFSECREF + + // R_DWARFFILEREF resolves to an index into the DWARF .debug_line + // file table for the specified file symbol. Must be applied to an + // attribute of form DW_FORM_data4. + R_DWARFFILEREF // Platform dependent relocations. Architectures with fixed width instructions // have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be @@ -183,6 +190,9 @@ const ( // R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS // address (offset from thread pointer), by encoding it into the instruction. R_ADDRMIPSTLS + // R_ADDRCUOFF resolves to a pointer-sized offset from the start of the + // symbol's DWARF compile unit. + R_ADDRCUOFF ) // IsDirectJump returns whether r is a relocation for a direct jump. diff --git a/libgo/go/cmd/internal/objabi/reloctype_string.go b/libgo/go/cmd/internal/objabi/reloctype_string.go index 182d03f78c1..a6efe9cad04 100644 --- a/libgo/go/cmd/internal/objabi/reloctype_string.go +++ b/libgo/go/cmd/internal/objabi/reloctype_string.go @@ -4,9 +4,9 @@ package objabi import "fmt" -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFF" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 248, 262, 276, 292, 306, 320, 331, 345, 360, 377, 395, 416, 426, 437, 450} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478} func (i RelocType) String() string { i -= 1 diff --git a/libgo/go/cmd/internal/objabi/symkind.go b/libgo/go/cmd/internal/objabi/symkind.go index b037e9e4ed1..ea180d0bf86 100644 --- a/libgo/go/cmd/internal/objabi/symkind.go +++ b/libgo/go/cmd/internal/objabi/symkind.go @@ -52,9 +52,10 @@ const ( SBSS // Statically data that is initially all 0s and does not contain pointers SNOPTRBSS - // Thread-local data that is initally all 0s + // Thread-local data that is initially all 0s STLSBSS // Debugging data SDWARFINFO SDWARFRANGE + SDWARFLOC ) diff --git a/libgo/go/cmd/internal/objabi/symkind_string.go b/libgo/go/cmd/internal/objabi/symkind_string.go index 5123dc7097f..3064c8ee051 100644 --- a/libgo/go/cmd/internal/objabi/symkind_string.go +++ b/libgo/go/cmd/internal/objabi/symkind_string.go @@ -4,9 +4,9 @@ package objabi import "fmt" -const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE" +const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOC" -var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72} +var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81} func (i SymKind) String() string { if i >= SymKind(len(_SymKind_index)-1) { diff --git a/libgo/go/cmd/internal/objabi/util.go b/libgo/go/cmd/internal/objabi/util.go index 1da05021f50..f8949e05a2b 100644 --- a/libgo/go/cmd/internal/objabi/util.go +++ b/libgo/go/cmd/internal/objabi/util.go @@ -24,6 +24,7 @@ var ( GOOS = envOr("GOOS", defaultGOOS) GO386 = envOr("GO386", defaultGO386) GOARM = goarm() + GOMIPS = gomips() Version = version ) @@ -41,6 +42,15 @@ func goarm() int { panic("unreachable") } +func gomips() string { + switch v := envOr("GOMIPS", defaultGOMIPS); v { + case "hardfloat", "softfloat": + return v + } + log.Fatalf("Invalid GOMIPS value. Must be hardfloat or softfloat.") + panic("unreachable") +} + func Getgoextlinkenabled() string { return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) } diff --git a/libgo/go/cmd/internal/objabi/zbootstrap.go b/libgo/go/cmd/internal/objabi/zbootstrap.go deleted file mode 100644 index 56450fac618..00000000000 --- a/libgo/go/cmd/internal/objabi/zbootstrap.go +++ /dev/null @@ -1,15 +0,0 @@ -// auto generated by go tool dist - -package objabi - -import "runtime" - -const defaultGOROOT = `/home/iant/go1.9` -const defaultGO386 = `sse2` -const defaultGOARM = `5` -const defaultGOOS = runtime.GOOS -const defaultGOARCH = runtime.GOARCH -const defaultGO_EXTLINK_ENABLED = `` -const version = `go1.9rc2` -const stackGuardMultiplier = 1 -const goexperiment = `` diff --git a/libgo/go/cmd/internal/test2json/test2json.go b/libgo/go/cmd/internal/test2json/test2json.go new file mode 100644 index 00000000000..3e09c8d9151 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/test2json.go @@ -0,0 +1,413 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package test2json implements conversion of test binary output to JSON. +// It is used by cmd/test2json and cmd/go. +// +// See the cmd/test2json documentation for details of the JSON encoding. +package test2json + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// Mode controls details of the conversion. +type Mode int + +const ( + Timestamp Mode = 1 << iota // include Time in events +) + +// event is the JSON struct we emit. +type event struct { + Time *time.Time `json:",omitempty"` + Action string + Package string `json:",omitempty"` + Test string `json:",omitempty"` + Elapsed *float64 `json:",omitempty"` + Output *textBytes `json:",omitempty"` +} + +// textBytes is a hack to get JSON to emit a []byte as a string +// without actually copying it to a string. +// It implements encoding.TextMarshaler, which returns its text form as a []byte, +// and then json encodes that text form as a string (which was our goal). +type textBytes []byte + +func (b textBytes) MarshalText() ([]byte, error) { return b, nil } + +// A converter holds the state of a test-to-JSON conversion. +// It implements io.WriteCloser; the caller writes test output in, +// and the converter writes JSON output to w. +type converter struct { + w io.Writer // JSON output stream + pkg string // package to name in events + mode Mode // mode bits + start time.Time // time converter started + testName string // name of current test, for output attribution + report []*event // pending test result reports (nested for subtests) + result string // overall test result if seen + input lineBuffer // input buffer + output lineBuffer // output buffer +} + +// inBuffer and outBuffer are the input and output buffer sizes. +// They're variables so that they can be reduced during testing. +// +// The input buffer needs to be able to hold any single test +// directive line we want to recognize, like: +// +// --- PASS: very/nested/s/u/b/t/e/s/t +// +// If anyone reports a test directive line > 4k not working, it will +// be defensible to suggest they restructure their test or test names. +// +// The output buffer must be >= utf8.UTFMax, so that it can +// accumulate any single UTF8 sequence. Lines that fit entirely +// within the output buffer are emitted in single output events. +// Otherwise they are split into multiple events. +// The output buffer size therefore limits the size of the encoding +// of a single JSON output event. 1k seems like a reasonable balance +// between wanting to avoid splitting an output line and not wanting to +// generate enormous output events. +var ( + inBuffer = 4096 + outBuffer = 1024 +) + +// NewConverter returns a "test to json" converter. +// Writes on the returned writer are written as JSON to w, +// with minimal delay. +// +// The writes to w are whole JSON events ending in \n, +// so that it is safe to run multiple tests writing to multiple converters +// writing to a single underlying output stream w. +// As long as the underlying output w can handle concurrent writes +// from multiple goroutines, the result will be a JSON stream +// describing the relative ordering of execution in all the concurrent tests. +// +// The mode flag adjusts the behavior of the converter. +// Passing ModeTime includes event timestamps and elapsed times. +// +// The pkg string, if present, specifies the import path to +// report in the JSON stream. +func NewConverter(w io.Writer, pkg string, mode Mode) io.WriteCloser { + c := new(converter) + *c = converter{ + w: w, + pkg: pkg, + mode: mode, + start: time.Now(), + input: lineBuffer{ + b: make([]byte, 0, inBuffer), + line: c.handleInputLine, + part: c.output.write, + }, + output: lineBuffer{ + b: make([]byte, 0, outBuffer), + line: c.writeOutputEvent, + part: c.writeOutputEvent, + }, + } + return c +} + +// Write writes the test input to the converter. +func (c *converter) Write(b []byte) (int, error) { + c.input.write(b) + return len(b), nil +} + +var ( + bigPass = []byte("PASS\n") + bigFail = []byte("FAIL\n") + + updates = [][]byte{ + []byte("=== RUN "), + []byte("=== PAUSE "), + []byte("=== CONT "), + } + + reports = [][]byte{ + []byte("--- PASS: "), + []byte("--- FAIL: "), + []byte("--- SKIP: "), + } + + fourSpace = []byte(" ") + + skipLinePrefix = []byte("? \t") + skipLineSuffix = []byte("\t[no test files]\n") +) + +// handleInputLine handles a single whole test output line. +// It must write the line to c.output but may choose to do so +// before or after emitting other events. +func (c *converter) handleInputLine(line []byte) { + // Final PASS or FAIL. + if bytes.Equal(line, bigPass) || bytes.Equal(line, bigFail) { + c.flushReport(0) + c.output.write(line) + if bytes.Equal(line, bigPass) { + c.result = "pass" + } else { + c.result = "fail" + } + return + } + + // Special case for entirely skipped test binary: "? \tpkgname\t[no test files]\n" is only line. + // Report it as plain output but remember to say skip in the final summary. + if bytes.HasPrefix(line, skipLinePrefix) && bytes.HasSuffix(line, skipLineSuffix) && len(c.report) == 0 { + c.result = "skip" + } + + // "=== RUN " + // "=== PAUSE " + // "=== CONT " + origLine := line + ok := false + indent := 0 + for _, magic := range updates { + if bytes.HasPrefix(line, magic) { + ok = true + break + } + } + if !ok { + // "--- PASS: " + // "--- FAIL: " + // "--- SKIP: " + // but possibly indented. + for bytes.HasPrefix(line, fourSpace) { + line = line[4:] + indent++ + } + for _, magic := range reports { + if bytes.HasPrefix(line, magic) { + ok = true + break + } + } + } + + if !ok { + // Not a special test output line. + c.output.write(origLine) + return + } + + // Parse out action and test name. + action := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(string(line[4:4+6])), ":")) + name := strings.TrimSpace(string(line[4+6:])) + + e := &event{Action: action} + if line[0] == '-' { // PASS or FAIL report + // Parse out elapsed time. + if i := strings.Index(name, " ("); i >= 0 { + if strings.HasSuffix(name, "s)") { + t, err := strconv.ParseFloat(name[i+2:len(name)-2], 64) + if err == nil { + if c.mode&Timestamp != 0 { + e.Elapsed = &t + } + } + } + name = name[:i] + } + if len(c.report) < indent { + // Nested deeper than expected. + // Treat this line as plain output. + return + } + // Flush reports at this indentation level or deeper. + c.flushReport(indent) + e.Test = name + c.testName = name + c.report = append(c.report, e) + c.output.write(origLine) + return + } + // === update. + // Finish any pending PASS/FAIL reports. + c.flushReport(0) + c.testName = name + + if action == "pause" { + // For a pause, we want to write the pause notification before + // delivering the pause event, just so it doesn't look like the test + // is generating output immediately after being paused. + c.output.write(origLine) + } + c.writeEvent(e) + if action != "pause" { + c.output.write(origLine) + } + + return +} + +// flushReport flushes all pending PASS/FAIL reports at levels >= depth. +func (c *converter) flushReport(depth int) { + c.testName = "" + for len(c.report) > depth { + e := c.report[len(c.report)-1] + c.report = c.report[:len(c.report)-1] + c.writeEvent(e) + } +} + +// Close marks the end of the go test output. +// It flushes any pending input and then output (only partial lines at this point) +// and then emits the final overall package-level pass/fail event. +func (c *converter) Close() error { + c.input.flush() + c.output.flush() + e := &event{Action: "fail"} + if c.result != "" { + e.Action = c.result + } + if c.mode&Timestamp != 0 { + dt := time.Since(c.start).Round(1 * time.Millisecond).Seconds() + e.Elapsed = &dt + } + c.writeEvent(e) + return nil +} + +// writeOutputEvent writes a single output event with the given bytes. +func (c *converter) writeOutputEvent(out []byte) { + c.writeEvent(&event{ + Action: "output", + Output: (*textBytes)(&out), + }) +} + +// writeEvent writes a single event. +// It adds the package, time (if requested), and test name (if needed). +func (c *converter) writeEvent(e *event) { + e.Package = c.pkg + if c.mode&Timestamp != 0 { + t := time.Now() + e.Time = &t + } + if e.Test == "" { + e.Test = c.testName + } + js, err := json.Marshal(e) + if err != nil { + // Should not happen - event is valid for json.Marshal. + c.w.Write([]byte(fmt.Sprintf("testjson internal error: %v\n", err))) + return + } + js = append(js, '\n') + c.w.Write(js) +} + +// A lineBuffer is an I/O buffer that reacts to writes by invoking +// input-processing callbacks on whole lines or (for long lines that +// have been split) line fragments. +// +// It should be initialized with b set to a buffer of length 0 but non-zero capacity, +// and line and part set to the desired input processors. +// The lineBuffer will call line(x) for any whole line x (including the final newline) +// that fits entirely in cap(b). It will handle input lines longer than cap(b) by +// calling part(x) for sections of the line. The line will be split at UTF8 boundaries, +// and the final call to part for a long line includes the final newline. +type lineBuffer struct { + b []byte // buffer + mid bool // whether we're in the middle of a long line + line func([]byte) // line callback + part func([]byte) // partial line callback +} + +// write writes b to the buffer. +func (l *lineBuffer) write(b []byte) { + for len(b) > 0 { + // Copy what we can into b. + m := copy(l.b[len(l.b):cap(l.b)], b) + l.b = l.b[:len(l.b)+m] + b = b[m:] + + // Process lines in b. + i := 0 + for i < len(l.b) { + j := bytes.IndexByte(l.b[i:], '\n') + if j < 0 { + break + } + e := i + j + 1 + if l.mid { + // Found the end of a partial line. + l.part(l.b[i:e]) + l.mid = false + } else { + // Found a whole line. + l.line(l.b[i:e]) + } + i = e + } + + // Whatever's left in l.b is a line fragment. + if i == 0 && len(l.b) == cap(l.b) { + // The whole buffer is a fragment. + // Emit it as the beginning (or continuation) of a partial line. + t := trimUTF8(l.b) + l.part(l.b[:t]) + l.b = l.b[:copy(l.b, l.b[t:])] + l.mid = true + } + + // There's room for more input. + // Slide it down in hope of completing the line. + if i > 0 { + l.b = l.b[:copy(l.b, l.b[i:])] + } + } +} + +// flush flushes the line buffer. +func (l *lineBuffer) flush() { + if len(l.b) > 0 { + // Must be a line without a \n, so a partial line. + l.part(l.b) + l.b = l.b[:0] + } +} + +// trimUTF8 returns a length t as close to len(b) as possible such that b[:t] +// does not end in the middle of a possibly-valid UTF-8 sequence. +// +// If a large text buffer must be split before position i at the latest, +// splitting at position trimUTF(b[:i]) avoids splitting a UTF-8 sequence. +func trimUTF8(b []byte) int { + // Scan backward to find non-continuation byte. + for i := 1; i < utf8.UTFMax && i <= len(b); i++ { + if c := b[len(b)-i]; c&0xc0 != 0x80 { + switch { + case c&0xe0 == 0xc0: + if i < 2 { + return len(b) - i + } + case c&0xf0 == 0xe0: + if i < 3 { + return len(b) - i + } + case c&0xf8 == 0xf0: + if i < 4 { + return len(b) - i + } + } + break + } + } + return len(b) +} diff --git a/libgo/go/cmd/internal/test2json/test2json_test.go b/libgo/go/cmd/internal/test2json/test2json_test.go new file mode 100644 index 00000000000..4683907888c --- /dev/null +++ b/libgo/go/cmd/internal/test2json/test2json_test.go @@ -0,0 +1,277 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package test2json + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io" + "io/ioutil" + "path/filepath" + "reflect" + "strings" + "testing" + "unicode/utf8" +) + +var update = flag.Bool("update", false, "rewrite testdata/*.json files") + +func TestGolden(t *testing.T) { + files, err := filepath.Glob("testdata/*.test") + if err != nil { + t.Fatal(err) + } + for _, file := range files { + name := strings.TrimSuffix(filepath.Base(file), ".test") + t.Run(name, func(t *testing.T) { + orig, err := ioutil.ReadFile(file) + if err != nil { + t.Fatal(err) + } + + // Test one line written to c at a time. + // Assume that's the most likely to be handled correctly. + var buf bytes.Buffer + c := NewConverter(&buf, "", 0) + in := append([]byte{}, orig...) + for _, line := range bytes.SplitAfter(in, []byte("\n")) { + writeAndKill(c, line) + } + c.Close() + + if *update { + js := strings.TrimSuffix(file, ".test") + ".json" + t.Logf("rewriting %s", js) + if err := ioutil.WriteFile(js, buf.Bytes(), 0666); err != nil { + t.Fatal(err) + } + return + } + + want, err := ioutil.ReadFile(strings.TrimSuffix(file, ".test") + ".json") + if err != nil { + t.Fatal(err) + } + diffJSON(t, buf.Bytes(), want) + if t.Failed() { + // If the line-at-a-time conversion fails, no point testing boundary conditions. + return + } + + // Write entire input in bulk. + t.Run("bulk", func(t *testing.T) { + buf.Reset() + c = NewConverter(&buf, "", 0) + in = append([]byte{}, orig...) + writeAndKill(c, in) + c.Close() + diffJSON(t, buf.Bytes(), want) + }) + + // Write 2 bytes at a time on even boundaries. + t.Run("even2", func(t *testing.T) { + buf.Reset() + c = NewConverter(&buf, "", 0) + in = append([]byte{}, orig...) + for i := 0; i < len(in); i += 2 { + if i+2 <= len(in) { + writeAndKill(c, in[i:i+2]) + } else { + writeAndKill(c, in[i:]) + } + } + c.Close() + diffJSON(t, buf.Bytes(), want) + }) + + // Write 2 bytes at a time on odd boundaries. + t.Run("odd2", func(t *testing.T) { + buf.Reset() + c = NewConverter(&buf, "", 0) + in = append([]byte{}, orig...) + if len(in) > 0 { + writeAndKill(c, in[:1]) + } + for i := 1; i < len(in); i += 2 { + if i+2 <= len(in) { + writeAndKill(c, in[i:i+2]) + } else { + writeAndKill(c, in[i:]) + } + } + c.Close() + diffJSON(t, buf.Bytes(), want) + }) + + // Test with very small output buffers, to check that + // UTF8 sequences are not broken up. + for b := 5; b <= 8; b++ { + t.Run(fmt.Sprintf("tiny%d", b), func(t *testing.T) { + oldIn := inBuffer + oldOut := outBuffer + defer func() { + inBuffer = oldIn + outBuffer = oldOut + }() + inBuffer = 64 + outBuffer = b + buf.Reset() + c = NewConverter(&buf, "", 0) + in = append([]byte{}, orig...) + writeAndKill(c, in) + c.Close() + diffJSON(t, buf.Bytes(), want) + }) + } + }) + } +} + +// writeAndKill writes b to w and then fills b with Zs. +// The filling makes sure that if w is holding onto b for +// future use, that future use will have obviously wrong data. +func writeAndKill(w io.Writer, b []byte) { + w.Write(b) + for i := range b { + b[i] = 'Z' + } +} + +// diffJSON diffs the stream we have against the stream we want +// and fails the test with a useful message if they don't match. +func diffJSON(t *testing.T, have, want []byte) { + t.Helper() + type event map[string]interface{} + + // Parse into events, one per line. + parseEvents := func(b []byte) ([]event, []string) { + t.Helper() + var events []event + var lines []string + for _, line := range bytes.SplitAfter(b, []byte("\n")) { + if len(line) > 0 { + line = bytes.TrimSpace(line) + var e event + err := json.Unmarshal(line, &e) + if err != nil { + t.Errorf("unmarshal %s: %v", b, err) + continue + } + events = append(events, e) + lines = append(lines, string(line)) + } + } + return events, lines + } + haveEvents, haveLines := parseEvents(have) + wantEvents, wantLines := parseEvents(want) + if t.Failed() { + return + } + + // Make sure the events we have match the events we want. + // At each step we're matching haveEvents[i] against wantEvents[j]. + // i and j can move independently due to choices about exactly + // how to break up text in "output" events. + i := 0 + j := 0 + + // Fail reports a failure at the current i,j and stops the test. + // It shows the events around the current positions, + // with the current positions marked. + fail := func() { + var buf bytes.Buffer + show := func(i int, lines []string) { + for k := -2; k < 5; k++ { + marker := "" + if k == 0 { + marker = "» " + } + if 0 <= i+k && i+k < len(lines) { + fmt.Fprintf(&buf, "\t%s%s\n", marker, lines[i+k]) + } + } + if i >= len(lines) { + // show marker after end of input + fmt.Fprintf(&buf, "\t» \n") + } + } + fmt.Fprintf(&buf, "have:\n") + show(i, haveLines) + fmt.Fprintf(&buf, "want:\n") + show(j, wantLines) + t.Fatal(buf.String()) + } + + var outputTest string // current "Test" key in "output" events + var wantOutput, haveOutput string // collected "Output" of those events + + // getTest returns the "Test" setting, or "" if it is missing. + getTest := func(e event) string { + s, _ := e["Test"].(string) + return s + } + + // checkOutput collects output from the haveEvents for the current outputTest + // and then checks that the collected output matches the wanted output. + checkOutput := func() { + for i < len(haveEvents) && haveEvents[i]["Action"] == "output" && getTest(haveEvents[i]) == outputTest { + haveOutput += haveEvents[i]["Output"].(string) + i++ + } + if haveOutput != wantOutput { + t.Errorf("output mismatch for Test=%q:\nhave %q\nwant %q", outputTest, haveOutput, wantOutput) + fail() + } + haveOutput = "" + wantOutput = "" + } + + // Walk through wantEvents matching against haveEvents. + for j = range wantEvents { + e := wantEvents[j] + if e["Action"] == "output" && getTest(e) == outputTest { + wantOutput += e["Output"].(string) + continue + } + checkOutput() + if e["Action"] == "output" { + outputTest = getTest(e) + wantOutput += e["Output"].(string) + continue + } + if i >= len(haveEvents) { + t.Errorf("early end of event stream: missing event") + fail() + } + if !reflect.DeepEqual(haveEvents[i], e) { + t.Errorf("events out of sync") + fail() + } + i++ + } + checkOutput() + if i < len(haveEvents) { + t.Errorf("extra events in stream") + fail() + } +} + +func TestTrimUTF8(t *testing.T) { + s := "hello α ☺ 😂 world" // α is 2-byte, ☺ is 3-byte, 😂 is 4-byte + b := []byte(s) + for i := 0; i < len(s); i++ { + j := trimUTF8(b[:i]) + u := string([]rune(s[:j])) + string([]rune(s[j:])) + if u != s { + t.Errorf("trimUTF8(%q) = %d (-%d), not at boundary (split: %q %q)", s[:i], j, i-j, s[:j], s[j:]) + } + if utf8.FullRune(b[j:i]) { + t.Errorf("trimUTF8(%q) = %d (-%d), too early (missed: %q)", s[:j], j, i-j, s[j:i]) + } + } +} diff --git a/libgo/go/cmd/internal/test2json/testdata/ascii.json b/libgo/go/cmd/internal/test2json/testdata/ascii.json new file mode 100644 index 00000000000..67fccfc1121 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/ascii.json @@ -0,0 +1,10 @@ +{"Action":"run","Test":"TestAscii"} +{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n"} +{"Action":"output","Test":"TestAscii","Output":"I can eat glass, and it doesn't hurt me. I can eat glass, and it doesn't hurt me.\n"} +{"Action":"output","Test":"TestAscii","Output":"I CAN EAT GLASS, AND IT DOESN'T HURT ME. I CAN EAT GLASS, AND IT DOESN'T HURT ME.\n"} +{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii\n"} +{"Action":"output","Test":"TestAscii","Output":" i can eat glass, and it doesn't hurt me. i can eat glass, and it doesn't hurt me.\n"} +{"Action":"output","Test":"TestAscii","Output":" V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR. V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR.\n"} +{"Action":"pass","Test":"TestAscii"} +{"Action":"output","Output":"PASS\n"} +{"Action":"pass"} diff --git a/libgo/go/cmd/internal/test2json/testdata/ascii.test b/libgo/go/cmd/internal/test2json/testdata/ascii.test new file mode 100644 index 00000000000..4ff7453430c --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/ascii.test @@ -0,0 +1,7 @@ +=== RUN TestAscii +I can eat glass, and it doesn't hurt me. I can eat glass, and it doesn't hurt me. +I CAN EAT GLASS, AND IT DOESN'T HURT ME. I CAN EAT GLASS, AND IT DOESN'T HURT ME. +--- PASS: TestAscii + i can eat glass, and it doesn't hurt me. i can eat glass, and it doesn't hurt me. + V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR. V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR. +PASS diff --git a/libgo/go/cmd/internal/test2json/testdata/smiley.json b/libgo/go/cmd/internal/test2json/testdata/smiley.json new file mode 100644 index 00000000000..afa990d7c03 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/smiley.json @@ -0,0 +1,182 @@ +{"Action":"run","Test":"Test☺☹"} +{"Action":"output","Test":"Test☺☹","Output":"=== RUN Test☺☹\n"} +{"Action":"output","Test":"Test☺☹","Output":"=== PAUSE Test☺☹\n"} +{"Action":"pause","Test":"Test☺☹"} +{"Action":"run","Test":"Test☺☹Asm"} +{"Action":"output","Test":"Test☺☹Asm","Output":"=== RUN Test☺☹Asm\n"} +{"Action":"output","Test":"Test☺☹Asm","Output":"=== PAUSE Test☺☹Asm\n"} +{"Action":"pause","Test":"Test☺☹Asm"} +{"Action":"run","Test":"Test☺☹Dirs"} +{"Action":"output","Test":"Test☺☹Dirs","Output":"=== RUN Test☺☹Dirs\n"} +{"Action":"output","Test":"Test☺☹Dirs","Output":"=== PAUSE Test☺☹Dirs\n"} +{"Action":"pause","Test":"Test☺☹Dirs"} +{"Action":"run","Test":"TestTags"} +{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n"} +{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n"} +{"Action":"pause","Test":"TestTags"} +{"Action":"run","Test":"Test☺☹Verbose"} +{"Action":"output","Test":"Test☺☹Verbose","Output":"=== RUN Test☺☹Verbose\n"} +{"Action":"output","Test":"Test☺☹Verbose","Output":"=== PAUSE Test☺☹Verbose\n"} +{"Action":"pause","Test":"Test☺☹Verbose"} +{"Action":"cont","Test":"Test☺☹"} +{"Action":"output","Test":"Test☺☹","Output":"=== CONT Test☺☹\n"} +{"Action":"cont","Test":"TestTags"} +{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n"} +{"Action":"cont","Test":"Test☺☹Verbose"} +{"Action":"output","Test":"Test☺☹Verbose","Output":"=== CONT Test☺☹Verbose\n"} +{"Action":"run","Test":"TestTags/testtag"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n"} +{"Action":"pause","Test":"TestTags/testtag"} +{"Action":"cont","Test":"Test☺☹Dirs"} +{"Action":"output","Test":"Test☺☹Dirs","Output":"=== CONT Test☺☹Dirs\n"} +{"Action":"cont","Test":"Test☺☹Asm"} +{"Action":"output","Test":"Test☺☹Asm","Output":"=== CONT Test☺☹Asm\n"} +{"Action":"run","Test":"Test☺☹/0"} +{"Action":"output","Test":"Test☺☹/0","Output":"=== RUN Test☺☹/0\n"} +{"Action":"output","Test":"Test☺☹/0","Output":"=== PAUSE Test☺☹/0\n"} +{"Action":"pause","Test":"Test☺☹/0"} +{"Action":"run","Test":"Test☺☹/1"} +{"Action":"output","Test":"Test☺☹/1","Output":"=== RUN Test☺☹/1\n"} +{"Action":"output","Test":"Test☺☹/1","Output":"=== PAUSE Test☺☹/1\n"} +{"Action":"pause","Test":"Test☺☹/1"} +{"Action":"run","Test":"Test☺☹/2"} +{"Action":"output","Test":"Test☺☹/2","Output":"=== RUN Test☺☹/2\n"} +{"Action":"output","Test":"Test☺☹/2","Output":"=== PAUSE Test☺☹/2\n"} +{"Action":"pause","Test":"Test☺☹/2"} +{"Action":"run","Test":"Test☺☹/3"} +{"Action":"output","Test":"Test☺☹/3","Output":"=== RUN Test☺☹/3\n"} +{"Action":"output","Test":"Test☺☹/3","Output":"=== PAUSE Test☺☹/3\n"} +{"Action":"pause","Test":"Test☺☹/3"} +{"Action":"run","Test":"Test☺☹/4"} +{"Action":"output","Test":"Test☺☹/4","Output":"=== RUN Test☺☹/4\n"} +{"Action":"run","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n"} +{"Action":"output","Test":"Test☺☹/4","Output":"=== PAUSE Test☺☹/4\n"} +{"Action":"pause","Test":"Test☺☹/4"} +{"Action":"run","Test":"Test☺☹/5"} +{"Action":"output","Test":"Test☺☹/5","Output":"=== RUN Test☺☹/5\n"} +{"Action":"output","Test":"Test☺☹/5","Output":"=== PAUSE Test☺☹/5\n"} +{"Action":"pause","Test":"Test☺☹/5"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n"} +{"Action":"pause","Test":"TestTags/x_testtag_y"} +{"Action":"run","Test":"Test☺☹/6"} +{"Action":"output","Test":"Test☺☹/6","Output":"=== RUN Test☺☹/6\n"} +{"Action":"run","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n"} +{"Action":"pause","Test":"TestTags/x,testtag,y"} +{"Action":"run","Test":"Test☺☹Dirs/testingpkg"} +{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== RUN Test☺☹Dirs/testingpkg\n"} +{"Action":"output","Test":"Test☺☹/6","Output":"=== PAUSE Test☺☹/6\n"} +{"Action":"pause","Test":"Test☺☹/6"} +{"Action":"cont","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n"} +{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== PAUSE Test☺☹Dirs/testingpkg\n"} +{"Action":"pause","Test":"Test☺☹Dirs/testingpkg"} +{"Action":"run","Test":"Test☺☹Dirs/divergent"} +{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== RUN Test☺☹Dirs/divergent\n"} +{"Action":"run","Test":"Test☺☹/7"} +{"Action":"output","Test":"Test☺☹/7","Output":"=== RUN Test☺☹/7\n"} +{"Action":"output","Test":"Test☺☹/7","Output":"=== PAUSE Test☺☹/7\n"} +{"Action":"pause","Test":"Test☺☹/7"} +{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== PAUSE Test☺☹Dirs/divergent\n"} +{"Action":"pause","Test":"Test☺☹Dirs/divergent"} +{"Action":"cont","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n"} +{"Action":"cont","Test":"TestTags/testtag"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n"} +{"Action":"run","Test":"Test☺☹Dirs/buildtag"} +{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== RUN Test☺☹Dirs/buildtag\n"} +{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== PAUSE Test☺☹Dirs/buildtag\n"} +{"Action":"pause","Test":"Test☺☹Dirs/buildtag"} +{"Action":"cont","Test":"Test☺☹/0"} +{"Action":"output","Test":"Test☺☹/0","Output":"=== CONT Test☺☹/0\n"} +{"Action":"cont","Test":"Test☺☹/4"} +{"Action":"output","Test":"Test☺☹/4","Output":"=== CONT Test☺☹/4\n"} +{"Action":"run","Test":"Test☺☹Dirs/incomplete"} +{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== RUN Test☺☹Dirs/incomplete\n"} +{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== PAUSE Test☺☹Dirs/incomplete\n"} +{"Action":"pause","Test":"Test☺☹Dirs/incomplete"} +{"Action":"run","Test":"Test☺☹Dirs/cgo"} +{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== RUN Test☺☹Dirs/cgo\n"} +{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== PAUSE Test☺☹Dirs/cgo\n"} +{"Action":"pause","Test":"Test☺☹Dirs/cgo"} +{"Action":"cont","Test":"Test☺☹/7"} +{"Action":"output","Test":"Test☺☹/7","Output":"=== CONT Test☺☹/7\n"} +{"Action":"cont","Test":"Test☺☹/6"} +{"Action":"output","Test":"Test☺☹/6","Output":"=== CONT Test☺☹/6\n"} +{"Action":"output","Test":"Test☺☹Verbose","Output":"--- PASS: Test☺☹Verbose (0.04s)\n"} +{"Action":"pass","Test":"Test☺☹Verbose"} +{"Action":"cont","Test":"Test☺☹/5"} +{"Action":"output","Test":"Test☺☹/5","Output":"=== CONT Test☺☹/5\n"} +{"Action":"cont","Test":"Test☺☹/3"} +{"Action":"output","Test":"Test☺☹/3","Output":"=== CONT Test☺☹/3\n"} +{"Action":"cont","Test":"Test☺☹/2"} +{"Action":"output","Test":"Test☺☹/2","Output":"=== CONT Test☺☹/2\n"} +{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":" \tvet_test.go:187: -tags=x testtag y\n"} +{"Action":"pass","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":" \tvet_test.go:187: -tags=x,testtag,y\n"} +{"Action":"pass","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"} +{"Action":"output","Test":"TestTags/testtag","Output":" \tvet_test.go:187: -tags=testtag\n"} +{"Action":"pass","Test":"TestTags/testtag"} +{"Action":"pass","Test":"TestTags"} +{"Action":"cont","Test":"Test☺☹/1"} +{"Action":"output","Test":"Test☺☹/1","Output":"=== CONT Test☺☹/1\n"} +{"Action":"cont","Test":"Test☺☹Dirs/testingpkg"} +{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== CONT Test☺☹Dirs/testingpkg\n"} +{"Action":"cont","Test":"Test☺☹Dirs/buildtag"} +{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== CONT Test☺☹Dirs/buildtag\n"} +{"Action":"cont","Test":"Test☺☹Dirs/divergent"} +{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== CONT Test☺☹Dirs/divergent\n"} +{"Action":"cont","Test":"Test☺☹Dirs/incomplete"} +{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== CONT Test☺☹Dirs/incomplete\n"} +{"Action":"cont","Test":"Test☺☹Dirs/cgo"} +{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== CONT Test☺☹Dirs/cgo\n"} +{"Action":"output","Test":"Test☺☹","Output":"--- PASS: Test☺☹ (0.39s)\n"} +{"Action":"output","Test":"Test☺☹/5","Output":" --- PASS: Test☺☹/5 (0.07s)\n"} +{"Action":"output","Test":"Test☺☹/5","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/5"} +{"Action":"output","Test":"Test☺☹/3","Output":" --- PASS: Test☺☹/3 (0.07s)\n"} +{"Action":"output","Test":"Test☺☹/3","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/3"} +{"Action":"output","Test":"Test☺☹/6","Output":" --- PASS: Test☺☹/6 (0.07s)\n"} +{"Action":"output","Test":"Test☺☹/6","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/6"} +{"Action":"output","Test":"Test☺☹/2","Output":" --- PASS: Test☺☹/2 (0.07s)\n"} +{"Action":"output","Test":"Test☺☹/2","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/2"} +{"Action":"output","Test":"Test☺☹/0","Output":" --- PASS: Test☺☹/0 (0.13s)\n"} +{"Action":"output","Test":"Test☺☹/0","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/0"} +{"Action":"output","Test":"Test☺☹/4","Output":" --- PASS: Test☺☹/4 (0.16s)\n"} +{"Action":"output","Test":"Test☺☹/4","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/4"} +{"Action":"output","Test":"Test☺☹/1","Output":" --- PASS: Test☺☹/1 (0.07s)\n"} +{"Action":"output","Test":"Test☺☹/1","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/1"} +{"Action":"output","Test":"Test☺☹/7","Output":" --- PASS: Test☺☹/7 (0.19s)\n"} +{"Action":"output","Test":"Test☺☹/7","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"} +{"Action":"pass","Test":"Test☺☹/7"} +{"Action":"pass","Test":"Test☺☹"} +{"Action":"output","Test":"Test☺☹Dirs","Output":"--- PASS: Test☺☹Dirs (0.01s)\n"} +{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":" --- PASS: Test☺☹Dirs/testingpkg (0.06s)\n"} +{"Action":"pass","Test":"Test☺☹Dirs/testingpkg"} +{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":" --- PASS: Test☺☹Dirs/divergent (0.05s)\n"} +{"Action":"pass","Test":"Test☺☹Dirs/divergent"} +{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":" --- PASS: Test☺☹Dirs/buildtag (0.06s)\n"} +{"Action":"pass","Test":"Test☺☹Dirs/buildtag"} +{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":" --- PASS: Test☺☹Dirs/incomplete (0.05s)\n"} +{"Action":"pass","Test":"Test☺☹Dirs/incomplete"} +{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":" --- PASS: Test☺☹Dirs/cgo (0.04s)\n"} +{"Action":"pass","Test":"Test☺☹Dirs/cgo"} +{"Action":"pass","Test":"Test☺☹Dirs"} +{"Action":"output","Test":"Test☺☹Asm","Output":"--- PASS: Test☺☹Asm (0.75s)\n"} +{"Action":"pass","Test":"Test☺☹Asm"} +{"Action":"output","Output":"PASS\n"} +{"Action":"output","Output":"ok \tcmd/vet\t(cached)\n"} +{"Action":"pass"} diff --git a/libgo/go/cmd/internal/test2json/testdata/smiley.test b/libgo/go/cmd/internal/test2json/testdata/smiley.test new file mode 100644 index 00000000000..05edf5a312f --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/smiley.test @@ -0,0 +1,97 @@ +=== RUN Test☺☹ +=== PAUSE Test☺☹ +=== RUN Test☺☹Asm +=== PAUSE Test☺☹Asm +=== RUN Test☺☹Dirs +=== PAUSE Test☺☹Dirs +=== RUN TestTags +=== PAUSE TestTags +=== RUN Test☺☹Verbose +=== PAUSE Test☺☹Verbose +=== CONT Test☺☹ +=== CONT TestTags +=== CONT Test☺☹Verbose +=== RUN TestTags/testtag +=== PAUSE TestTags/testtag +=== CONT Test☺☹Dirs +=== CONT Test☺☹Asm +=== RUN Test☺☹/0 +=== PAUSE Test☺☹/0 +=== RUN Test☺☹/1 +=== PAUSE Test☺☹/1 +=== RUN Test☺☹/2 +=== PAUSE Test☺☹/2 +=== RUN Test☺☹/3 +=== PAUSE Test☺☹/3 +=== RUN Test☺☹/4 +=== RUN TestTags/x_testtag_y +=== PAUSE Test☺☹/4 +=== RUN Test☺☹/5 +=== PAUSE Test☺☹/5 +=== PAUSE TestTags/x_testtag_y +=== RUN Test☺☹/6 +=== RUN TestTags/x,testtag,y +=== PAUSE TestTags/x,testtag,y +=== RUN Test☺☹Dirs/testingpkg +=== PAUSE Test☺☹/6 +=== CONT TestTags/x,testtag,y +=== PAUSE Test☺☹Dirs/testingpkg +=== RUN Test☺☹Dirs/divergent +=== RUN Test☺☹/7 +=== PAUSE Test☺☹/7 +=== PAUSE Test☺☹Dirs/divergent +=== CONT TestTags/x_testtag_y +=== CONT TestTags/testtag +=== RUN Test☺☹Dirs/buildtag +=== PAUSE Test☺☹Dirs/buildtag +=== CONT Test☺☹/0 +=== CONT Test☺☹/4 +=== RUN Test☺☹Dirs/incomplete +=== PAUSE Test☺☹Dirs/incomplete +=== RUN Test☺☹Dirs/cgo +=== PAUSE Test☺☹Dirs/cgo +=== CONT Test☺☹/7 +=== CONT Test☺☹/6 +--- PASS: Test☺☹Verbose (0.04s) +=== CONT Test☺☹/5 +=== CONT Test☺☹/3 +=== CONT Test☺☹/2 +--- PASS: TestTags (0.00s) + --- PASS: TestTags/x_testtag_y (0.04s) + vet_test.go:187: -tags=x testtag y + --- PASS: TestTags/x,testtag,y (0.04s) + vet_test.go:187: -tags=x,testtag,y + --- PASS: TestTags/testtag (0.04s) + vet_test.go:187: -tags=testtag +=== CONT Test☺☹/1 +=== CONT Test☺☹Dirs/testingpkg +=== CONT Test☺☹Dirs/buildtag +=== CONT Test☺☹Dirs/divergent +=== CONT Test☺☹Dirs/incomplete +=== CONT Test☺☹Dirs/cgo +--- PASS: Test☺☹ (0.39s) + --- PASS: Test☺☹/5 (0.07s) + vet_test.go:114: φιλεσ: ["testdata/copylock_func.go" "testdata/rangeloop.go"] + --- PASS: Test☺☹/3 (0.07s) + vet_test.go:114: φιλεσ: ["testdata/composite.go" "testdata/nilfunc.go"] + --- PASS: Test☺☹/6 (0.07s) + vet_test.go:114: φιλεσ: ["testdata/copylock_range.go" "testdata/shadow.go"] + --- PASS: Test☺☹/2 (0.07s) + vet_test.go:114: φιλεσ: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"] + --- PASS: Test☺☹/0 (0.13s) + vet_test.go:114: φιλεσ: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"] + --- PASS: Test☺☹/4 (0.16s) + vet_test.go:114: φιλεσ: ["testdata/copylock.go" "testdata/print.go"] + --- PASS: Test☺☹/1 (0.07s) + vet_test.go:114: φιλεσ: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"] + --- PASS: Test☺☹/7 (0.19s) + vet_test.go:114: φιλεσ: ["testdata/deadcode.go" "testdata/shift.go"] +--- PASS: Test☺☹Dirs (0.01s) + --- PASS: Test☺☹Dirs/testingpkg (0.06s) + --- PASS: Test☺☹Dirs/divergent (0.05s) + --- PASS: Test☺☹Dirs/buildtag (0.06s) + --- PASS: Test☺☹Dirs/incomplete (0.05s) + --- PASS: Test☺☹Dirs/cgo (0.04s) +--- PASS: Test☺☹Asm (0.75s) +PASS +ok cmd/vet (cached) diff --git a/libgo/go/cmd/internal/test2json/testdata/unicode.json b/libgo/go/cmd/internal/test2json/testdata/unicode.json new file mode 100644 index 00000000000..9cfb5f2d498 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/unicode.json @@ -0,0 +1,10 @@ +{"Action":"run","Test":"TestUnicode"} +{"Action":"output","Test":"TestUnicode","Output":"=== RUN TestUnicode\n"} +{"Action":"output","Test":"TestUnicode","Output":"Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.\n"} +{"Action":"output","Test":"TestUnicode","Output":"私はガラスを食べられます。それは私を傷つけません。私はガラスを食べられます。それは私を傷つけません。\n"} +{"Action":"output","Test":"TestUnicode","Output":"--- PASS: TestUnicode\n"} +{"Action":"output","Test":"TestUnicode","Output":" ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ\n"} +{"Action":"output","Test":"TestUnicode","Output":" אני יכול לאכול זכוכית וזה לא מזיק לי. אני יכול לאכול זכוכית וזה לא מזיק לי.\n"} +{"Action":"pass","Test":"TestUnicode"} +{"Action":"output","Output":"PASS\n"} +{"Action":"pass"} diff --git a/libgo/go/cmd/internal/test2json/testdata/unicode.test b/libgo/go/cmd/internal/test2json/testdata/unicode.test new file mode 100644 index 00000000000..58c620d5f74 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/unicode.test @@ -0,0 +1,7 @@ +=== RUN TestUnicode +Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. +私はガラスを食べられます。それは私を傷つけません。私はガラスを食べられます。それは私を傷つけません。 +--- PASS: TestUnicode + ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ + אני יכול לאכול זכוכית וזה לא מזיק לי. אני יכול לאכול זכוכית וזה לא מזיק לי. +PASS diff --git a/libgo/go/cmd/internal/test2json/testdata/vet.json b/libgo/go/cmd/internal/test2json/testdata/vet.json new file mode 100644 index 00000000000..8c5921d686f --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/vet.json @@ -0,0 +1,182 @@ +{"Action":"run","Test":"TestVet"} +{"Action":"output","Test":"TestVet","Output":"=== RUN TestVet\n"} +{"Action":"output","Test":"TestVet","Output":"=== PAUSE TestVet\n"} +{"Action":"pause","Test":"TestVet"} +{"Action":"run","Test":"TestVetAsm"} +{"Action":"output","Test":"TestVetAsm","Output":"=== RUN TestVetAsm\n"} +{"Action":"output","Test":"TestVetAsm","Output":"=== PAUSE TestVetAsm\n"} +{"Action":"pause","Test":"TestVetAsm"} +{"Action":"run","Test":"TestVetDirs"} +{"Action":"output","Test":"TestVetDirs","Output":"=== RUN TestVetDirs\n"} +{"Action":"output","Test":"TestVetDirs","Output":"=== PAUSE TestVetDirs\n"} +{"Action":"pause","Test":"TestVetDirs"} +{"Action":"run","Test":"TestTags"} +{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n"} +{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n"} +{"Action":"pause","Test":"TestTags"} +{"Action":"run","Test":"TestVetVerbose"} +{"Action":"output","Test":"TestVetVerbose","Output":"=== RUN TestVetVerbose\n"} +{"Action":"output","Test":"TestVetVerbose","Output":"=== PAUSE TestVetVerbose\n"} +{"Action":"pause","Test":"TestVetVerbose"} +{"Action":"cont","Test":"TestVet"} +{"Action":"output","Test":"TestVet","Output":"=== CONT TestVet\n"} +{"Action":"cont","Test":"TestTags"} +{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n"} +{"Action":"cont","Test":"TestVetVerbose"} +{"Action":"output","Test":"TestVetVerbose","Output":"=== CONT TestVetVerbose\n"} +{"Action":"run","Test":"TestTags/testtag"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n"} +{"Action":"pause","Test":"TestTags/testtag"} +{"Action":"cont","Test":"TestVetDirs"} +{"Action":"output","Test":"TestVetDirs","Output":"=== CONT TestVetDirs\n"} +{"Action":"cont","Test":"TestVetAsm"} +{"Action":"output","Test":"TestVetAsm","Output":"=== CONT TestVetAsm\n"} +{"Action":"run","Test":"TestVet/0"} +{"Action":"output","Test":"TestVet/0","Output":"=== RUN TestVet/0\n"} +{"Action":"output","Test":"TestVet/0","Output":"=== PAUSE TestVet/0\n"} +{"Action":"pause","Test":"TestVet/0"} +{"Action":"run","Test":"TestVet/1"} +{"Action":"output","Test":"TestVet/1","Output":"=== RUN TestVet/1\n"} +{"Action":"output","Test":"TestVet/1","Output":"=== PAUSE TestVet/1\n"} +{"Action":"pause","Test":"TestVet/1"} +{"Action":"run","Test":"TestVet/2"} +{"Action":"output","Test":"TestVet/2","Output":"=== RUN TestVet/2\n"} +{"Action":"output","Test":"TestVet/2","Output":"=== PAUSE TestVet/2\n"} +{"Action":"pause","Test":"TestVet/2"} +{"Action":"run","Test":"TestVet/3"} +{"Action":"output","Test":"TestVet/3","Output":"=== RUN TestVet/3\n"} +{"Action":"output","Test":"TestVet/3","Output":"=== PAUSE TestVet/3\n"} +{"Action":"pause","Test":"TestVet/3"} +{"Action":"run","Test":"TestVet/4"} +{"Action":"output","Test":"TestVet/4","Output":"=== RUN TestVet/4\n"} +{"Action":"run","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n"} +{"Action":"output","Test":"TestVet/4","Output":"=== PAUSE TestVet/4\n"} +{"Action":"pause","Test":"TestVet/4"} +{"Action":"run","Test":"TestVet/5"} +{"Action":"output","Test":"TestVet/5","Output":"=== RUN TestVet/5\n"} +{"Action":"output","Test":"TestVet/5","Output":"=== PAUSE TestVet/5\n"} +{"Action":"pause","Test":"TestVet/5"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n"} +{"Action":"pause","Test":"TestTags/x_testtag_y"} +{"Action":"run","Test":"TestVet/6"} +{"Action":"output","Test":"TestVet/6","Output":"=== RUN TestVet/6\n"} +{"Action":"run","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n"} +{"Action":"pause","Test":"TestTags/x,testtag,y"} +{"Action":"run","Test":"TestVetDirs/testingpkg"} +{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== RUN TestVetDirs/testingpkg\n"} +{"Action":"output","Test":"TestVet/6","Output":"=== PAUSE TestVet/6\n"} +{"Action":"pause","Test":"TestVet/6"} +{"Action":"cont","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n"} +{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== PAUSE TestVetDirs/testingpkg\n"} +{"Action":"pause","Test":"TestVetDirs/testingpkg"} +{"Action":"run","Test":"TestVetDirs/divergent"} +{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== RUN TestVetDirs/divergent\n"} +{"Action":"run","Test":"TestVet/7"} +{"Action":"output","Test":"TestVet/7","Output":"=== RUN TestVet/7\n"} +{"Action":"output","Test":"TestVet/7","Output":"=== PAUSE TestVet/7\n"} +{"Action":"pause","Test":"TestVet/7"} +{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== PAUSE TestVetDirs/divergent\n"} +{"Action":"pause","Test":"TestVetDirs/divergent"} +{"Action":"cont","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n"} +{"Action":"cont","Test":"TestTags/testtag"} +{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n"} +{"Action":"run","Test":"TestVetDirs/buildtag"} +{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== RUN TestVetDirs/buildtag\n"} +{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== PAUSE TestVetDirs/buildtag\n"} +{"Action":"pause","Test":"TestVetDirs/buildtag"} +{"Action":"cont","Test":"TestVet/0"} +{"Action":"output","Test":"TestVet/0","Output":"=== CONT TestVet/0\n"} +{"Action":"cont","Test":"TestVet/4"} +{"Action":"output","Test":"TestVet/4","Output":"=== CONT TestVet/4\n"} +{"Action":"run","Test":"TestVetDirs/incomplete"} +{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== RUN TestVetDirs/incomplete\n"} +{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== PAUSE TestVetDirs/incomplete\n"} +{"Action":"pause","Test":"TestVetDirs/incomplete"} +{"Action":"run","Test":"TestVetDirs/cgo"} +{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== RUN TestVetDirs/cgo\n"} +{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== PAUSE TestVetDirs/cgo\n"} +{"Action":"pause","Test":"TestVetDirs/cgo"} +{"Action":"cont","Test":"TestVet/7"} +{"Action":"output","Test":"TestVet/7","Output":"=== CONT TestVet/7\n"} +{"Action":"cont","Test":"TestVet/6"} +{"Action":"output","Test":"TestVet/6","Output":"=== CONT TestVet/6\n"} +{"Action":"output","Test":"TestVetVerbose","Output":"--- PASS: TestVetVerbose (0.04s)\n"} +{"Action":"pass","Test":"TestVetVerbose"} +{"Action":"cont","Test":"TestVet/5"} +{"Action":"output","Test":"TestVet/5","Output":"=== CONT TestVet/5\n"} +{"Action":"cont","Test":"TestVet/3"} +{"Action":"output","Test":"TestVet/3","Output":"=== CONT TestVet/3\n"} +{"Action":"cont","Test":"TestVet/2"} +{"Action":"output","Test":"TestVet/2","Output":"=== CONT TestVet/2\n"} +{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"} +{"Action":"output","Test":"TestTags/x_testtag_y","Output":" \tvet_test.go:187: -tags=x testtag y\n"} +{"Action":"pass","Test":"TestTags/x_testtag_y"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"} +{"Action":"output","Test":"TestTags/x,testtag,y","Output":" \tvet_test.go:187: -tags=x,testtag,y\n"} +{"Action":"pass","Test":"TestTags/x,testtag,y"} +{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"} +{"Action":"output","Test":"TestTags/testtag","Output":" \tvet_test.go:187: -tags=testtag\n"} +{"Action":"pass","Test":"TestTags/testtag"} +{"Action":"pass","Test":"TestTags"} +{"Action":"cont","Test":"TestVet/1"} +{"Action":"output","Test":"TestVet/1","Output":"=== CONT TestVet/1\n"} +{"Action":"cont","Test":"TestVetDirs/testingpkg"} +{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== CONT TestVetDirs/testingpkg\n"} +{"Action":"cont","Test":"TestVetDirs/buildtag"} +{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== CONT TestVetDirs/buildtag\n"} +{"Action":"cont","Test":"TestVetDirs/divergent"} +{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== CONT TestVetDirs/divergent\n"} +{"Action":"cont","Test":"TestVetDirs/incomplete"} +{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== CONT TestVetDirs/incomplete\n"} +{"Action":"cont","Test":"TestVetDirs/cgo"} +{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== CONT TestVetDirs/cgo\n"} +{"Action":"output","Test":"TestVet","Output":"--- PASS: TestVet (0.39s)\n"} +{"Action":"output","Test":"TestVet/5","Output":" --- PASS: TestVet/5 (0.07s)\n"} +{"Action":"output","Test":"TestVet/5","Output":" \tvet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"} +{"Action":"pass","Test":"TestVet/5"} +{"Action":"output","Test":"TestVet/3","Output":" --- PASS: TestVet/3 (0.07s)\n"} +{"Action":"output","Test":"TestVet/3","Output":" \tvet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"} +{"Action":"pass","Test":"TestVet/3"} +{"Action":"output","Test":"TestVet/6","Output":" --- PASS: TestVet/6 (0.07s)\n"} +{"Action":"output","Test":"TestVet/6","Output":" \tvet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"} +{"Action":"pass","Test":"TestVet/6"} +{"Action":"output","Test":"TestVet/2","Output":" --- PASS: TestVet/2 (0.07s)\n"} +{"Action":"output","Test":"TestVet/2","Output":" \tvet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"} +{"Action":"pass","Test":"TestVet/2"} +{"Action":"output","Test":"TestVet/0","Output":" --- PASS: TestVet/0 (0.13s)\n"} +{"Action":"output","Test":"TestVet/0","Output":" \tvet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"} +{"Action":"pass","Test":"TestVet/0"} +{"Action":"output","Test":"TestVet/4","Output":" --- PASS: TestVet/4 (0.16s)\n"} +{"Action":"output","Test":"TestVet/4","Output":" \tvet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"} +{"Action":"pass","Test":"TestVet/4"} +{"Action":"output","Test":"TestVet/1","Output":" --- PASS: TestVet/1 (0.07s)\n"} +{"Action":"output","Test":"TestVet/1","Output":" \tvet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"} +{"Action":"pass","Test":"TestVet/1"} +{"Action":"output","Test":"TestVet/7","Output":" --- PASS: TestVet/7 (0.19s)\n"} +{"Action":"output","Test":"TestVet/7","Output":" \tvet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"} +{"Action":"pass","Test":"TestVet/7"} +{"Action":"pass","Test":"TestVet"} +{"Action":"output","Test":"TestVetDirs","Output":"--- PASS: TestVetDirs (0.01s)\n"} +{"Action":"output","Test":"TestVetDirs/testingpkg","Output":" --- PASS: TestVetDirs/testingpkg (0.06s)\n"} +{"Action":"pass","Test":"TestVetDirs/testingpkg"} +{"Action":"output","Test":"TestVetDirs/divergent","Output":" --- PASS: TestVetDirs/divergent (0.05s)\n"} +{"Action":"pass","Test":"TestVetDirs/divergent"} +{"Action":"output","Test":"TestVetDirs/buildtag","Output":" --- PASS: TestVetDirs/buildtag (0.06s)\n"} +{"Action":"pass","Test":"TestVetDirs/buildtag"} +{"Action":"output","Test":"TestVetDirs/incomplete","Output":" --- PASS: TestVetDirs/incomplete (0.05s)\n"} +{"Action":"pass","Test":"TestVetDirs/incomplete"} +{"Action":"output","Test":"TestVetDirs/cgo","Output":" --- PASS: TestVetDirs/cgo (0.04s)\n"} +{"Action":"pass","Test":"TestVetDirs/cgo"} +{"Action":"pass","Test":"TestVetDirs"} +{"Action":"output","Test":"TestVetAsm","Output":"--- PASS: TestVetAsm (0.75s)\n"} +{"Action":"pass","Test":"TestVetAsm"} +{"Action":"output","Output":"PASS\n"} +{"Action":"output","Output":"ok \tcmd/vet\t(cached)\n"} +{"Action":"pass"} diff --git a/libgo/go/cmd/internal/test2json/testdata/vet.test b/libgo/go/cmd/internal/test2json/testdata/vet.test new file mode 100644 index 00000000000..3389559cb81 --- /dev/null +++ b/libgo/go/cmd/internal/test2json/testdata/vet.test @@ -0,0 +1,97 @@ +=== RUN TestVet +=== PAUSE TestVet +=== RUN TestVetAsm +=== PAUSE TestVetAsm +=== RUN TestVetDirs +=== PAUSE TestVetDirs +=== RUN TestTags +=== PAUSE TestTags +=== RUN TestVetVerbose +=== PAUSE TestVetVerbose +=== CONT TestVet +=== CONT TestTags +=== CONT TestVetVerbose +=== RUN TestTags/testtag +=== PAUSE TestTags/testtag +=== CONT TestVetDirs +=== CONT TestVetAsm +=== RUN TestVet/0 +=== PAUSE TestVet/0 +=== RUN TestVet/1 +=== PAUSE TestVet/1 +=== RUN TestVet/2 +=== PAUSE TestVet/2 +=== RUN TestVet/3 +=== PAUSE TestVet/3 +=== RUN TestVet/4 +=== RUN TestTags/x_testtag_y +=== PAUSE TestVet/4 +=== RUN TestVet/5 +=== PAUSE TestVet/5 +=== PAUSE TestTags/x_testtag_y +=== RUN TestVet/6 +=== RUN TestTags/x,testtag,y +=== PAUSE TestTags/x,testtag,y +=== RUN TestVetDirs/testingpkg +=== PAUSE TestVet/6 +=== CONT TestTags/x,testtag,y +=== PAUSE TestVetDirs/testingpkg +=== RUN TestVetDirs/divergent +=== RUN TestVet/7 +=== PAUSE TestVet/7 +=== PAUSE TestVetDirs/divergent +=== CONT TestTags/x_testtag_y +=== CONT TestTags/testtag +=== RUN TestVetDirs/buildtag +=== PAUSE TestVetDirs/buildtag +=== CONT TestVet/0 +=== CONT TestVet/4 +=== RUN TestVetDirs/incomplete +=== PAUSE TestVetDirs/incomplete +=== RUN TestVetDirs/cgo +=== PAUSE TestVetDirs/cgo +=== CONT TestVet/7 +=== CONT TestVet/6 +--- PASS: TestVetVerbose (0.04s) +=== CONT TestVet/5 +=== CONT TestVet/3 +=== CONT TestVet/2 +--- PASS: TestTags (0.00s) + --- PASS: TestTags/x_testtag_y (0.04s) + vet_test.go:187: -tags=x testtag y + --- PASS: TestTags/x,testtag,y (0.04s) + vet_test.go:187: -tags=x,testtag,y + --- PASS: TestTags/testtag (0.04s) + vet_test.go:187: -tags=testtag +=== CONT TestVet/1 +=== CONT TestVetDirs/testingpkg +=== CONT TestVetDirs/buildtag +=== CONT TestVetDirs/divergent +=== CONT TestVetDirs/incomplete +=== CONT TestVetDirs/cgo +--- PASS: TestVet (0.39s) + --- PASS: TestVet/5 (0.07s) + vet_test.go:114: files: ["testdata/copylock_func.go" "testdata/rangeloop.go"] + --- PASS: TestVet/3 (0.07s) + vet_test.go:114: files: ["testdata/composite.go" "testdata/nilfunc.go"] + --- PASS: TestVet/6 (0.07s) + vet_test.go:114: files: ["testdata/copylock_range.go" "testdata/shadow.go"] + --- PASS: TestVet/2 (0.07s) + vet_test.go:114: files: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"] + --- PASS: TestVet/0 (0.13s) + vet_test.go:114: files: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"] + --- PASS: TestVet/4 (0.16s) + vet_test.go:114: files: ["testdata/copylock.go" "testdata/print.go"] + --- PASS: TestVet/1 (0.07s) + vet_test.go:114: files: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"] + --- PASS: TestVet/7 (0.19s) + vet_test.go:114: files: ["testdata/deadcode.go" "testdata/shift.go"] +--- PASS: TestVetDirs (0.01s) + --- PASS: TestVetDirs/testingpkg (0.06s) + --- PASS: TestVetDirs/divergent (0.05s) + --- PASS: TestVetDirs/buildtag (0.06s) + --- PASS: TestVetDirs/incomplete (0.05s) + --- PASS: TestVetDirs/cgo (0.04s) +--- PASS: TestVetAsm (0.75s) +PASS +ok cmd/vet (cached) diff --git a/libgo/go/cmd/test2json/main.go b/libgo/go/cmd/test2json/main.go new file mode 100644 index 00000000000..7bdc867bbe5 --- /dev/null +++ b/libgo/go/cmd/test2json/main.go @@ -0,0 +1,131 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test2json converts go test output to a machine-readable JSON stream. +// +// Usage: +// +// go tool test2json [-p pkg] [-t] [./pkg.test -test.v] +// +// Test2json runs the given test command and converts its output to JSON; +// with no command specified, test2json expects test output on standard input. +// It writes a corresponding stream of JSON events to standard output. +// There is no unnecessary input or output buffering, so that +// the JSON stream can be read for “live updates” of test status. +// +// The -p flag sets the package reported in each test event. +// +// The -t flag requests that time stamps be added to each test event. +// +// Note that test2json is only intended for converting a single test +// binary's output. To convert the output of a "go test" command, +// use "go test -json" instead of invoking test2json directly. +// +// Output Format +// +// The JSON stream is a newline-separated sequence of TestEvent objects +// corresponding to the Go struct: +// +// type TestEvent struct { +// Time time.Time // encodes as an RFC3339-format string +// Action string +// Package string +// Test string +// Elapsed float64 // seconds +// Output string +// } +// +// The Time field holds the time the event happened. +// It is conventionally omitted for cached test results. +// +// The Action field is one of a fixed set of action descriptions: +// +// run - the test has started running +// pause - the test has been paused +// cont - the test has continued running +// pass - the test passed +// fail - the test failed +// output - the test printed output +// +// The Package field, if present, specifies the package being tested. +// When the go command runs parallel tests in -json mode, events from +// different tests are interlaced; the Package field allows readers to +// separate them. +// +// The Test field, if present, specifies the test or example, or benchmark +// function that caused the event. Events for the overall package test +// do not set Test. +// +// The Elapsed field is set for "pass" and "fail" events. It gives the time +// elapsed for the specific test or the overall package test that passed or failed. +// +// The Output field is set for Action == "output" and is a portion of the test's output +// (standard output and standard error merged together). The output is +// unmodified except that invalid UTF-8 output from a test is coerced +// into valid UTF-8 by use of replacement characters. With that one exception, +// the concatenation of the Output fields of all output events is the exact +// output of the test execution. +// +package main + +import ( + "flag" + "fmt" + "io" + "os" + "os/exec" + + "cmd/internal/test2json" +) + +var ( + flagP = flag.String("p", "", "report `pkg` as the package being tested in each event") + flagT = flag.Bool("t", false, "include timestamps in events") +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go tool test2json [-p pkg] [-t] [./pkg.test -test.v]\n") + os.Exit(2) +} + +func main() { + flag.Usage = usage + flag.Parse() + + var mode test2json.Mode + if *flagT { + mode |= test2json.Timestamp + } + c := test2json.NewConverter(os.Stdout, *flagP, mode) + defer c.Close() + + if flag.NArg() == 0 { + io.Copy(c, os.Stdin) + } else { + args := flag.Args() + cmd := exec.Command(args[0], args[1:]...) + w := &countWriter{0, c} + cmd.Stdout = w + cmd.Stderr = w + if err := cmd.Run(); err != nil { + if w.n > 0 { + // Assume command printed why it failed. + } else { + fmt.Fprintf(c, "test2json: %v\n", err) + } + c.Close() + os.Exit(1) + } + } +} + +type countWriter struct { + n int64 + w io.Writer +} + +func (w *countWriter) Write(b []byte) (int, error) { + w.n += int64(len(b)) + return w.w.Write(b) +} diff --git a/libgo/go/cmd/vet/README b/libgo/go/cmd/vet/README new file mode 100644 index 00000000000..5ab75494d3e --- /dev/null +++ b/libgo/go/cmd/vet/README @@ -0,0 +1,33 @@ +Vet is a tool that checks correctness of Go programs. It runs a suite of tests, +each tailored to check for a particular class of errors. Examples include incorrect +Printf format verbs and malformed build tags. + +Over time many checks have been added to vet's suite, but many more have been +rejected as not appropriate for the tool. The criteria applied when selecting which +checks to add are: + +Correctness: + +Vet's checks are about correctness, not style. A vet check must identify real or +potential bugs that could cause incorrect compilation or execution. A check that +only identifies stylistic points or alternative correct approaches to a situation +is not acceptable. + +Frequency: + +Vet is run every day by many programmers, often as part of every compilation or +submission. The cost in execution time is considerable, especially in aggregate, +so checks must be likely enough to find real problems that they are worth the +overhead of the added check. A new check that finds only a handful of problems +across all existing programs, even if the problem is significant, is not worth +adding to the suite everyone runs daily. + +Precision: + +Most of vet's checks are heuristic and can generate both false positives (flagging +correct programs) and false negatives (not flagging incorrect ones). The rate of +both these failures must be very small. A check that is too noisy will be ignored +by the programmer overwhelmed by the output; a check that misses too many of the +cases it's looking for will give a false sense of security. Neither is acceptable. +A vet check must be accurate enough that everything it reports is worth examining, +and complete enough to encourage real confidence. diff --git a/libgo/go/cmd/vet/all/main.go b/libgo/go/cmd/vet/all/main.go new file mode 100644 index 00000000000..09167af6d53 --- /dev/null +++ b/libgo/go/cmd/vet/all/main.go @@ -0,0 +1,318 @@ +// Copyright 2016 The Go 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 + +// The vet/all command runs go vet on the standard library and commands. +// It compares the output against a set of whitelists +// maintained in the whitelist directory. +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "go/build" + "go/types" + "internal/testenv" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync/atomic" +) + +var ( + flagPlatforms = flag.String("p", "", "platform(s) to use e.g. linux/amd64,darwin/386") + flagAll = flag.Bool("all", false, "run all platforms") + flagNoLines = flag.Bool("n", false, "don't print line numbers") +) + +var cmdGoPath string +var failed uint32 // updated atomically + +func main() { + log.SetPrefix("vet/all: ") + log.SetFlags(0) + + var err error + cmdGoPath, err = testenv.GoTool() + if err != nil { + log.Print("could not find cmd/go; skipping") + // We're on a platform that can't run cmd/go. + // We want this script to be able to run as part of all.bash, + // so return cleanly rather than with exit code 1. + return + } + + flag.Parse() + switch { + case *flagAll && *flagPlatforms != "": + log.Print("-all and -p flags are incompatible") + flag.Usage() + os.Exit(2) + case *flagPlatforms != "": + vetPlatforms(parseFlagPlatforms()) + case *flagAll: + vetPlatforms(allPlatforms()) + default: + hostPlatform.vet() + } + if atomic.LoadUint32(&failed) != 0 { + os.Exit(1) + } +} + +var hostPlatform = platform{os: build.Default.GOOS, arch: build.Default.GOARCH} + +func allPlatforms() []platform { + var pp []platform + cmd := exec.Command(cmdGoPath, "tool", "dist", "list") + out, err := cmd.Output() + if err != nil { + log.Fatal(err) + } + lines := bytes.Split(out, []byte{'\n'}) + for _, line := range lines { + if len(line) == 0 { + continue + } + pp = append(pp, parsePlatform(string(line))) + } + return pp +} + +func parseFlagPlatforms() []platform { + var pp []platform + components := strings.Split(*flagPlatforms, ",") + for _, c := range components { + pp = append(pp, parsePlatform(c)) + } + return pp +} + +func parsePlatform(s string) platform { + vv := strings.Split(s, "/") + if len(vv) != 2 { + log.Fatalf("could not parse platform %s, must be of form goos/goarch", s) + } + return platform{os: vv[0], arch: vv[1]} +} + +type whitelist map[string]int + +// load adds entries from the whitelist file, if present, for os/arch to w. +func (w whitelist) load(goos string, goarch string) { + sz := types.SizesFor("gc", goarch) + if sz == nil { + log.Fatalf("unknown type sizes for arch %q", goarch) + } + archbits := 8 * sz.Sizeof(types.Typ[types.UnsafePointer]) + + // Look up whether goarch has a shared arch suffix, + // such as mips64x for mips64 and mips64le. + archsuff := goarch + if x, ok := archAsmX[goarch]; ok { + archsuff = x + } + + // Load whitelists. + filenames := []string{ + "all.txt", + goos + ".txt", + goarch + ".txt", + goos + "_" + goarch + ".txt", + fmt.Sprintf("%dbit.txt", archbits), + } + if goarch != archsuff { + filenames = append(filenames, + archsuff+".txt", + goos+"_"+archsuff+".txt", + ) + } + + // We allow error message templates using GOOS and GOARCH. + if goos == "android" { + goos = "linux" // so many special cases :( + } + + // Read whitelists and do template substitution. + replace := strings.NewReplacer("GOOS", goos, "GOARCH", goarch, "ARCHSUFF", archsuff) + + for _, filename := range filenames { + path := filepath.Join("whitelist", filename) + f, err := os.Open(path) + if err != nil { + // Allow not-exist errors; not all combinations have whitelists. + if os.IsNotExist(err) { + continue + } + log.Fatal(err) + } + scan := bufio.NewScanner(f) + for scan.Scan() { + line := scan.Text() + if len(line) == 0 || strings.HasPrefix(line, "//") { + continue + } + w[replace.Replace(line)]++ + } + if err := scan.Err(); err != nil { + log.Fatal(err) + } + } +} + +type platform struct { + os string + arch string +} + +func (p platform) String() string { + return p.os + "/" + p.arch +} + +// ignorePathPrefixes are file path prefixes that should be ignored wholesale. +var ignorePathPrefixes = [...]string{ + // These testdata dirs have lots of intentionally broken/bad code for tests. + "cmd/go/testdata/", + "cmd/vet/testdata/", + "go/printer/testdata/", +} + +func vetPlatforms(pp []platform) { + for _, p := range pp { + p.vet() + } +} + +func (p platform) vet() { + var buf bytes.Buffer + fmt.Fprintf(&buf, "go run main.go -p %s\n", p) + + // Load whitelist(s). + w := make(whitelist) + w.load(p.os, p.arch) + + // 'go tool vet .' is considerably faster than 'go vet ./...' + // TODO: The unsafeptr checks are disabled for now, + // because there are so many false positives, + // and no clear way to improve vet to eliminate large chunks of them. + // And having them in the whitelists will just cause annoyance + // and churn when working on the runtime. + cmd := exec.Command(cmdGoPath, "tool", "vet", "-unsafeptr=false", "-source", ".") + cmd.Dir = filepath.Join(runtime.GOROOT(), "src") + cmd.Env = append(os.Environ(), "GOOS="+p.os, "GOARCH="+p.arch, "CGO_ENABLED=0") + stderr, err := cmd.StderrPipe() + if err != nil { + log.Fatal(err) + } + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + // Process vet output. + scan := bufio.NewScanner(stderr) + var parseFailed bool +NextLine: + for scan.Scan() { + line := scan.Text() + if strings.HasPrefix(line, "vet: ") { + // Typecheck failure: Malformed syntax or multiple packages or the like. + // This will yield nicer error messages elsewhere, so ignore them here. + continue + } + + if strings.HasPrefix(line, "panic: ") { + // Panic in vet. Don't filter anything, we want the complete output. + parseFailed = true + fmt.Fprintf(os.Stderr, "panic in vet (to reproduce: go run main.go -p %s):\n", p) + fmt.Fprintln(os.Stderr, line) + io.Copy(os.Stderr, stderr) + break + } + + fields := strings.SplitN(line, ":", 3) + var file, lineno, msg string + switch len(fields) { + case 2: + // vet message with no line number + file, msg = fields[0], fields[1] + case 3: + file, lineno, msg = fields[0], fields[1], fields[2] + default: + if !parseFailed { + parseFailed = true + fmt.Fprintf(os.Stderr, "failed to parse %s vet output:\n", p) + } + fmt.Fprintln(os.Stderr, line) + } + msg = strings.TrimSpace(msg) + + for _, ignore := range ignorePathPrefixes { + if strings.HasPrefix(file, filepath.FromSlash(ignore)) { + continue NextLine + } + } + + key := file + ": " + msg + if w[key] == 0 { + // Vet error with no match in the whitelist. Print it. + if *flagNoLines { + fmt.Fprintf(&buf, "%s: %s\n", file, msg) + } else { + fmt.Fprintf(&buf, "%s:%s: %s\n", file, lineno, msg) + } + atomic.StoreUint32(&failed, 1) + continue + } + w[key]-- + } + if parseFailed { + atomic.StoreUint32(&failed, 1) + return + } + if scan.Err() != nil { + log.Fatalf("failed to scan vet output: %v", scan.Err()) + } + err = cmd.Wait() + // We expect vet to fail. + // Make sure it has failed appropriately, though (for example, not a PathError). + if _, ok := err.(*exec.ExitError); !ok { + log.Fatalf("unexpected go vet execution failure: %v", err) + } + printedHeader := false + if len(w) > 0 { + for k, v := range w { + if v != 0 { + if !printedHeader { + fmt.Fprintln(&buf, "unmatched whitelist entries:") + printedHeader = true + } + for i := 0; i < v; i++ { + fmt.Fprintln(&buf, k) + } + atomic.StoreUint32(&failed, 1) + } + } + } + + os.Stdout.Write(buf.Bytes()) +} + +// archAsmX maps architectures to the suffix usually used for their assembly files, +// if different than the arch name itself. +var archAsmX = map[string]string{ + "android": "linux", + "mips64": "mips64x", + "mips64le": "mips64x", + "mips": "mipsx", + "mipsle": "mipsx", + "ppc64": "ppc64x", + "ppc64le": "ppc64x", +} diff --git a/libgo/go/cmd/vet/all/whitelist/386.txt b/libgo/go/cmd/vet/all/whitelist/386.txt new file mode 100644 index 00000000000..505856f3686 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/386.txt @@ -0,0 +1,27 @@ +// 386-specific vet whitelist. See readme.txt for details. + +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes + +// startup code uses non-standard calling convention and intentionally +// omits args. +runtime/asm_386.s: [386] rt0_go: use of 4(SP) points beyond argument frame + +// reflect trampolines intentionally omit arg size. Same for morestack. +runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame +runtime/asm_386.s: [386] morestack: use of 8(SP) points beyond argument frame +runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame + +// Intentionally missing declarations. These are special assembly routines. +runtime/asm_386.s: [386] ldt0setup: function ldt0setup missing Go declaration +runtime/asm_386.s: [386] emptyfunc: function emptyfunc missing Go declaration +runtime/asm_386.s: [386] aeshashbody: function aeshashbody missing Go declaration +runtime/asm_386.s: [386] memeqbody: function memeqbody missing Go declaration +runtime/asm_386.s: [386] cmpbody: function cmpbody missing Go declaration +runtime/asm_386.s: [386] addmoduledata: function addmoduledata missing Go declaration +runtime/duff_386.s: [386] duffzero: function duffzero missing Go declaration +runtime/duff_386.s: [386] duffcopy: function duffcopy missing Go declaration + +runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go declaration +runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration + +runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/all.txt b/libgo/go/cmd/vet/all/whitelist/all.txt new file mode 100644 index 00000000000..6792d263a5e --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/all.txt @@ -0,0 +1,50 @@ +// Non-platform-specific vet whitelist. See readme.txt for details. + +// Real problems that we can't fix. + +// This is a bad WriteTo signature. Errors are being ignored! +// However, we can't change it due to the Go 1 compatibility promise. +go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have signature WriteTo(io.Writer) (int64, error) + + +// False positives. + +// Nothing much to do about cross-package assembly. Unfortunate. +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: call is in package reflect +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Equal is in package bytes +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package bytes +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package strings + +// Legitimate vet complaints in which we are testing for correct runtime behavior +// in bad situations that vet can also detect statically. +encoding/json/decode_test.go: struct field m has json tag but is not exported +encoding/json/decode_test.go: struct field m2 has json tag but is not exported +encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key +runtime/testdata/testprog/deadlock.go: unreachable code +runtime/testdata/testprog/deadlock.go: unreachable code +sync/cond_test.go: assignment copies lock value to c2: sync.Cond contains sync.noCopy + +// Non-standard method signatures. +// These cases are basically ok. +// Errors are handled reasonably and there's no clear need for interface satisfaction. +// Except for the runtime/pprof case, the API is not exported. +cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error) +cmd/internal/bio/buf.go: method Seek(offset int64, whence int) int64 should have signature Seek(int64, int) (int64, error) +fmt/print.go: method WriteByte(c byte) should have signature WriteByte(byte) error +runtime/pprof/pprof.go: method WriteTo(w io.Writer, debug int) error should have signature WriteTo(io.Writer) (int64, error) + +// These encoding/xml methods have the correct signature. +// vet doesn't know it because they are *in* the encoding/xml package. +// It's not worth teaching vet about the distinction, so whitelist them. +encoding/gob/encode.go: method WriteByte(c byte) should have signature WriteByte(byte) error +encoding/xml/marshal.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error +encoding/xml/marshal_test.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error +encoding/xml/read.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error +encoding/xml/read_test.go: method UnmarshalXML(d *Decoder, start StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error +encoding/xml/xml_test.go: method UnmarshalXML(*Decoder, StartElement) error should have signature UnmarshalXML(*xml.Decoder, xml.StartElement) error + +// Long struct tags used to test reflect internals +cmd/link/link_test.go: struct field tag "\n\tLondon. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning, one might imagine, for the death of the sun. Dogs, undistinguishable in mire. Horses, scarcely better; splashed to their very blinkers. Foot passengers, jostling one another’s umbrellas in a general infection of ill temper, and losing their foot-hold at street-corners, where tens of thousands of other foot passengers have been slipping and sliding since the day broke (if this day ever broke), adding new deposits to the crust upon crust of mud, sticking at those points tenaciously to the pavement, and accumulating at compound interest.\n\n\tFog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pensioners, wheezing by the firesides of their wards; fog in the stem and bowl of the afternoon pipe of the wrathful skipper, down in his close cabin; fog cruelly pinching the toes and fingers of his shivering little ‘prentice boy on deck. Chance people on the bridges peeping over the parapets into a nether sky of fog, with fog all round them, as if they were up in a balloon and hanging in the misty clouds.\n\n\tGas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look.\n\n\tThe raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery." not compatible with reflect.StructTag.Get: bad syntax for struct tag key +cmd/link/link_test.go: struct field tag "\n\tIt was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again." not compatible with reflect.StructTag.Get: bad syntax for struct tag key +cmd/link/link_test.go: struct field tag "\n\tJarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless." not compatible with reflect.StructTag.Get: bad syntax for struct tag key +cmd/link/link_test.go: struct field tag "\n\tThe one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble." not compatible with reflect.StructTag.Get: bad syntax for struct tag key diff --git a/libgo/go/cmd/vet/all/whitelist/amd64.txt b/libgo/go/cmd/vet/all/whitelist/amd64.txt new file mode 100644 index 00000000000..ebde7be58b0 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/amd64.txt @@ -0,0 +1,34 @@ +// amd64-specific vet whitelist. See readme.txt for details. + + +// False positives. + + +// reflect trampolines intentionally omit arg size. Same for morestack. +runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame +runtime/asm_amd64.s: [amd64] morestack: use of 16(SP) points beyond argument frame +runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame + +// Nothing much to do about cross-package assembly. Unfortunate. +runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package strings +runtime/asm_amd64.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes +runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package bytes +runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package strings +runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package bytes + +// Intentionally missing declarations. These are special assembly routines. +// Some are jumped into from other routines, with values in specific registers. +// duff* have direct calls from the compiler. +// Others use the platform ABI. +// There is no sensible corresponding Go prototype. +runtime/asm_amd64.s: [amd64] aeshashbody: function aeshashbody missing Go declaration +runtime/asm_amd64.s: [amd64] memeqbody: function memeqbody missing Go declaration +runtime/asm_amd64.s: [amd64] cmpbody: function cmpbody missing Go declaration +runtime/asm_amd64.s: [amd64] indexbytebody: function indexbytebody missing Go declaration +runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go declaration +runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration +runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration +runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration +runtime/asm_amd64.s: [amd64] indexShortStr: function indexShortStr missing Go declaration +runtime/asm_amd64.s: [amd64] countByte: function countByte missing Go declaration +runtime/asm_amd64.s: [amd64] gcWriteBarrier: function gcWriteBarrier missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/android_386.txt b/libgo/go/cmd/vet/all/whitelist/android_386.txt new file mode 100644 index 00000000000..5095f2fc0c7 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/android_386.txt @@ -0,0 +1,8 @@ +// android/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration + +// These SP references occur after a stack-altering call. They're fine. +runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP) +runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP) +runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/android_amd64.txt b/libgo/go/cmd/vet/all/whitelist/android_amd64.txt new file mode 100644 index 00000000000..90dabb02090 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/android_amd64.txt @@ -0,0 +1,3 @@ +// android/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/android_arm.txt b/libgo/go/cmd/vet/all/whitelist/android_arm.txt new file mode 100644 index 00000000000..fbd569e6046 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/android_arm.txt @@ -0,0 +1,5 @@ +// android/arm-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP) +runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP) +runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/arm.txt b/libgo/go/cmd/vet/all/whitelist/arm.txt new file mode 100644 index 00000000000..839346c2d49 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/arm.txt @@ -0,0 +1,21 @@ +// arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes + +// reflect trampolines intentionally omit arg size. Same for morestack. +runtime/asm_arm.s: [arm] morestack: use of 4(R13) points beyond argument frame + +// Intentionally missing declarations. +runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration +runtime/asm_arm.s: [arm] abort: function abort missing Go declaration +runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration +runtime/asm_arm.s: [arm] cmpbody: function cmpbody missing Go declaration +runtime/asm_arm.s: [arm] usplitR0: function usplitR0 missing Go declaration +runtime/asm_arm.s: [arm] addmoduledata: function addmoduledata missing Go declaration +runtime/duff_arm.s: [arm] duffzero: function duffzero missing Go declaration +runtime/duff_arm.s: [arm] duffcopy: function duffcopy missing Go declaration +runtime/tls_arm.s: [arm] save_g: function save_g missing Go declaration +runtime/tls_arm.s: [arm] load_g: function load_g missing Go declaration +runtime/tls_arm.s: [arm] _initcgo: function _initcgo missing Go declaration + +runtime/internal/atomic/asm_arm.s: [arm] cas: function cas missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/arm64.txt b/libgo/go/cmd/vet/all/whitelist/arm64.txt new file mode 100644 index 00000000000..24fc6f42235 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/arm64.txt @@ -0,0 +1,11 @@ +// arm64-specific vet whitelist. See readme.txt for details. + +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes + +// Intentionally missing declarations. +runtime/asm_arm64.s: [arm64] abort: function abort missing Go declaration +runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration +runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration +runtime/duff_arm64.s: [arm64] duffcopy: function duffcopy missing Go declaration +runtime/tls_arm64.s: [arm64] load_g: function load_g missing Go declaration +runtime/tls_arm64.s: [arm64] save_g: function save_g missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_386.txt b/libgo/go/cmd/vet/all/whitelist/darwin_386.txt new file mode 100644 index 00000000000..d19d7d7bd04 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/darwin_386.txt @@ -0,0 +1,9 @@ +// darwin/386-specific vet whitelist. See readme.txt for details. + +// Ok + +runtime/sys_darwin_386.s: [386] now: function now missing Go declaration +runtime/sys_darwin_386.s: [386] bsdthread_start: function bsdthread_start missing Go declaration +runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration +runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration +runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt b/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt new file mode 100644 index 00000000000..94a4e8fa75b --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt @@ -0,0 +1,5 @@ +// darwin/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_darwin_amd64.s: [amd64] bsdthread_start: function bsdthread_start missing Go declaration +runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration +runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt b/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt new file mode 100644 index 00000000000..0e619be4623 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt @@ -0,0 +1,12 @@ +// darwin/arm-specific vet whitelist. See readme.txt for details. + +// False positives due to comments in assembly. +// To be removed. See CL 27154. + +runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP) + + +// Ok. + +runtime/sys_darwin_arm.s: [arm] bsdthread_start: function bsdthread_start missing Go declaration +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt b/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt new file mode 100644 index 00000000000..793cccf8dd8 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt @@ -0,0 +1,8 @@ +// darwin/arm64-specific vet whitelist. See readme.txt for details. + +runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) +runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) +runtime/sys_darwin_arm64.s: [arm64] bsdthread_create: RET without writing to 4-byte ret+24(FP) +runtime/sys_darwin_arm64.s: [arm64] bsdthread_start: function bsdthread_start missing Go declaration +runtime/sys_darwin_arm64.s: [arm64] bsdthread_register: RET without writing to 4-byte ret+0(FP) +runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/dragonfly_amd64.txt b/libgo/go/cmd/vet/all/whitelist/dragonfly_amd64.txt new file mode 100644 index 00000000000..6c441597939 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/dragonfly_amd64.txt @@ -0,0 +1,7 @@ +// dragonfly/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_dragonfly_amd64.s: [amd64] settls: function settls missing Go declaration + +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP) +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP) +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/freebsd_386.txt b/libgo/go/cmd/vet/all/whitelist/freebsd_386.txt new file mode 100644 index 00000000000..d37132cebb2 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/freebsd_386.txt @@ -0,0 +1,19 @@ +// freebsd/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_freebsd_386.s: [386] thr_start: unknown variable mm +runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable signo +runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable info +runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context +runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context +runtime/sys_freebsd_386.s: [386] setldt: function setldt missing Go declaration +runtime/sys_freebsd_386.s: [386] i386_set_ldt: function i386_set_ldt missing Go declaration +syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/freebsd_amd64.txt b/libgo/go/cmd/vet/all/whitelist/freebsd_amd64.txt new file mode 100644 index 00000000000..a910f48ca5d --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/freebsd_amd64.txt @@ -0,0 +1,6 @@ +// freebsd/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_freebsd_amd64.s: [amd64] settls: function settls missing Go declaration +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP) +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP) +syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/freebsd_arm.txt b/libgo/go/cmd/vet/all/whitelist/freebsd_arm.txt new file mode 100644 index 00000000000..11e5c42fd82 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/freebsd_arm.txt @@ -0,0 +1,4 @@ +// freebsd/arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration +runtime/sys_freebsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/linux_386.txt b/libgo/go/cmd/vet/all/whitelist/linux_386.txt new file mode 100644 index 00000000000..a5111ca8763 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/linux_386.txt @@ -0,0 +1,13 @@ +// linux/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration + +// These SP references occur after a stack-altering call. They're fine. +runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP) +runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP) +runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP) + +// Android-specific; stubs missing on other linux platforms. +runtime/sys_linux_386.s: [386] access: function access missing Go declaration +runtime/sys_linux_386.s: [386] connect: function connect missing Go declaration +runtime/sys_linux_386.s: [386] socket: function socket missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/linux_amd64.txt b/libgo/go/cmd/vet/all/whitelist/linux_amd64.txt new file mode 100644 index 00000000000..69ba65d54be --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/linux_amd64.txt @@ -0,0 +1,8 @@ +// linux/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration + +// Android-specific; stubs missing on other linux platforms. +runtime/sys_linux_amd64.s: [amd64] access: function access missing Go declaration +runtime/sys_linux_amd64.s: [amd64] connect: function connect missing Go declaration +runtime/sys_linux_amd64.s: [amd64] socket: function socket missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/linux_arm.txt b/libgo/go/cmd/vet/all/whitelist/linux_arm.txt new file mode 100644 index 00000000000..fbf0e270aa9 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/linux_arm.txt @@ -0,0 +1,12 @@ +// linux/arm-specific vet whitelist. See readme.txt for details. + + +// These SP references occur after a stack-altering call. They're fine. +runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP) +runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP) + +// Special functions. +runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration +runtime/sys_linux_arm.s: [arm] access: function access missing Go declaration +runtime/sys_linux_arm.s: [arm] connect: function connect missing Go declaration +runtime/sys_linux_arm.s: [arm] socket: function socket missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/linux_arm64.txt b/libgo/go/cmd/vet/all/whitelist/linux_arm64.txt new file mode 100644 index 00000000000..67280b72731 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/linux_arm64.txt @@ -0,0 +1,5 @@ +// linux/arm64-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_arm64.s: [arm64] access: function access missing Go declaration +runtime/sys_linux_arm64.s: [arm64] connect: function connect missing Go declaration +runtime/sys_linux_arm64.s: [arm64] socket: function socket missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt b/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt new file mode 100644 index 00000000000..21e87e37d8c --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt @@ -0,0 +1,5 @@ +// linux/ppc64-specific vet whitelist. See readme.txt for details. + +runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration +runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration +runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame diff --git a/libgo/go/cmd/vet/all/whitelist/mips.txt b/libgo/go/cmd/vet/all/whitelist/mips.txt new file mode 100644 index 00000000000..ad29336ad1b --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/mips.txt @@ -0,0 +1,7 @@ +// mips64-specific vet whitelist. See readme.txt for details. + +// Work around if-def'd code. Will be fixed by golang.org/issue/17544. +runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_lo+0(FP); expected sec_lo+4(FP) +runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_hi+4(FP); expected sec_hi+0(FP) +runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_lo+0(FP); expected ret_lo+4(FP) +runtime/sys_linux_mipsx.s: [mips] nanotime: invalid offset ret_hi+4(FP); expected ret_hi+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/mips64x.txt b/libgo/go/cmd/vet/all/whitelist/mips64x.txt new file mode 100644 index 00000000000..5354d21c642 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/mips64x.txt @@ -0,0 +1,6 @@ +// mips64-specific vet whitelist. See readme.txt for details. + +runtime/asm_mips64x.s: [GOARCH] abort: function abort missing Go declaration +runtime/duff_mips64x.s: [GOARCH] duffzero: function duffzero missing Go declaration +runtime/tls_mips64x.s: [GOARCH] save_g: function save_g missing Go declaration +runtime/tls_mips64x.s: [GOARCH] load_g: function load_g missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/mipsle.txt b/libgo/go/cmd/vet/all/whitelist/mipsle.txt new file mode 100644 index 00000000000..929216905e6 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/mipsle.txt @@ -0,0 +1,7 @@ +// mips64-specific vet whitelist. See readme.txt for details. + +// Work around if-def'd code. Will be fixed by golang.org/issue/17544. +runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_lo+4(FP); expected sec_lo+0(FP) +runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_hi+0(FP); expected sec_hi+4(FP) +runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_lo+4(FP); expected ret_lo+0(FP) +runtime/sys_linux_mipsx.s: [mipsle] nanotime: invalid offset ret_hi+0(FP); expected ret_hi+4(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/mipsx.txt b/libgo/go/cmd/vet/all/whitelist/mipsx.txt new file mode 100644 index 00000000000..860f8399211 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/mipsx.txt @@ -0,0 +1,9 @@ +// mips64-specific vet whitelist. See readme.txt for details. + +runtime/asm_mipsx.s: [GOARCH] abort: function abort missing Go declaration +runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration +runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration +runtime/asm_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes +runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP) +runtime/sys_linux_mipsx.s: [GOARCH] clone: 4(R29) should be flags+0(FP) +runtime/sys_linux_mipsx.s: [GOARCH] clone: 8(R29) should be stk+4(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/nacl_386.txt b/libgo/go/cmd/vet/all/whitelist/nacl_386.txt new file mode 100644 index 00000000000..68bba518ac6 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/nacl_386.txt @@ -0,0 +1,13 @@ +// nacl/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: naclWrite is in package syscall +runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: now is in package syscall +runtime/sys_nacl_386.s: [386] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration +runtime/sys_nacl_386.s: [386] setldt: function setldt missing Go declaration +runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame +runtime/sys_nacl_386.s: [386] sigtramp: use of 4(SP) points beyond argument frame +runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt +runtime/sys_nacl_386.s: [386] sigtramp: use of 8(SP) points beyond argument frame +runtime/sys_nacl_386.s: [386] sigtramp: use of 12(SP) points beyond argument frame +runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame +runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt diff --git a/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt b/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt new file mode 100644 index 00000000000..4b2aad2aacd --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt @@ -0,0 +1,29 @@ +// nacl/amd64p32-specific vet whitelist. See readme.txt for details. + +// reflect trampolines intentionally omit arg size. Same for morestack. +runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame +runtime/asm_amd64p32.s: [amd64p32] morestack: use of 16(SP) points beyond argument frame +runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame + +runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt +runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt +runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt +runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt +runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt +runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_sysinfo: function nacl_sysinfo missing Go declaration +runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: naclWrite is in package syscall +runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: now is in package syscall +runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration +runtime/sys_nacl_amd64p32.s: [amd64p32] settls: function settls missing Go declaration + +// Clearer using FP than SP, but that requires named offsets. +runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argc +runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv + +runtime/asm_amd64p32.s: [amd64p32] memeqbody: function memeqbody missing Go declaration +runtime/asm_amd64p32.s: [amd64p32] cannot check cross-package assembly function: Compare is in package bytes +runtime/asm_amd64p32.s: [amd64p32] cmpbody: function cmpbody missing Go declaration +runtime/asm_amd64p32.s: [amd64p32] indexbytebody: function indexbytebody missing Go declaration +runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP) + +runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/nacl_arm.txt b/libgo/go/cmd/vet/all/whitelist/nacl_arm.txt new file mode 100644 index 00000000000..cc0fcbab7f2 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/nacl_arm.txt @@ -0,0 +1,8 @@ +// nacl/arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration +runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: naclWrite is in package syscall +runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: now is in package syscall +runtime/sys_nacl_arm.s: [arm] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration +runtime/sys_nacl_arm.s: [arm] nacl_sysinfo: function nacl_sysinfo missing Go declaration +runtime/sys_nacl_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/netbsd.txt b/libgo/go/cmd/vet/all/whitelist/netbsd.txt new file mode 100644 index 00000000000..48bfde5017f --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/netbsd.txt @@ -0,0 +1,3 @@ +// netbsd-specific vet whitelist. See readme.txt for details. + +runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] sigreturn_tramp: function sigreturn_tramp missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/netbsd_386.txt b/libgo/go/cmd/vet/all/whitelist/netbsd_386.txt new file mode 100644 index 00000000000..1d1f323d7ca --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/netbsd_386.txt @@ -0,0 +1,23 @@ +// netbsd/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] settls: function settls missing Go declaration + +runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 140(SP) points beyond argument frame +runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame +runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame +runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable signo +runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable info +runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable context +runtime/sys_netbsd_386.s: [386] setldt: function setldt missing Go declaration +runtime/sys_netbsd_386.s: [386] setldt: use of 16(SP) points beyond argument frame + +syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/netbsd_amd64.txt b/libgo/go/cmd/vet/all/whitelist/netbsd_amd64.txt new file mode 100644 index 00000000000..8b14dc506df --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/netbsd_amd64.txt @@ -0,0 +1,3 @@ +// netbsd/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_netbsd_amd64.s: [amd64] settls: function settls missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/netbsd_arm.txt b/libgo/go/cmd/vet/all/whitelist/netbsd_arm.txt new file mode 100644 index 00000000000..c0a0aa2114e --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/netbsd_arm.txt @@ -0,0 +1,5 @@ +// netbsd/arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration +runtime/sys_netbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration +syscall/asm_netbsd_arm.s: [arm] Syscall9: unknown variable trap; offset 0 is num+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/openbsd_386.txt b/libgo/go/cmd/vet/all/whitelist/openbsd_386.txt new file mode 100644 index 00000000000..b5c0a736c2f --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/openbsd_386.txt @@ -0,0 +1,17 @@ +// openbsd/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable signo +runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable info +runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable context +runtime/sys_openbsd_386.s: [386] setldt: function setldt missing Go declaration +runtime/sys_openbsd_386.s: [386] settls: function settls missing Go declaration +syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP) +syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/openbsd_amd64.txt b/libgo/go/cmd/vet/all/whitelist/openbsd_amd64.txt new file mode 100644 index 00000000000..433f62ca07a --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/openbsd_amd64.txt @@ -0,0 +1,3 @@ +// openbsd/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_openbsd_amd64.s: [amd64] settls: function settls missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/openbsd_arm.txt b/libgo/go/cmd/vet/all/whitelist/openbsd_arm.txt new file mode 100644 index 00000000000..16bf26c7349 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/openbsd_arm.txt @@ -0,0 +1,4 @@ +// openbsd/arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration +runtime/sys_openbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/plan9_386.txt b/libgo/go/cmd/vet/all/whitelist/plan9_386.txt new file mode 100644 index 00000000000..153116100d4 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/plan9_386.txt @@ -0,0 +1,3 @@ +// plan9/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_plan9_386.s: [386] setldt: function setldt missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/plan9_amd64.txt b/libgo/go/cmd/vet/all/whitelist/plan9_amd64.txt new file mode 100644 index 00000000000..39fc8e2c3c5 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/plan9_amd64.txt @@ -0,0 +1,4 @@ +// plan9/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_plan9_amd64.s: [amd64] setldt: function setldt missing Go declaration +runtime/sys_plan9_amd64.s: [amd64] settls: function settls missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/plan9_arm.txt b/libgo/go/cmd/vet/all/whitelist/plan9_arm.txt new file mode 100644 index 00000000000..5af32717606 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/plan9_arm.txt @@ -0,0 +1,4 @@ +// plan9/arm-specific vet whitelist. See readme.txt for details. + +runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration +runtime/sys_plan9_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/ppc64x.txt b/libgo/go/cmd/vet/all/whitelist/ppc64x.txt new file mode 100644 index 00000000000..4f6444e1026 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/ppc64x.txt @@ -0,0 +1,12 @@ +// ppc64-specific vet whitelist. See readme.txt for details. + +runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes + +runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration +runtime/asm_ppc64x.s: [GOARCH] abort: function abort missing Go declaration +runtime/asm_ppc64x.s: [GOARCH] memeqbody: function memeqbody missing Go declaration +runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame +runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration +runtime/duff_ppc64x.s: [GOARCH] duffzero: function duffzero missing Go declaration +runtime/tls_ppc64x.s: [GOARCH] save_g: function save_g missing Go declaration +runtime/tls_ppc64x.s: [GOARCH] load_g: function load_g missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/readme.txt b/libgo/go/cmd/vet/all/whitelist/readme.txt new file mode 100644 index 00000000000..4f83757dbc2 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/readme.txt @@ -0,0 +1,4 @@ +This directory contains whitelists for vet complaints about the standard library and commands. +They are line-based and unordered, although counts of duplicated lines matter. +Each line matches vet's output, except that line numbers are removed to avoid churn. +There are also os-, arch-, and bitwidth-specific whitelists. diff --git a/libgo/go/cmd/vet/all/whitelist/s390x.txt b/libgo/go/cmd/vet/all/whitelist/s390x.txt new file mode 100644 index 00000000000..f18236c4f11 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/s390x.txt @@ -0,0 +1,17 @@ +runtime/asm_s390x.s: [s390x] abort: function abort missing Go declaration +runtime/asm_s390x.s: [s390x] memeqbody: function memeqbody missing Go declaration +runtime/asm_s390x.s: [s390x] memeqbodyclc: function memeqbodyclc missing Go declaration +runtime/asm_s390x.s: [s390x] indexbytebody: function indexbytebody missing Go declaration +runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes +runtime/asm_s390x.s: [s390x] cmpbody: function cmpbody missing Go declaration +runtime/asm_s390x.s: [s390x] cmpbodyclc: function cmpbodyclc missing Go declaration +runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package strings +runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package bytes +runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package strings +runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package bytes +runtime/asm_s390x.s: [s390x] indexShortStr: function indexShortStr missing Go declaration +runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration +runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl_xc missing Go declaration +runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration +runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration +runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/solaris_amd64.txt b/libgo/go/cmd/vet/all/whitelist/solaris_amd64.txt new file mode 100644 index 00000000000..26a9da42710 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/solaris_amd64.txt @@ -0,0 +1,6 @@ +// solaris/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_solaris_amd64.s: [amd64] settls: function settls missing Go declaration +runtime/sys_solaris_amd64.s: [amd64] pipe1: function pipe1 missing Go declaration +runtime/sys_solaris_amd64.s: [amd64] asmsysvicall6: function asmsysvicall6 missing Go declaration +runtime/sys_solaris_amd64.s: [amd64] usleep2: function usleep2 missing Go declaration diff --git a/libgo/go/cmd/vet/all/whitelist/windows.txt b/libgo/go/cmd/vet/all/whitelist/windows.txt new file mode 100644 index 00000000000..2c101aeb980 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/windows.txt @@ -0,0 +1,7 @@ +// windows-specific vet whitelist. See readme.txt for details. + +// Issue 18609 +crypto/x509/root_windows.go: unreachable code + +runtime/sys_windows_ARCHSUFF.s: [GOARCH] sigtramp: function sigtramp missing Go declaration +runtime/sys_windows_ARCHSUFF.s: [GOARCH] onosstack: unknown variable usec; offset 0 is fn+0(FP) diff --git a/libgo/go/cmd/vet/all/whitelist/windows_386.txt b/libgo/go/cmd/vet/all/whitelist/windows_386.txt new file mode 100644 index 00000000000..788684a49d9 --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/windows_386.txt @@ -0,0 +1,10 @@ +// windows/386-specific vet whitelist. See readme.txt for details. + +runtime/sys_windows_386.s: [386] profileloop: use of 4(SP) points beyond argument frame +runtime/sys_windows_386.s: [386] ctrlhandler: 4(SP) should be _type+0(FP) +runtime/sys_windows_386.s: [386] setldt: function setldt missing Go declaration +runtime/zcallback_windows.s: [386] callbackasm: function callbackasm missing Go declaration +runtime/sys_windows_386.s: [386] callbackasm1+0: function callbackasm1+0 missing Go declaration +runtime/sys_windows_386.s: [386] tstart: function tstart missing Go declaration +runtime/sys_windows_386.s: [386] tstart_stdcall: RET without writing to 4-byte ret+4(FP) +runtime/sys_windows_386.s: [386] cannot check cross-package assembly function: now is in package time diff --git a/libgo/go/cmd/vet/all/whitelist/windows_amd64.txt b/libgo/go/cmd/vet/all/whitelist/windows_amd64.txt new file mode 100644 index 00000000000..3be4602579e --- /dev/null +++ b/libgo/go/cmd/vet/all/whitelist/windows_amd64.txt @@ -0,0 +1,9 @@ +// windows/amd64-specific vet whitelist. See readme.txt for details. + +runtime/sys_windows_amd64.s: [amd64] ctrlhandler: 16(SP) should be _type+0(FP) +runtime/sys_windows_amd64.s: [amd64] ctrlhandler: RET without writing to 4-byte ret+8(FP) +runtime/sys_windows_amd64.s: [amd64] callbackasm1: function callbackasm1 missing Go declaration +runtime/sys_windows_amd64.s: [amd64] tstart_stdcall: RET without writing to 4-byte ret+8(FP) +runtime/sys_windows_amd64.s: [amd64] settls: function settls missing Go declaration +runtime/sys_windows_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time +runtime/zcallback_windows.s: [amd64] callbackasm: function callbackasm missing Go declaration diff --git a/libgo/go/cmd/vet/asmdecl.go b/libgo/go/cmd/vet/asmdecl.go new file mode 100644 index 00000000000..b01d23d342b --- /dev/null +++ b/libgo/go/cmd/vet/asmdecl.go @@ -0,0 +1,730 @@ +// 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. + +// Identify mismatches between assembly files and Go func declarations. + +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/build" + "go/token" + "go/types" + "regexp" + "strconv" + "strings" +) + +// 'kind' is a kind of assembly variable. +// The kinds 1, 2, 4, 8 stand for values of that size. +type asmKind int + +// These special kinds are not valid sizes. +const ( + asmString asmKind = 100 + iota + asmSlice + asmArray + asmInterface + asmEmptyInterface + asmStruct + asmComplex +) + +// An asmArch describes assembly parameters for an architecture +type asmArch struct { + name string + bigEndian bool + stack string + lr bool + // calculated during initialization + sizes types.Sizes + intSize int + ptrSize int + maxAlign int +} + +// An asmFunc describes the expected variables for a function on a given architecture. +type asmFunc struct { + arch *asmArch + size int // size of all arguments + vars map[string]*asmVar + varByOffset map[int]*asmVar +} + +// An asmVar describes a single assembly variable. +type asmVar struct { + name string + kind asmKind + typ string + off int + size int + inner []*asmVar +} + +var ( + asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false} + asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true} + asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true} + asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false} + asmArchAmd64p32 = asmArch{name: "amd64p32", bigEndian: false, stack: "SP", lr: false} + asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true} + asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true} + asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true} + asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true} + asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true} + asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true} + asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true} + + arches = []*asmArch{ + &asmArch386, + &asmArchArm, + &asmArchArm64, + &asmArchAmd64, + &asmArchAmd64p32, + &asmArchMips, + &asmArchMipsLE, + &asmArchMips64, + &asmArchMips64LE, + &asmArchPpc64, + &asmArchPpc64LE, + &asmArchS390X, + } +) + +func init() { + for _, arch := range arches { + arch.sizes = types.SizesFor("gc", arch.name) + if arch.sizes == nil { + panic("missing SizesFor for gc/" + arch.name) + } + arch.intSize = int(arch.sizes.Sizeof(types.Typ[types.Int])) + arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer])) + arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64])) + } +} + +var ( + re = regexp.MustCompile + asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`) + asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+()]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`) + asmDATA = re(`\b(DATA|GLOBL)\b`) + asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`) + asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`) + asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`) + asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`) + ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`) +) + +func asmCheck(pkg *Package) { + if !vet("asmdecl") { + return + } + + // No work if no assembly files. + if !pkg.hasFileWithSuffix(".s") { + return + } + + // Gather declarations. knownFunc[name][arch] is func description. + knownFunc := make(map[string]map[string]*asmFunc) + + for _, f := range pkg.files { + if f.file != nil { + for _, decl := range f.file.Decls { + if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil { + knownFunc[decl.Name.Name] = f.asmParseDecl(decl) + } + } + } + } + +Files: + for _, f := range pkg.files { + if !strings.HasSuffix(f.name, ".s") { + continue + } + Println("Checking file", f.name) + + // Determine architecture from file name if possible. + var arch string + var archDef *asmArch + for _, a := range arches { + if strings.HasSuffix(f.name, "_"+a.name+".s") { + arch = a.name + archDef = a + break + } + } + + lines := strings.SplitAfter(string(f.content), "\n") + var ( + fn *asmFunc + fnName string + localSize, argSize int + wroteSP bool + haveRetArg bool + retLine []int + ) + + flushRet := func() { + if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 { + v := fn.vars["ret"] + for _, line := range retLine { + f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off) + } + } + retLine = nil + } + for lineno, line := range lines { + lineno++ + + badf := func(format string, args ...interface{}) { + f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...)) + } + + if arch == "" { + // Determine architecture from +build line if possible. + if m := asmPlusBuild.FindStringSubmatch(line); m != nil { + // There can be multiple architectures in a single +build line, + // so accumulate them all and then prefer the one that + // matches build.Default.GOARCH. + var archCandidates []*asmArch + for _, fld := range strings.Fields(m[1]) { + for _, a := range arches { + if a.name == fld { + archCandidates = append(archCandidates, a) + } + } + } + for _, a := range archCandidates { + if a.name == build.Default.GOARCH { + archCandidates = []*asmArch{a} + break + } + } + if len(archCandidates) > 0 { + arch = archCandidates[0].name + archDef = archCandidates[0] + } + } + } + + if m := asmTEXT.FindStringSubmatch(line); m != nil { + flushRet() + if arch == "" { + // Arch not specified by filename or build tags. + // Fall back to build.Default.GOARCH. + for _, a := range arches { + if a.name == build.Default.GOARCH { + arch = a.name + archDef = a + break + } + } + if arch == "" { + f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name) + continue Files + } + } + fnName = m[2] + if pkgName := strings.TrimSpace(m[1]); pkgName != "" { + pathParts := strings.Split(pkgName, "∕") + pkgName = pathParts[len(pathParts)-1] + if pkgName != f.pkg.path { + f.Warnf(token.NoPos, "%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", f.name, lineno, arch, fnName, pkgName) + fn = nil + fnName = "" + continue + } + } + fn = knownFunc[fnName][arch] + if fn != nil { + size, _ := strconv.Atoi(m[5]) + flag := m[3] + if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) { + badf("wrong argument size %d; expected $...-%d", size, fn.size) + } + } + localSize, _ = strconv.Atoi(m[4]) + localSize += archDef.intSize + if archDef.lr { + // Account for caller's saved LR + localSize += archDef.intSize + } + argSize, _ = strconv.Atoi(m[5]) + if fn == nil && !strings.Contains(fnName, "<>") { + badf("function %s missing Go declaration", fnName) + } + wroteSP = false + haveRetArg = false + continue + } else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") { + // function, but not visible from Go (didn't match asmTEXT), so stop checking + flushRet() + fn = nil + fnName = "" + continue + } + + if strings.Contains(line, "RET") { + retLine = append(retLine, lineno) + } + + if fnName == "" { + continue + } + + if asmDATA.FindStringSubmatch(line) != nil { + fn = nil + } + + if archDef == nil { + continue + } + + if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) { + wroteSP = true + continue + } + + for _, m := range asmSP.FindAllStringSubmatch(line, -1) { + if m[3] != archDef.stack || wroteSP { + continue + } + off := 0 + if m[1] != "" { + off, _ = strconv.Atoi(m[2]) + } + if off >= localSize { + if fn != nil { + v := fn.varByOffset[off-localSize] + if v != nil { + badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize) + continue + } + } + if off >= localSize+argSize { + badf("use of %s points beyond argument frame", m[1]) + continue + } + badf("use of %s to access argument frame", m[1]) + } + } + + if fn == nil { + continue + } + + for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) { + off, _ := strconv.Atoi(m[2]) + v := fn.varByOffset[off] + if v != nil { + badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off) + } else { + badf("use of unnamed argument %s", m[1]) + } + } + + for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) { + name := m[1] + off := 0 + if m[2] != "" { + off, _ = strconv.Atoi(m[2]) + } + if name == "ret" || strings.HasPrefix(name, "ret_") { + haveRetArg = true + } + v := fn.vars[name] + if v == nil { + // Allow argframe+0(FP). + if name == "argframe" && off == 0 { + continue + } + v = fn.varByOffset[off] + if v != nil { + badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off) + } else { + badf("unknown variable %s", name) + } + continue + } + asmCheckVar(badf, fn, line, m[0], off, v) + } + } + flushRet() + } +} + +func asmKindForType(t types.Type, size int) asmKind { + switch t := t.Underlying().(type) { + case *types.Basic: + switch t.Kind() { + case types.String: + return asmString + case types.Complex64, types.Complex128: + return asmComplex + } + return asmKind(size) + case *types.Pointer, *types.Chan, *types.Map, *types.Signature: + return asmKind(size) + case *types.Struct: + return asmStruct + case *types.Interface: + if t.Empty() { + return asmEmptyInterface + } + return asmInterface + case *types.Array: + return asmArray + case *types.Slice: + return asmSlice + } + panic("unreachable") +} + +// A component is an assembly-addressable component of a composite type, +// or a composite type itself. +type component struct { + size int + offset int + kind asmKind + typ string + suffix string // Such as _base for string base, _0_lo for lo half of first element of [1]uint64 on 32 bit machine. + outer string // The suffix for immediately containing composite type. +} + +func newComponent(suffix string, kind asmKind, typ string, offset, size int, outer string) component { + return component{suffix: suffix, kind: kind, typ: typ, offset: offset, size: size, outer: outer} +} + +// componentsOfType generates a list of components of type t. +// For example, given string, the components are the string itself, the base, and the length. +func componentsOfType(arch *asmArch, t types.Type) []component { + return appendComponentsRecursive(arch, t, nil, "", 0) +} + +// appendComponentsRecursive implements componentsOfType. +// Recursion is required to correct handle structs and arrays, +// which can contain arbitrary other types. +func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component { + s := t.String() + size := int(arch.sizes.Sizeof(t)) + kind := asmKindForType(t, size) + cc = append(cc, newComponent(suffix, kind, s, off, size, suffix)) + + switch kind { + case 8: + if arch.ptrSize == 4 { + w1, w2 := "lo", "hi" + if arch.bigEndian { + w1, w2 = w2, w1 + } + cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix)) + cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix)) + } + + case asmEmptyInterface: + cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize), "interface type", off, arch.ptrSize, suffix)) + cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix)) + + case asmInterface: + cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize), "interface itable", off, arch.ptrSize, suffix)) + cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix)) + + case asmSlice: + cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "slice base", off, arch.ptrSize, suffix)) + cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "slice len", off+arch.ptrSize, arch.intSize, suffix)) + cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize), "slice cap", off+arch.ptrSize+arch.intSize, arch.intSize, suffix)) + + case asmString: + cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "string base", off, arch.ptrSize, suffix)) + cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "string len", off+arch.ptrSize, arch.intSize, suffix)) + + case asmComplex: + fsize := size / 2 + cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix)) + cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix)) + + case asmStruct: + tu := t.Underlying().(*types.Struct) + fields := make([]*types.Var, tu.NumFields()) + for i := 0; i < tu.NumFields(); i++ { + fields[i] = tu.Field(i) + } + offsets := arch.sizes.Offsetsof(fields) + for i, f := range fields { + cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i])) + } + + case asmArray: + tu := t.Underlying().(*types.Array) + elem := tu.Elem() + // Calculate offset of each element array. + fields := []*types.Var{ + types.NewVar(token.NoPos, nil, "fake0", elem), + types.NewVar(token.NoPos, nil, "fake1", elem), + } + offsets := arch.sizes.Offsetsof(fields) + elemoff := int(offsets[1]) + for i := 0; i < int(tu.Len()); i++ { + cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff) + } + } + + return cc +} + +// asmParseDecl parses a function decl for expected assembly variables. +func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc { + var ( + arch *asmArch + fn *asmFunc + offset int + ) + + // addParams adds asmVars for each of the parameters in list. + // isret indicates whether the list are the arguments or the return values. + addParams := func(list []*ast.Field, isret bool) { + argnum := 0 + for _, fld := range list { + t := f.pkg.types[fld.Type].Type + align := int(arch.sizes.Alignof(t)) + size := int(arch.sizes.Sizeof(t)) + offset += -offset & (align - 1) + cc := componentsOfType(arch, t) + + // names is the list of names with this type. + names := fld.Names + if len(names) == 0 { + // Anonymous args will be called arg, arg1, arg2, ... + // Similarly so for return values: ret, ret1, ret2, ... + name := "arg" + if isret { + name = "ret" + } + if argnum > 0 { + name += strconv.Itoa(argnum) + } + names = []*ast.Ident{ast.NewIdent(name)} + } + argnum += len(names) + + // Create variable for each name. + for _, id := range names { + name := id.Name + for _, c := range cc { + outer := name + c.outer + v := asmVar{ + name: name + c.suffix, + kind: c.kind, + typ: c.typ, + off: offset + c.offset, + size: c.size, + } + if vo := fn.vars[outer]; vo != nil { + vo.inner = append(vo.inner, &v) + } + fn.vars[v.name] = &v + for i := 0; i < v.size; i++ { + fn.varByOffset[v.off+i] = &v + } + } + offset += size + } + } + } + + m := make(map[string]*asmFunc) + for _, arch = range arches { + fn = &asmFunc{ + arch: arch, + vars: make(map[string]*asmVar), + varByOffset: make(map[int]*asmVar), + } + offset = 0 + addParams(decl.Type.Params.List, false) + if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 { + offset += -offset & (arch.maxAlign - 1) + addParams(decl.Type.Results.List, true) + } + fn.size = offset + m[arch.name] = fn + } + + return m +} + +// asmCheckVar checks a single variable reference. +func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) { + m := asmOpcode.FindStringSubmatch(line) + if m == nil { + if !strings.HasPrefix(strings.TrimSpace(line), "//") { + badf("cannot find assembly opcode") + } + return + } + + // Determine operand sizes from instruction. + // Typically the suffix suffices, but there are exceptions. + var src, dst, kind asmKind + op := m[1] + switch fn.arch.name + "." + op { + case "386.FMOVLP": + src, dst = 8, 4 + case "arm.MOVD": + src = 8 + case "arm.MOVW": + src = 4 + case "arm.MOVH", "arm.MOVHU": + src = 2 + case "arm.MOVB", "arm.MOVBU": + src = 1 + // LEA* opcodes don't really read the second arg. + // They just take the address of it. + case "386.LEAL": + dst = 4 + case "amd64.LEAQ": + dst = 8 + case "amd64p32.LEAL": + dst = 4 + default: + switch fn.arch.name { + case "386", "amd64": + if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) { + // FMOVDP, FXCHD, etc + src = 8 + break + } + if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") { + // PINSRD, PEXTRD, etc + src = 4 + break + } + if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) { + // FMOVFP, FXCHF, etc + src = 4 + break + } + if strings.HasSuffix(op, "SD") { + // MOVSD, SQRTSD, etc + src = 8 + break + } + if strings.HasSuffix(op, "SS") { + // MOVSS, SQRTSS, etc + src = 4 + break + } + if strings.HasPrefix(op, "SET") { + // SETEQ, etc + src = 1 + break + } + switch op[len(op)-1] { + case 'B': + src = 1 + case 'W': + src = 2 + case 'L': + src = 4 + case 'D', 'Q': + src = 8 + } + case "ppc64", "ppc64le": + // Strip standard suffixes to reveal size letter. + m := ppc64Suff.FindStringSubmatch(op) + if m != nil { + switch m[1][0] { + case 'B': + src = 1 + case 'H': + src = 2 + case 'W': + src = 4 + case 'D': + src = 8 + } + } + case "mips", "mipsle", "mips64", "mips64le": + switch op { + case "MOVB", "MOVBU": + src = 1 + case "MOVH", "MOVHU": + src = 2 + case "MOVW", "MOVWU", "MOVF": + src = 4 + case "MOVV", "MOVD": + src = 8 + } + case "s390x": + switch op { + case "MOVB", "MOVBZ": + src = 1 + case "MOVH", "MOVHZ": + src = 2 + case "MOVW", "MOVWZ", "FMOVS": + src = 4 + case "MOVD", "FMOVD": + src = 8 + } + } + } + if dst == 0 { + dst = src + } + + // Determine whether the match we're holding + // is the first or second argument. + if strings.Index(line, expr) > strings.Index(line, ",") { + kind = dst + } else { + kind = src + } + + vk := v.kind + vs := v.size + vt := v.typ + switch vk { + case asmInterface, asmEmptyInterface, asmString, asmSlice: + // allow reference to first word (pointer) + vk = v.inner[0].kind + vs = v.inner[0].size + vt = v.inner[0].typ + } + + if off != v.off { + var inner bytes.Buffer + for i, vi := range v.inner { + if len(v.inner) > 1 { + fmt.Fprintf(&inner, ",") + } + fmt.Fprintf(&inner, " ") + if i == len(v.inner)-1 { + fmt.Fprintf(&inner, "or ") + } + fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off) + } + badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String()) + return + } + if kind != 0 && kind != vk { + var inner bytes.Buffer + if len(v.inner) > 0 { + fmt.Fprintf(&inner, " containing") + for i, vi := range v.inner { + if i > 0 && len(v.inner) > 2 { + fmt.Fprintf(&inner, ",") + } + fmt.Fprintf(&inner, " ") + if i > 0 && i == len(v.inner)-1 { + fmt.Fprintf(&inner, "and ") + } + fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off) + } + } + badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vs, inner.String()) + } +} diff --git a/libgo/go/cmd/vet/assign.go b/libgo/go/cmd/vet/assign.go new file mode 100644 index 00000000000..bfa5b303293 --- /dev/null +++ b/libgo/go/cmd/vet/assign.go @@ -0,0 +1,52 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +This file contains the code to check for useless assignments. +*/ + +package main + +import ( + "go/ast" + "go/token" + "reflect" +) + +func init() { + register("assign", + "check for useless assignments", + checkAssignStmt, + assignStmt) +} + +// TODO: should also check for assignments to struct fields inside methods +// that are on T instead of *T. + +// checkAssignStmt checks for assignments of the form " = ". +// These are almost always useless, and even when they aren't they are usually a mistake. +func checkAssignStmt(f *File, node ast.Node) { + stmt := node.(*ast.AssignStmt) + if stmt.Tok != token.ASSIGN { + return // ignore := + } + if len(stmt.Lhs) != len(stmt.Rhs) { + // If LHS and RHS have different cardinality, they can't be the same. + return + } + for i, lhs := range stmt.Lhs { + rhs := stmt.Rhs[i] + if hasSideEffects(lhs) || hasSideEffects(rhs) { + continue // expressions may not be equal + } + if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { + continue // short-circuit the heavy-weight gofmt check + } + le := f.gofmt(lhs) + re := f.gofmt(rhs) + if le == re { + f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le) + } + } +} diff --git a/libgo/go/cmd/vet/atomic.go b/libgo/go/cmd/vet/atomic.go new file mode 100644 index 00000000000..b2ca2d80f30 --- /dev/null +++ b/libgo/go/cmd/vet/atomic.go @@ -0,0 +1,69 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" + "go/token" +) + +func init() { + register("atomic", + "check for common mistaken usages of the sync/atomic package", + checkAtomicAssignment, + assignStmt) +} + +// checkAtomicAssignment walks the assignment statement checking for common +// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1) +func checkAtomicAssignment(f *File, node ast.Node) { + n := node.(*ast.AssignStmt) + if len(n.Lhs) != len(n.Rhs) { + return + } + if len(n.Lhs) == 1 && n.Tok == token.DEFINE { + return + } + + for i, right := range n.Rhs { + call, ok := right.(*ast.CallExpr) + if !ok { + continue + } + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + continue + } + pkg, ok := sel.X.(*ast.Ident) + if !ok || pkg.Name != "atomic" { + continue + } + + switch sel.Sel.Name { + case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr": + f.checkAtomicAddAssignment(n.Lhs[i], call) + } + } +} + +// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value +// to the same variable being used in the operation +func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) { + if len(call.Args) != 2 { + return + } + arg := call.Args[0] + broken := false + + if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND { + broken = f.gofmt(left) == f.gofmt(uarg.X) + } else if star, ok := left.(*ast.StarExpr); ok { + broken = f.gofmt(star.X) == f.gofmt(arg) + } + + if broken { + f.Bad(left.Pos(), "direct assignment to atomic value") + } +} diff --git a/libgo/go/cmd/vet/bool.go b/libgo/go/cmd/vet/bool.go new file mode 100644 index 00000000000..07c2a93dffa --- /dev/null +++ b/libgo/go/cmd/vet/bool.go @@ -0,0 +1,186 @@ +// Copyright 2014 The Go 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 boolean condition tests. + +package main + +import ( + "go/ast" + "go/token" +) + +func init() { + register("bool", + "check for mistakes involving boolean operators", + checkBool, + binaryExpr) +} + +func checkBool(f *File, n ast.Node) { + e := n.(*ast.BinaryExpr) + + var op boolOp + switch e.Op { + case token.LOR: + op = or + case token.LAND: + op = and + default: + return + } + + comm := op.commutativeSets(e) + for _, exprs := range comm { + op.checkRedundant(f, exprs) + op.checkSuspect(f, exprs) + } +} + +type boolOp struct { + name string + tok token.Token // token corresponding to this operator + badEq token.Token // token corresponding to the equality test that should not be used with this operator +} + +var ( + or = boolOp{"or", token.LOR, token.NEQ} + and = boolOp{"and", token.LAND, token.EQL} +) + +// commutativeSets returns all side effect free sets of +// expressions in e that are connected by op. +// For example, given 'a || b || f() || c || d' with the or op, +// commutativeSets returns {{b, a}, {d, c}}. +func (op boolOp) commutativeSets(e *ast.BinaryExpr) [][]ast.Expr { + exprs := op.split(e) + + // Partition the slice of expressions into commutative sets. + i := 0 + var sets [][]ast.Expr + for j := 0; j <= len(exprs); j++ { + if j == len(exprs) || hasSideEffects(exprs[j]) { + if i < j { + sets = append(sets, exprs[i:j]) + } + i = j + 1 + } + } + + return sets +} + +// checkRedundant checks for expressions of the form +// e && e +// e || e +// Exprs must contain only side effect free expressions. +func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) { + seen := make(map[string]bool) + for _, e := range exprs { + efmt := f.gofmt(e) + if seen[efmt] { + f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt) + } else { + seen[efmt] = true + } + } +} + +// checkSuspect checks for expressions of the form +// x != c1 || x != c2 +// x == c1 && x == c2 +// where c1 and c2 are constant expressions. +// If c1 and c2 are the same then it's redundant; +// if c1 and c2 are different then it's always true or always false. +// Exprs must contain only side effect free expressions. +func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) { + // seen maps from expressions 'x' to equality expressions 'x != c'. + seen := make(map[string]string) + + for _, e := range exprs { + bin, ok := e.(*ast.BinaryExpr) + if !ok || bin.Op != op.badEq { + continue + } + + // In order to avoid false positives, restrict to cases + // in which one of the operands is constant. We're then + // interested in the other operand. + // In the rare case in which both operands are constant + // (e.g. runtime.GOOS and "windows"), we'll only catch + // mistakes if the LHS is repeated, which is how most + // code is written. + var x ast.Expr + switch { + case f.pkg.types[bin.Y].Value != nil: + x = bin.X + case f.pkg.types[bin.X].Value != nil: + x = bin.Y + default: + continue + } + + // e is of the form 'x != c' or 'x == c'. + xfmt := f.gofmt(x) + efmt := f.gofmt(e) + if prev, found := seen[xfmt]; found { + // checkRedundant handles the case in which efmt == prev. + if efmt != prev { + f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev) + } + } else { + seen[xfmt] = efmt + } + } +} + +// hasSideEffects reports whether evaluation of e has side effects. +func hasSideEffects(e ast.Expr) bool { + safe := true + ast.Inspect(e, func(node ast.Node) bool { + switch n := node.(type) { + // Using CallExpr here will catch conversions + // as well as function and method invocations. + // We'll live with the false negatives for now. + case *ast.CallExpr: + safe = false + return false + case *ast.UnaryExpr: + if n.Op == token.ARROW { + safe = false + return false + } + } + return true + }) + return !safe +} + +// split returns a slice of all subexpressions in e that are connected by op. +// For example, given 'a || (b || c) || d' with the or op, +// split returns []{d, c, b, a}. +func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) { + for { + e = unparen(e) + if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok { + exprs = append(exprs, op.split(b.Y)...) + e = b.X + } else { + exprs = append(exprs, e) + break + } + } + return +} + +// unparen returns e with any enclosing parentheses stripped. +func unparen(e ast.Expr) ast.Expr { + for { + p, ok := e.(*ast.ParenExpr) + if !ok { + return e + } + e = p.X + } +} diff --git a/libgo/go/cmd/vet/buildtag.go b/libgo/go/cmd/vet/buildtag.go new file mode 100644 index 00000000000..80d8f819240 --- /dev/null +++ b/libgo/go/cmd/vet/buildtag.go @@ -0,0 +1,91 @@ +// 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 main + +import ( + "bytes" + "fmt" + "os" + "strings" + "unicode" +) + +var ( + nl = []byte("\n") + slashSlash = []byte("//") + plusBuild = []byte("+build") +) + +// checkBuildTag checks that build tags are in the correct location and well-formed. +func checkBuildTag(name string, data []byte) { + if !vet("buildtags") { + return + } + lines := bytes.SplitAfter(data, nl) + + // Determine cutpoint where +build comments are no longer valid. + // They are valid in leading // comments in the file followed by + // a blank line. + var cutoff int + for i, line := range lines { + line = bytes.TrimSpace(line) + if len(line) == 0 { + cutoff = i + continue + } + if bytes.HasPrefix(line, slashSlash) { + continue + } + break + } + + for i, line := range lines { + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, slashSlash) { + continue + } + text := bytes.TrimSpace(line[2:]) + if bytes.HasPrefix(text, plusBuild) { + fields := bytes.Fields(text) + if !bytes.Equal(fields[0], plusBuild) { + // Comment is something like +buildasdf not +build. + fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) + setExit(1) + continue + } + if i >= cutoff { + fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1) + setExit(1) + continue + } + // Check arguments. + Args: + for _, arg := range fields[1:] { + for _, elem := range strings.Split(string(arg), ",") { + if strings.HasPrefix(elem, "!!") { + fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg) + setExit(1) + break Args + } + elem = strings.TrimPrefix(elem, "!") + for _, c := range elem { + if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { + fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg) + setExit(1) + break Args + } + } + } + } + continue + } + // Comment with +build but not at beginning. + if bytes.Contains(line, plusBuild) && i < cutoff { + fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) + setExit(1) + continue + } + } +} diff --git a/libgo/go/cmd/vet/cgo.go b/libgo/go/cmd/vet/cgo.go new file mode 100644 index 00000000000..76364ff6ed8 --- /dev/null +++ b/libgo/go/cmd/vet/cgo.go @@ -0,0 +1,141 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check for invalid cgo pointer passing. +// This looks for code that uses cgo to call C code passing values +// whose types are almost always invalid according to the cgo pointer +// sharing rules. +// Specifically, it warns about attempts to pass a Go chan, map, func, +// or slice to C, either directly, or via a pointer, array, or struct. + +package main + +import ( + "go/ast" + "go/token" + "go/types" +) + +func init() { + register("cgocall", + "check for types that may not be passed to cgo calls", + checkCgoCall, + callExpr) +} + +func checkCgoCall(f *File, node ast.Node) { + x := node.(*ast.CallExpr) + + // We are only looking for calls to functions imported from + // the "C" package. + sel, ok := x.Fun.(*ast.SelectorExpr) + if !ok { + return + } + id, ok := sel.X.(*ast.Ident) + if !ok { + return + } + + pkgname, ok := f.pkg.uses[id].(*types.PkgName) + if !ok || pkgname.Imported().Path() != "C" { + return + } + + // A call to C.CBytes passes a pointer but is always safe. + if sel.Sel.Name == "CBytes" { + return + } + + for _, arg := range x.Args { + if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) { + f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") + } + + // Check for passing the address of a bad type. + if conv, ok := arg.(*ast.CallExpr); ok && len(conv.Args) == 1 && f.hasBasicType(conv.Fun, types.UnsafePointer) { + arg = conv.Args[0] + } + if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND { + if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) { + f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") + } + } + } +} + +// cgoBaseType tries to look through type conversions involving +// unsafe.Pointer to find the real type. It converts: +// unsafe.Pointer(x) => x +// *(*unsafe.Pointer)(unsafe.Pointer(&x)) => x +func cgoBaseType(f *File, arg ast.Expr) types.Type { + switch arg := arg.(type) { + case *ast.CallExpr: + if len(arg.Args) == 1 && f.hasBasicType(arg.Fun, types.UnsafePointer) { + return cgoBaseType(f, arg.Args[0]) + } + case *ast.StarExpr: + call, ok := arg.X.(*ast.CallExpr) + if !ok || len(call.Args) != 1 { + break + } + // Here arg is *f(v). + t := f.pkg.types[call.Fun].Type + if t == nil { + break + } + ptr, ok := t.Underlying().(*types.Pointer) + if !ok { + break + } + // Here arg is *(*p)(v) + elem, ok := ptr.Elem().Underlying().(*types.Basic) + if !ok || elem.Kind() != types.UnsafePointer { + break + } + // Here arg is *(*unsafe.Pointer)(v) + call, ok = call.Args[0].(*ast.CallExpr) + if !ok || len(call.Args) != 1 { + break + } + // Here arg is *(*unsafe.Pointer)(f(v)) + if !f.hasBasicType(call.Fun, types.UnsafePointer) { + break + } + // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(v)) + u, ok := call.Args[0].(*ast.UnaryExpr) + if !ok || u.Op != token.AND { + break + } + // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(&v)) + return cgoBaseType(f, u.X) + } + + return f.pkg.types[arg].Type +} + +// typeOKForCgoCall reports whether the type of arg is OK to pass to a +// C function using cgo. This is not true for Go types with embedded +// pointers. m is used to avoid infinite recursion on recursive types. +func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool { + if t == nil || m[t] { + return true + } + m[t] = true + switch t := t.Underlying().(type) { + case *types.Chan, *types.Map, *types.Signature, *types.Slice: + return false + case *types.Pointer: + return typeOKForCgoCall(t.Elem(), m) + case *types.Array: + return typeOKForCgoCall(t.Elem(), m) + case *types.Struct: + for i := 0; i < t.NumFields(); i++ { + if !typeOKForCgoCall(t.Field(i).Type(), m) { + return false + } + } + } + return true +} diff --git a/libgo/go/cmd/vet/composite.go b/libgo/go/cmd/vet/composite.go new file mode 100644 index 00000000000..f704f181bf0 --- /dev/null +++ b/libgo/go/cmd/vet/composite.go @@ -0,0 +1,82 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the test for unkeyed struct literals. + +package main + +import ( + "cmd/vet/internal/whitelist" + "flag" + "go/ast" + "go/types" + "strings" +) + +var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only") + +func init() { + register("composites", + "check that composite literals used field-keyed elements", + checkUnkeyedLiteral, + compositeLit) +} + +// checkUnkeyedLiteral checks if a composite literal is a struct literal with +// unkeyed fields. +func checkUnkeyedLiteral(f *File, node ast.Node) { + cl := node.(*ast.CompositeLit) + + typ := f.pkg.types[cl].Type + if typ == nil { + // cannot determine composite literals' type, skip it + return + } + typeName := typ.String() + if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] { + // skip whitelisted types + return + } + if _, ok := typ.Underlying().(*types.Struct); !ok { + // skip non-struct composite literals + return + } + if isLocalType(f, typeName) { + // allow unkeyed locally defined composite literal + return + } + + // check if the CompositeLit contains an unkeyed field + allKeyValue := true + for _, e := range cl.Elts { + if _, ok := e.(*ast.KeyValueExpr); !ok { + allKeyValue = false + break + } + } + if allKeyValue { + // all the composite literal fields are keyed + return + } + + f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName) +} + +func isLocalType(f *File, typeName string) bool { + if strings.HasPrefix(typeName, "struct{") { + // struct literals are local types + return true + } + + pkgname := f.pkg.path + if strings.HasPrefix(typeName, pkgname+".") { + return true + } + + // treat types as local inside test packages with _test name suffix + if strings.HasSuffix(pkgname, "_test") { + pkgname = pkgname[:len(pkgname)-len("_test")] + } + return strings.HasPrefix(typeName, pkgname+".") +} diff --git a/libgo/go/cmd/vet/copylock.go b/libgo/go/cmd/vet/copylock.go new file mode 100644 index 00000000000..ce14e1af343 --- /dev/null +++ b/libgo/go/cmd/vet/copylock.go @@ -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. + +// This file contains the code to check that locks are not passed by value. + +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" +) + +func init() { + register("copylocks", + "check that locks are not passed by value", + checkCopyLocks, + funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt) +} + +// checkCopyLocks checks whether node might +// inadvertently copy a lock. +func checkCopyLocks(f *File, node ast.Node) { + switch node := node.(type) { + case *ast.RangeStmt: + checkCopyLocksRange(f, node) + case *ast.FuncDecl: + checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type) + case *ast.FuncLit: + checkCopyLocksFunc(f, "func", nil, node.Type) + case *ast.CallExpr: + checkCopyLocksCallExpr(f, node) + case *ast.AssignStmt: + checkCopyLocksAssign(f, node) + case *ast.GenDecl: + checkCopyLocksGenDecl(f, node) + case *ast.CompositeLit: + checkCopyLocksCompositeLit(f, node) + case *ast.ReturnStmt: + checkCopyLocksReturnStmt(f, node) + } +} + +// checkCopyLocksAssign checks whether an assignment +// copies a lock. +func checkCopyLocksAssign(f *File, as *ast.AssignStmt) { + for i, x := range as.Rhs { + if path := lockPathRhs(f, x); path != nil { + f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path) + } + } +} + +// checkCopyLocksGenDecl checks whether lock is copied +// in variable declaration. +func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) { + if gd.Tok != token.VAR { + return + } + for _, spec := range gd.Specs { + valueSpec := spec.(*ast.ValueSpec) + for i, x := range valueSpec.Values { + if path := lockPathRhs(f, x); path != nil { + f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path) + } + } + } +} + +// checkCopyLocksCompositeLit detects lock copy inside a composite literal +func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) { + for _, x := range cl.Elts { + if node, ok := x.(*ast.KeyValueExpr); ok { + x = node.Value + } + if path := lockPathRhs(f, x); path != nil { + f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path) + } + } +} + +// checkCopyLocksReturnStmt detects lock copy in return statement +func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) { + for _, x := range rs.Results { + if path := lockPathRhs(f, x); path != nil { + f.Badf(x.Pos(), "return copies lock value: %v", path) + } + } +} + +// checkCopyLocksCallExpr detects lock copy in the arguments to a function call +func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) { + var id *ast.Ident + switch fun := ce.Fun.(type) { + case *ast.Ident: + id = fun + case *ast.SelectorExpr: + id = fun.Sel + } + if fun, ok := f.pkg.uses[id].(*types.Builtin); ok { + switch fun.Name() { + case "new", "len", "cap", "Sizeof": + return + } + } + for _, x := range ce.Args { + if path := lockPathRhs(f, x); path != nil { + f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path) + } + } +} + +// checkCopyLocksFunc checks whether a function might +// inadvertently copy a lock, by checking whether +// its receiver, parameters, or return values +// are locks. +func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) { + if recv != nil && len(recv.List) > 0 { + expr := recv.List[0].Type + if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil { + f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path) + } + } + + if typ.Params != nil { + for _, field := range typ.Params.List { + expr := field.Type + if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil { + f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path) + } + } + } + + // Don't check typ.Results. If T has a Lock field it's OK to write + // return T{} + // because that is returning the zero value. Leave result checking + // to the return statement. +} + +// checkCopyLocksRange checks whether a range statement +// might inadvertently copy a lock by checking whether +// any of the range variables are locks. +func checkCopyLocksRange(f *File, r *ast.RangeStmt) { + checkCopyLocksRangeVar(f, r.Tok, r.Key) + checkCopyLocksRangeVar(f, r.Tok, r.Value) +} + +func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) { + if e == nil { + return + } + id, isId := e.(*ast.Ident) + if isId && id.Name == "_" { + return + } + + var typ types.Type + if rtok == token.DEFINE { + if !isId { + return + } + obj := f.pkg.defs[id] + if obj == nil { + return + } + typ = obj.Type() + } else { + typ = f.pkg.types[e].Type + } + + if typ == nil { + return + } + if path := lockPath(f.pkg.typesPkg, typ); path != nil { + f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path) + } +} + +type typePath []types.Type + +// String pretty-prints a typePath. +func (path typePath) String() string { + n := len(path) + var buf bytes.Buffer + for i := range path { + if i > 0 { + fmt.Fprint(&buf, " contains ") + } + // The human-readable path is in reverse order, outermost to innermost. + fmt.Fprint(&buf, path[n-i-1].String()) + } + return buf.String() +} + +func lockPathRhs(f *File, x ast.Expr) typePath { + if _, ok := x.(*ast.CompositeLit); ok { + return nil + } + if _, ok := x.(*ast.CallExpr); ok { + // A call may return a zero value. + return nil + } + if star, ok := x.(*ast.StarExpr); ok { + if _, ok := star.X.(*ast.CallExpr); ok { + // A call may return a pointer to a zero value. + return nil + } + } + return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type) +} + +// lockPath returns a typePath describing the location of a lock value +// contained in typ. If there is no contained lock, it returns nil. +func lockPath(tpkg *types.Package, typ types.Type) typePath { + if typ == nil { + return nil + } + + for { + atyp, ok := typ.Underlying().(*types.Array) + if !ok { + break + } + typ = atyp.Elem() + } + + // We're only interested in the case in which the underlying + // type is a struct. (Interfaces and pointers are safe to copy.) + styp, ok := typ.Underlying().(*types.Struct) + if !ok { + return nil + } + + // We're looking for cases in which a reference to this type + // can be locked, but a value cannot. This differentiates + // embedded interfaces from embedded values. + if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil { + if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil { + return []types.Type{typ} + } + } + + nfields := styp.NumFields() + for i := 0; i < nfields; i++ { + ftyp := styp.Field(i).Type() + subpath := lockPath(tpkg, ftyp) + if subpath != nil { + return append(subpath, typ) + } + } + + return nil +} diff --git a/libgo/go/cmd/vet/dead.go b/libgo/go/cmd/vet/dead.go new file mode 100644 index 00000000000..130f619626d --- /dev/null +++ b/libgo/go/cmd/vet/dead.go @@ -0,0 +1,108 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// Simplified dead code detector. Used for skipping certain checks +// on unreachable code (for instance, shift checks on arch-specific code). + +package main + +import ( + "go/ast" + "go/constant" +) + +// updateDead puts unreachable "if" and "case" nodes into f.dead. +func (f *File) updateDead(node ast.Node) { + if f.dead[node] { + // The node is already marked as dead. + return + } + + switch stmt := node.(type) { + case *ast.IfStmt: + // "if" branch is dead if its condition evaluates + // to constant false. + v := f.pkg.types[stmt.Cond].Value + if v == nil { + return + } + if !constant.BoolVal(v) { + f.setDead(stmt.Body) + return + } + f.setDead(stmt.Else) + case *ast.SwitchStmt: + // Case clause with empty switch tag is dead if it evaluates + // to constant false. + if stmt.Tag == nil { + BodyLoopBool: + for _, stmt := range stmt.Body.List { + cc := stmt.(*ast.CaseClause) + if cc.List == nil { + // Skip default case. + continue + } + for _, expr := range cc.List { + v := f.pkg.types[expr].Value + if v == nil || constant.BoolVal(v) { + continue BodyLoopBool + } + } + f.setDead(cc) + } + return + } + + // Case clause is dead if its constant value doesn't match + // the constant value from the switch tag. + // TODO: This handles integer comparisons only. + v := f.pkg.types[stmt.Tag].Value + if v == nil || v.Kind() != constant.Int { + return + } + tagN, ok := constant.Uint64Val(v) + if !ok { + return + } + BodyLoopInt: + for _, x := range stmt.Body.List { + cc := x.(*ast.CaseClause) + if cc.List == nil { + // Skip default case. + continue + } + for _, expr := range cc.List { + v := f.pkg.types[expr].Value + if v == nil { + continue BodyLoopInt + } + n, ok := constant.Uint64Val(v) + if !ok || tagN == n { + continue BodyLoopInt + } + } + f.setDead(cc) + } + } +} + +// setDead marks the node and all the children as dead. +func (f *File) setDead(node ast.Node) { + dv := deadVisitor{ + f: f, + } + ast.Walk(dv, node) +} + +type deadVisitor struct { + f *File +} + +func (dv deadVisitor) Visit(node ast.Node) ast.Visitor { + if node == nil { + return nil + } + dv.f.dead[node] = true + return dv +} diff --git a/libgo/go/cmd/vet/deadcode.go b/libgo/go/cmd/vet/deadcode.go new file mode 100644 index 00000000000..b1077aef38f --- /dev/null +++ b/libgo/go/cmd/vet/deadcode.go @@ -0,0 +1,298 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check for syntactically unreachable code. + +package main + +import ( + "go/ast" + "go/token" +) + +func init() { + register("unreachable", + "check for unreachable code", + checkUnreachable, + funcDecl, funcLit) +} + +type deadState struct { + f *File + hasBreak map[ast.Stmt]bool + hasGoto map[string]bool + labels map[string]ast.Stmt + breakTarget ast.Stmt + + reachable bool +} + +// checkUnreachable checks a function body for dead code. +// +// TODO(adonovan): use the new cfg package, which is more precise. +func checkUnreachable(f *File, node ast.Node) { + var body *ast.BlockStmt + switch n := node.(type) { + case *ast.FuncDecl: + body = n.Body + case *ast.FuncLit: + body = n.Body + } + if body == nil { + return + } + + d := &deadState{ + f: f, + hasBreak: make(map[ast.Stmt]bool), + hasGoto: make(map[string]bool), + labels: make(map[string]ast.Stmt), + } + + d.findLabels(body) + + d.reachable = true + d.findDead(body) +} + +// findLabels gathers information about the labels defined and used by stmt +// and about which statements break, whether a label is involved or not. +func (d *deadState) findLabels(stmt ast.Stmt) { + switch x := stmt.(type) { + default: + d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x) + + case *ast.AssignStmt, + *ast.BadStmt, + *ast.DeclStmt, + *ast.DeferStmt, + *ast.EmptyStmt, + *ast.ExprStmt, + *ast.GoStmt, + *ast.IncDecStmt, + *ast.ReturnStmt, + *ast.SendStmt: + // no statements inside + + case *ast.BlockStmt: + for _, stmt := range x.List { + d.findLabels(stmt) + } + + case *ast.BranchStmt: + switch x.Tok { + case token.GOTO: + if x.Label != nil { + d.hasGoto[x.Label.Name] = true + } + + case token.BREAK: + stmt := d.breakTarget + if x.Label != nil { + stmt = d.labels[x.Label.Name] + } + if stmt != nil { + d.hasBreak[stmt] = true + } + } + + case *ast.IfStmt: + d.findLabels(x.Body) + if x.Else != nil { + d.findLabels(x.Else) + } + + case *ast.LabeledStmt: + d.labels[x.Label.Name] = x.Stmt + d.findLabels(x.Stmt) + + // These cases are all the same, but the x.Body only works + // when the specific type of x is known, so the cases cannot + // be merged. + case *ast.ForStmt: + outer := d.breakTarget + d.breakTarget = x + d.findLabels(x.Body) + d.breakTarget = outer + + case *ast.RangeStmt: + outer := d.breakTarget + d.breakTarget = x + d.findLabels(x.Body) + d.breakTarget = outer + + case *ast.SelectStmt: + outer := d.breakTarget + d.breakTarget = x + d.findLabels(x.Body) + d.breakTarget = outer + + case *ast.SwitchStmt: + outer := d.breakTarget + d.breakTarget = x + d.findLabels(x.Body) + d.breakTarget = outer + + case *ast.TypeSwitchStmt: + outer := d.breakTarget + d.breakTarget = x + d.findLabels(x.Body) + d.breakTarget = outer + + case *ast.CommClause: + for _, stmt := range x.Body { + d.findLabels(stmt) + } + + case *ast.CaseClause: + for _, stmt := range x.Body { + d.findLabels(stmt) + } + } +} + +// findDead walks the statement looking for dead code. +// If d.reachable is false on entry, stmt itself is dead. +// When findDead returns, d.reachable tells whether the +// statement following stmt is reachable. +func (d *deadState) findDead(stmt ast.Stmt) { + // Is this a labeled goto target? + // If so, assume it is reachable due to the goto. + // This is slightly conservative, in that we don't + // check that the goto is reachable, so + // L: goto L + // will not provoke a warning. + // But it's good enough. + if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] { + d.reachable = true + } + + if !d.reachable { + switch stmt.(type) { + case *ast.EmptyStmt: + // do not warn about unreachable empty statements + default: + d.f.Bad(stmt.Pos(), "unreachable code") + d.reachable = true // silence error about next statement + } + } + + switch x := stmt.(type) { + default: + d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x) + + case *ast.AssignStmt, + *ast.BadStmt, + *ast.DeclStmt, + *ast.DeferStmt, + *ast.EmptyStmt, + *ast.GoStmt, + *ast.IncDecStmt, + *ast.SendStmt: + // no control flow + + case *ast.BlockStmt: + for _, stmt := range x.List { + d.findDead(stmt) + } + + case *ast.BranchStmt: + switch x.Tok { + case token.BREAK, token.GOTO, token.FALLTHROUGH: + d.reachable = false + case token.CONTINUE: + // NOTE: We accept "continue" statements as terminating. + // They are not necessary in the spec definition of terminating, + // because a continue statement cannot be the final statement + // before a return. But for the more general problem of syntactically + // identifying dead code, continue redirects control flow just + // like the other terminating statements. + d.reachable = false + } + + case *ast.ExprStmt: + // Call to panic? + call, ok := x.X.(*ast.CallExpr) + if ok { + name, ok := call.Fun.(*ast.Ident) + if ok && name.Name == "panic" && name.Obj == nil { + d.reachable = false + } + } + + case *ast.ForStmt: + d.findDead(x.Body) + d.reachable = x.Cond != nil || d.hasBreak[x] + + case *ast.IfStmt: + d.findDead(x.Body) + if x.Else != nil { + r := d.reachable + d.reachable = true + d.findDead(x.Else) + d.reachable = d.reachable || r + } else { + // might not have executed if statement + d.reachable = true + } + + case *ast.LabeledStmt: + d.findDead(x.Stmt) + + case *ast.RangeStmt: + d.findDead(x.Body) + d.reachable = true + + case *ast.ReturnStmt: + d.reachable = false + + case *ast.SelectStmt: + // NOTE: Unlike switch and type switch below, we don't care + // whether a select has a default, because a select without a + // default blocks until one of the cases can run. That's different + // from a switch without a default, which behaves like it has + // a default with an empty body. + anyReachable := false + for _, comm := range x.Body.List { + d.reachable = true + for _, stmt := range comm.(*ast.CommClause).Body { + d.findDead(stmt) + } + anyReachable = anyReachable || d.reachable + } + d.reachable = anyReachable || d.hasBreak[x] + + case *ast.SwitchStmt: + anyReachable := false + hasDefault := false + for _, cas := range x.Body.List { + cc := cas.(*ast.CaseClause) + if cc.List == nil { + hasDefault = true + } + d.reachable = true + for _, stmt := range cc.Body { + d.findDead(stmt) + } + anyReachable = anyReachable || d.reachable + } + d.reachable = anyReachable || d.hasBreak[x] || !hasDefault + + case *ast.TypeSwitchStmt: + anyReachable := false + hasDefault := false + for _, cas := range x.Body.List { + cc := cas.(*ast.CaseClause) + if cc.List == nil { + hasDefault = true + } + d.reachable = true + for _, stmt := range cc.Body { + d.findDead(stmt) + } + anyReachable = anyReachable || d.reachable + } + d.reachable = anyReachable || d.hasBreak[x] || !hasDefault + } +} diff --git a/libgo/go/cmd/vet/doc.go b/libgo/go/cmd/vet/doc.go new file mode 100644 index 00000000000..3df975cacc4 --- /dev/null +++ b/libgo/go/cmd/vet/doc.go @@ -0,0 +1,224 @@ +// 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. + +/* + +Vet examines Go source code and reports suspicious constructs, such as Printf +calls whose arguments do not align with the format string. Vet uses heuristics +that do not guarantee all reports are genuine problems, but it can find errors +not caught by the compilers. + +Vet is normally invoked using the go command by running "go vet": + + go vet +vets the package in the current directory. + + go vet package/path/name +vets the package whose path is provided. + +Use "go help packages" to see other ways of specifying which packages to vet. + +Vet's exit code is 2 for erroneous invocation of the tool, 1 if a +problem was reported, and 0 otherwise. Note that the tool does not +check every possible problem and depends on unreliable heuristics +so it should be used as guidance only, not as a firm indicator of +program correctness. + +By default the -all flag is set so all checks are performed. +If any flags are explicitly set to true, only those tests are run. Conversely, if +any flag is explicitly set to false, only those tests are disabled. Thus -printf=true +runs the printf check, -printf=false runs all checks except the printf check. + +By default vet uses the object files generated by 'go install some/pkg' to typecheck the code. +If the -source flag is provided, vet uses only source code. + +Available checks: + +Assembly declarations + +Flag: -asmdecl + +Mismatches between assembly files and Go function declarations. + +Useless assignments + +Flag: -assign + +Check for useless assignments. + +Atomic mistakes + +Flag: -atomic + +Common mistaken usages of the sync/atomic package. + +Boolean conditions + +Flag: -bool + +Mistakes involving boolean operators. + +Build tags + +Flag: -buildtags + +Badly formed or misplaced +build tags. + +Invalid uses of cgo + +Flag: -cgocall + +Detect some violations of the cgo pointer passing rules. + +Unkeyed composite literals + +Flag: -composites + +Composite struct literals that do not use the field-keyed syntax. + +Copying locks + +Flag: -copylocks + +Locks that are erroneously passed by value. + +HTTP responses used incorrectly + +Flag: -httpresponse + +Mistakes deferring a function call on an HTTP response before +checking whether the error returned with the response was nil. + +Failure to call the cancelation function returned by WithCancel + +Flag: -lostcancel + +The cancelation function returned by context.WithCancel, WithTimeout, +and WithDeadline must be called or the new context will remain live +until its parent context is cancelled. +(The background context is never cancelled.) + +Methods + +Flag: -methods + +Non-standard signatures for methods with familiar names, including: + Format GobEncode GobDecode MarshalJSON MarshalXML + Peek ReadByte ReadFrom ReadRune Scan Seek + UnmarshalJSON UnreadByte UnreadRune WriteByte + WriteTo + +Nil function comparison + +Flag: -nilfunc + +Comparisons between functions and nil. + +Printf family + +Flag: -printf + +Suspicious calls to functions in the Printf family, including any functions +with these names, disregarding case: + Print Printf Println + Fprint Fprintf Fprintln + Sprint Sprintf Sprintln + Error Errorf + Fatal Fatalf + Log Logf + Panic Panicf Panicln +The -printfuncs flag can be used to redefine this list. +If the function name ends with an 'f', the function is assumed to take +a format descriptor string in the manner of fmt.Printf. If not, vet +complains about arguments that look like format descriptor strings. + +It also checks for errors such as using a Writer as the first argument of +Printf. + +Range loop variables + +Flag: -rangeloops + +Incorrect uses of range loop variables in closures. + +Shadowed variables + +Flag: -shadow=false (experimental; must be set explicitly) + +Variables that may have been unintentionally shadowed. + +Shifts + +Flag: -shift + +Shifts equal to or longer than the variable's length. + +Struct tags + +Flag: -structtags + +Struct tags that do not follow the format understood by reflect.StructTag.Get. +Well-known encoding struct tags (json, xml) used with unexported fields. + +Tests and documentation examples + +Flag: -tests + +Mistakes involving tests including functions with incorrect names or signatures +and example tests that document identifiers not in the package. + +Unreachable code + +Flag: -unreachable + +Unreachable code. + +Misuse of unsafe Pointers + +Flag: -unsafeptr + +Likely incorrect uses of unsafe.Pointer to convert integers to pointers. +A conversion from uintptr to unsafe.Pointer is invalid if it implies that +there is a uintptr-typed word in memory that holds a pointer value, +because that word will be invisible to stack copying and to the garbage +collector. + +Unused result of certain function calls + +Flag: -unusedresult + +Calls to well-known functions and methods that return a value that is +discarded. By default, this includes functions like fmt.Errorf and +fmt.Sprintf and methods like String and Error. The flags -unusedfuncs +and -unusedstringmethods control the set. + +Other flags + +These flags configure the behavior of vet: + + -all (default true) + Enable all non-experimental checks. + -v + Verbose mode + -printfuncs + A comma-separated list of print-like function names + to supplement the standard list. + For more information, see the discussion of the -printf flag. + -shadowstrict + Whether to be strict about shadowing; can be noisy. + +Using vet directly + +For testing and debugging vet can be run directly by invoking +"go tool vet" or just running the binary. Run this way, vet might not +have up to date information for imported packages. + + go tool vet source/directory/*.go +vets the files named, all of which must be in the same package. + + go tool vet source/directory +recursively descends the directory, vetting each package it finds. + +*/ +package main diff --git a/libgo/go/cmd/vet/httpresponse.go b/libgo/go/cmd/vet/httpresponse.go new file mode 100644 index 00000000000..791d11d5bde --- /dev/null +++ b/libgo/go/cmd/vet/httpresponse.go @@ -0,0 +1,137 @@ +// Copyright 2016 The Go 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 check for http.Response values being used before +// checking for errors. + +package main + +import ( + "go/ast" + "go/types" +) + +func init() { + register("httpresponse", + "check errors are checked before using an http Response", + checkHTTPResponse, callExpr) +} + +func checkHTTPResponse(f *File, node ast.Node) { + call := node.(*ast.CallExpr) + if !isHTTPFuncOrMethodOnClient(f, call) { + return // the function call is not related to this check. + } + + finder := &blockStmtFinder{node: call} + ast.Walk(finder, f.file) + stmts := finder.stmts() + if len(stmts) < 2 { + return // the call to the http function is the last statement of the block. + } + + asg, ok := stmts[0].(*ast.AssignStmt) + if !ok { + return // the first statement is not assignment. + } + resp := rootIdent(asg.Lhs[0]) + if resp == nil { + return // could not find the http.Response in the assignment. + } + + def, ok := stmts[1].(*ast.DeferStmt) + if !ok { + return // the following statement is not a defer. + } + root := rootIdent(def.Call.Fun) + if root == nil { + return // could not find the receiver of the defer call. + } + + if resp.Obj == root.Obj { + f.Badf(root.Pos(), "using %s before checking for errors", resp.Name) + } +} + +// isHTTPFuncOrMethodOnClient checks whether the given call expression is on +// either a function of the net/http package or a method of http.Client that +// returns (*http.Response, error). +func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool { + fun, _ := expr.Fun.(*ast.SelectorExpr) + sig, _ := f.pkg.types[fun].Type.(*types.Signature) + if sig == nil { + return false // the call is not on of the form x.f() + } + + res := sig.Results() + if res.Len() != 2 { + return false // the function called does not return two values. + } + if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") { + return false // the first return type is not *http.Response. + } + if !types.Identical(res.At(1).Type().Underlying(), errorType) { + return false // the second return type is not error + } + + typ := f.pkg.types[fun.X].Type + if typ == nil { + id, ok := fun.X.(*ast.Ident) + return ok && id.Name == "http" // function in net/http package. + } + + if isNamedType(typ, "net/http", "Client") { + return true // method on http.Client. + } + ptr, ok := typ.(*types.Pointer) + return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. +} + +// blockStmtFinder is an ast.Visitor that given any ast node can find the +// statement containing it and its succeeding statements in the same block. +type blockStmtFinder struct { + node ast.Node // target of search + stmt ast.Stmt // innermost statement enclosing argument to Visit + block *ast.BlockStmt // innermost block enclosing argument to Visit. +} + +// Visit finds f.node performing a search down the ast tree. +// It keeps the last block statement and statement seen for later use. +func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor { + if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() { + return nil // not here + } + switch n := node.(type) { + case *ast.BlockStmt: + f.block = n + case ast.Stmt: + f.stmt = n + } + if f.node.Pos() == node.Pos() && f.node.End() == node.End() { + return nil // found + } + return f // keep looking +} + +// stmts returns the statements of f.block starting from the one including f.node. +func (f *blockStmtFinder) stmts() []ast.Stmt { + for i, v := range f.block.List { + if f.stmt == v { + return f.block.List[i:] + } + } + return nil +} + +// rootIdent finds the root identifier x in a chain of selections x.y.z, or nil if not found. +func rootIdent(n ast.Node) *ast.Ident { + switch n := n.(type) { + case *ast.SelectorExpr: + return rootIdent(n.X) + case *ast.Ident: + return n + default: + return nil + } +} diff --git a/libgo/go/cmd/vet/internal/cfg/builder.go b/libgo/go/cmd/vet/internal/cfg/builder.go new file mode 100644 index 00000000000..da1cc7e6384 --- /dev/null +++ b/libgo/go/cmd/vet/internal/cfg/builder.go @@ -0,0 +1,512 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cfg + +// This file implements the CFG construction pass. + +import ( + "fmt" + "go/ast" + "go/token" +) + +type builder struct { + cfg *CFG + mayReturn func(*ast.CallExpr) bool + current *Block + lblocks map[*ast.Object]*lblock // labeled blocks + targets *targets // linked stack of branch targets +} + +func (b *builder) stmt(_s ast.Stmt) { + // The label of the current statement. If non-nil, its _goto + // target is always set; its _break and _continue are set only + // within the body of switch/typeswitch/select/for/range. + // It is effectively an additional default-nil parameter of stmt(). + var label *lblock +start: + switch s := _s.(type) { + case *ast.BadStmt, + *ast.SendStmt, + *ast.IncDecStmt, + *ast.GoStmt, + *ast.DeferStmt, + *ast.EmptyStmt, + *ast.AssignStmt: + // No effect on control flow. + b.add(s) + + case *ast.ExprStmt: + b.add(s) + if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) { + // Calls to panic, os.Exit, etc, never return. + b.current = b.newUnreachableBlock("unreachable.call") + } + + case *ast.DeclStmt: + // Treat each var ValueSpec as a separate statement. + d := s.Decl.(*ast.GenDecl) + if d.Tok == token.VAR { + for _, spec := range d.Specs { + if spec, ok := spec.(*ast.ValueSpec); ok { + b.add(spec) + } + } + } + + case *ast.LabeledStmt: + label = b.labeledBlock(s.Label) + b.jump(label._goto) + b.current = label._goto + _s = s.Stmt + goto start // effectively: tailcall stmt(g, s.Stmt, label) + + case *ast.ReturnStmt: + b.add(s) + b.current = b.newUnreachableBlock("unreachable.return") + + case *ast.BranchStmt: + var block *Block + switch s.Tok { + case token.BREAK: + if s.Label != nil { + if lb := b.labeledBlock(s.Label); lb != nil { + block = lb._break + } + } else { + for t := b.targets; t != nil && block == nil; t = t.tail { + block = t._break + } + } + + case token.CONTINUE: + if s.Label != nil { + if lb := b.labeledBlock(s.Label); lb != nil { + block = lb._continue + } + } else { + for t := b.targets; t != nil && block == nil; t = t.tail { + block = t._continue + } + } + + case token.FALLTHROUGH: + for t := b.targets; t != nil; t = t.tail { + block = t._fallthrough + } + + case token.GOTO: + if s.Label != nil { + block = b.labeledBlock(s.Label)._goto + } + } + if block == nil { + block = b.newBlock("undefined.branch") + } + b.jump(block) + b.current = b.newUnreachableBlock("unreachable.branch") + + case *ast.BlockStmt: + b.stmtList(s.List) + + case *ast.IfStmt: + if s.Init != nil { + b.stmt(s.Init) + } + then := b.newBlock("if.then") + done := b.newBlock("if.done") + _else := done + if s.Else != nil { + _else = b.newBlock("if.else") + } + b.add(s.Cond) + b.ifelse(then, _else) + b.current = then + b.stmt(s.Body) + b.jump(done) + + if s.Else != nil { + b.current = _else + b.stmt(s.Else) + b.jump(done) + } + + b.current = done + + case *ast.SwitchStmt: + b.switchStmt(s, label) + + case *ast.TypeSwitchStmt: + b.typeSwitchStmt(s, label) + + case *ast.SelectStmt: + b.selectStmt(s, label) + + case *ast.ForStmt: + b.forStmt(s, label) + + case *ast.RangeStmt: + b.rangeStmt(s, label) + + default: + panic(fmt.Sprintf("unexpected statement kind: %T", s)) + } +} + +func (b *builder) stmtList(list []ast.Stmt) { + for _, s := range list { + b.stmt(s) + } +} + +func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) { + if s.Init != nil { + b.stmt(s.Init) + } + if s.Tag != nil { + b.add(s.Tag) + } + done := b.newBlock("switch.done") + if label != nil { + label._break = done + } + // We pull the default case (if present) down to the end. + // But each fallthrough label must point to the next + // body block in source order, so we preallocate a + // body block (fallthru) for the next case. + // Unfortunately this makes for a confusing block order. + var defaultBody *[]ast.Stmt + var defaultFallthrough *Block + var fallthru, defaultBlock *Block + ncases := len(s.Body.List) + for i, clause := range s.Body.List { + body := fallthru + if body == nil { + body = b.newBlock("switch.body") // first case only + } + + // Preallocate body block for the next case. + fallthru = done + if i+1 < ncases { + fallthru = b.newBlock("switch.body") + } + + cc := clause.(*ast.CaseClause) + if cc.List == nil { + // Default case. + defaultBody = &cc.Body + defaultFallthrough = fallthru + defaultBlock = body + continue + } + + var nextCond *Block + for _, cond := range cc.List { + nextCond = b.newBlock("switch.next") + b.add(cond) // one half of the tag==cond condition + b.ifelse(body, nextCond) + b.current = nextCond + } + b.current = body + b.targets = &targets{ + tail: b.targets, + _break: done, + _fallthrough: fallthru, + } + b.stmtList(cc.Body) + b.targets = b.targets.tail + b.jump(done) + b.current = nextCond + } + if defaultBlock != nil { + b.jump(defaultBlock) + b.current = defaultBlock + b.targets = &targets{ + tail: b.targets, + _break: done, + _fallthrough: defaultFallthrough, + } + b.stmtList(*defaultBody) + b.targets = b.targets.tail + } + b.jump(done) + b.current = done +} + +func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) { + if s.Init != nil { + b.stmt(s.Init) + } + if s.Assign != nil { + b.add(s.Assign) + } + + done := b.newBlock("typeswitch.done") + if label != nil { + label._break = done + } + var default_ *ast.CaseClause + for _, clause := range s.Body.List { + cc := clause.(*ast.CaseClause) + if cc.List == nil { + default_ = cc + continue + } + body := b.newBlock("typeswitch.body") + var next *Block + for _, casetype := range cc.List { + next = b.newBlock("typeswitch.next") + // casetype is a type, so don't call b.add(casetype). + // This block logically contains a type assertion, + // x.(casetype), but it's unclear how to represent x. + _ = casetype + b.ifelse(body, next) + b.current = next + } + b.current = body + b.typeCaseBody(cc, done) + b.current = next + } + if default_ != nil { + b.typeCaseBody(default_, done) + } else { + b.jump(done) + } + b.current = done +} + +func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) { + b.targets = &targets{ + tail: b.targets, + _break: done, + } + b.stmtList(cc.Body) + b.targets = b.targets.tail + b.jump(done) +} + +func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) { + // First evaluate channel expressions. + // TODO(adonovan): fix: evaluate only channel exprs here. + for _, clause := range s.Body.List { + if comm := clause.(*ast.CommClause).Comm; comm != nil { + b.stmt(comm) + } + } + + done := b.newBlock("select.done") + if label != nil { + label._break = done + } + + var defaultBody *[]ast.Stmt + for _, cc := range s.Body.List { + clause := cc.(*ast.CommClause) + if clause.Comm == nil { + defaultBody = &clause.Body + continue + } + body := b.newBlock("select.body") + next := b.newBlock("select.next") + b.ifelse(body, next) + b.current = body + b.targets = &targets{ + tail: b.targets, + _break: done, + } + switch comm := clause.Comm.(type) { + case *ast.ExprStmt: // <-ch + // nop + case *ast.AssignStmt: // x := <-states[state].Chan + b.add(comm.Lhs[0]) + } + b.stmtList(clause.Body) + b.targets = b.targets.tail + b.jump(done) + b.current = next + } + if defaultBody != nil { + b.targets = &targets{ + tail: b.targets, + _break: done, + } + b.stmtList(*defaultBody) + b.targets = b.targets.tail + b.jump(done) + } + b.current = done +} + +func (b *builder) forStmt(s *ast.ForStmt, label *lblock) { + // ...init... + // jump loop + // loop: + // if cond goto body else done + // body: + // ...body... + // jump post + // post: (target of continue) + // ...post... + // jump loop + // done: (target of break) + if s.Init != nil { + b.stmt(s.Init) + } + body := b.newBlock("for.body") + done := b.newBlock("for.done") // target of 'break' + loop := body // target of back-edge + if s.Cond != nil { + loop = b.newBlock("for.loop") + } + cont := loop // target of 'continue' + if s.Post != nil { + cont = b.newBlock("for.post") + } + if label != nil { + label._break = done + label._continue = cont + } + b.jump(loop) + b.current = loop + if loop != body { + b.add(s.Cond) + b.ifelse(body, done) + b.current = body + } + b.targets = &targets{ + tail: b.targets, + _break: done, + _continue: cont, + } + b.stmt(s.Body) + b.targets = b.targets.tail + b.jump(cont) + + if s.Post != nil { + b.current = cont + b.stmt(s.Post) + b.jump(loop) // back-edge + } + b.current = done +} + +func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) { + b.add(s.X) + + if s.Key != nil { + b.add(s.Key) + } + if s.Value != nil { + b.add(s.Value) + } + + // ... + // loop: (target of continue) + // if ... goto body else done + // body: + // ... + // jump loop + // done: (target of break) + + loop := b.newBlock("range.loop") + b.jump(loop) + b.current = loop + + body := b.newBlock("range.body") + done := b.newBlock("range.done") + b.ifelse(body, done) + b.current = body + + if label != nil { + label._break = done + label._continue = loop + } + b.targets = &targets{ + tail: b.targets, + _break: done, + _continue: loop, + } + b.stmt(s.Body) + b.targets = b.targets.tail + b.jump(loop) // back-edge + b.current = done +} + +// -------- helpers -------- + +// Destinations associated with unlabeled for/switch/select stmts. +// We push/pop one of these as we enter/leave each construct and for +// each BranchStmt we scan for the innermost target of the right type. +// +type targets struct { + tail *targets // rest of stack + _break *Block + _continue *Block + _fallthrough *Block +} + +// Destinations associated with a labeled block. +// We populate these as labels are encountered in forward gotos or +// labeled statements. +// +type lblock struct { + _goto *Block + _break *Block + _continue *Block +} + +// labeledBlock returns the branch target associated with the +// specified label, creating it if needed. +// +func (b *builder) labeledBlock(label *ast.Ident) *lblock { + lb := b.lblocks[label.Obj] + if lb == nil { + lb = &lblock{_goto: b.newBlock(label.Name)} + if b.lblocks == nil { + b.lblocks = make(map[*ast.Object]*lblock) + } + b.lblocks[label.Obj] = lb + } + return lb +} + +// newBlock appends a new unconnected basic block to b.cfg's block +// slice and returns it. +// It does not automatically become the current block. +// comment is an optional string for more readable debugging output. +func (b *builder) newBlock(comment string) *Block { + g := b.cfg + block := &Block{ + index: int32(len(g.Blocks)), + comment: comment, + } + block.Succs = block.succs2[:0] + g.Blocks = append(g.Blocks, block) + return block +} + +func (b *builder) newUnreachableBlock(comment string) *Block { + block := b.newBlock(comment) + block.unreachable = true + return block +} + +func (b *builder) add(n ast.Node) { + b.current.Nodes = append(b.current.Nodes, n) +} + +// jump adds an edge from the current block to the target block, +// and sets b.current to nil. +func (b *builder) jump(target *Block) { + b.current.Succs = append(b.current.Succs, target) + b.current = nil +} + +// ifelse emits edges from the current block to the t and f blocks, +// and sets b.current to nil. +func (b *builder) ifelse(t, f *Block) { + b.current.Succs = append(b.current.Succs, t, f) + b.current = nil +} diff --git a/libgo/go/cmd/vet/internal/cfg/cfg.go b/libgo/go/cmd/vet/internal/cfg/cfg.go new file mode 100644 index 00000000000..e4d5bfe5d2d --- /dev/null +++ b/libgo/go/cmd/vet/internal/cfg/cfg.go @@ -0,0 +1,142 @@ +// Copyright 2016 The Go 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 package constructs a simple control-flow graph (CFG) of the +// statements and expressions within a single function. +// +// Use cfg.New to construct the CFG for a function body. +// +// The blocks of the CFG contain all the function's non-control +// statements. The CFG does not contain control statements such as If, +// Switch, Select, and Branch, but does contain their subexpressions. +// For example, this source code: +// +// if x := f(); x != nil { +// T() +// } else { +// F() +// } +// +// produces this CFG: +// +// 1: x := f() +// x != nil +// succs: 2, 3 +// 2: T() +// succs: 4 +// 3: F() +// succs: 4 +// 4: +// +// The CFG does contain Return statements; even implicit returns are +// materialized (at the position of the function's closing brace). +// +// The CFG does not record conditions associated with conditional branch +// edges, nor the short-circuit semantics of the && and || operators, +// nor abnormal control flow caused by panic. If you need this +// information, use golang.org/x/tools/go/ssa instead. +// +package cfg + +// Although the vet tool has type information, it is often extremely +// fragmentary, so for simplicity this package does not depend on +// go/types. Consequently control-flow conditions are ignored even +// when constant, and "mayReturn" information must be provided by the +// client. +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/token" +) + +// A CFG represents the control-flow graph of a single function. +// +// The entry point is Blocks[0]; there may be multiple return blocks. +type CFG struct { + Blocks []*Block // block[0] is entry; order otherwise undefined +} + +// A Block represents a basic block: a list of statements and +// expressions that are always evaluated sequentially. +// +// A block may have 0-2 successors: zero for a return block or a block +// that calls a function such as panic that never returns; one for a +// normal (jump) block; and two for a conditional (if) block. +type Block struct { + Nodes []ast.Node // statements, expressions, and ValueSpecs + Succs []*Block // successor nodes in the graph + + comment string // for debugging + index int32 // index within CFG.Blocks + unreachable bool // is block of stmts following return/panic/for{} + succs2 [2]*Block // underlying array for Succs +} + +// New returns a new control-flow graph for the specified function body, +// which must be non-nil. +// +// The CFG builder calls mayReturn to determine whether a given function +// call may return. For example, calls to panic, os.Exit, and log.Fatal +// do not return, so the builder can remove infeasible graph edges +// following such calls. The builder calls mayReturn only for a +// CallExpr beneath an ExprStmt. +func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG { + b := builder{ + mayReturn: mayReturn, + cfg: new(CFG), + } + b.current = b.newBlock("entry") + b.stmt(body) + + // Does control fall off the end of the function's body? + // Make implicit return explicit. + if b.current != nil && !b.current.unreachable { + b.add(&ast.ReturnStmt{ + Return: body.End() - 1, + }) + } + + return b.cfg +} + +func (b *Block) String() string { + return fmt.Sprintf("block %d (%s)", b.index, b.comment) +} + +// Return returns the return statement at the end of this block if present, nil otherwise. +func (b *Block) Return() (ret *ast.ReturnStmt) { + if len(b.Nodes) > 0 { + ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt) + } + return +} + +// Format formats the control-flow graph for ease of debugging. +func (g *CFG) Format(fset *token.FileSet) string { + var buf bytes.Buffer + for _, b := range g.Blocks { + fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment) + for _, n := range b.Nodes { + fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n)) + } + if len(b.Succs) > 0 { + fmt.Fprintf(&buf, "\tsuccs:") + for _, succ := range b.Succs { + fmt.Fprintf(&buf, " %d", succ.index) + } + buf.WriteByte('\n') + } + buf.WriteByte('\n') + } + return buf.String() +} + +func formatNode(fset *token.FileSet, n ast.Node) string { + var buf bytes.Buffer + format.Node(&buf, fset, n) + // Indent secondary lines by a tab. + return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1)) +} diff --git a/libgo/go/cmd/vet/internal/cfg/cfg_test.go b/libgo/go/cmd/vet/internal/cfg/cfg_test.go new file mode 100644 index 00000000000..2400fed6f4b --- /dev/null +++ b/libgo/go/cmd/vet/internal/cfg/cfg_test.go @@ -0,0 +1,190 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cfg + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" + "testing" +) + +const src = `package main + +import "log" + +func f1() { + live() + return + dead() +} + +func f2() { + for { + live() + } + dead() +} + +func f3() { + if true { // even known values are ignored + return + } + for true { // even known values are ignored + live() + } + for { + live() + } + dead() +} + +func f4(x int) { + switch x { + case 1: + live() + fallthrough + case 2: + live() + log.Fatal() + default: + panic("oops") + } + dead() +} + +func f4(ch chan int) { + select { + case <-ch: + live() + return + default: + live() + panic("oops") + } + dead() +} + +func f5(unknown bool) { + for { + if unknown { + break + } + continue + dead() + } + live() +} + +func f6(unknown bool) { +outer: + for { + for { + break outer + dead() + } + dead() + } + live() +} + +func f7() { + for { + break nosuchlabel + dead() + } + dead() +} + +func f8() { + select{} + dead() +} + +func f9(ch chan int) { + select { + case <-ch: + return + } + dead() +} + +func f10(ch chan int) { + select { + case <-ch: + return + dead() + default: + } + live() +} + +func f11() { + goto; // mustn't crash + dead() +} + +` + +func TestDeadCode(t *testing.T) { + // We'll use dead code detection to verify the CFG. + + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0)) + if err != nil { + t.Fatal(err) + } + for _, decl := range f.Decls { + if decl, ok := decl.(*ast.FuncDecl); ok { + g := New(decl.Body, mayReturn) + + // Mark blocks reachable from entry. + live := make(map[*Block]bool) + var visit func(*Block) + visit = func(b *Block) { + if !live[b] { + live[b] = true + for _, succ := range b.Succs { + visit(succ) + } + } + } + visit(g.Blocks[0]) + + // Print statements in unreachable blocks + // (in order determined by builder). + var buf bytes.Buffer + for _, b := range g.Blocks { + if !live[b] { + for _, n := range b.Nodes { + fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n)) + } + } + } + + // Check that the result contains "dead" at least once but not "live". + if !bytes.Contains(buf.Bytes(), []byte("dead")) || + bytes.Contains(buf.Bytes(), []byte("live")) { + t.Errorf("unexpected dead statements in function %s:\n%s", + decl.Name.Name, + &buf) + t.Logf("control flow graph:\n%s", g.Format(fset)) + } + } + } +} + +// A trivial mayReturn predicate that looks only at syntax, not types. +func mayReturn(call *ast.CallExpr) bool { + switch fun := call.Fun.(type) { + case *ast.Ident: + return fun.Name != "panic" + case *ast.SelectorExpr: + return fun.Sel.Name != "Fatal" + } + return true +} diff --git a/libgo/go/cmd/vet/internal/whitelist/whitelist.go b/libgo/go/cmd/vet/internal/whitelist/whitelist.go new file mode 100644 index 00000000000..fdd65d37323 --- /dev/null +++ b/libgo/go/cmd/vet/internal/whitelist/whitelist.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 whitelist defines exceptions for the vet tool. +package whitelist + +// UnkeyedLiteral is a white list of types in the standard packages +// that are used with unkeyed literals we deem to be acceptable. +var UnkeyedLiteral = map[string]bool{ + // These image and image/color struct types are frozen. We will never add fields to them. + "image/color.Alpha16": true, + "image/color.Alpha": true, + "image/color.CMYK": true, + "image/color.Gray16": true, + "image/color.Gray": true, + "image/color.NRGBA64": true, + "image/color.NRGBA": true, + "image/color.NYCbCrA": true, + "image/color.RGBA64": true, + "image/color.RGBA": true, + "image/color.YCbCr": true, + "image.Point": true, + "image.Rectangle": true, + "image.Uniform": true, + + "unicode.Range16": true, +} diff --git a/libgo/go/cmd/vet/lostcancel.go b/libgo/go/cmd/vet/lostcancel.go new file mode 100644 index 00000000000..ee0342035fe --- /dev/null +++ b/libgo/go/cmd/vet/lostcancel.go @@ -0,0 +1,322 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/vet/internal/cfg" + "fmt" + "go/ast" + "go/types" + "strconv" +) + +func init() { + register("lostcancel", + "check for failure to call cancelation function returned by context.WithCancel", + checkLostCancel, + funcDecl, funcLit) +} + +const debugLostCancel = false + +var contextPackage = "context" + +// checkLostCancel reports a failure to the call the cancel function +// returned by context.WithCancel, either because the variable was +// assigned to the blank identifier, or because there exists a +// control-flow path from the call to a return statement and that path +// does not "use" the cancel function. Any reference to the variable +// counts as a use, even within a nested function literal. +// +// checkLostCancel analyzes a single named or literal function. +func checkLostCancel(f *File, node ast.Node) { + // Fast path: bypass check if file doesn't use context.WithCancel. + if !hasImport(f.file, contextPackage) { + return + } + + // Maps each cancel variable to its defining ValueSpec/AssignStmt. + cancelvars := make(map[*types.Var]ast.Node) + + // Find the set of cancel vars to analyze. + stack := make([]ast.Node, 0, 32) + ast.Inspect(node, func(n ast.Node) bool { + switch n.(type) { + case *ast.FuncLit: + if len(stack) > 0 { + return false // don't stray into nested functions + } + case nil: + stack = stack[:len(stack)-1] // pop + return true + } + stack = append(stack, n) // push + + // Look for [{AssignStmt,ValueSpec} CallExpr SelectorExpr]: + // + // ctx, cancel := context.WithCancel(...) + // ctx, cancel = context.WithCancel(...) + // var ctx, cancel = context.WithCancel(...) + // + if isContextWithCancel(f, n) && isCall(stack[len(stack)-2]) { + var id *ast.Ident // id of cancel var + stmt := stack[len(stack)-3] + switch stmt := stmt.(type) { + case *ast.ValueSpec: + if len(stmt.Names) > 1 { + id = stmt.Names[1] + } + case *ast.AssignStmt: + if len(stmt.Lhs) > 1 { + id, _ = stmt.Lhs[1].(*ast.Ident) + } + } + if id != nil { + if id.Name == "_" { + f.Badf(id.Pos(), "the cancel function returned by context.%s should be called, not discarded, to avoid a context leak", + n.(*ast.SelectorExpr).Sel.Name) + } else if v, ok := f.pkg.uses[id].(*types.Var); ok { + cancelvars[v] = stmt + } else if v, ok := f.pkg.defs[id].(*types.Var); ok { + cancelvars[v] = stmt + } + } + } + + return true + }) + + if len(cancelvars) == 0 { + return // no need to build CFG + } + + // Tell the CFG builder which functions never return. + info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors} + mayReturn := func(call *ast.CallExpr) bool { + name := callName(info, call) + return !noReturnFuncs[name] + } + + // Build the CFG. + var g *cfg.CFG + var sig *types.Signature + switch node := node.(type) { + case *ast.FuncDecl: + obj := f.pkg.defs[node.Name] + if obj == nil { + return // type error (e.g. duplicate function declaration) + } + sig, _ = obj.Type().(*types.Signature) + g = cfg.New(node.Body, mayReturn) + case *ast.FuncLit: + sig, _ = f.pkg.types[node.Type].Type.(*types.Signature) + g = cfg.New(node.Body, mayReturn) + } + + // Print CFG. + if debugLostCancel { + fmt.Println(g.Format(f.fset)) + } + + // Examine the CFG for each variable in turn. + // (It would be more efficient to analyze all cancelvars in a + // single pass over the AST, but seldom is there more than one.) + for v, stmt := range cancelvars { + if ret := lostCancelPath(f, g, v, stmt, sig); ret != nil { + lineno := f.fset.Position(stmt.Pos()).Line + f.Badf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name()) + f.Badf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno) + } + } +} + +func isCall(n ast.Node) bool { _, ok := n.(*ast.CallExpr); return ok } + +func hasImport(f *ast.File, path string) bool { + for _, imp := range f.Imports { + v, _ := strconv.Unquote(imp.Path.Value) + if v == path { + return true + } + } + return false +} + +// isContextWithCancel reports whether n is one of the qualified identifiers +// context.With{Cancel,Timeout,Deadline}. +func isContextWithCancel(f *File, n ast.Node) bool { + if sel, ok := n.(*ast.SelectorExpr); ok { + switch sel.Sel.Name { + case "WithCancel", "WithTimeout", "WithDeadline": + if x, ok := sel.X.(*ast.Ident); ok { + if pkgname, ok := f.pkg.uses[x].(*types.PkgName); ok { + return pkgname.Imported().Path() == contextPackage + } + // Import failed, so we can't check package path. + // Just check the local package name (heuristic). + return x.Name == "context" + } + } + } + return false +} + +// lostCancelPath finds a path through the CFG, from stmt (which defines +// the 'cancel' variable v) to a return statement, that doesn't "use" v. +// If it finds one, it returns the return statement (which may be synthetic). +// sig is the function's type, if known. +func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt { + vIsNamedResult := sig != nil && tupleContains(sig.Results(), v) + + // uses reports whether stmts contain a "use" of variable v. + uses := func(f *File, v *types.Var, stmts []ast.Node) bool { + found := false + for _, stmt := range stmts { + ast.Inspect(stmt, func(n ast.Node) bool { + switch n := n.(type) { + case *ast.Ident: + if f.pkg.uses[n] == v { + found = true + } + case *ast.ReturnStmt: + // A naked return statement counts as a use + // of the named result variables. + if n.Results == nil && vIsNamedResult { + found = true + } + } + return !found + }) + } + return found + } + + // blockUses computes "uses" for each block, caching the result. + memo := make(map[*cfg.Block]bool) + blockUses := func(f *File, v *types.Var, b *cfg.Block) bool { + res, ok := memo[b] + if !ok { + res = uses(f, v, b.Nodes) + memo[b] = res + } + return res + } + + // Find the var's defining block in the CFG, + // plus the rest of the statements of that block. + var defblock *cfg.Block + var rest []ast.Node +outer: + for _, b := range g.Blocks { + for i, n := range b.Nodes { + if n == stmt { + defblock = b + rest = b.Nodes[i+1:] + break outer + } + } + } + if defblock == nil { + panic("internal error: can't find defining block for cancel var") + } + + // Is v "used" in the remainder of its defining block? + if uses(f, v, rest) { + return nil + } + + // Does the defining block return without using v? + if ret := defblock.Return(); ret != nil { + return ret + } + + // Search the CFG depth-first for a path, from defblock to a + // return block, in which v is never "used". + seen := make(map[*cfg.Block]bool) + var search func(blocks []*cfg.Block) *ast.ReturnStmt + search = func(blocks []*cfg.Block) *ast.ReturnStmt { + for _, b := range blocks { + if !seen[b] { + seen[b] = true + + // Prune the search if the block uses v. + if blockUses(f, v, b) { + continue + } + + // Found path to return statement? + if ret := b.Return(); ret != nil { + if debugLostCancel { + fmt.Printf("found path to return in block %s\n", b) + } + return ret // found + } + + // Recur + if ret := search(b.Succs); ret != nil { + if debugLostCancel { + fmt.Printf(" from block %s\n", b) + } + return ret + } + } + } + return nil + } + return search(defblock.Succs) +} + +func tupleContains(tuple *types.Tuple, v *types.Var) bool { + for i := 0; i < tuple.Len(); i++ { + if tuple.At(i) == v { + return true + } + } + return false +} + +var noReturnFuncs = map[string]bool{ + "(*testing.common).FailNow": true, + "(*testing.common).Fatal": true, + "(*testing.common).Fatalf": true, + "(*testing.common).Skip": true, + "(*testing.common).SkipNow": true, + "(*testing.common).Skipf": true, + "log.Fatal": true, + "log.Fatalf": true, + "log.Fatalln": true, + "os.Exit": true, + "panic": true, + "runtime.Goexit": true, +} + +// callName returns the canonical name of the builtin, method, or +// function called by call, if known. +func callName(info *types.Info, call *ast.CallExpr) string { + switch fun := call.Fun.(type) { + case *ast.Ident: + // builtin, e.g. "panic" + if obj, ok := info.Uses[fun].(*types.Builtin); ok { + return obj.Name() + } + case *ast.SelectorExpr: + if sel, ok := info.Selections[fun]; ok && sel.Kind() == types.MethodVal { + // method call, e.g. "(*testing.common).Fatal" + meth := sel.Obj() + return fmt.Sprintf("(%s).%s", + meth.Type().(*types.Signature).Recv().Type(), + meth.Name()) + } + if obj, ok := info.Uses[fun.Sel]; ok { + // qualified identifier, e.g. "os.Exit" + return fmt.Sprintf("%s.%s", + obj.Pkg().Path(), + obj.Name()) + } + } + + // function with no name, or defined in missing imported package + return "" +} diff --git a/libgo/go/cmd/vet/main.go b/libgo/go/cmd/vet/main.go new file mode 100644 index 00000000000..9d28ebd7876 --- /dev/null +++ b/libgo/go/cmd/vet/main.go @@ -0,0 +1,619 @@ +// 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. + +// Vet is a simple checker for static errors in Go source code. +// See doc.go for more information. +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "go/ast" + "go/build" + "go/importer" + "go/parser" + "go/printer" + "go/token" + "go/types" + "io" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" +) + +// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go. + +var ( + verbose = flag.Bool("v", false, "verbose") + source = flag.Bool("source", false, "import from source instead of compiled object files") + tags = flag.String("tags", "", "space-separated list of build tags to apply when parsing") + tagList = []string{} // exploded version of tags flag; set in main + + vcfg vetConfig + mustTypecheck bool +) + +var exitCode = 0 + +// "-all" flag enables all non-experimental checks +var all = triStateFlag("all", unset, "enable all non-experimental checks") + +// Flags to control which individual checks to perform. +var report = map[string]*triState{ + // Only unusual checks are written here. + // Most checks that operate during the AST walk are added by register. + "asmdecl": triStateFlag("asmdecl", unset, "check assembly against Go declarations"), + "buildtags": triStateFlag("buildtags", unset, "check that +build tags are valid"), +} + +// experimental records the flags enabling experimental features. These must be +// requested explicitly; they are not enabled by -all. +var experimental = map[string]bool{} + +// setTrueCount record how many flags are explicitly set to true. +var setTrueCount int + +// dirsRun and filesRun indicate whether the vet is applied to directory or +// file targets. The distinction affects which checks are run. +var dirsRun, filesRun bool + +// includesNonTest indicates whether the vet is applied to non-test targets. +// Certain checks are relevant only if they touch both test and non-test files. +var includesNonTest bool + +// A triState is a boolean that knows whether it has been set to either true or false. +// It is used to identify if a flag appears; the standard boolean flag cannot +// distinguish missing from unset. It also satisfies flag.Value. +type triState int + +const ( + unset triState = iota + setTrue + setFalse +) + +func triStateFlag(name string, value triState, usage string) *triState { + flag.Var(&value, name, usage) + return &value +} + +// triState implements flag.Value, flag.Getter, and flag.boolFlag. +// They work like boolean flags: we can say vet -printf as well as vet -printf=true +func (ts *triState) Get() interface{} { + return *ts == setTrue +} + +func (ts triState) isTrue() bool { + return ts == setTrue +} + +func (ts *triState) Set(value string) error { + b, err := strconv.ParseBool(value) + if err != nil { + return err + } + if b { + *ts = setTrue + setTrueCount++ + } else { + *ts = setFalse + } + return nil +} + +func (ts *triState) String() string { + switch *ts { + case unset: + return "true" // An unset flag will be set by -all, so defaults to true. + case setTrue: + return "true" + case setFalse: + return "false" + } + panic("not reached") +} + +func (ts triState) IsBoolFlag() bool { + return true +} + +// vet tells whether to report errors for the named check, a flag name. +func vet(name string) bool { + return report[name].isTrue() +} + +// setExit sets the value for os.Exit when it is called, later. It +// remembers the highest value. +func setExit(err int) { + if err > exitCode { + exitCode = err + } +} + +var ( + // Each of these vars has a corresponding case in (*File).Visit. + assignStmt *ast.AssignStmt + binaryExpr *ast.BinaryExpr + callExpr *ast.CallExpr + compositeLit *ast.CompositeLit + exprStmt *ast.ExprStmt + forStmt *ast.ForStmt + funcDecl *ast.FuncDecl + funcLit *ast.FuncLit + genDecl *ast.GenDecl + interfaceType *ast.InterfaceType + rangeStmt *ast.RangeStmt + returnStmt *ast.ReturnStmt + structType *ast.StructType + + // checkers is a two-level map. + // The outer level is keyed by a nil pointer, one of the AST vars above. + // The inner level is keyed by checker name. + checkers = make(map[ast.Node]map[string]func(*File, ast.Node)) +) + +func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) { + report[name] = triStateFlag(name, unset, usage) + for _, typ := range types { + m := checkers[typ] + if m == nil { + m = make(map[string]func(*File, ast.Node)) + checkers[typ] = m + } + m[name] = fn + } +} + +// Usage is a replacement usage function for the flags package. +func Usage() { + fmt.Fprintf(os.Stderr, "Usage of vet:\n") + fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n") + fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n") + fmt.Fprintf(os.Stderr, "By default, -all is set and all non-experimental checks are run.\n") + fmt.Fprintf(os.Stderr, "For more information run\n") + fmt.Fprintf(os.Stderr, "\tgo doc cmd/vet\n\n") + fmt.Fprintf(os.Stderr, "Flags:\n") + flag.PrintDefaults() + os.Exit(2) +} + +// File is a wrapper for the state of a file used in the parser. +// The parse tree walkers are all methods of this type. +type File struct { + pkg *Package + fset *token.FileSet + name string + content []byte + file *ast.File + b bytes.Buffer // for use by methods + + // Parsed package "foo" when checking package "foo_test" + basePkg *Package + + // The objects that are receivers of a "String() string" method. + // This is used by the recursiveStringer method in print.go. + stringers map[*ast.Object]bool + + // Registered checkers to run. + checkers map[ast.Node][]func(*File, ast.Node) + + // Unreachable nodes; can be ignored in shift check. + dead map[ast.Node]bool +} + +func main() { + flag.Usage = Usage + flag.Parse() + + // If any flag is set, we run only those checks requested. + // If all flag is set true or if no flags are set true, set all the non-experimental ones + // not explicitly set (in effect, set the "-all" flag). + if setTrueCount == 0 || *all == setTrue { + for name, setting := range report { + if *setting == unset && !experimental[name] { + *setting = setTrue + } + } + } + + // Accept space-separated tags because that matches + // the go command's other subcommands. + // Accept commas because go tool vet traditionally has. + tagList = strings.Fields(strings.Replace(*tags, ",", " ", -1)) + + initPrintFlags() + initUnusedFlags() + + if flag.NArg() == 0 { + Usage() + } + + // Special case for "go vet" passing an explicit configuration: + // single argument ending in vet.cfg. + // Once we have a more general mechanism for obtaining this + // information from build tools like the go command, + // vet should be changed to use it. This vet.cfg hack is an + // experiment to learn about what form that information should take. + if flag.NArg() == 1 && strings.HasSuffix(flag.Arg(0), "vet.cfg") { + doPackageCfg(flag.Arg(0)) + os.Exit(exitCode) + } + + for _, name := range flag.Args() { + // Is it a directory? + fi, err := os.Stat(name) + if err != nil { + warnf("error walking tree: %s", err) + continue + } + if fi.IsDir() { + dirsRun = true + } else { + filesRun = true + if !strings.HasSuffix(name, "_test.go") { + includesNonTest = true + } + } + } + if dirsRun && filesRun { + Usage() + } + if dirsRun { + for _, name := range flag.Args() { + walkDir(name) + } + os.Exit(exitCode) + } + if doPackage(flag.Args(), nil) == nil { + warnf("no files checked") + } + os.Exit(exitCode) +} + +// prefixDirectory places the directory name on the beginning of each name in the list. +func prefixDirectory(directory string, names []string) { + if directory != "." { + for i, name := range names { + names[i] = filepath.Join(directory, name) + } + } +} + +// vetConfig is the JSON config struct prepared by the Go command. +type vetConfig struct { + Compiler string + Dir string + ImportPath string + GoFiles []string + ImportMap map[string]string + PackageFile map[string]string + + SucceedOnTypecheckFailure bool + + imp types.Importer +} + +func (v *vetConfig) Import(path string) (*types.Package, error) { + if v.imp == nil { + v.imp = importer.For(v.Compiler, v.openPackageFile) + } + if path == "unsafe" { + return v.imp.Import("unsafe") + } + p := v.ImportMap[path] + if p == "" { + return nil, fmt.Errorf("unknown import path %q", path) + } + if v.PackageFile[p] == "" && v.Compiler != "gccgo" { + return nil, fmt.Errorf("unknown package file for import %q", path) + } + return v.imp.Import(p) +} + +func (v *vetConfig) openPackageFile(path string) (io.ReadCloser, error) { + file := v.PackageFile[path] + if file == "" { + // Note that path here has been translated via v.ImportMap, + // unlike in the error in Import above. We prefer the error in + // Import, but it's worth diagnosing this one too, just in case. + return nil, fmt.Errorf("unknown package file for %q", path) + } + f, err := os.Open(file) + if err != nil { + return nil, err + } + return f, nil +} + +// doPackageCfg analyzes a single package described in a config file. +func doPackageCfg(cfgFile string) { + js, err := ioutil.ReadFile(cfgFile) + if err != nil { + errorf("%v", err) + } + if err := json.Unmarshal(js, &vcfg); err != nil { + errorf("parsing vet config %s: %v", cfgFile, err) + } + stdImporter = &vcfg + inittypes() + mustTypecheck = true + doPackage(vcfg.GoFiles, nil) +} + +// doPackageDir analyzes the single package found in the directory, if there is one, +// plus a test package, if there is one. +func doPackageDir(directory string) { + context := build.Default + if len(context.BuildTags) != 0 { + warnf("build tags %s previously set", context.BuildTags) + } + context.BuildTags = append(tagList, context.BuildTags...) + + pkg, err := context.ImportDir(directory, 0) + if err != nil { + // If it's just that there are no go source files, that's fine. + if _, nogo := err.(*build.NoGoError); nogo { + return + } + // Non-fatal: we are doing a recursive walk and there may be other directories. + warnf("cannot process directory %s: %s", directory, err) + return + } + var names []string + names = append(names, pkg.GoFiles...) + names = append(names, pkg.CgoFiles...) + names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package. + names = append(names, pkg.SFiles...) + prefixDirectory(directory, names) + basePkg := doPackage(names, nil) + // Is there also a "foo_test" package? If so, do that one as well. + if len(pkg.XTestGoFiles) > 0 { + names = pkg.XTestGoFiles + prefixDirectory(directory, names) + doPackage(names, basePkg) + } +} + +type Package struct { + path string + defs map[*ast.Ident]types.Object + uses map[*ast.Ident]types.Object + selectors map[*ast.SelectorExpr]*types.Selection + types map[ast.Expr]types.TypeAndValue + spans map[types.Object]Span + files []*File + typesPkg *types.Package +} + +// doPackage analyzes the single package constructed from the named files. +// It returns the parsed Package or nil if none of the files have been checked. +func doPackage(names []string, basePkg *Package) *Package { + var files []*File + var astFiles []*ast.File + fs := token.NewFileSet() + for _, name := range names { + data, err := ioutil.ReadFile(name) + if err != nil { + // Warn but continue to next package. + warnf("%s: %s", name, err) + return nil + } + checkBuildTag(name, data) + var parsedFile *ast.File + if strings.HasSuffix(name, ".go") { + parsedFile, err = parser.ParseFile(fs, name, data, 0) + if err != nil { + warnf("%s: %s", name, err) + return nil + } + astFiles = append(astFiles, parsedFile) + } + files = append(files, &File{ + fset: fs, + content: data, + name: name, + file: parsedFile, + dead: make(map[ast.Node]bool), + }) + } + if len(astFiles) == 0 { + return nil + } + pkg := new(Package) + pkg.path = astFiles[0].Name.Name + pkg.files = files + // Type check the package. + errs := pkg.check(fs, astFiles) + if errs != nil { + if vcfg.SucceedOnTypecheckFailure { + os.Exit(0) + } + if *verbose || mustTypecheck { + for _, err := range errs { + fmt.Fprintf(os.Stderr, "%v\n", err) + } + if mustTypecheck { + // This message could be silenced, and we could just exit, + // but it might be helpful at least at first to make clear that the + // above errors are coming from vet and not the compiler + // (they often look like compiler errors, such as "declared but not used"). + errorf("typecheck failures") + } + } + } + + // Check. + chk := make(map[ast.Node][]func(*File, ast.Node)) + for typ, set := range checkers { + for name, fn := range set { + if vet(name) { + chk[typ] = append(chk[typ], fn) + } + } + } + for _, file := range files { + file.pkg = pkg + file.basePkg = basePkg + file.checkers = chk + if file.file != nil { + file.walkFile(file.name, file.file) + } + } + asmCheck(pkg) + return pkg +} + +func visit(path string, f os.FileInfo, err error) error { + if err != nil { + warnf("walk error: %s", err) + return err + } + // One package per directory. Ignore the files themselves. + if !f.IsDir() { + return nil + } + doPackageDir(path) + return nil +} + +func (pkg *Package) hasFileWithSuffix(suffix string) bool { + for _, f := range pkg.files { + if strings.HasSuffix(f.name, suffix) { + return true + } + } + return false +} + +// walkDir recursively walks the tree looking for Go packages. +func walkDir(root string) { + filepath.Walk(root, visit) +} + +// errorf formats the error to standard error, adding program +// identification and a newline, and exits. +func errorf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...) + os.Exit(2) +} + +// warnf formats the error to standard error, adding program +// identification and a newline, but does not exit. +func warnf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...) + setExit(1) +} + +// Println is fmt.Println guarded by -v. +func Println(args ...interface{}) { + if !*verbose { + return + } + fmt.Println(args...) +} + +// Printf is fmt.Printf guarded by -v. +func Printf(format string, args ...interface{}) { + if !*verbose { + return + } + fmt.Printf(format+"\n", args...) +} + +// Bad reports an error and sets the exit code.. +func (f *File) Bad(pos token.Pos, args ...interface{}) { + f.Warn(pos, args...) + setExit(1) +} + +// Badf reports a formatted error and sets the exit code. +func (f *File) Badf(pos token.Pos, format string, args ...interface{}) { + f.Warnf(pos, format, args...) + setExit(1) +} + +// loc returns a formatted representation of the position. +func (f *File) loc(pos token.Pos) string { + if pos == token.NoPos { + return "" + } + // Do not print columns. Because the pos often points to the start of an + // expression instead of the inner part with the actual error, the + // precision can mislead. + posn := f.fset.Position(pos) + return fmt.Sprintf("%s:%d", posn.Filename, posn.Line) +} + +// locPrefix returns a formatted representation of the position for use as a line prefix. +func (f *File) locPrefix(pos token.Pos) string { + if pos == token.NoPos { + return "" + } + return fmt.Sprintf("%s: ", f.loc(pos)) +} + +// Warn reports an error but does not set the exit code. +func (f *File) Warn(pos token.Pos, args ...interface{}) { + fmt.Fprintf(os.Stderr, "%s%s", f.locPrefix(pos), fmt.Sprintln(args...)) +} + +// Warnf reports a formatted error but does not set the exit code. +func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "%s%s\n", f.locPrefix(pos), fmt.Sprintf(format, args...)) +} + +// walkFile walks the file's tree. +func (f *File) walkFile(name string, file *ast.File) { + Println("Checking file", name) + ast.Walk(f, file) +} + +// Visit implements the ast.Visitor interface. +func (f *File) Visit(node ast.Node) ast.Visitor { + f.updateDead(node) + var key ast.Node + switch node.(type) { + case *ast.AssignStmt: + key = assignStmt + case *ast.BinaryExpr: + key = binaryExpr + case *ast.CallExpr: + key = callExpr + case *ast.CompositeLit: + key = compositeLit + case *ast.ExprStmt: + key = exprStmt + case *ast.ForStmt: + key = forStmt + case *ast.FuncDecl: + key = funcDecl + case *ast.FuncLit: + key = funcLit + case *ast.GenDecl: + key = genDecl + case *ast.InterfaceType: + key = interfaceType + case *ast.RangeStmt: + key = rangeStmt + case *ast.ReturnStmt: + key = returnStmt + case *ast.StructType: + key = structType + } + for _, fn := range f.checkers[key] { + fn(f, node) + } + return f +} + +// gofmt returns a string representation of the expression. +func (f *File) gofmt(x ast.Expr) string { + f.b.Reset() + printer.Fprint(&f.b, f.fset, x) + return f.b.String() +} diff --git a/libgo/go/cmd/vet/method.go b/libgo/go/cmd/vet/method.go new file mode 100644 index 00000000000..b13ce2fcb56 --- /dev/null +++ b/libgo/go/cmd/vet/method.go @@ -0,0 +1,181 @@ +// 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. + +// This file contains the code to check canonical methods. + +package main + +import ( + "fmt" + "go/ast" + "go/printer" + "strings" +) + +func init() { + register("methods", + "check that canonically named methods are canonically defined", + checkCanonicalMethod, + funcDecl, interfaceType) +} + +type MethodSig struct { + args []string + results []string +} + +// canonicalMethods lists the input and output types for Go methods +// that are checked using dynamic interface checks. Because the +// checks are dynamic, such methods would not cause a compile error +// if they have the wrong signature: instead the dynamic check would +// fail, sometimes mysteriously. If a method is found with a name listed +// here but not the input/output types listed here, vet complains. +// +// A few of the canonical methods have very common names. +// For example, a type might implement a Scan method that +// has nothing to do with fmt.Scanner, but we still want to check +// the methods that are intended to implement fmt.Scanner. +// To do that, the arguments that have a = prefix are treated as +// signals that the canonical meaning is intended: if a Scan +// method doesn't have a fmt.ScanState as its first argument, +// we let it go. But if it does have a fmt.ScanState, then the +// rest has to match. +var canonicalMethods = map[string]MethodSig{ + // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict + "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter + "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder + "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder + "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler + "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler + "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader + "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom + "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader + "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner + "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker + "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler + "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler + "UnreadByte": {[]string{}, []string{"error"}}, + "UnreadRune": {[]string{}, []string{"error"}}, + "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer) + "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo +} + +func checkCanonicalMethod(f *File, node ast.Node) { + switch n := node.(type) { + case *ast.FuncDecl: + if n.Recv != nil { + canonicalMethod(f, n.Name, n.Type) + } + case *ast.InterfaceType: + for _, field := range n.Methods.List { + for _, id := range field.Names { + canonicalMethod(f, id, field.Type.(*ast.FuncType)) + } + } + } +} + +func canonicalMethod(f *File, id *ast.Ident, t *ast.FuncType) { + // Expected input/output. + expect, ok := canonicalMethods[id.Name] + if !ok { + return + } + + // Actual input/output + args := typeFlatten(t.Params.List) + var results []ast.Expr + if t.Results != nil { + results = typeFlatten(t.Results.List) + } + + // Do the =s (if any) all match? + if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") { + return + } + + // Everything must match. + if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") { + expectFmt := id.Name + "(" + argjoin(expect.args) + ")" + if len(expect.results) == 1 { + expectFmt += " " + argjoin(expect.results) + } else if len(expect.results) > 1 { + expectFmt += " (" + argjoin(expect.results) + ")" + } + + f.b.Reset() + if err := printer.Fprint(&f.b, f.fset, t); err != nil { + fmt.Fprintf(&f.b, "<%s>", err) + } + actual := f.b.String() + actual = strings.TrimPrefix(actual, "func") + actual = id.Name + actual + + f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt) + } +} + +func argjoin(x []string) string { + y := make([]string, len(x)) + for i, s := range x { + if s[0] == '=' { + s = s[1:] + } + y[i] = s + } + return strings.Join(y, ", ") +} + +// Turn parameter list into slice of types +// (in the ast, types are Exprs). +// Have to handle f(int, bool) and f(x, y, z int) +// so not a simple 1-to-1 conversion. +func typeFlatten(l []*ast.Field) []ast.Expr { + var t []ast.Expr + for _, f := range l { + if len(f.Names) == 0 { + t = append(t, f.Type) + continue + } + for range f.Names { + t = append(t, f.Type) + } + } + return t +} + +// Does each type in expect with the given prefix match the corresponding type in actual? +func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool { + for i, x := range expect { + if !strings.HasPrefix(x, prefix) { + continue + } + if i >= len(actual) { + return false + } + if !f.matchParamType(x, actual[i]) { + return false + } + } + if prefix == "" && len(actual) > len(expect) { + return false + } + return true +} + +// Does this one type match? +func (f *File) matchParamType(expect string, actual ast.Expr) bool { + if strings.HasPrefix(expect, "=") { + expect = expect[1:] + } + // Strip package name if we're in that package. + if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' { + expect = expect[n+1:] + } + + // Overkill but easy. + f.b.Reset() + printer.Fprint(&f.b, f.fset, actual) + return f.b.String() == expect +} diff --git a/libgo/go/cmd/vet/nilfunc.go b/libgo/go/cmd/vet/nilfunc.go new file mode 100644 index 00000000000..bfe05e3353d --- /dev/null +++ b/libgo/go/cmd/vet/nilfunc.go @@ -0,0 +1,67 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +This file contains the code to check for useless function comparisons. +A useless comparison is one like f == nil as opposed to f() == nil. +*/ + +package main + +import ( + "go/ast" + "go/token" + "go/types" +) + +func init() { + register("nilfunc", + "check for comparisons between functions and nil", + checkNilFuncComparison, + binaryExpr) +} + +func checkNilFuncComparison(f *File, node ast.Node) { + e := node.(*ast.BinaryExpr) + + // Only want == or != comparisons. + if e.Op != token.EQL && e.Op != token.NEQ { + return + } + + // Only want comparisons with a nil identifier on one side. + var e2 ast.Expr + switch { + case f.isNil(e.X): + e2 = e.Y + case f.isNil(e.Y): + e2 = e.X + default: + return + } + + // Only want identifiers or selector expressions. + var obj types.Object + switch v := e2.(type) { + case *ast.Ident: + obj = f.pkg.uses[v] + case *ast.SelectorExpr: + obj = f.pkg.uses[v.Sel] + default: + return + } + + // Only want functions. + if _, ok := obj.(*types.Func); !ok { + return + } + + f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ) +} + +// isNil reports whether the provided expression is the built-in nil +// identifier. +func (f *File) isNil(e ast.Expr) bool { + return f.pkg.types[e].Type == types.Typ[types.UntypedNil] +} diff --git a/libgo/go/cmd/vet/print.go b/libgo/go/cmd/vet/print.go new file mode 100644 index 00000000000..456fbcc044d --- /dev/null +++ b/libgo/go/cmd/vet/print.go @@ -0,0 +1,780 @@ +// 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. + +// This file contains the printf-checker. + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/constant" + "go/token" + "go/types" + "regexp" + "strconv" + "strings" + "unicode/utf8" +) + +var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check") + +func init() { + register("printf", + "check printf-like invocations", + checkFmtPrintfCall, + funcDecl, callExpr) +} + +func initPrintFlags() { + if *printfuncs == "" { + return + } + for _, name := range strings.Split(*printfuncs, ",") { + if len(name) == 0 { + flag.Usage() + } + + // Backwards compatibility: skip optional first argument + // index after the colon. + if colon := strings.LastIndex(name, ":"); colon > 0 { + name = name[:colon] + } + + isPrint[strings.ToLower(name)] = true + } +} + +// TODO(rsc): Incorporate user-defined printf wrappers again. +// The general plan is to allow vet of one package P to output +// additional information to supply to later vets of packages +// importing P. Then vet of P can record a list of printf wrappers +// and the later vet using P.Printf will find it in the list and check it. +// That's not ready for Go 1.10. +// When that does happen, uncomment the user-defined printf +// wrapper tests in testdata/print.go. + +// isPrint records the print functions. +// If a key ends in 'f' then it is assumed to be a formatted print. +var isPrint = map[string]bool{ + "fmt.Errorf": true, + "fmt.Fprint": true, + "fmt.Fprintf": true, + "fmt.Fprintln": true, + "fmt.Print": true, + "fmt.Printf": true, + "fmt.Println": true, + "fmt.Sprint": true, + "fmt.Sprintf": true, + "fmt.Sprintln": true, + "log.Fatal": true, + "log.Fatalf": true, + "log.Fatalln": true, + "log.Logger.Fatal": true, + "log.Logger.Fatalf": true, + "log.Logger.Fatalln": true, + "log.Logger.Panic": true, + "log.Logger.Panicf": true, + "log.Logger.Panicln": true, + "log.Logger.Printf": true, + "log.Logger.Println": true, + "log.Panic": true, + "log.Panicf": true, + "log.Panicln": true, + "log.Print": true, + "log.Printf": true, + "log.Println": true, + "testing.B.Error": true, + "testing.B.Errorf": true, + "testing.B.Fatal": true, + "testing.B.Fatalf": true, + "testing.B.Log": true, + "testing.B.Logf": true, + "testing.B.Skip": true, + "testing.B.Skipf": true, + "testing.T.Error": true, + "testing.T.Errorf": true, + "testing.T.Fatal": true, + "testing.T.Fatalf": true, + "testing.T.Log": true, + "testing.T.Logf": true, + "testing.T.Skip": true, + "testing.T.Skipf": true, + "testing.TB.Error": true, + "testing.TB.Errorf": true, + "testing.TB.Fatal": true, + "testing.TB.Fatalf": true, + "testing.TB.Log": true, + "testing.TB.Logf": true, + "testing.TB.Skip": true, + "testing.TB.Skipf": true, +} + +// formatString returns the format string argument and its index within +// the given printf-like call expression. +// +// The last parameter before variadic arguments is assumed to be +// a format string. +// +// The first string literal or string constant is assumed to be a format string +// if the call's signature cannot be determined. +// +// If it cannot find any format string parameter, it returns ("", -1). +func formatString(f *File, call *ast.CallExpr) (format string, idx int) { + typ := f.pkg.types[call.Fun].Type + if typ != nil { + if sig, ok := typ.(*types.Signature); ok { + if !sig.Variadic() { + // Skip checking non-variadic functions. + return "", -1 + } + idx := sig.Params().Len() - 2 + if idx < 0 { + // Skip checking variadic functions without + // fixed arguments. + return "", -1 + } + s, ok := stringConstantArg(f, call, idx) + if !ok { + // The last argument before variadic args isn't a string. + return "", -1 + } + return s, idx + } + } + + // Cannot determine call's signature. Fall back to scanning for the first + // string constant in the call. + for idx := range call.Args { + if s, ok := stringConstantArg(f, call, idx); ok { + return s, idx + } + if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] { + // Skip checking a call with a non-constant format + // string argument, since its contents are unavailable + // for validation. + return "", -1 + } + } + return "", -1 +} + +// stringConstantArg returns call's string constant argument at the index idx. +// +// ("", false) is returned if call's argument at the index idx isn't a string +// constant. +func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) { + if idx >= len(call.Args) { + return "", false + } + arg := call.Args[idx] + lit := f.pkg.types[arg].Value + if lit != nil && lit.Kind() == constant.String { + return constant.StringVal(lit), true + } + return "", false +} + +// checkCall triggers the print-specific checks if the call invokes a print function. +func checkFmtPrintfCall(f *File, node ast.Node) { + if f.pkg.typesPkg == nil { + // This check now requires type information. + return + } + + if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) { + // Remember we saw this. + if f.stringers == nil { + f.stringers = make(map[*ast.Object]bool) + } + if l := d.Recv.List; len(l) == 1 { + if n := l[0].Names; len(n) == 1 { + f.stringers[n[0].Obj] = true + } + } + return + } + + call, ok := node.(*ast.CallExpr) + if !ok { + return + } + + // Construct name like pkg.Printf or pkg.Type.Printf for lookup. + var name string + switch x := call.Fun.(type) { + case *ast.Ident: + if fn, ok := f.pkg.uses[x].(*types.Func); ok { + var pkg string + if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg { + pkg = vcfg.ImportPath + } else { + pkg = fn.Pkg().Path() + } + name = pkg + "." + x.Name + break + } + + case *ast.SelectorExpr: + // Check for "fmt.Printf". + if id, ok := x.X.(*ast.Ident); ok { + if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok { + name = pkgName.Imported().Path() + "." + x.Sel.Name + break + } + } + + // Check for t.Logf where t is a *testing.T. + if sel := f.pkg.selectors[x]; sel != nil { + recv := sel.Recv() + if p, ok := recv.(*types.Pointer); ok { + recv = p.Elem() + } + if named, ok := recv.(*types.Named); ok { + obj := named.Obj() + var pkg string + if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg { + pkg = vcfg.ImportPath + } else { + pkg = obj.Pkg().Path() + } + name = pkg + "." + obj.Name() + "." + x.Sel.Name + break + } + } + } + if name == "" { + return + } + + shortName := name[strings.LastIndex(name, ".")+1:] + + _, ok = isPrint[name] + if !ok { + // Next look up just "printf", for use with -printfuncs. + _, ok = isPrint[strings.ToLower(shortName)] + } + if ok { + if strings.HasSuffix(name, "f") { + f.checkPrintf(call, shortName) + } else { + f.checkPrint(call, shortName) + } + } +} + +// isStringer returns true if the provided declaration is a "String() string" +// method, an implementation of fmt.Stringer. +func isStringer(f *File, d *ast.FuncDecl) bool { + return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil && + len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 && + f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String] +} + +// isFormatter reports whether t satisfies fmt.Formatter. +// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt. +func (f *File) isFormatter(t types.Type) bool { + return formatterType != nil && types.Implements(t, formatterType) +} + +// formatState holds the parsed representation of a printf directive such as "%3.*[4]d". +// It is constructed by parsePrintfVerb. +type formatState struct { + verb rune // the format verb: 'd' for "%d" + format string // the full format directive from % through verb, "%.3d". + name string // Printf, Sprintf etc. + flags []byte // the list of # + etc. + argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call + firstArg int // Index of first argument after the format in the Printf call. + // Used only during parse. + file *File + call *ast.CallExpr + argNum int // Which argument we're expecting to format now. + indexPending bool // Whether we have an indexed argument that has not resolved. + nbytes int // number of bytes of the format string consumed. +} + +// checkPrintf checks a call to a formatted print routine such as Printf. +func (f *File) checkPrintf(call *ast.CallExpr, name string) { + format, idx := formatString(f, call) + if idx < 0 { + if *verbose { + f.Warn(call.Pos(), "can't check non-constant format in call to", name) + } + return + } + + firstArg := idx + 1 // Arguments are immediately after format string. + if !strings.Contains(format, "%") { + if len(call.Args) > firstArg { + f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name) + } + return + } + // Hard part: check formats against args. + argNum := firstArg + maxArgNum := firstArg + for i, w := 0, 0; i < len(format); i += w { + w = 1 + if format[i] != '%' { + continue + } + state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum) + if state == nil { + return + } + w = len(state.format) + if !f.okPrintfArg(call, state) { // One error per format is enough. + return + } + if len(state.argNums) > 0 { + // Continue with the next sequential argument. + argNum = state.argNums[len(state.argNums)-1] + 1 + } + for _, n := range state.argNums { + if n >= maxArgNum { + maxArgNum = n + 1 + } + } + } + // Dotdotdot is hard. + if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { + return + } + // There should be no leftover arguments. + if maxArgNum != len(call.Args) { + expect := maxArgNum - firstArg + numArgs := len(call.Args) - firstArg + f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg")) + } +} + +// parseFlags accepts any printf flags. +func (s *formatState) parseFlags() { + for s.nbytes < len(s.format) { + switch c := s.format[s.nbytes]; c { + case '#', '0', '+', '-', ' ': + s.flags = append(s.flags, c) + s.nbytes++ + default: + return + } + } +} + +// scanNum advances through a decimal number if present. +func (s *formatState) scanNum() { + for ; s.nbytes < len(s.format); s.nbytes++ { + c := s.format[s.nbytes] + if c < '0' || '9' < c { + return + } + } +} + +// parseIndex scans an index expression. It returns false if there is a syntax error. +func (s *formatState) parseIndex() bool { + if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { + return true + } + // Argument index present. + s.nbytes++ // skip '[' + start := s.nbytes + s.scanNum() + ok := true + if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { + ok = false + s.nbytes = strings.Index(s.format, "]") + if s.nbytes < 0 { + s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format) + return false + } + } + arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) + if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { + s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) + return false + } + s.nbytes++ // skip ']' + arg := int(arg32) + arg += s.firstArg - 1 // We want to zero-index the actual arguments. + s.argNum = arg + s.indexPending = true + return true +} + +// parseNum scans a width or precision (or *). It returns false if there's a bad index expression. +func (s *formatState) parseNum() bool { + if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { + if s.indexPending { // Absorb it. + s.indexPending = false + } + s.nbytes++ + s.argNums = append(s.argNums, s.argNum) + s.argNum++ + } else { + s.scanNum() + } + return true +} + +// parsePrecision scans for a precision. It returns false if there's a bad index expression. +func (s *formatState) parsePrecision() bool { + // If there's a period, there may be a precision. + if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { + s.flags = append(s.flags, '.') // Treat precision as a flag. + s.nbytes++ + if !s.parseIndex() { + return false + } + if !s.parseNum() { + return false + } + } + return true +} + +// parsePrintfVerb looks the formatting directive that begins the format string +// and returns a formatState that encodes what the directive wants, without looking +// at the actual arguments present in the call. The result is nil if there is an error. +func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { + state := &formatState{ + format: format, + name: name, + flags: make([]byte, 0, 5), + argNum: argNum, + argNums: make([]int, 0, 1), + nbytes: 1, // There's guaranteed to be a percent sign. + firstArg: firstArg, + file: f, + call: call, + } + // There may be flags. + state.parseFlags() + // There may be an index. + if !state.parseIndex() { + return nil + } + // There may be a width. + if !state.parseNum() { + return nil + } + // There may be a precision. + if !state.parsePrecision() { + return nil + } + // Now a verb, possibly prefixed by an index (which we may already have). + if !state.indexPending && !state.parseIndex() { + return nil + } + if state.nbytes == len(state.format) { + f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format) + return nil + } + verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) + state.verb = verb + state.nbytes += w + if verb != '%' { + state.argNums = append(state.argNums, state.argNum) + } + state.format = state.format[:state.nbytes] + return state +} + +// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. +type printfArgType int + +const ( + argBool printfArgType = 1 << iota + argInt + argRune + argString + argFloat + argComplex + argPointer + anyType printfArgType = ^0 +) + +type printVerb struct { + verb rune // User may provide verb through Formatter; could be a rune. + flags string // known flags are all ASCII + typ printfArgType +} + +// Common flag sets for printf verbs. +const ( + noFlag = "" + numFlag = " -+.0" + sharpNumFlag = " -+.0#" + allFlags = " -+.0#" +) + +// printVerbs identifies which flags are known to printf for each verb. +var printVerbs = []printVerb{ + // '-' is a width modifier, always valid. + // '.' is a precision for float, max width for strings. + // '+' is required sign for numbers, Go format for %v. + // '#' is alternate format for several verbs. + // ' ' is spacer for numbers + {'%', noFlag, 0}, + {'b', numFlag, argInt | argFloat | argComplex}, + {'c', "-", argRune | argInt}, + {'d', numFlag, argInt}, + {'e', sharpNumFlag, argFloat | argComplex}, + {'E', sharpNumFlag, argFloat | argComplex}, + {'f', sharpNumFlag, argFloat | argComplex}, + {'F', sharpNumFlag, argFloat | argComplex}, + {'g', sharpNumFlag, argFloat | argComplex}, + {'G', sharpNumFlag, argFloat | argComplex}, + {'o', sharpNumFlag, argInt}, + {'p', "-#", argPointer}, + {'q', " -+.0#", argRune | argInt | argString}, + {'s', " -+.0", argString}, + {'t', "-", argBool}, + {'T', "-", anyType}, + {'U', "-#", argRune | argInt}, + {'v', allFlags, anyType}, + {'x', sharpNumFlag, argRune | argInt | argString}, + {'X', sharpNumFlag, argRune | argInt | argString}, +} + +// okPrintfArg compares the formatState to the arguments actually present, +// reporting any discrepancies it can discern. If the final argument is ellipsissed, +// there's little it can do for that. +func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) { + var v printVerb + found := false + // Linear scan is fast enough for a small list. + for _, v = range printVerbs { + if v.verb == state.verb { + found = true + break + } + } + + // Does current arg implement fmt.Formatter? + formatter := false + if state.argNum < len(call.Args) { + if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok { + formatter = f.isFormatter(tv.Type) + } + } + + if !formatter { + if !found { + f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb) + return false + } + for _, flag := range state.flags { + if !strings.ContainsRune(v.flags, rune(flag)) { + f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag) + return false + } + } + } + // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all + // but the final arg must be an integer. + trueArgs := 1 + if state.verb == '%' { + trueArgs = 0 + } + nargs := len(state.argNums) + for i := 0; i < nargs-trueArgs; i++ { + argNum := state.argNums[i] + if !f.argCanBeChecked(call, i, state) { + return + } + arg := call.Args[argNum] + if !f.matchArgType(argInt, nil, arg) { + f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg)) + return false + } + } + if state.verb == '%' || formatter { + return true + } + argNum := state.argNums[len(state.argNums)-1] + if !f.argCanBeChecked(call, len(state.argNums)-1, state) { + return false + } + arg := call.Args[argNum] + if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' { + f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg)) + return false + } + if !f.matchArgType(v.typ, nil, arg) { + typeString := "" + if typ := f.pkg.types[arg].Type; typ != nil { + typeString = typ.String() + } + f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString) + return false + } + if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) { + f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg)) + return false + } + return true +} + +// recursiveStringer reports whether the provided argument is r or &r for the +// fmt.Stringer receiver identifier r. +func (f *File) recursiveStringer(e ast.Expr) bool { + if len(f.stringers) == 0 { + return false + } + var obj *ast.Object + switch e := e.(type) { + case *ast.Ident: + obj = e.Obj + case *ast.UnaryExpr: + if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { + obj = id.Obj + } + } + + // It's unlikely to be a recursive stringer if it has a Format method. + if typ := f.pkg.types[e].Type; typ != nil { + // Not a perfect match; see issue 6259. + if f.hasMethod(typ, "Format") { + return false + } + } + + // We compare the underlying Object, which checks that the identifier + // is the one we declared as the receiver for the String method in + // which this printf appears. + return f.stringers[obj] +} + +// isFunctionValue reports whether the expression is a function as opposed to a function call. +// It is almost always a mistake to print a function value. +func (f *File) isFunctionValue(e ast.Expr) bool { + if typ := f.pkg.types[e].Type; typ != nil { + _, ok := typ.(*types.Signature) + return ok + } + return false +} + +// argCanBeChecked reports whether the specified argument is statically present; +// it may be beyond the list of arguments or in a terminal slice... argument, which +// means we can't see it. +func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool { + argNum := state.argNums[formatArg] + if argNum <= 0 { + // Shouldn't happen, so catch it with prejudice. + panic("negative arg num") + } + if argNum < len(call.Args)-1 { + return true // Always OK. + } + if call.Ellipsis.IsValid() { + return false // We just can't tell; there could be many more arguments. + } + if argNum < len(call.Args) { + return true + } + // There are bad indexes in the format or there are fewer arguments than the format needs. + // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". + arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. + f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has only %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg")) + return false +} + +// printFormatRE is the regexp we match and report as a possible format string +// in the first argument to unformatted prints like fmt.Print. +// We exclude the space flag, so that printing a string like "x % y" is not reported as a format. +var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) + +const ( + flagsRE = `[+\-#]*` + indexOptRE = `(\[[0-9]+\])?` + numOptRE = `([0-9]+|` + indexOptRE + `\*)?` + verbRE = `[bcdefgopqstvxEFGUX]` +) + +// checkPrint checks a call to an unformatted print routine such as Println. +func (f *File) checkPrint(call *ast.CallExpr, name string) { + firstArg := 0 + typ := f.pkg.types[call.Fun].Type + if typ == nil { + // Skip checking functions with unknown type. + return + } + if sig, ok := typ.(*types.Signature); ok { + if !sig.Variadic() { + // Skip checking non-variadic functions. + return + } + params := sig.Params() + firstArg = params.Len() - 1 + + typ := params.At(firstArg).Type() + typ = typ.(*types.Slice).Elem() + it, ok := typ.(*types.Interface) + if !ok || !it.Empty() { + // Skip variadic functions accepting non-interface{} args. + return + } + } + args := call.Args + if len(args) <= firstArg { + // Skip calls without variadic args. + return + } + args = args[firstArg:] + + if firstArg == 0 { + if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { + if x, ok := sel.X.(*ast.Ident); ok { + if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { + f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0])) + } + } + } + } + + arg := args[0] + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + // Ignore trailing % character in lit.Value. + // The % in "abc 0.0%" couldn't be a formatting directive. + s := strings.TrimSuffix(lit.Value, `%"`) + if strings.Contains(s, "%") { + m := printFormatRE.FindStringSubmatch(s) + if m != nil { + f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0]) + } + } + } + if strings.HasSuffix(name, "ln") { + // The last item, if a string, should not have a newline. + arg = args[len(args)-1] + if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { + str, _ := strconv.Unquote(lit.Value) + if strings.HasSuffix(str, "\n") { + f.Badf(call.Pos(), "%s arg list ends with redundant newline", name) + } + } + } + for _, arg := range args { + if f.isFunctionValue(arg) { + f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg)) + } + if f.recursiveStringer(arg) { + f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg)) + } + } +} + +// count(n, what) returns "1 what" or "N whats" +// (assuming the plural of what is whats). +func count(n int, what string) string { + if n == 1 { + return "1 " + what + } + return fmt.Sprintf("%d %ss", n, what) +} diff --git a/libgo/go/cmd/vet/rangeloop.go b/libgo/go/cmd/vet/rangeloop.go new file mode 100644 index 00000000000..53a41364dfe --- /dev/null +++ b/libgo/go/cmd/vet/rangeloop.go @@ -0,0 +1,105 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +This file contains the code to check range loop variables bound inside function +literals that are deferred or launched in new goroutines. We only check +instances where the defer or go statement is the last statement in the loop +body, as otherwise we would need whole program analysis. + +For example: + + for i, v := range s { + go func() { + println(i, v) // not what you might expect + }() + } + +See: https://golang.org/doc/go_faq.html#closures_and_goroutines +*/ + +package main + +import "go/ast" + +func init() { + register("rangeloops", + "check that loop variables are used correctly", + checkLoop, + rangeStmt, forStmt) +} + +// checkLoop walks the body of the provided loop statement, checking whether +// its index or value variables are used unsafely inside goroutines or deferred +// function literals. +func checkLoop(f *File, node ast.Node) { + // Find the variables updated by the loop statement. + var vars []*ast.Ident + addVar := func(expr ast.Expr) { + if id, ok := expr.(*ast.Ident); ok { + vars = append(vars, id) + } + } + var body *ast.BlockStmt + switch n := node.(type) { + case *ast.RangeStmt: + body = n.Body + addVar(n.Key) + addVar(n.Value) + case *ast.ForStmt: + body = n.Body + switch post := n.Post.(type) { + case *ast.AssignStmt: + // e.g. for p = head; p != nil; p = p.next + for _, lhs := range post.Lhs { + addVar(lhs) + } + case *ast.IncDecStmt: + // e.g. for i := 0; i < n; i++ + addVar(post.X) + } + } + if vars == nil { + return + } + + // Inspect a go or defer statement + // if it's the last one in the loop body. + // (We give up if there are following statements, + // because it's hard to prove go isn't followed by wait, + // or defer by return.) + if len(body.List) == 0 { + return + } + var last *ast.CallExpr + switch s := body.List[len(body.List)-1].(type) { + case *ast.GoStmt: + last = s.Call + case *ast.DeferStmt: + last = s.Call + default: + return + } + lit, ok := last.Fun.(*ast.FuncLit) + if !ok { + return + } + ast.Inspect(lit.Body, func(n ast.Node) bool { + id, ok := n.(*ast.Ident) + if !ok || id.Obj == nil { + return true + } + if f.pkg.types[id].Type == nil { + // Not referring to a variable (e.g. struct field name) + return true + } + for _, v := range vars { + if v.Obj == id.Obj { + f.Badf(id.Pos(), "loop variable %s captured by func literal", + id.Name) + } + } + return true + }) +} diff --git a/libgo/go/cmd/vet/shadow.go b/libgo/go/cmd/vet/shadow.go new file mode 100644 index 00000000000..29c952fd885 --- /dev/null +++ b/libgo/go/cmd/vet/shadow.go @@ -0,0 +1,246 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +This file contains the code to check for shadowed variables. +A shadowed variable is a variable declared in an inner scope +with the same name and type as a variable in an outer scope, +and where the outer variable is mentioned after the inner one +is declared. + +(This definition can be refined; the module generates too many +false positives and is not yet enabled by default.) + +For example: + + func BadRead(f *os.File, buf []byte) error { + var err error + for { + n, err := f.Read(buf) // shadows the function variable 'err' + if err != nil { + break // causes return of wrong value + } + foo(buf) + } + return err + } + +*/ + +package main + +import ( + "flag" + "go/ast" + "go/token" + "go/types" +) + +var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy") + +func init() { + register("shadow", + "check for shadowed variables (experimental; must be set explicitly)", + checkShadow, + assignStmt, genDecl) + experimental["shadow"] = true +} + +func checkShadow(f *File, node ast.Node) { + switch n := node.(type) { + case *ast.AssignStmt: + checkShadowAssignment(f, n) + case *ast.GenDecl: + checkShadowDecl(f, n) + } +} + +// Span stores the minimum range of byte positions in the file in which a +// given variable (types.Object) is mentioned. It is lexically defined: it spans +// from the beginning of its first mention to the end of its last mention. +// A variable is considered shadowed (if *strictShadowing is off) only if the +// shadowing variable is declared within the span of the shadowed variable. +// In other words, if a variable is shadowed but not used after the shadowed +// variable is declared, it is inconsequential and not worth complaining about. +// This simple check dramatically reduces the nuisance rate for the shadowing +// check, at least until something cleverer comes along. +// +// One wrinkle: A "naked return" is a silent use of a variable that the Span +// will not capture, but the compilers catch naked returns of shadowed +// variables so we don't need to. +// +// Cases this gets wrong (TODO): +// - If a for loop's continuation statement mentions a variable redeclared in +// the block, we should complain about it but don't. +// - A variable declared inside a function literal can falsely be identified +// as shadowing a variable in the outer function. +// +type Span struct { + min token.Pos + max token.Pos +} + +// contains reports whether the position is inside the span. +func (s Span) contains(pos token.Pos) bool { + return s.min <= pos && pos < s.max +} + +// growSpan expands the span for the object to contain the instance represented +// by the identifier. +func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) { + if *strictShadowing { + return // No need + } + pos := ident.Pos() + end := ident.End() + span, ok := pkg.spans[obj] + if ok { + if span.min > pos { + span.min = pos + } + if span.max < end { + span.max = end + } + } else { + span = Span{pos, end} + } + pkg.spans[obj] = span +} + +// checkShadowAssignment checks for shadowing in a short variable declaration. +func checkShadowAssignment(f *File, a *ast.AssignStmt) { + if a.Tok != token.DEFINE { + return + } + if f.idiomaticShortRedecl(a) { + return + } + for _, expr := range a.Lhs { + ident, ok := expr.(*ast.Ident) + if !ok { + f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier") + return + } + checkShadowing(f, ident) + } +} + +// idiomaticShortRedecl reports whether this short declaration can be ignored for +// the purposes of shadowing, that is, that any redeclarations it contains are deliberate. +func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool { + // Don't complain about deliberate redeclarations of the form + // i := i + // Such constructs are idiomatic in range loops to create a new variable + // for each iteration. Another example is + // switch n := n.(type) + if len(a.Rhs) != len(a.Lhs) { + return false + } + // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.) + for i, expr := range a.Lhs { + lhs, ok := expr.(*ast.Ident) + if !ok { + f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier") + return true // Don't do any more processing. + } + switch rhs := a.Rhs[i].(type) { + case *ast.Ident: + if lhs.Name != rhs.Name { + return false + } + case *ast.TypeAssertExpr: + if id, ok := rhs.X.(*ast.Ident); ok { + if lhs.Name != id.Name { + return false + } + } + default: + return false + } + } + return true +} + +// idiomaticRedecl reports whether this declaration spec can be ignored for +// the purposes of shadowing, that is, that any redeclarations it contains are deliberate. +func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool { + // Don't complain about deliberate redeclarations of the form + // var i, j = i, j + if len(d.Names) != len(d.Values) { + return false + } + for i, lhs := range d.Names { + if rhs, ok := d.Values[i].(*ast.Ident); ok { + if lhs.Name != rhs.Name { + return false + } + } + } + return true +} + +// checkShadowDecl checks for shadowing in a general variable declaration. +func checkShadowDecl(f *File, d *ast.GenDecl) { + if d.Tok != token.VAR { + return + } + for _, spec := range d.Specs { + valueSpec, ok := spec.(*ast.ValueSpec) + if !ok { + f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec") + return + } + // Don't complain about deliberate redeclarations of the form + // var i = i + if f.idiomaticRedecl(valueSpec) { + return + } + for _, ident := range valueSpec.Names { + checkShadowing(f, ident) + } + } +} + +// checkShadowing checks whether the identifier shadows an identifier in an outer scope. +func checkShadowing(f *File, ident *ast.Ident) { + if ident.Name == "_" { + // Can't shadow the blank identifier. + return + } + obj := f.pkg.defs[ident] + if obj == nil { + return + } + // obj.Parent.Parent is the surrounding scope. If we can find another declaration + // starting from there, we have a shadowed identifier. + _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos()) + if shadowed == nil { + return + } + // Don't complain if it's shadowing a universe-declared identifier; that's fine. + if shadowed.Parent() == types.Universe { + return + } + if *strictShadowing { + // The shadowed identifier must appear before this one to be an instance of shadowing. + if shadowed.Pos() > ident.Pos() { + return + } + } else { + // Don't complain if the span of validity of the shadowed identifier doesn't include + // the shadowing identifier. + span, ok := f.pkg.spans[shadowed] + if !ok { + f.Badf(ident.Pos(), "internal error: no range for %q", ident.Name) + return + } + if !span.contains(ident.Pos()) { + return + } + } + // Don't complain if the types differ: that implies the programmer really wants two different things. + if types.Identical(obj.Type(), shadowed.Type()) { + f.Badf(ident.Pos(), "declaration of %q shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos())) + } +} diff --git a/libgo/go/cmd/vet/shift.go b/libgo/go/cmd/vet/shift.go new file mode 100644 index 00000000000..1e48d325242 --- /dev/null +++ b/libgo/go/cmd/vet/shift.go @@ -0,0 +1,98 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +This file contains the code to check for suspicious shifts. +*/ + +package main + +import ( + "go/ast" + "go/constant" + "go/token" + "go/types" +) + +func init() { + register("shift", + "check for useless shifts", + checkShift, + binaryExpr, assignStmt) +} + +func checkShift(f *File, node ast.Node) { + if f.dead[node] { + // Skip shift checks on unreachable nodes. + return + } + + switch node := node.(type) { + case *ast.BinaryExpr: + if node.Op == token.SHL || node.Op == token.SHR { + checkLongShift(f, node, node.X, node.Y) + } + case *ast.AssignStmt: + if len(node.Lhs) != 1 || len(node.Rhs) != 1 { + return + } + if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN { + checkLongShift(f, node, node.Lhs[0], node.Rhs[0]) + } + } +} + +// checkLongShift checks if shift or shift-assign operations shift by more than +// the length of the underlying variable. +func checkLongShift(f *File, node ast.Node, x, y ast.Expr) { + if f.pkg.types[x].Value != nil { + // Ignore shifts of constants. + // These are frequently used for bit-twiddling tricks + // like ^uint(0) >> 63 for 32/64 bit detection and compatibility. + return + } + + v := f.pkg.types[y].Value + if v == nil { + return + } + amt, ok := constant.Int64Val(v) + if !ok { + return + } + t := f.pkg.types[x].Type + if t == nil { + return + } + b, ok := t.Underlying().(*types.Basic) + if !ok { + return + } + var size int64 + switch b.Kind() { + case types.Uint8, types.Int8: + size = 8 + case types.Uint16, types.Int16: + size = 16 + case types.Uint32, types.Int32: + size = 32 + case types.Uint64, types.Int64: + size = 64 + case types.Int, types.Uint: + size = uintBitSize + case types.Uintptr: + size = uintptrBitSize + default: + return + } + if amt >= size { + ident := f.gofmt(x) + f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt) + } +} + +var ( + uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint]) + uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr]) +) diff --git a/libgo/go/cmd/vet/structtag.go b/libgo/go/cmd/vet/structtag.go new file mode 100644 index 00000000000..3bc30c47405 --- /dev/null +++ b/libgo/go/cmd/vet/structtag.go @@ -0,0 +1,226 @@ +// 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. + +// This file contains the test for canonical struct tags. + +package main + +import ( + "errors" + "go/ast" + "go/token" + "reflect" + "strconv" + "strings" +) + +func init() { + register("structtags", + "check that struct field tags have canonical format and apply to exported fields as needed", + checkStructFieldTags, + structType) +} + +// checkStructFieldTags checks all the field tags of a struct, including checking for duplicates. +func checkStructFieldTags(f *File, node ast.Node) { + var seen map[[2]string]token.Pos + for _, field := range node.(*ast.StructType).Fields.List { + checkCanonicalFieldTag(f, field, &seen) + } +} + +var checkTagDups = []string{"json", "xml"} +var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} + +// checkCanonicalFieldTag checks a single struct field tag. +func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token.Pos) { + if field.Tag == nil { + return + } + + tag, err := strconv.Unquote(field.Tag.Value) + if err != nil { + f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value) + return + } + + if err := validateStructTag(tag); err != nil { + raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string + f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err) + } + + for _, key := range checkTagDups { + val := reflect.StructTag(tag).Get(key) + if val == "" || val == "-" || val[0] == ',' { + continue + } + if key == "xml" && len(field.Names) > 0 && field.Names[0].Name == "XMLName" { + // XMLName defines the XML element name of the struct being + // checked. That name cannot collide with element or attribute + // names defined on other fields of the struct. Vet does not have a + // check for untagged fields of type struct defining their own name + // by containing a field named XMLName; see issue 18256. + continue + } + if i := strings.Index(val, ","); i >= 0 { + if key == "xml" { + // Use a separate namespace for XML attributes. + for _, opt := range strings.Split(val[i:], ",") { + if opt == "attr" { + key += " attribute" // Key is part of the error message. + break + } + } + } + val = val[:i] + } + if *seen == nil { + *seen = map[[2]string]token.Pos{} + } + if pos, ok := (*seen)[[2]string{key, val}]; ok { + var name string + if len(field.Names) > 0 { + name = field.Names[0].Name + } else { + name = field.Type.(*ast.Ident).Name + } + f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", name, key, val, f.loc(pos)) + } else { + (*seen)[[2]string{key, val}] = field.Pos() + } + } + + // Check for use of json or xml tags with unexported fields. + + // Embedded struct. Nothing to do for now, but that + // may change, depending on what happens with issue 7363. + if len(field.Names) == 0 { + return + } + + if field.Names[0].IsExported() { + return + } + + for _, enc := range [...]string{"json", "xml"} { + if reflect.StructTag(tag).Get(enc) != "" { + f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc) + return + } + } +} + +var ( + errTagSyntax = errors.New("bad syntax for struct tag pair") + errTagKeySyntax = errors.New("bad syntax for struct tag key") + errTagValueSyntax = errors.New("bad syntax for struct tag value") + errTagValueSpace = errors.New("suspicious space in struct tag value") + errTagSpace = errors.New("key:\"value\" pairs not separated by spaces") +) + +// validateStructTag parses the struct tag and returns an error if it is not +// in the canonical format, which is a space-separated list of key:"value" +// settings. The value may contain spaces. +func validateStructTag(tag string) error { + // This code is based on the StructTag.Get code in package reflect. + + n := 0 + for ; tag != ""; n++ { + if n > 0 && tag != "" && tag[0] != ' ' { + // More restrictive than reflect, but catches likely mistakes + // like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y". + return errTagSpace + } + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + if i == 0 { + return errTagKeySyntax + } + if i+1 >= len(tag) || tag[i] != ':' { + return errTagSyntax + } + if tag[i+1] != '"' { + return errTagValueSyntax + } + key := tag[:i] + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + return errTagValueSyntax + } + qvalue := tag[:i+1] + tag = tag[i+1:] + + value, err := strconv.Unquote(qvalue) + if err != nil { + return errTagValueSyntax + } + + if !checkTagSpaces[key] { + continue + } + + switch key { + case "xml": + // If the first or last character in the XML tag is a space, it is + // suspicious. + if strings.Trim(value, " ") != value { + return errTagValueSpace + } + + // If there are multiple spaces, they are suspicious. + if strings.Count(value, " ") > 1 { + return errTagValueSpace + } + + // If there is no comma, skip the rest of the checks. + comma := strings.IndexRune(value, ',') + if comma < 0 { + continue + } + + // If the character before a comma is a space, this is suspicious. + if comma > 0 && value[comma-1] == ' ' { + return errTagValueSpace + } + value = value[comma+1:] + case "json": + // JSON allows using spaces in the name, so skip it. + comma := strings.IndexRune(value, ',') + if comma < 0 { + continue + } + value = value[comma+1:] + } + + if strings.IndexByte(value, ' ') >= 0 { + return errTagValueSpace + } + } + return nil +} diff --git a/libgo/go/cmd/vet/testdata/asm/asm.go b/libgo/go/cmd/vet/testdata/asm/asm.go new file mode 100644 index 00000000000..e6d6d031061 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm.go @@ -0,0 +1,45 @@ +// 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. + +// +build ignore + +// This file contains declarations to test the assembly in test_asm.s. + +package testdata + +type S struct { + i int32 + b bool + s string +} + +func arg1(x int8, y uint8) +func arg2(x int16, y uint16) +func arg4(x int32, y uint32) +func arg8(x int64, y uint64) +func argint(x int, y uint) +func argptr(x *byte, y *byte, c chan int, m map[int]int, f func()) +func argstring(x, y string) +func argslice(x, y []string) +func argiface(x interface{}, y interface { + m() +}) +func argcomplex(x complex64, y complex128) +func argstruct(x S, y struct{}) +func argarray(x [2]S) +func returnint() int +func returnbyte(x int) byte +func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte) +func returnintmissing() int +func leaf(x, y int) int + +func noprof(x int) +func dupok(x int) +func nosplit(x int) +func rodata(x int) +func noptr(x int) +func wrapper(x int) + +func f15271() (x uint32) +func f17584(x float32, y complex64) diff --git a/libgo/go/cmd/vet/testdata/asm/asm1.s b/libgo/go/cmd/vet/testdata/asm/asm1.s new file mode 100644 index 00000000000..cac6ed22cd0 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm1.s @@ -0,0 +1,315 @@ +// 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 +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), AX + // MOVB x+0(FP), AX // commented out instructions used to panic + MOVB y+1(FP), BX + MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value" + MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value" + MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + TESTB x+0(FP), AX + TESTB y+1(FP), BX + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value" + TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value" + TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value" + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value" + TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value" + TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)" + MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)" + MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVW x+0(FP), AX + MOVW y+2(FP), BX + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value" + MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value" + MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value" + MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value" + TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value" + TESTW x+0(FP), AX + TESTW y+2(FP), BX + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value" + TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value" + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value" + TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value" + TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value" + MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value" + MOVL x+0(FP), AX + MOVL y+4(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value" + MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value" + MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value" + TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value" + TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value" + TESTL x+0(FP), AX + TESTL y+4(FP), AX + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value" + TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value" + TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value" + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value" + MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value" + MOVQ x+0(FP), AX + MOVQ y+8(FP), AX + MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value" + TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value" + TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value" + TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value" + TESTQ x+0(FP), AX + TESTQ y+8(FP), AX + TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value" + MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value" + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value" + MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value" + MOVQ x+0(FP), AX + MOVQ y+8(FP), AX + MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value" + TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value" + TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value" + TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value" + TESTQ x+0(FP), AX + TESTQ y+8(FP), AX + TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value" + MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value" + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value" + MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value" + MOVQ x+0(FP), AX + MOVQ y+8(FP), AX + MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value" + TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value" + TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value" + TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value" + TESTQ x+0(FP), AX + TESTQ y+8(FP), AX + TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value" + MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value" + MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value" + RET + +TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value" + MOVQ x+0(FP), AX + MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value" + MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value" + MOVQ x_base+0(FP), AX + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value" + MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value" + MOVQ x_len+8(FP), AX + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)" + MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)" + RET + +TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value" + MOVQ x+0(FP), AX + MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value" + MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value" + MOVQ x_base+0(FP), AX + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value" + MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value" + MOVQ x_len+8(FP), AX + MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVQ x_cap+16(FP), AX + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)" + MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)" + MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-32 + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value" + MOVQ x+0(FP), AX + MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value" + MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value" + MOVQ x_type+0(FP), AX + MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value" + MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value" + MOVQ x_data+8(FP), AX + MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value" + MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value" + MOVQ y+16(FP), AX + MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVQ y_itable+16(FP), AX + MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)" + MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value" + MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value" + MOVQ y_data+24(FP), AX + RET + +TEXT ·argcomplex(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24" + MOVSS x+0(FP), X0 // ERROR "invalid MOVSS of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)" + MOVSD x+0(FP), X0 // ERROR "invalid MOVSD of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)" + MOVSS x_real+0(FP), X0 + MOVSD x_real+0(FP), X0 // ERROR "invalid MOVSD of x_real\+0\(FP\); real\(complex64\) is 4-byte value" + MOVSS x_real+4(FP), X0 // ERROR "invalid offset x_real\+4\(FP\); expected x_real\+0\(FP\)" + MOVSS x_imag+4(FP), X0 + MOVSD x_imag+4(FP), X0 // ERROR "invalid MOVSD of x_imag\+4\(FP\); imag\(complex64\) is 4-byte value" + MOVSS x_imag+8(FP), X0 // ERROR "invalid offset x_imag\+8\(FP\); expected x_imag\+4\(FP\)" + MOVSD y+8(FP), X0 // ERROR "invalid MOVSD of y\+8\(FP\); complex128 is 16-byte value containing y_real\+8\(FP\) and y_imag\+16\(FP\)" + MOVSS y_real+8(FP), X0 // ERROR "invalid MOVSS of y_real\+8\(FP\); real\(complex128\) is 8-byte value" + MOVSD y_real+8(FP), X0 + MOVSS y_real+16(FP), X0 // ERROR "invalid offset y_real\+16\(FP\); expected y_real\+8\(FP\)" + MOVSS y_imag+16(FP), X0 // ERROR "invalid MOVSS of y_imag\+16\(FP\); imag\(complex128\) is 8-byte value" + MOVSD y_imag+16(FP), X0 + MOVSS y_imag+24(FP), X0 // ERROR "invalid offset y_imag\+24\(FP\); expected y_imag\+16\(FP\)" + RET + +TEXT ·argstruct(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-24" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); testdata.S is 24-byte value" + MOVQ x_i+0(FP), AX // ERROR "invalid MOVQ of x_i\+0\(FP\); int32 is 4-byte value" + MOVQ x_b+0(FP), AX // ERROR "invalid offset x_b\+0\(FP\); expected x_b\+4\(FP\)" + MOVQ x_s+8(FP), AX + MOVQ x_s_base+8(FP), AX + MOVQ x_s+16(FP), AX // ERROR "invalid offset x_s\+16\(FP\); expected x_s\+8\(FP\), x_s_base\+8\(FP\), or x_s_len\+16\(FP\)" + MOVQ x_s_len+16(FP), AX + RET + +TEXT ·argarray(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-48" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \[2\]testdata.S is 48-byte value" + MOVQ x_0_i+0(FP), AX // ERROR "invalid MOVQ of x_0_i\+0\(FP\); int32 is 4-byte value" + MOVQ x_0_b+0(FP), AX // ERROR "invalid offset x_0_b\+0\(FP\); expected x_0_b\+4\(FP\)" + MOVQ x_0_s+8(FP), AX + MOVQ x_0_s_base+8(FP), AX + MOVQ x_0_s+16(FP), AX // ERROR "invalid offset x_0_s\+16\(FP\); expected x_0_s\+8\(FP\), x_0_s_base\+8\(FP\), or x_0_s_len\+16\(FP\)" + MOVQ x_0_s_len+16(FP), AX + MOVB foo+25(FP), AX // ERROR "unknown variable foo; offset 25 is x_1_i\+24\(FP\)" + MOVQ x_1_s+32(FP), AX + MOVQ x_1_s_base+32(FP), AX + MOVQ x_1_s+40(FP), AX // ERROR "invalid offset x_1_s\+40\(FP\); expected x_1_s\+32\(FP\), x_1_s_base\+32\(FP\), or x_1_s_len\+40\(FP\)" + MOVQ x_1_s_len+40(FP), AX + RET + +TEXT ·returnint(SB),0,$0-8 + MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value" + MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value" + MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value" + MOVQ AX, ret+0(FP) + MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-9 + MOVQ x+0(FP), AX + MOVB AX, ret+8(FP) + MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value" + MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value" + MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value" + MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-41 + MOVB x+0(FP), AX + MOVQ AX, r1+8(FP) + MOVW AX, r2+16(FP) + MOVQ AX, r3+24(FP) + MOVQ AX, r3_base+24(FP) + MOVQ AX, r3_len+32(FP) + MOVB AX, r4+40(FP) + MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-8 + RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)" + + +// issue 15271 +TEXT ·f15271(SB), NOSPLIT, $0-4 + // Stick 123 into the low 32 bits of X0. + MOVQ $123, AX + PINSRD $0, AX, X0 + + // Return them. + PEXTRD $0, X0, x+0(FP) + RET + +// issue 17584 +TEXT ·f17584(SB), NOSPLIT, $12 + MOVSS x+0(FP), X0 + MOVSS y_real+4(FP), X0 + MOVSS y_imag+8(FP), X0 + RET diff --git a/libgo/go/cmd/vet/testdata/asm/asm2.s b/libgo/go/cmd/vet/testdata/asm/asm2.s new file mode 100644 index 00000000000..c33c02a70b2 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm2.s @@ -0,0 +1,257 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), AX + MOVB y+1(FP), BX + MOVW x+0(FP), AX // ERROR "\[386\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value" + MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value" + MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + TESTB x+0(FP), AX + TESTB y+1(FP), BX + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value" + TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value" + TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value" + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value" + TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value" + TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 4(SP), AX // ERROR "4\(SP\) should be x\+0\(FP\)" + MOVB 5(SP), AX // ERROR "5\(SP\) should be y\+1\(FP\)" + MOVB 6(SP), AX // ERROR "use of 6\(SP\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVW x+0(FP), AX + MOVW y+2(FP), BX + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value" + MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value" + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value" + MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value" + MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value" + TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value" + TESTW x+0(FP), AX + TESTW y+2(FP), BX + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value" + TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value" + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value" + TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value" + TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value" + MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value" + MOVL x+0(FP), AX + MOVL y+4(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value" + MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value" + MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value" + TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value" + TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value" + TESTL x+0(FP), AX + TESTL y+4(FP), AX + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value" + TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value" + TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value" + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value" + MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)" + MOVL x_lo+0(FP), AX + MOVL x_hi+4(FP), AX + MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)" + MOVL y_lo+8(FP), AX + MOVL y_hi+12(FP), AX + MOVQ x+0(FP), AX + MOVQ y+8(FP), AX + MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value" + TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value" + TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value" + TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)" + TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)" + TESTQ x+0(FP), AX + TESTQ y+8(FP), AX + TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value" + MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value" + MOVL x+0(FP), AX + MOVL y+4(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value" + MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value" + MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value" + TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value" + TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value" + TESTL x+0(FP), AX + TESTL y+4(FP), AX + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value" + TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value" + TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value" + MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value" + MOVL x+0(FP), AX + MOVL y+4(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value" + MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value" + MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value" + TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value" + TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value" + TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value" + TESTL x+0(FP), AX + TESTL y+4(FP), AX + TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value" + TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value" + TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + MOVW c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value" + MOVW m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value" + MOVW f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value" + RET + +TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value" + MOVL x+0(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value" + MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value" + MOVL x_base+0(FP), AX + MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value" + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value" + MOVL x_len+4(FP), AX + MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value" + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)" + MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)" + RET + +TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value" + MOVL x+0(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value" + MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value" + MOVL x_base+0(FP), AX + MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value" + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value" + MOVL x_len+4(FP), AX + MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value" + MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVW x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value" + MOVL x_cap+8(FP), AX + MOVQ x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value" + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)" + MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)" + MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-16 + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value" + MOVL x+0(FP), AX + MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value" + MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value" + MOVL x_type+0(FP), AX + MOVQ x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value" + MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVW x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value" + MOVL x_data+4(FP), AX + MOVQ x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value" + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value" + MOVL y+8(FP), AX + MOVQ y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value" + MOVW y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value" + MOVL y_itable+8(FP), AX + MOVQ y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value" + MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)" + MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVL y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVW y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value" + MOVL y_data+12(FP), AX + MOVQ y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value" + RET + +TEXT ·returnint(SB),0,$0-4 + MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value" + MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value" + MOVL AX, ret+0(FP) + MOVQ AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value" + MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-5 + MOVL x+0(FP), AX + MOVB AX, ret+4(FP) + MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" + MOVL AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value" + MOVQ AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value" + MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-21 + MOVB x+0(FP), AX + MOVL AX, r1+4(FP) + MOVW AX, r2+8(FP) + MOVL AX, r3+12(FP) + MOVL AX, r3_base+12(FP) + MOVL AX, r3_len+16(FP) + MOVB AX, r4+20(FP) + MOVQ AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-4 + RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)" diff --git a/libgo/go/cmd/vet/testdata/asm/asm3.s b/libgo/go/cmd/vet/testdata/asm/asm3.s new file mode 100644 index 00000000000..3d69356a0f9 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm3.s @@ -0,0 +1,178 @@ +// 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 arm +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), AX + MOVB y+1(FP), BX + MOVH x+0(FP), AX // ERROR "\[arm\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" + MOVH y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 8(R13), AX // ERROR "8\(R13\) should be x\+0\(FP\)" + MOVB 9(R13), AX // ERROR "9\(R13\) should be y\+1\(FP\)" + MOVB 10(R13), AX // ERROR "use of 10\(R13\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVH x+0(FP), AX + MOVH y+2(FP), BX + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value" + MOVW y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" + MOVH x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVH y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" + MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), AX + MOVW y+4(FP), AX + MOVW x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" + MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)" + MOVW x_lo+0(FP), AX + MOVW x_hi+4(FP), AX + MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)" + MOVW y_lo+8(FP), AX + MOVW y_hi+12(FP), AX + MOVQ x+0(FP), AX + MOVQ y+8(FP), AX + MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value" + MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value" + MOVW x+0(FP), AX + MOVW y+4(FP), AX + MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20" + MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value" + MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value" + MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value" + MOVW x+0(FP), AX + MOVW y+4(FP), AX + MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + MOVH c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value" + MOVH m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value" + MOVH f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value" + RET + +TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value" + MOVW x+0(FP), AX + MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value" + MOVW x_base+0(FP), AX + MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value" + MOVW x_len+4(FP), AX + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)" + MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)" + RET + +TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24" + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value" + MOVW x+0(FP), AX + MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value" + MOVW x_base+0(FP), AX + MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value" + MOVW x_len+4(FP), AX + MOVH x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVH x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value" + MOVW x_cap+8(FP), AX + MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)" + MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)" + MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-16 + MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value" + MOVW x+0(FP), AX + MOVH x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value" + MOVW x_type+0(FP), AX + MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVH x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVH x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value" + MOVW x_data+4(FP), AX + MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value" + MOVW y+8(FP), AX + MOVH y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value" + MOVW y_itable+8(FP), AX + MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)" + MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value" + MOVW y_data+12(FP), AX + RET + +TEXT ·returnint(SB),0,$0-4 + MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value" + MOVH AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value" + MOVW AX, ret+0(FP) + MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-5 + MOVW x+0(FP), AX + MOVB AX, ret+4(FP) + MOVH AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value" + MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" + MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-21 + MOVB x+0(FP), AX + MOVW AX, r1+4(FP) + MOVH AX, r2+8(FP) + MOVW AX, r3+12(FP) + MOVW AX, r3_base+12(FP) + MOVW AX, r3_len+16(FP) + MOVB AX, r4+20(FP) + MOVB AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-4 + RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)" + +TEXT ·leaf(SB),0,$-4-12 + MOVW x+0(FP), AX + MOVW y+4(FP), AX + MOVW AX, ret+8(FP) + RET diff --git a/libgo/go/cmd/vet/testdata/asm/asm4.s b/libgo/go/cmd/vet/testdata/asm/asm4.s new file mode 100644 index 00000000000..044b050b6b9 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm4.s @@ -0,0 +1,26 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64 +// +build vet_test + +// Test cases for symbolic NOSPLIT etc. on TEXT symbols. + +TEXT ·noprof(SB),NOPROF,$0-8 + RET + +TEXT ·dupok(SB),DUPOK,$0-8 + RET + +TEXT ·nosplit(SB),NOSPLIT,$0 + RET + +TEXT ·rodata(SB),RODATA,$0-8 + RET + +TEXT ·noptr(SB),NOPTR|NOSPLIT,$0 + RET + +TEXT ·wrapper(SB),WRAPPER,$0-8 + RET diff --git a/libgo/go/cmd/vet/testdata/asm/asm5.s b/libgo/go/cmd/vet/testdata/asm/asm5.s new file mode 100644 index 00000000000..c6176e9669f --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm5.s @@ -0,0 +1,193 @@ +// Copyright 2016 The Go 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 mips64 +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), R1 + MOVBU y+1(FP), R2 + MOVH x+0(FP), R1 // ERROR "\[mips64\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" + MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value" + MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int8 is 1-byte value" + MOVV y+1(FP), R1 // ERROR "invalid MOVV of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 16(R29), R1 // ERROR "16\(R29\) should be x\+0\(FP\)" + MOVB 17(R29), R1 // ERROR "17\(R29\) should be y\+1\(FP\)" + MOVB 18(R29), R1 // ERROR "use of 18\(R29\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVHU x+0(FP), R1 + MOVH y+2(FP), R2 + MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value" + MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" + MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int16 is 2-byte value" + MOVV y+2(FP), R1 // ERROR "invalid MOVV of y\+2\(FP\); uint16 is 2-byte value" + MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" + MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), R1 + MOVW y+4(FP), R1 + MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int32 is 4-byte value" + MOVV y+4(FP), R1 // ERROR "invalid MOVV of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value" + MOVV x+0(FP), R1 + MOVV y+8(FP), R1 + MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value" + MOVV x+0(FP), R1 + MOVV y+8(FP), R1 + MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value" + MOVV x+0(FP), R1 + MOVV y+8(FP), R1 + MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value" + MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value" + MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value" + RET + +TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value" + MOVV x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value" + MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value" + MOVV x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value" + MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value" + MOVV x_len+8(FP), R1 + MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)" + MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)" + RET + +TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value" + MOVV x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value" + MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value" + MOVV x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value" + MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value" + MOVV x_len+8(FP), R1 + MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVV x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVV x_cap+16(FP), R1 + MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)" + MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)" + MOVV y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-32 + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value" + MOVV x+0(FP), R1 + MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value" + MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value" + MOVV x_type+0(FP), R1 + MOVV x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVV x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVV x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value" + MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value" + MOVV x_data+8(FP), R1 + MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value" + MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value" + MOVV y+16(FP), R1 + MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVV y_itable+16(FP), R1 + MOVV y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)" + MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVV y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value" + MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value" + MOVV y_data+24(FP), R1 + RET + +TEXT ·returnint(SB),0,$0-8 + MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value" + MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value" + MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value" + MOVV R1, ret+0(FP) + MOVV R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVV R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-9 + MOVV x+0(FP), R1 + MOVB R1, ret+8(FP) + MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value" + MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value" + MOVV R1, ret+8(FP) // ERROR "invalid MOVV of ret\+8\(FP\); byte is 1-byte value" + MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-41 + MOVB x+0(FP), R1 + MOVV R1, r1+8(FP) + MOVH R1, r2+16(FP) + MOVV R1, r3+24(FP) + MOVV R1, r3_base+24(FP) + MOVV R1, r3_len+32(FP) + MOVB R1, r4+40(FP) + MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-8 + RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)" diff --git a/libgo/go/cmd/vet/testdata/asm/asm6.s b/libgo/go/cmd/vet/testdata/asm/asm6.s new file mode 100644 index 00000000000..4e85ab3dcf9 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm6.s @@ -0,0 +1,193 @@ +// Copyright 2016 The Go 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 s390x +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), R1 + MOVBZ y+1(FP), R2 + MOVH x+0(FP), R1 // ERROR "\[s390x\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" + MOVHZ y+1(FP), R1 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVWZ y+1(FP), R1 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value" + MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value" + MOVD y+1(FP), R1 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVBZ y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 16(R15), R1 // ERROR "16\(R15\) should be x\+0\(FP\)" + MOVB 17(R15), R1 // ERROR "17\(R15\) should be y\+1\(FP\)" + MOVB 18(R15), R1 // ERROR "use of 18\(R15\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVBZ x+0(FP), R1 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVHZ x+0(FP), R1 + MOVH y+2(FP), R2 + MOVWZ x+0(FP), R1 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value" + MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" + MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value" + MOVD y+2(FP), R1 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value" + MOVHZ x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" + MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), R1 + MOVW y+4(FP), R1 + MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value" + MOVD y+4(FP), R1 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value" + MOVD x+0(FP), R1 + MOVD y+8(FP), R1 + MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value" + MOVD x+0(FP), R1 + MOVD y+8(FP), R1 + MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value" + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value" + MOVD x+0(FP), R1 + MOVD y+8(FP), R1 + MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value" + MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value" + MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value" + RET + +TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value" + MOVD x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value" + MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value" + MOVD x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value" + MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value" + MOVD x_len+8(FP), R1 + MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)" + MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)" + RET + +TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value" + MOVD x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value" + MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value" + MOVD x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value" + MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value" + MOVD x_len+8(FP), R1 + MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVD x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVD x_cap+16(FP), R1 + MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)" + MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)" + MOVD y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-32 + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value" + MOVD x+0(FP), R1 + MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value" + MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value" + MOVD x_type+0(FP), R1 + MOVD x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVD x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVD x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value" + MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value" + MOVD x_data+8(FP), R1 + MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value" + MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value" + MOVD y+16(FP), R1 + MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVD y_itable+16(FP), R1 + MOVD y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)" + MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVD y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value" + MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value" + MOVD y_data+24(FP), R1 + RET + +TEXT ·returnint(SB),0,$0-8 + MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value" + MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value" + MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value" + MOVD R1, ret+0(FP) + MOVD R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVD R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-9 + MOVD x+0(FP), R1 + MOVB R1, ret+8(FP) + MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value" + MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value" + MOVD R1, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value" + MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-41 + MOVB x+0(FP), R1 + MOVD R1, r1+8(FP) + MOVH R1, r2+16(FP) + MOVD R1, r3+24(FP) + MOVD R1, r3_base+24(FP) + MOVD R1, r3_len+32(FP) + MOVB R1, r4+40(FP) + MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-8 + RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)" diff --git a/libgo/go/cmd/vet/testdata/asm/asm7.s b/libgo/go/cmd/vet/testdata/asm/asm7.s new file mode 100644 index 00000000000..d5ff5460a56 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm/asm7.s @@ -0,0 +1,193 @@ +// Copyright 2016 The Go 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 ppc64 ppc64le +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), R3 + MOVBZ y+1(FP), R4 + MOVH x+0(FP), R3 // ERROR "\[(ppc64|ppc64le)\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" + MOVHZ y+1(FP), R3 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVWZ y+1(FP), R3 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value" + MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value" + MOVD y+1(FP), R3 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), R3 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVBZ y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 16(R1), R3 // ERROR "16\(R1\) should be x\+0\(FP\)" + MOVB 17(R1), R3 // ERROR "17\(R1\) should be y\+1\(FP\)" + MOVB 18(R1), R3 // ERROR "use of 18\(R1\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVBZ x+0(FP), R3 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), R3 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVHZ x+0(FP), R3 + MOVH y+2(FP), R4 + MOVWZ x+0(FP), R3 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value" + MOVW y+2(FP), R3 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" + MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value" + MOVD y+2(FP), R3 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value" + MOVHZ x+2(FP), R3 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVH y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), R4 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" + MOVH y+4(FP), R3 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), R3 + MOVW y+4(FP), R3 + MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value" + MOVD y+4(FP), R3 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+4(FP), R3 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" + MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value" + MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value" + MOVD x+0(FP), R3 + MOVD y+8(FP), R3 + MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value" + MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value" + MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value" + MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value" + MOVD x+0(FP), R3 + MOVD y+8(FP), R3 + MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40" + MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value" + MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value" + MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value" + MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value" + MOVD x+0(FP), R3 + MOVD y+8(FP), R3 + MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)" + MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)" + MOVW c+16(FP), R3 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value" + MOVW m+24(FP), R3 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value" + MOVW f+32(FP), R3 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value" + RET + +TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value" + MOVD x+0(FP), R3 + MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value" + MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value" + MOVD x_base+0(FP), R3 + MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value" + MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value" + MOVD x_len+8(FP), R3 + MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)" + MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)" + RET + +TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48" + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value" + MOVD x+0(FP), R3 + MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value" + MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value" + MOVD x_base+0(FP), R3 + MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)" + MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value" + MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value" + MOVD x_len+8(FP), R3 + MOVH x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVW x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVD x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)" + MOVH x_cap+16(FP), R3 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVW x_cap+16(FP), R3 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value" + MOVD x_cap+16(FP), R3 + MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)" + MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)" + MOVD y_cap+16(FP), R3 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-32 + MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value" + MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value" + MOVD x+0(FP), R3 + MOVH x_type+0(FP), R3 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value" + MOVW x_type+0(FP), R3 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value" + MOVD x_type+0(FP), R3 + MOVD x_itable+0(FP), R3 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVD x_itable+1(FP), R3 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVH x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVW x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVD x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)" + MOVH x_data+8(FP), R3 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value" + MOVW x_data+8(FP), R3 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value" + MOVD x_data+8(FP), R3 + MOVH y+16(FP), R3 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value" + MOVW y+16(FP), R3 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value" + MOVD y+16(FP), R3 + MOVH y_itable+16(FP), R3 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVW y_itable+16(FP), R3 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value" + MOVD y_itable+16(FP), R3 + MOVD y_type+16(FP), R3 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)" + MOVH y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVW y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVD y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)" + MOVH y_data+24(FP), R3 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value" + MOVW y_data+24(FP), R3 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value" + MOVD y_data+24(FP), R3 + RET + +TEXT ·returnint(SB),0,$0-8 + MOVB R3, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value" + MOVH R3, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value" + MOVW R3, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value" + MOVD R3, ret+0(FP) + MOVD R3, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)" + MOVD R3, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-9 + MOVD x+0(FP), R3 + MOVB R3, ret+8(FP) + MOVH R3, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value" + MOVW R3, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value" + MOVD R3, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value" + MOVB R3, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-41 + MOVB x+0(FP), R3 + MOVD R3, r1+8(FP) + MOVH R3, r2+16(FP) + MOVD R3, r3+24(FP) + MOVD R3, r3_base+24(FP) + MOVD R3, r3_len+32(FP) + MOVB R3, r4+40(FP) + MOVW R3, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-8 + RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)" diff --git a/libgo/go/cmd/vet/testdata/asm8.s b/libgo/go/cmd/vet/testdata/asm8.s new file mode 100644 index 00000000000..550d92a8d2d --- /dev/null +++ b/libgo/go/cmd/vet/testdata/asm8.s @@ -0,0 +1,165 @@ +// Copyright 2016 The Go 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 mipsle +// +build vet_test + +TEXT ·arg1(SB),0,$0-2 + MOVB x+0(FP), R1 + MOVBU y+1(FP), R2 + MOVH x+0(FP), R1 // ERROR "\[mipsle\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value" + MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value" + MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value" + MOVW y+1(FP), R1 // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value" + MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)" + MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)" + MOVB 8(R29), R1 // ERROR "8\(R29\) should be x\+0\(FP\)" + MOVB 9(R29), R1 // ERROR "9\(R29\) should be y\+1\(FP\)" + MOVB 10(R29), R1 // ERROR "use of 10\(R29\) points beyond argument frame" + RET + +TEXT ·arg2(SB),0,$0-4 + MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value" + MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value" + MOVHU x+0(FP), R1 + MOVH y+2(FP), R2 + MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value" + MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value" + MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)" + MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)" + RET + +TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value" + MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value" + MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value" + MOVW x+0(FP), R1 + MOVW y+4(FP), R1 + MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value" + MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value" + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value" + MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)" + MOVW x_lo+0(FP), R1 + MOVW x_hi+4(FP), R1 + MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)" + MOVW y_lo+8(FP), R1 + MOVW y_hi+12(FP), R1 + RET + +TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value" + MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value" + MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value" + MOVW x+0(FP), R1 + MOVW y+4(FP), R1 + MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + RET + +TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20" + MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value" + MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value" + MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value" + MOVW x+0(FP), R1 + MOVW y+4(FP), R1 + MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)" + MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)" + MOVH c+8(FP), R1 // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value" + MOVH m+12(FP), R1 // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value" + MOVH f+16(FP), R1 // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value" + RET + +TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value" + MOVW x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value" + MOVW x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value" + MOVW x_len+4(FP), R1 + MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)" + MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)" + RET + +TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24" + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value" + MOVW x+0(FP), R1 + MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value" + MOVW x_base+0(FP), R1 + MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)" + MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value" + MOVW x_len+4(FP), R1 + MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)" + MOVH x_cap+8(FP), R1 // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value" + MOVW x_cap+8(FP), R1 + MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)" + MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)" + MOVW y_cap+8(FP), R1 // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)" + RET + +TEXT ·argiface(SB),0,$0-16 + MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value" + MOVW x+0(FP), R1 + MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value" + MOVW x_type+0(FP), R1 + MOVQ x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)" + MOVQ x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)" + MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVQ x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)" + MOVH x_data+4(FP), R1 // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value" + MOVW x_data+4(FP), R1 + MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value" + MOVW y+8(FP), R1 + MOVH y_itable+8(FP), R1 // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value" + MOVW y_itable+8(FP), R1 + MOVW y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)" + MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)" + MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value" + MOVW y_data+12(FP), AX + RET + +TEXT ·returnbyte(SB),0,$0-5 + MOVW x+0(FP), R1 + MOVB R1, ret+4(FP) + MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value" + MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" + MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" + RET + +TEXT ·returnbyte(SB),0,$0-5 + MOVW x+0(FP), R1 + MOVB R1, ret+4(FP) + MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value" + MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value" + MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)" + RET + +TEXT ·returnnamed(SB),0,$0-21 + MOVB x+0(FP), AX + MOVW R1, r1+4(FP) + MOVH R1, r2+8(FP) + MOVW R1, r3+12(FP) + MOVW R1, r3_base+12(FP) + MOVW R1, r3_len+16(FP) + MOVB R1, r4+20(FP) + MOVB R1, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value" + RET + +TEXT ·returnintmissing(SB),0,$0-4 + RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)" diff --git a/libgo/go/cmd/vet/testdata/assign.go b/libgo/go/cmd/vet/testdata/assign.go new file mode 100644 index 00000000000..6140ad4db8c --- /dev/null +++ b/libgo/go/cmd/vet/testdata/assign.go @@ -0,0 +1,31 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the useless-assignment checker. + +package testdata + +import "math/rand" + +type ST struct { + x int + l []int +} + +func (s *ST) SetX(x int, ch chan int) { + // Accidental self-assignment; it should be "s.x = x" + x = x // ERROR "self-assignment of x to x" + // Another mistake + s.x = s.x // ERROR "self-assignment of s.x to s.x" + + s.l[0] = s.l[0] // ERROR "self-assignment of s.l.0. to s.l.0." + + // Bail on any potential side effects to avoid false positives + s.l[num()] = s.l[num()] + rng := rand.New(rand.NewSource(0)) + s.l[rng.Intn(len(s.l))] = s.l[rng.Intn(len(s.l))] + s.l[<-ch] = s.l[<-ch] +} + +func num() int { return 2 } diff --git a/libgo/go/cmd/vet/testdata/atomic.go b/libgo/go/cmd/vet/testdata/atomic.go new file mode 100644 index 00000000000..d5a8e611844 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/atomic.go @@ -0,0 +1,52 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the atomic checker. + +package testdata + +import ( + "sync/atomic" +) + +type Counter uint64 + +func AtomicTests() { + x := uint64(1) + x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value" + _, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value" + x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" + + y := &x + *y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value" + + var su struct{ Counter uint64 } + su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value" + z1 := atomic.AddUint64(&su.Counter, 1) + _ = z1 // Avoid err "z declared and not used" + + var sp struct{ Counter *uint64 } + *sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value" + z2 := atomic.AddUint64(sp.Counter, 1) + _ = z2 // Avoid err "z declared and not used" + + au := []uint64{10, 20} + au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value" + au[1] = atomic.AddUint64(&au[0], 1) + + ap := []*uint64{&au[0], &au[1]} + *ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value" + *ap[1] = atomic.AddUint64(ap[0], 1) + + x = atomic.AddUint64() // Used to make vet crash; now silently ignored. + + { + // A variable declaration creates a new variable in the current scope. + x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16" + + // Re-declaration assigns a new value. + x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" + _ = w + } +} diff --git a/libgo/go/cmd/vet/testdata/bool.go b/libgo/go/cmd/vet/testdata/bool.go new file mode 100644 index 00000000000..af6cc011dd6 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/bool.go @@ -0,0 +1,113 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the bool checker. + +package testdata + +import "io" + +func RatherStupidConditions() { + var f, g func() int + if f() == 0 || f() == 0 { // OK f might have side effects + } + if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w" + } + _ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil" + + _ = i == byte(1) || i == byte(1) // TODO conversions are treated as if they may have side effects + + var c chan int + _ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values + for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j" + } + + var i, j, k int + _ = i+1 == 1 || i+1 == 1 // ERROR "redundant or: i\+1 == 1 || i\+1 == 1" + _ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1" + + _ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect + _ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" + + // Test partition edge cases + _ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || f() == 1 || f() == 1 || i == 1 + + _ = i == 1 || (i == 1 || i == 2) // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || (f() == 1 || i == 1) // OK f may alter i as a side effect + _ = i == 1 || (i == 1 || f() == 1) // ERROR "redundant or: i == 1 || i == 1" + _ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1" + + var a, b bool + _ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1" + + // Check that all redundant ors are flagged + _ = j == 0 || + i == 1 || + f() == 1 || + j == 0 || // ERROR "redundant or: j == 0 || j == 0" + i == 1 || // ERROR "redundant or: i == 1 || i == 1" + i == 1 || // ERROR "redundant or: i == 1 || i == 1" + i == 1 || + j == 0 || + k == 0 + + _ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3" + + // These test that redundant, suspect expressions do not trigger multiple errors. + _ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0" + _ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0" + + // and is dual to or; check the basics and + // let the or tests pull the rest of the weight. + _ = 0 != <-c && 0 != <-c // OK subsequent receives may yield different values + _ = f() != 0 && f() != 0 // OK f might have side effects + _ = f != nil && f != nil // ERROR "redundant and: f != nil && f != nil" + _ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1" + _ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect + _ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1" +} + +func RoyallySuspectConditions() { + var i, j int + + _ = i == 0 || i == 1 // OK + _ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1" + _ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i" + _ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i" + _ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1" + + _ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1" + + _ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9" + + _ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1" + + _ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4" + + _ = i != 0 || j != 0 + _ = 0 != i || 0 != j + + var s string + _ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other." + + _ = "et" != "alii" || "et" != "cetera" // ERROR "suspect or: .et. != .alii. || .et. != .cetera." + _ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code + + var err error + _ = err != nil || err != io.EOF // TODO catch this case? + + // Sanity check and. + _ = i != 0 && i != 1 // OK + _ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1" + _ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i" + _ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i" + _ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1" +} diff --git a/libgo/go/cmd/vet/testdata/buildtag/buildtag.go b/libgo/go/cmd/vet/testdata/buildtag/buildtag.go new file mode 100644 index 00000000000..f12f895dfb1 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/buildtag/buildtag.go @@ -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 contains tests for the buildtag checker. + +// +builder // ERROR "possible malformed \+build comment" +// +build !ignore + +package testdata + +// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" + +var _ = 3 diff --git a/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go b/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go new file mode 100644 index 00000000000..fbe10cf748f --- /dev/null +++ b/libgo/go/cmd/vet/testdata/buildtag/buildtag_bad.go @@ -0,0 +1,15 @@ +// This file contains misplaced or malformed build constraints. +// The Go tool will skip it, because the constraints are invalid. +// It serves only to test the tag checker during make test. + +// Mention +build // ERROR "possible malformed \+build comment" + +// +build !!bang // ERROR "invalid double negative in build constraint" +// +build @#$ // ERROR "invalid non-alphanumeric build constraint" + +// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" +package bad + +// This is package 'bad' rather than 'main' so the erroneous build +// tag doesn't end up looking like a package doc for the vet command +// when examined by godoc. diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo.go b/libgo/go/cmd/vet/testdata/cgo/cgo.go new file mode 100644 index 00000000000..d0df7cf6787 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/cgo/cgo.go @@ -0,0 +1,59 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the cgo checker. + +package testdata + +// void f(void *); +import "C" + +import "unsafe" + +func CgoTests() { + var c chan bool + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer" + + var m map[string]string + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer" + + var f func() + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer" + + var s []int + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer" + + var a [1][]int + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer" + + var st struct{ f []int } + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer" + C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer" + + // The following cases are OK. + var i int + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i))) + C.f(unsafe.Pointer(&i)) + + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0]))) + C.f(unsafe.Pointer(&s[0])) + + var a2 [1]int + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2))) + C.f(unsafe.Pointer(&a2)) + + var st2 struct{ i int } + C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2))) + C.f(unsafe.Pointer(&st2)) + + type cgoStruct struct{ p *cgoStruct } + C.f(unsafe.Pointer(&cgoStruct{})) + + C.CBytes([]byte("hello")) +} diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo2.go b/libgo/go/cmd/vet/testdata/cgo/cgo2.go new file mode 100644 index 00000000000..4f271168931 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/cgo/cgo2.go @@ -0,0 +1,12 @@ +// Copyright 2016 The Go 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 the cgo checker on a file that doesn't use cgo. + +package testdata + +var _ = C.f(*p(**p)) + +// Passing a pointer (via the slice), but C isn't cgo. +var _ = C.f([]int{3}) diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo3.go b/libgo/go/cmd/vet/testdata/cgo/cgo3.go new file mode 100644 index 00000000000..0b1518e1f93 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/cgo/cgo3.go @@ -0,0 +1,13 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Used by TestVetVerbose to test that vet -v doesn't fail because it +// can't find "C". + +package testdata + +import "C" + +func F() { +} diff --git a/libgo/go/cmd/vet/testdata/cgo/cgo4.go b/libgo/go/cmd/vet/testdata/cgo/cgo4.go new file mode 100644 index 00000000000..67b54506aba --- /dev/null +++ b/libgo/go/cmd/vet/testdata/cgo/cgo4.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go 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 the cgo checker on a file that doesn't use cgo, but has an +// import named "C". + +package testdata + +import C "fmt" + +var _ = C.Println(*p(**p)) + +// Passing a pointer (via a slice), but C is fmt, not cgo. +var _ = C.Println([]int{3}) diff --git a/libgo/go/cmd/vet/testdata/composite.go b/libgo/go/cmd/vet/testdata/composite.go new file mode 100644 index 00000000000..2e6ce262cc1 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/composite.go @@ -0,0 +1,103 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the test for untagged struct literals. + +package testdata + +import ( + "flag" + "go/scanner" + "image" + "unicode" + + "path/to/unknownpkg" +) + +var Okay1 = []string{ + "Name", + "Usage", + "DefValue", +} + +var Okay2 = map[string]bool{ + "Name": true, + "Usage": true, + "DefValue": true, +} + +var Okay3 = struct { + X string + Y string + Z string +}{ + "Name", + "Usage", + "DefValue", +} + +var Okay4 = []struct { + A int + B int +}{ + {1, 2}, + {3, 4}, +} + +type MyStruct struct { + X string + Y string + Z string +} + +var Okay5 = &MyStruct{ + "Name", + "Usage", + "DefValue", +} + +var Okay6 = []MyStruct{ + {"foo", "bar", "baz"}, + {"aa", "bb", "cc"}, +} + +// Testing is awkward because we need to reference things from a separate package +// to trigger the warnings. + +var goodStructLiteral = flag.Flag{ + Name: "Name", + Usage: "Usage", +} +var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields" + "Name", + "Usage", + nil, // Value + "DefValue", +} + +// SpecialCase is a named slice of CaseRange to test issue 9171. +var goodNamedSliceLiteral = unicode.SpecialCase{ + {Lo: 1, Hi: 2}, + unicode.CaseRange{Lo: 1, Hi: 2}, +} +var badNamedSliceLiteral = unicode.SpecialCase{ + {1, 2}, // ERROR "unkeyed fields" + unicode.CaseRange{1, 2}, // ERROR "unkeyed fields" +} + +// ErrorList is a named slice, so no warnings should be emitted. +var goodScannerErrorList = scanner.ErrorList{ + &scanner.Error{Msg: "foobar"}, +} +var badScannerErrorList = scanner.ErrorList{ + &scanner.Error{"foobar"}, // ERROR "unkeyed fields" +} + +// Check whitelisted structs: if vet is run with --compositewhitelist=false, +// this line triggers an error. +var whitelistedPoint = image.Point{1, 2} + +// Do not check type from unknown package. +// See issue 15408. +var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"} diff --git a/libgo/go/cmd/vet/testdata/copylock.go b/libgo/go/cmd/vet/testdata/copylock.go new file mode 100644 index 00000000000..e9902a27f10 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/copylock.go @@ -0,0 +1,188 @@ +package testdata + +import ( + "sync" + "sync/atomic" + "unsafe" + . "unsafe" + unsafe1 "unsafe" +) + +func OkFunc() { + var x *sync.Mutex + p := x + var y sync.Mutex + p = &y + + var z = sync.Mutex{} + w := sync.Mutex{} + + w = sync.Mutex{} + q := struct{ L sync.Mutex }{ + L: sync.Mutex{}, + } + + yy := []Tlock{ + Tlock{}, + Tlock{ + once: sync.Once{}, + }, + } + + nl := new(sync.Mutex) + mx := make([]sync.Mutex, 10) + xx := struct{ L *sync.Mutex }{ + L: new(sync.Mutex), + } +} + +type Tlock struct { + once sync.Once +} + +func BadFunc() { + var x *sync.Mutex + p := x + var y sync.Mutex + p = &y + *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex" + + var t Tlock + var tp *Tlock + tp = &t + *tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" + t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex" + + y := *x // ERROR "assignment copies lock value to y: sync.Mutex" + var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex" + + w := struct{ L sync.Mutex }{ + L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex" + } + var q = map[int]Tlock{ + 1: t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex" + 2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" + } + yy := []Tlock{ + t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex" + *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex" + } + + // override 'new' keyword + new := func(interface{}) {} + new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex" + + // copy of array of locks + var muA [5]sync.Mutex + muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex" + muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex" + muSlice := muA[:] // OK + + // multidimensional array + var mmuA [5][5]sync.Mutex + mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex" + mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex" + mmuSlice := mmuA[:] // OK + + // slice copy is ok + var fmuA [5][][5]sync.Mutex + fmuB := fmuA // OK + fmuA = fmuB // OK + fmuSlice := fmuA[:] // OK +} + +func LenAndCapOnLockArrays() { + var a [5]sync.Mutex + aLen := len(a) // OK + aCap := cap(a) // OK + + // override 'len' and 'cap' keywords + + len := func(interface{}) {} + len(a) // ERROR "call of len copies lock value: sync.Mutex" + + cap := func(interface{}) {} + cap(a) // ERROR "call of cap copies lock value: sync.Mutex" +} + +func SizeofMutex() { + var mu sync.Mutex + unsafe.Sizeof(mu) // OK + unsafe1.Sizeof(mu) // OK + Sizeof(mu) // OK + unsafe := struct{ Sizeof func(interface{}) }{} + unsafe.Sizeof(mu) // ERROR "call of unsafe.Sizeof copies lock value: sync.Mutex" + Sizeof := func(interface{}) {} + Sizeof(mu) // ERROR "call of Sizeof copies lock value: sync.Mutex" +} + +// SyncTypesCheck checks copying of sync.* types except sync.Mutex +func SyncTypesCheck() { + // sync.RWMutex copying + var rwmuX sync.RWMutex + var rwmuXX = sync.RWMutex{} + rwmuX1 := new(sync.RWMutex) + rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" + rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex" + var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex" + rwmuP := &rwmuX + rwmuZ := &sync.RWMutex{} + + // sync.Cond copying + var condX sync.Cond + var condXX = sync.Cond{} + condX1 := new(sync.Cond) + condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" + condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy" + var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy" + condP := &condX + condZ := &sync.Cond{ + L: &sync.Mutex{}, + } + condZ = sync.NewCond(&sync.Mutex{}) + + // sync.WaitGroup copying + var wgX sync.WaitGroup + var wgXX = sync.WaitGroup{} + wgX1 := new(sync.WaitGroup) + wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" + wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy" + var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy" + wgP := &wgX + wgZ := &sync.WaitGroup{} + + // sync.Pool copying + var poolX sync.Pool + var poolXX = sync.Pool{} + poolX1 := new(sync.Pool) + poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" + poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy" + var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy" + poolP := &poolX + poolZ := &sync.Pool{} + + // sync.Once copying + var onceX sync.Once + var onceXX = sync.Once{} + onceX1 := new(sync.Once) + onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" + onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex" + var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex" + onceP := &onceX + onceZ := &sync.Once{} +} + +// AtomicTypesCheck checks copying of sync/atomic types +func AtomicTypesCheck() { + // atomic.Value copying + var vX atomic.Value + var vXX = atomic.Value{} + vX1 := new(atomic.Value) + // These are OK because the value has not been used yet. + // (And vet can't tell whether it has been used, so they're always OK.) + vY := vX + vY = vX + var vYY = vX + vP := &vX + vZ := &atomic.Value{} +} diff --git a/libgo/go/cmd/vet/testdata/copylock_func.go b/libgo/go/cmd/vet/testdata/copylock_func.go new file mode 100644 index 00000000000..280747a3bf4 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/copylock_func.go @@ -0,0 +1,136 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the copylock checker's +// function declaration analysis. + +package testdata + +import "sync" + +func OkFunc(*sync.Mutex) {} +func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex" +func BadFunc2(sync.Map) {} // ERROR "BadFunc2 passes lock by value: sync.Map contains sync.Mutex" +func OkRet() *sync.Mutex {} +func BadRet() sync.Mutex {} // Don't warn about results + +var ( + OkClosure = func(*sync.Mutex) {} + BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex" + BadClosure2 = func(sync.Map) {} // ERROR "func passes lock by value: sync.Map contains sync.Mutex" +) + +type EmbeddedRWMutex struct { + sync.RWMutex +} + +func (*EmbeddedRWMutex) OkMeth() {} +func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex" +func OkFunc(e *EmbeddedRWMutex) {} +func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex" +func OkRet() *EmbeddedRWMutex {} +func BadRet() EmbeddedRWMutex {} // Don't warn about results + +type FieldMutex struct { + s sync.Mutex +} + +func (*FieldMutex) OkMeth() {} +func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex" +func OkFunc(*FieldMutex) {} +func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex" + +type L0 struct { + L1 +} + +type L1 struct { + l L2 +} + +type L2 struct { + sync.Mutex +} + +func (*L0) Ok() {} +func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2" + +type EmbeddedMutexPointer struct { + s *sync.Mutex // safe to copy this pointer +} + +func (*EmbeddedMutexPointer) Ok() {} +func (EmbeddedMutexPointer) AlsoOk() {} +func StillOk(EmbeddedMutexPointer) {} +func LookinGood() EmbeddedMutexPointer {} + +type EmbeddedLocker struct { + sync.Locker // safe to copy interface values +} + +func (*EmbeddedLocker) Ok() {} +func (EmbeddedLocker) AlsoOk() {} + +type CustomLock struct{} + +func (*CustomLock) Lock() {} +func (*CustomLock) Unlock() {} + +func Ok(*CustomLock) {} +func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock" + +// Passing lock values into interface function arguments +func FuncCallInterfaceArg(f func(a int, b interface{})) { + var m sync.Mutex + var t struct{ lock sync.Mutex } + + f(1, "foo") + f(2, &t) + f(3, &sync.Mutex{}) + f(4, m) // ERROR "call of f copies lock value: sync.Mutex" + f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex" + var fntab []func(t) + fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex" +} + +// Returning lock via interface value +func ReturnViaInterface(x int) (int, interface{}) { + var m sync.Mutex + var t struct{ lock sync.Mutex } + + switch x % 4 { + case 0: + return 0, "qwe" + case 1: + return 1, &sync.Mutex{} + case 2: + return 2, m // ERROR "return copies lock value: sync.Mutex" + default: + return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex" + } +} + +// Some cases that we don't warn about. + +func AcceptedCases() { + x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227) + x = BadRet() // function call on RHS is OK (#16227) + x = *OKRet() // indirection of function call on RHS is OK (#16227) +} + +// TODO: Unfortunate cases + +// Non-ideal error message: +// Since we're looking for Lock methods, sync.Once's underlying +// sync.Mutex gets called out, but without any reference to the sync.Once. +type LocalOnce sync.Once + +func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex" + +// False negative: +// LocalMutex doesn't have a Lock method. +// Nevertheless, it is probably a bad idea to pass it by value. +type LocalMutex sync.Mutex + +func (LocalMutex) Bad() {} // WANTED: An error here :( diff --git a/libgo/go/cmd/vet/testdata/copylock_range.go b/libgo/go/cmd/vet/testdata/copylock_range.go new file mode 100644 index 00000000000..f127381213c --- /dev/null +++ b/libgo/go/cmd/vet/testdata/copylock_range.go @@ -0,0 +1,67 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the copylock checker's +// range statement analysis. + +package testdata + +import "sync" + +func rangeMutex() { + var mu sync.Mutex + var i int + + var s []sync.Mutex + for range s { + } + for i = range s { + } + for i := range s { + } + for i, _ = range s { + } + for i, _ := range s { + } + for _, mu = range s { // ERROR "range var mu copies lock: sync.Mutex" + } + for _, m := range s { // ERROR "range var m copies lock: sync.Mutex" + } + for i, mu = range s { // ERROR "range var mu copies lock: sync.Mutex" + } + for i, m := range s { // ERROR "range var m copies lock: sync.Mutex" + } + + var a [3]sync.Mutex + for _, m := range a { // ERROR "range var m copies lock: sync.Mutex" + } + + var m map[sync.Mutex]sync.Mutex + for k := range m { // ERROR "range var k copies lock: sync.Mutex" + } + for mu, _ = range m { // ERROR "range var mu copies lock: sync.Mutex" + } + for k, _ := range m { // ERROR "range var k copies lock: sync.Mutex" + } + for _, mu = range m { // ERROR "range var mu copies lock: sync.Mutex" + } + for _, v := range m { // ERROR "range var v copies lock: sync.Mutex" + } + + var c chan sync.Mutex + for range c { + } + for mu = range c { // ERROR "range var mu copies lock: sync.Mutex" + } + for v := range c { // ERROR "range var v copies lock: sync.Mutex" + } + + // Test non-idents in range variables + var t struct { + i int + mu sync.Mutex + } + for t.i, t.mu = range s { // ERROR "range var t.mu copies lock: sync.Mutex" + } +} diff --git a/libgo/go/cmd/vet/testdata/deadcode.go b/libgo/go/cmd/vet/testdata/deadcode.go new file mode 100644 index 00000000000..5370bc32f65 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/deadcode.go @@ -0,0 +1,2125 @@ +// 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 contains tests for the dead code checker. + +package testdata + +type T int + +var x interface{} +var c chan int + +func external() int // ok + +func _() int { +} + +func _() int { + print(1) +} + +func _() int { + print(1) + return 2 + println() // ERROR "unreachable code" +} + +func _() int { +L: + print(1) + goto L + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + panic(2) + println() // ERROR "unreachable code" +} + +// but only builtin panic +func _() int { + var panic = func(int) {} + print(1) + panic(2) + println() // ok +} + +func _() int { + { + print(1) + return 2 + println() // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + { + print(1) + return 2 + } + println() // ERROR "unreachable code" +} + +func _() int { +L: + { + print(1) + goto L + println() // ERROR "unreachable code" + } + println() // ok +} + +func _() int { +L: + { + print(1) + goto L + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + { + panic(2) + } +} + +func _() int { + print(1) + { + panic(2) + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + { + panic(2) + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + return 2 + { // ERROR "unreachable code" + } +} + +func _() int { +L: + print(1) + goto L + { // ERROR "unreachable code" + } +} + +func _() int { + print(1) + panic(2) + { // ERROR "unreachable code" + } +} + +func _() int { + { + print(1) + return 2 + { // ERROR "unreachable code" + } + } +} + +func _() int { +L: + { + print(1) + goto L + { // ERROR "unreachable code" + } + } +} + +func _() int { + print(1) + { + panic(2) + { // ERROR "unreachable code" + } + } +} + +func _() int { + { + print(1) + return 2 + } + { // ERROR "unreachable code" + } +} + +func _() int { +L: + { + print(1) + goto L + } + { // ERROR "unreachable code" + } +} + +func _() int { + print(1) + { + panic(2) + } + { // ERROR "unreachable code" + } +} + +func _() int { + print(1) + if x == nil { + panic(2) + } else { + panic(3) + } + println() // ERROR "unreachable code" +} + +func _() int { +L: + print(1) + if x == nil { + panic(2) + } else { + goto L + } + println() // ERROR "unreachable code" +} + +func _() int { +L: + print(1) + if x == nil { + panic(2) + } else if x == 1 { + return 0 + } else if x != 2 { + panic(3) + } else { + goto L + } + println() // ERROR "unreachable code" +} + +// if-else chain missing final else is not okay, even if the +// conditions cover every possible case. + +func _() int { + print(1) + if x == nil { + panic(2) + } else if x != nil { + panic(3) + } + println() // ok +} + +func _() int { + print(1) + if x == nil { + panic(2) + } + println() // ok +} + +func _() int { +L: + print(1) + if x == nil { + panic(2) + } else if x == 1 { + return 0 + } else if x != 1 { + panic(3) + } + println() // ok +} + +func _() int { + print(1) + for { + } + println() // ERROR "unreachable code" +} + +func _() int { + for { + for { + break + } + } + println() // ERROR "unreachable code" +} + +func _() int { + for { + for { + break + println() // ERROR "unreachable code" + } + } +} + +func _() int { + for { + for { + continue + println() // ERROR "unreachable code" + } + } +} + +func _() int { + for { + L: + for { + break L + } + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + for { + break + } + println() // ok +} + +func _() int { + for { + for { + } + break // ERROR "unreachable code" + } + println() // ok +} + +func _() int { +L: + for { + for { + break L + } + } + println() // ok +} + +func _() int { + print(1) + for x == nil { + } + println() // ok +} + +func _() int { + for x == nil { + for { + break + } + } + println() // ok +} + +func _() int { + for x == nil { + L: + for { + break L + } + } + println() // ok +} + +func _() int { + print(1) + for true { + } + println() // ok +} + +func _() int { + for true { + for { + break + } + } + println() // ok +} + +func _() int { + for true { + L: + for { + break L + } + } + println() // ok +} + +func _() int { + print(1) + select {} + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + select { + case <-c: + print(2) + for { + } + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + select { + case <-c: + print(2) + for { + } + } + println() // ERROR "unreachable code" +} + +func _() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + case c <- 1: + print(2) + goto L + println() // ERROR "unreachable code" + } +} + +func _() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + goto L + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + default: + select {} + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + default: + select {} + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + select { + case <-c: + print(2) + } + println() // ok +} + +func _() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + goto L // ERROR "unreachable code" + case c <- 1: + print(2) + } + println() // ok +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + default: + print(2) + } + println() // ok +} + +func _() int { + print(1) + select { + default: + break + } + println() // ok +} + +func _() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + break // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + print(1) +L: + select { + case <-c: + print(2) + for { + break L + } + } + println() // ok +} + +func _() int { + print(1) +L: + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + break L + } + println() // ok +} + +func _() int { + print(1) + select { + case <-c: + print(1) + panic("abc") + default: + select {} + break // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + println() // ERROR "unreachable code" + default: + return 4 + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + default: + return 4 + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch x { + default: + return 4 + println() // ERROR "unreachable code" + case 1: + print(2) + panic(3) + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x { + default: + return 4 + case 1: + print(2) + panic(3) + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + default: + return 4 + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + default: + return 4 + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch { + } + println() // ok +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + case 2: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x { + case 2: + return 4 + case 1: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + case 2: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) +L: + switch x { + case 1: + print(2) + panic(3) + break L // ERROR "unreachable code" + default: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x { + default: + return 4 + break // ERROR "unreachable code" + case 1: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) +L: + switch x { + case 1: + print(2) + for { + break L + } + default: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + println() // ERROR "unreachable code" + default: + return 4 + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + default: + return 4 + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch x.(type) { + default: + return 4 + println() // ERROR "unreachable code" + case int: + print(2) + panic(3) + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x.(type) { + default: + return 4 + case int: + print(2) + panic(3) + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + default: + return 4 + println() // ERROR "unreachable code" + } +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + default: + return 4 + } + println() // ERROR "unreachable code" +} + +func _() int { + print(1) + switch { + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + case float64: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + case float64: + return 4 + case int: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + case float64: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) +L: + switch x.(type) { + case int: + print(2) + panic(3) + break L // ERROR "unreachable code" + default: + return 4 + } + println() // ok +} + +func _() int { + print(1) + switch x.(type) { + default: + return 4 + break // ERROR "unreachable code" + case int: + print(2) + panic(3) + } + println() // ok +} + +func _() int { + print(1) +L: + switch x.(type) { + case int: + print(2) + for { + break L + } + default: + return 4 + } + println() // ok +} + +// again, but without the leading print(1). +// testing that everything works when the terminating statement is first. + +func _() int { + println() // ok +} + +func _() int { + return 2 + println() // ERROR "unreachable code" +} + +func _() int { +L: + goto L + println() // ERROR "unreachable code" +} + +func _() int { + panic(2) + println() // ERROR "unreachable code" +} + +// but only builtin panic +func _() int { + var panic = func(int) {} + panic(2) + println() // ok +} + +func _() int { + { + return 2 + println() // ERROR "unreachable code" + } +} + +func _() int { + { + return 2 + } + println() // ERROR "unreachable code" +} + +func _() int { +L: + { + goto L + println() // ERROR "unreachable code" + } +} + +func _() int { +L: + { + goto L + } + println() // ERROR "unreachable code" +} + +func _() int { + { + panic(2) + println() // ERROR "unreachable code" + } +} + +func _() int { + { + panic(2) + } + println() // ERROR "unreachable code" +} + +func _() int { + return 2 + { // ERROR "unreachable code" + } + println() // ok +} + +func _() int { +L: + goto L + { // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + panic(2) + { // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + { + return 2 + { // ERROR "unreachable code" + } + } + println() // ok +} + +func _() int { +L: + { + goto L + { // ERROR "unreachable code" + } + } + println() // ok +} + +func _() int { + { + panic(2) + { // ERROR "unreachable code" + } + } + println() // ok +} + +func _() int { + { + return 2 + } + { // ERROR "unreachable code" + } + println() // ok +} + +func _() int { +L: + { + goto L + } + { // ERROR "unreachable code" + } + println() // ok +} + +func _() int { + { + panic(2) + } + { // ERROR "unreachable code" + } + println() // ok +} + +// again, with func literals + +var _ = func() int { +} + +var _ = func() int { + print(1) +} + +var _ = func() int { + print(1) + return 2 + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + print(1) + goto L + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + panic(2) + println() // ERROR "unreachable code" +} + +// but only builtin panic +var _ = func() int { + var panic = func(int) {} + print(1) + panic(2) + println() // ok +} + +var _ = func() int { + { + print(1) + return 2 + println() // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + { + print(1) + return 2 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + { + print(1) + goto L + println() // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { +L: + { + print(1) + goto L + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + { + panic(2) + } +} + +var _ = func() int { + print(1) + { + panic(2) + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + { + panic(2) + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + return 2 + { // ERROR "unreachable code" + } +} + +var _ = func() int { +L: + print(1) + goto L + { // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + panic(2) + { // ERROR "unreachable code" + } +} + +var _ = func() int { + { + print(1) + return 2 + { // ERROR "unreachable code" + } + } +} + +var _ = func() int { +L: + { + print(1) + goto L + { // ERROR "unreachable code" + } + } +} + +var _ = func() int { + print(1) + { + panic(2) + { // ERROR "unreachable code" + } + } +} + +var _ = func() int { + { + print(1) + return 2 + } + { // ERROR "unreachable code" + } +} + +var _ = func() int { +L: + { + print(1) + goto L + } + { // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + { + panic(2) + } + { // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } else { + panic(3) + } + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + print(1) + if x == nil { + panic(2) + } else { + goto L + } + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + print(1) + if x == nil { + panic(2) + } else if x == 1 { + return 0 + } else if x != 2 { + panic(3) + } else { + goto L + } + println() // ERROR "unreachable code" +} + +// if-else chain missing final else is not okay, even if the +// conditions cover every possible case. + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } else if x != nil { + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) + if x == nil { + panic(2) + } + println() // ok +} + +var _ = func() int { +L: + print(1) + if x == nil { + panic(2) + } else if x == 1 { + return 0 + } else if x != 1 { + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) + for { + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + for { + for { + break + } + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + for { + for { + break + println() // ERROR "unreachable code" + } + } +} + +var _ = func() int { + for { + for { + continue + println() // ERROR "unreachable code" + } + } +} + +var _ = func() int { + for { + L: + for { + break L + } + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + for { + break + } + println() // ok +} + +var _ = func() int { + for { + for { + } + break // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { +L: + for { + for { + break L + } + } + println() // ok +} + +var _ = func() int { + print(1) + for x == nil { + } + println() // ok +} + +var _ = func() int { + for x == nil { + for { + break + } + } + println() // ok +} + +var _ = func() int { + for x == nil { + L: + for { + break L + } + } + println() // ok +} + +var _ = func() int { + print(1) + for true { + } + println() // ok +} + +var _ = func() int { + for true { + for { + break + } + } + println() // ok +} + +var _ = func() int { + for true { + L: + for { + break L + } + } + println() // ok +} + +var _ = func() int { + print(1) + select {} + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + for { + } + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + for { + } + } + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + case c <- 1: + print(2) + goto L + println() // ERROR "unreachable code" + } +} + +var _ = func() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + goto L + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + println() // ERROR "unreachable code" + default: + select {} + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + default: + select {} + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + } + println() // ok +} + +var _ = func() int { +L: + print(1) + select { + case <-c: + print(2) + panic("abc") + goto L // ERROR "unreachable code" + case c <- 1: + print(2) + } + println() // ok +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + default: + print(2) + } + println() // ok +} + +var _ = func() int { + print(1) + select { + default: + break + } + println() // ok +} + +var _ = func() int { + print(1) + select { + case <-c: + print(2) + panic("abc") + break // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + print(1) +L: + select { + case <-c: + print(2) + for { + break L + } + } + println() // ok +} + +var _ = func() int { + print(1) +L: + select { + case <-c: + print(2) + panic("abc") + case c <- 1: + print(2) + break L + } + println() // ok +} + +var _ = func() int { + print(1) + select { + case <-c: + print(1) + panic("abc") + default: + select {} + break // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + println() // ERROR "unreachable code" + default: + return 4 + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + default: + return 4 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch x { + default: + return 4 + println() // ERROR "unreachable code" + case 1: + print(2) + panic(3) + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x { + default: + return 4 + case 1: + print(2) + panic(3) + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + default: + return 4 + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + default: + return 4 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch { + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + case 2: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + case 2: + return 4 + case 1: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + fallthrough + case 2: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + case 1: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) +L: + switch x { + case 1: + print(2) + panic(3) + break L // ERROR "unreachable code" + default: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x { + default: + return 4 + break // ERROR "unreachable code" + case 1: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) +L: + switch x { + case 1: + print(2) + for { + break L + } + default: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + println() // ERROR "unreachable code" + default: + return 4 + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + default: + return 4 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch x.(type) { + default: + return 4 + println() // ERROR "unreachable code" + case int: + print(2) + panic(3) + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x.(type) { + default: + return 4 + case int: + print(2) + panic(3) + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + default: + return 4 + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + default: + return 4 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + print(1) + switch { + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + case float64: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + case float64: + return 4 + case int: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + fallthrough + case float64: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + case int: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) +L: + switch x.(type) { + case int: + print(2) + panic(3) + break L // ERROR "unreachable code" + default: + return 4 + } + println() // ok +} + +var _ = func() int { + print(1) + switch x.(type) { + default: + return 4 + break // ERROR "unreachable code" + case int: + print(2) + panic(3) + } + println() // ok +} + +var _ = func() int { + print(1) +L: + switch x.(type) { + case int: + print(2) + for { + break L + } + default: + return 4 + } + println() // ok +} + +// again, but without the leading print(1). +// testing that everything works when the terminating statement is first. + +var _ = func() int { + println() // ok +} + +var _ = func() int { + return 2 + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + goto L + println() // ERROR "unreachable code" +} + +var _ = func() int { + panic(2) + println() // ERROR "unreachable code" +} + +// but only builtin panic +var _ = func() int { + var panic = func(int) {} + panic(2) + println() // ok +} + +var _ = func() int { + { + return 2 + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + { + return 2 + } + println() // ERROR "unreachable code" +} + +var _ = func() int { +L: + { + goto L + println() // ERROR "unreachable code" + } +} + +var _ = func() int { +L: + { + goto L + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + { + panic(2) + println() // ERROR "unreachable code" + } +} + +var _ = func() int { + { + panic(2) + } + println() // ERROR "unreachable code" +} + +var _ = func() int { + return 2 + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { +L: + goto L + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + panic(2) + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + { + return 2 + { // ERROR "unreachable code" + } + } + println() // ok +} + +var _ = func() int { +L: + { + goto L + { // ERROR "unreachable code" + } + } + println() // ok +} + +var _ = func() int { + { + panic(2) + { // ERROR "unreachable code" + } + } + println() // ok +} + +var _ = func() int { + { + return 2 + } + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { +L: + { + goto L + } + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() int { + { + panic(2) + } + { // ERROR "unreachable code" + } + println() // ok +} + +var _ = func() { + // goto without label used to panic + goto +} diff --git a/libgo/go/cmd/vet/testdata/divergent/buf.go b/libgo/go/cmd/vet/testdata/divergent/buf.go new file mode 100644 index 00000000000..0efe0f838d5 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/divergent/buf.go @@ -0,0 +1,17 @@ +// Test of examples with divergent packages. + +// Package buf ... +package buf + +// Buf is a ... +type Buf []byte + +// Append ... +func (*Buf) Append([]byte) {} + +func (Buf) Reset() {} + +func (Buf) Len() int { return 0 } + +// DefaultBuf is a ... +var DefaultBuf Buf diff --git a/libgo/go/cmd/vet/testdata/divergent/buf_test.go b/libgo/go/cmd/vet/testdata/divergent/buf_test.go new file mode 100644 index 00000000000..b75d55eaf4f --- /dev/null +++ b/libgo/go/cmd/vet/testdata/divergent/buf_test.go @@ -0,0 +1,35 @@ +// Test of examples with divergent packages. + +package buf_test + +func Example() {} // OK because is package-level. + +func Example_suffix() {} // OK because refers to suffix annotation. + +func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" + +func ExampleBuf() {} // OK because refers to known top-level type. + +func ExampleBuf_Append() {} // OK because refers to known method. + +func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear" + +func ExampleBuf_suffix() {} // OK because refers to suffix annotation. + +func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad" + +func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. + +func ExampleDefaultBuf() {} // OK because refers to top-level identifier. + +func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" + +func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" + +// "Puffer" is German for "Buffer". + +func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer" + +func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" + +func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" diff --git a/libgo/go/cmd/vet/testdata/httpresponse.go b/libgo/go/cmd/vet/testdata/httpresponse.go new file mode 100644 index 00000000000..7302a64a3b6 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/httpresponse.go @@ -0,0 +1,85 @@ +package testdata + +import ( + "log" + "net/http" +) + +func goodHTTPGet() { + res, err := http.Get("http://foo.com") + if err != nil { + log.Fatal(err) + } + defer res.Body.Close() +} + +func badHTTPGet() { + res, err := http.Get("http://foo.com") + defer res.Body.Close() // ERROR "using res before checking for errors" + if err != nil { + log.Fatal(err) + } +} + +func badHTTPHead() { + res, err := http.Head("http://foo.com") + defer res.Body.Close() // ERROR "using res before checking for errors" + if err != nil { + log.Fatal(err) + } +} + +func goodClientGet() { + client := http.DefaultClient + res, err := client.Get("http://foo.com") + if err != nil { + log.Fatal(err) + } + defer res.Body.Close() +} + +func badClientPtrGet() { + client := http.DefaultClient + resp, err := client.Get("http://foo.com") + defer resp.Body.Close() // ERROR "using resp before checking for errors" + if err != nil { + log.Fatal(err) + } +} + +func badClientGet() { + client := http.Client{} + resp, err := client.Get("http://foo.com") + defer resp.Body.Close() // ERROR "using resp before checking for errors" + if err != nil { + log.Fatal(err) + } +} + +func badClientPtrDo() { + client := http.DefaultClient + req, err := http.NewRequest("GET", "http://foo.com", nil) + if err != nil { + log.Fatal(err) + } + + resp, err := client.Do(req) + defer resp.Body.Close() // ERROR "using resp before checking for errors" + if err != nil { + log.Fatal(err) + } +} + +func badClientDo() { + var client http.Client + req, err := http.NewRequest("GET", "http://foo.com", nil) + if err != nil { + log.Fatal(err) + } + + resp, err := client.Do(req) + defer resp.Body.Close() // ERROR "using resp before checking for errors" + if err != nil { + log.Fatal(err) + } +} diff --git a/libgo/go/cmd/vet/testdata/incomplete/examples_test.go b/libgo/go/cmd/vet/testdata/incomplete/examples_test.go new file mode 100644 index 00000000000..445502b39ec --- /dev/null +++ b/libgo/go/cmd/vet/testdata/incomplete/examples_test.go @@ -0,0 +1,33 @@ +// Test of examples. + +package testdata + +func Example() {} // OK because is package-level. + +func Example_suffix() // OK because refers to suffix annotation. + +func Example_BadSuffix() // OK because non-test package was excluded. No false positives wanted. + +func ExampleBuf() // OK because non-test package was excluded. No false positives wanted. + +func ExampleBuf_Append() {} // OK because non-test package was excluded. No false positives wanted. + +func ExampleBuf_Clear() {} // OK because non-test package was excluded. No false positives wanted. + +func ExampleBuf_suffix() {} // OK because refers to suffix annotation. + +func ExampleBuf_Append_Bad() {} // OK because non-test package was excluded. No false positives wanted. + +func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. + +func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" + +func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" + +// "Puffer" is German for "Buffer". + +func ExamplePuffer() // OK because non-test package was excluded. No false positives wanted. + +func ExamplePuffer_Append() // OK because non-test package was excluded. No false positives wanted. + +func ExamplePuffer_suffix() // OK because non-test package was excluded. No false positives wanted. diff --git a/libgo/go/cmd/vet/testdata/lostcancel.go b/libgo/go/cmd/vet/testdata/lostcancel.go new file mode 100644 index 00000000000..b7549c00511 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/lostcancel.go @@ -0,0 +1,155 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testdata + +import ( + "context" + "log" + "os" + "testing" +) + +// Check the three functions and assignment forms (var, :=, =) we look for. +// (Do these early: line numbers are fragile.) +func _() { + var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)" +} // ERROR "this return statement may be reached without using the cancel var defined on line 17" + +func _() { + ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..." +} // ERROR "may be reached without using the cancel2 var defined on line 21" + +func _() { + var ctx context.Context + var cancel3 func() + ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..." +} // ERROR "this return statement may be reached without using the cancel3 var defined on line 27" + +func _() { + ctx, _ := context.WithCancel() // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak" + ctx, _ = context.WithTimeout() // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak" + ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak" +} + +func _() { + ctx, cancel := context.WithCancel() + defer cancel() // ok +} + +func _() { + ctx, cancel := context.WithCancel() // ERROR "not used on all paths" + if condition { + cancel() + } + return // ERROR "this return statement may be reached without using the cancel var" +} + +func _() { + ctx, cancel := context.WithCancel() + if condition { + cancel() + } else { + // ok: infinite loop + for { + print(0) + } + } +} + +func _() { + ctx, cancel := context.WithCancel() // ERROR "not used on all paths" + if condition { + cancel() + } else { + for i := 0; i < 10; i++ { + print(0) + } + } +} // ERROR "this return statement may be reached without using the cancel var" + +func _() { + ctx, cancel := context.WithCancel() + // ok: used on all paths + switch someInt { + case 0: + new(testing.T).FailNow() + case 1: + log.Fatal() + case 2: + cancel() + case 3: + print("hi") + fallthrough + default: + os.Exit(1) + } +} + +func _() { + ctx, cancel := context.WithCancel() // ERROR "not used on all paths" + switch someInt { + case 0: + new(testing.T).FailNow() + case 1: + log.Fatal() + case 2: + cancel() + case 3: + print("hi") // falls through to implicit return + default: + os.Exit(1) + } +} // ERROR "this return statement may be reached without using the cancel var" + +func _(ch chan int) int { + ctx, cancel := context.WithCancel() // ERROR "not used on all paths" + select { + case <-ch: + new(testing.T).FailNow() + case y <- ch: + print("hi") // falls through to implicit return + case ch <- 1: + cancel() + default: + os.Exit(1) + } +} // ERROR "this return statement may be reached without using the cancel var" + +func _(ch chan int) int { + ctx, cancel := context.WithCancel() + // A blocking select must execute one of its cases. + select { + case <-ch: + panic() + } +} + +func _() { + go func() { + ctx, cancel := context.WithCancel() // ERROR "not used on all paths" + print(ctx) + }() // ERROR "may be reached without using the cancel var" +} + +var condition bool +var someInt int + +// Regression test for Go issue 16143. +func _() { + var x struct{ f func() } + x.f() +} + +// Regression test for Go issue 16230. +func _() (ctx context.Context, cancel func()) { + ctx, cancel = context.WithCancel() + return // a naked return counts as a load of the named result values +} + +// Same as above, but for literal function. +var _ = func() (ctx context.Context, cancel func()) { + ctx, cancel = context.WithCancel() + return +} diff --git a/libgo/go/cmd/vet/testdata/method.go b/libgo/go/cmd/vet/testdata/method.go new file mode 100644 index 00000000000..52b500df272 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/method.go @@ -0,0 +1,22 @@ +// 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. + +// This file contains tests for the canonical method checker. + +// This file contains the code to check canonical methods. + +package testdata + +import ( + "fmt" +) + +type MethodTest int + +func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan" +} + +type MethodTestInterface interface { + ReadByte() byte // ERROR "should have signature ReadByte" +} diff --git a/libgo/go/cmd/vet/testdata/nilfunc.go b/libgo/go/cmd/vet/testdata/nilfunc.go new file mode 100644 index 00000000000..2ce7bc8ca82 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/nilfunc.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 testdata + +func F() {} + +type T struct { + F func() +} + +func (T) M() {} + +var Fv = F + +func Comparison() { + var t T + var fn func() + if fn == nil || Fv == nil || t.F == nil { + // no error; these func vars or fields may be nil + } + if F == nil { // ERROR "comparison of function F == nil is always false" + panic("can't happen") + } + if t.M == nil { // ERROR "comparison of function M == nil is always false" + panic("can't happen") + } + if F != nil { // ERROR "comparison of function F != nil is always true" + if t.M != nil { // ERROR "comparison of function M != nil is always true" + return + } + } + panic("can't happen") +} diff --git a/libgo/go/cmd/vet/testdata/print.go b/libgo/go/cmd/vet/testdata/print.go new file mode 100644 index 00000000000..55ab84fae76 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/print.go @@ -0,0 +1,535 @@ +// 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. + +// This file contains tests for the printf checker. + +// TODO(rsc): The user-defined wrapper tests are commented out +// because they produced too many false positives when vet was +// enabled during go test. See the TODO in ../print.go for a plan +// to fix that; when it's fixed, uncomment the user-defined wrapper tests. + +package testdata + +import ( + "fmt" + . "fmt" + "math" + "os" + "testing" + "unsafe" // just for test case printing unsafe.Pointer + // For testing printf-like functions from external package. + // "github.com/foobar/externalprintf" +) + +func UnsafePointerPrintfTest() { + var up unsafe.Pointer + fmt.Printf("%p, %x %X", up, up, up) +} + +// Error methods that do not satisfy the Error interface and should be checked. +type errorTest1 int + +func (errorTest1) Error(...interface{}) string { + return "hi" +} + +type errorTest2 int // Analogous to testing's *T type. +func (errorTest2) Error(...interface{}) { +} + +type errorTest3 int + +func (errorTest3) Error() { // No return value. +} + +type errorTest4 int + +func (errorTest4) Error() int { // Different return type. + return 3 +} + +type errorTest5 int + +func (errorTest5) error() { // niladic; don't complain if no args (was bug) +} + +// This function never executes, but it serves as a simple test for the program. +// Test with make test. +func PrintfTests() { + var b bool + var i int + var r rune + var s string + var x float64 + var p *int + var imap map[int]int + var fslice []float64 + var c complex64 + // Some good format/argtypes + fmt.Printf("") + fmt.Printf("%b %b %b", 3, i, x) + fmt.Printf("%c %c %c %c", 3, i, 'x', r) + fmt.Printf("%d %d %d", 3, i, imap) + fmt.Printf("%e %e %e %e", 3e9, x, fslice, c) + fmt.Printf("%E %E %E %E", 3e9, x, fslice, c) + fmt.Printf("%f %f %f %f", 3e9, x, fslice, c) + fmt.Printf("%F %F %F %F", 3e9, x, fslice, c) + fmt.Printf("%g %g %g %g", 3e9, x, fslice, c) + fmt.Printf("%G %G %G %G", 3e9, x, fslice, c) + fmt.Printf("%b %b %b %b", 3e9, x, fslice, c) + fmt.Printf("%o %o", 3, i) + fmt.Printf("%p %p", p, nil) + fmt.Printf("%q %q %q %q", 3, i, 'x', r) + fmt.Printf("%s %s %s", "hi", s, []byte{65}) + fmt.Printf("%t %t", true, b) + fmt.Printf("%T %T", 3, i) + fmt.Printf("%U %U", 3, i) + fmt.Printf("%v %v", 3, i) + fmt.Printf("%x %x %x %x", 3, i, "hi", s) + fmt.Printf("%X %X %X %X", 3, i, "hi", s) + fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3) + fmt.Printf("%s", &stringerv) + fmt.Printf("%v", &stringerv) + fmt.Printf("%T", &stringerv) + fmt.Printf("%s", &embeddedStringerv) + fmt.Printf("%v", &embeddedStringerv) + fmt.Printf("%T", &embeddedStringerv) + fmt.Printf("%v", notstringerv) + fmt.Printf("%T", notstringerv) + fmt.Printf("%q", stringerarrayv) + fmt.Printf("%v", stringerarrayv) + fmt.Printf("%s", stringerarrayv) + fmt.Printf("%v", notstringerarrayv) + fmt.Printf("%T", notstringerarrayv) + fmt.Printf("%d", new(Formatter)) + fmt.Printf("%*%", 2) // Ridiculous but allowed. + fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say. + + fmt.Printf("%g", 1+2i) + fmt.Printf("%#e %#E %#f %#F %#g %#G", 1.2, 1.2, 1.2, 1.2, 1.2, 1.2) // OK since Go 1.9 + // Some bad format/argTypes + fmt.Printf("%b", "hi") // ERROR "Printf format %b has arg \x22hi\x22 of wrong type string" + fmt.Printf("%t", c) // ERROR "Printf format %t has arg c of wrong type complex64" + fmt.Printf("%t", 1+2i) // ERROR "Printf format %t has arg 1 \+ 2i of wrong type complex128" + fmt.Printf("%c", 2.3) // ERROR "Printf format %c has arg 2.3 of wrong type float64" + fmt.Printf("%d", 2.3) // ERROR "Printf format %d has arg 2.3 of wrong type float64" + fmt.Printf("%e", "hi") // ERROR "Printf format %e has arg \x22hi\x22 of wrong type string" + fmt.Printf("%E", true) // ERROR "Printf format %E has arg true of wrong type bool" + fmt.Printf("%f", "hi") // ERROR "Printf format %f has arg \x22hi\x22 of wrong type string" + fmt.Printf("%F", 'x') // ERROR "Printf format %F has arg 'x' of wrong type rune" + fmt.Printf("%g", "hi") // ERROR "Printf format %g has arg \x22hi\x22 of wrong type string" + fmt.Printf("%g", imap) // ERROR "Printf format %g has arg imap of wrong type map\[int\]int" + fmt.Printf("%G", i) // ERROR "Printf format %G has arg i of wrong type int" + fmt.Printf("%o", x) // ERROR "Printf format %o has arg x of wrong type float64" + fmt.Printf("%p", 23) // ERROR "Printf format %p has arg 23 of wrong type int" + fmt.Printf("%q", x) // ERROR "Printf format %q has arg x of wrong type float64" + fmt.Printf("%s", b) // ERROR "Printf format %s has arg b of wrong type bool" + fmt.Printf("%s", byte(65)) // ERROR "Printf format %s has arg byte\(65\) of wrong type byte" + fmt.Printf("%t", 23) // ERROR "Printf format %t has arg 23 of wrong type int" + fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64" + fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil" + fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64" + fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.stringer" + fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.stringer" + fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer" + fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer" + fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer" + fmt.Printf("%t", notstringerv) // ERROR "Printf format %t has arg notstringerv of wrong type testdata.notstringer" + fmt.Printf("%t", stringerarrayv) // ERROR "Printf format %t has arg stringerarrayv of wrong type testdata.stringerarray" + fmt.Printf("%t", notstringerarrayv) // ERROR "Printf format %t has arg notstringerarrayv of wrong type testdata.notstringerarray" + fmt.Printf("%q", notstringerarrayv) // ERROR "Printf format %q has arg notstringerarrayv of wrong type testdata.notstringerarray" + fmt.Printf("%d", BoolFormatter(true)) // ERROR "Printf format %d has arg BoolFormatter\(true\) of wrong type testdata.BoolFormatter" + fmt.Printf("%z", FormatterVal(true)) // correct (the type is responsible for formatting) + fmt.Printf("%d", FormatterVal(true)) // correct (the type is responsible for formatting) + fmt.Printf("%s", nonemptyinterface) // correct (the type is responsible for formatting) + fmt.Printf("%.*s %d %6g", 3, "hi", 23, 'x') // ERROR "Printf format %6g has arg 'x' of wrong type rune" + fmt.Println() // not an error + fmt.Println("%s", "hi") // ERROR "Println call has possible formatting directive %s" + fmt.Println("%v", "hi") // ERROR "Println call has possible formatting directive %v" + fmt.Println("0.0%") // correct (trailing % couldn't be a formatting directive) + fmt.Printf("%s", "hi", 3) // ERROR "Printf call needs 1 arg but has 2 args" + _ = fmt.Sprintf("%"+("s"), "hi", 3) // ERROR "Sprintf call needs 1 arg but has 2 args" + fmt.Printf("%s%%%d", "hi", 3) // correct + fmt.Printf("%08s", "woo") // correct + fmt.Printf("% 8s", "woo") // correct + fmt.Printf("%.*d", 3, 3) // correct + fmt.Printf("%.*d x", 3, 3, 3, 3) // ERROR "Printf call needs 2 args but has 4 args" + fmt.Printf("%.*d x", "hi", 3) // ERROR "Printf format %.*d uses non-int \x22hi\x22 as argument of \*" + fmt.Printf("%.*d x", i, 3) // correct + fmt.Printf("%.*d x", s, 3) // ERROR "Printf format %.\*d uses non-int s as argument of \*" + fmt.Printf("%*% x", 0.22) // ERROR "Printf format %\*% uses non-int 0.22 as argument of \*" + fmt.Printf("%q %q", multi()...) // ok + fmt.Printf("%#q", `blah`) // ok + // printf("now is the time", "buddy") // no error "printf call has arguments but no formatting directives" + Printf("now is the time", "buddy") // ERROR "Printf call has arguments but no formatting directives" + Printf("hi") // ok + const format = "%s %s\n" + Printf(format, "hi", "there") + Printf(format, "hi") // ERROR "Printf format %s reads arg #2, but call has only 1 arg$" + Printf("%s %d %.3v %q", "str", 4) // ERROR "Printf format %.3v reads arg #3, but call has only 2 args" + f := new(stringer) + f.Warn(0, "%s", "hello", 3) // ERROR "Warn call has possible formatting directive %s" + f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args" + f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r" + f.Warnf(0, "%#s", "hello") // ERROR "Warnf format %#s has unrecognized flag #" + fmt.Printf("%#s", FormatterVal(true)) // correct (the type is responsible for formatting) + Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string" + Printf("%d", percentDV) + Printf("%d", &percentDV) + Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type testdata.notPercentDStruct" + Printf("%d", ¬PercentDV) // ERROR "Printf format %d has arg ¬PercentDV of wrong type \*testdata.notPercentDStruct" + Printf("%p", ¬PercentDV) // Works regardless: we print it as a pointer. + Printf("%s", percentSV) + Printf("%s", &percentSV) + // Good argument reorderings. + Printf("%[1]d", 3) + Printf("%[1]*d", 3, 1) + Printf("%[2]*[1]d", 1, 3) + Printf("%[2]*.[1]*[3]d", 2, 3, 4) + fmt.Fprintf(os.Stderr, "%[2]*.[1]*[3]d", 2, 3, 4) // Use Fprintf to make sure we count arguments correctly. + // Bad argument reorderings. + Printf("%[xd", 3) // ERROR "Printf format %\[xd is missing closing \]" + Printf("%[x]d x", 3) // ERROR "Printf format has invalid argument index \[x\]" + Printf("%[3]*s x", "hi", 2) // ERROR "Printf format has invalid argument index \[3\]" + _ = fmt.Sprintf("%[3]d x", 2) // ERROR "Sprintf format has invalid argument index \[3\]" + Printf("%[2]*.[1]*[3]d x", 2, "hi", 4) // ERROR "Printf format %\[2]\*\.\[1\]\*\[3\]d uses non-int \x22hi\x22 as argument of \*" + Printf("%[0]s x", "arg1") // ERROR "Printf format has invalid argument index \[0\]" + Printf("%[0]d x", 1) // ERROR "Printf format has invalid argument index \[0\]" + // Something that satisfies the error interface. + var e error + fmt.Println(e.Error()) // ok + // Something that looks like an error interface but isn't, such as the (*T).Error method + // in the testing package. + var et1 *testing.T + et1.Error() // ok + et1.Error("hi") // ok + et1.Error("%d", 3) // ERROR "Error call has possible formatting directive %d" + var et3 errorTest3 + et3.Error() // ok, not an error method. + var et4 errorTest4 + et4.Error() // ok, not an error method. + var et5 errorTest5 + et5.error() // ok, not an error method. + // Interfaces can be used with any verb. + var iface interface { + ToTheMadness() bool // Method ToTheMadness usually returns false + } + fmt.Printf("%f", iface) // ok: fmt treats interfaces as transparent and iface may well have a float concrete type + // Can't print a function. + Printf("%d", someFunction) // ERROR "Printf format %d arg someFunction is a func value, not called" + Printf("%v", someFunction) // ERROR "Printf format %v arg someFunction is a func value, not called" + Println(someFunction) // ERROR "Println arg someFunction is a func value, not called" + Printf("%p", someFunction) // ok: maybe someone wants to see the pointer + Printf("%T", someFunction) // ok: maybe someone wants to see the type + // Bug: used to recur forever. + Printf("%p %x", recursiveStructV, recursiveStructV.next) + Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) + Printf("%p %x", recursiveSliceV, recursiveSliceV) + Printf("%p %x", recursiveMapV, recursiveMapV) + // Special handling for Log. + math.Log(3) // OK + var t *testing.T + t.Log("%d", 3) // ERROR "Log call has possible formatting directive %d" + t.Logf("%d", 3) + t.Logf("%d", "hi") // ERROR "Logf format %d has arg \x22hi\x22 of wrong type string" + + // Errorf(1, "%d", 3) // OK + // Errorf(1, "%d", "hi") // no error "Errorf format %d has arg \x22hi\x22 of wrong type string" + + // Multiple string arguments before variadic args + // errorf("WARNING", "foobar") // OK + // errorf("INFO", "s=%s, n=%d", "foo", 1) // OK + // errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has only 0 args" + + // Printf from external package + // externalprintf.Printf("%d", 42) // OK + // externalprintf.Printf("foobar") // OK + // level := 123 + // externalprintf.Logf(level, "%d", 42) // OK + // externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK + // externalprintf.Logf(level, "%d") // no error "Logf format %d reads arg #1, but call has only 0 args" + // var formatStr = "%s %s" + // externalprintf.Sprintf(formatStr, "a", "b") // OK + // externalprintf.Logf(level, formatStr, "a", "b") // OK + + // user-defined Println-like functions + ss := &someStruct{} + ss.Log(someFunction, "foo") // OK + ss.Error(someFunction, someFunction) // OK + ss.Println() // OK + ss.Println(1.234, "foo") // OK + ss.Println(1, someFunction) // no error "Println arg someFunction is a func value, not called" + ss.log(someFunction) // OK + ss.log(someFunction, "bar", 1.33) // OK + ss.log(someFunction, someFunction) // no error "log arg someFunction is a func value, not called" + + // indexed arguments + Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4) // OK + Printf("%d %[0]d %d %[2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[0\]" + Printf("%d %[3]d %d %[-2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[-2\]" + Printf("%d %[3]d %d %[2234234234234]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[2234234234234\]" + Printf("%d %[3]d %-10d %[2]d x", 1, 2, 3) // ERROR "Printf format %-10d reads arg #4, but call has only 3 args" + Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5) // ERROR "Printf call needs 4 args but has 5 args" + Printf("%[1][3]d x", 1, 2) // ERROR "Printf format %\[1\]\[ has unknown verb \[" + + // wrote Println but meant Fprintln + Printf("%p\n", os.Stdout) // OK + Println(os.Stdout, "hello") // ERROR "Println does not take io.Writer but has first arg os.Stdout" + + Printf(someString(), "hello") // OK + +} + +func someString() string { return "X" } + +type someStruct struct{} + +// Log is non-variadic user-define Println-like function. +// Calls to this func must be skipped when checking +// for Println-like arguments. +func (ss *someStruct) Log(f func(), s string) {} + +// Error is variadic user-define Println-like function. +// Calls to this func mustn't be checked for Println-like arguments, +// since variadic arguments type isn't interface{}. +func (ss *someStruct) Error(args ...func()) {} + +// Println is variadic user-defined Println-like function. +// Calls to this func must be checked for Println-like arguments. +func (ss *someStruct) Println(args ...interface{}) {} + +// log is variadic user-defined Println-like function. +// Calls to this func must be checked for Println-like arguments. +func (ss *someStruct) log(f func(), args ...interface{}) {} + +// A function we use as a function value; it has no other purpose. +func someFunction() {} + +/* +// Printf is used by the test so we must declare it. +func Printf(format string, args ...interface{}) { + panic("don't call - testing only") +} + +// Println is used by the test so we must declare it. +func Println(args ...interface{}) { + panic("don't call - testing only") +} + +// Logf is used by the test so we must declare it. +func Logf(format string, args ...interface{}) { + panic("don't call - testing only") +} + +// Log is used by the test so we must declare it. +func Log(args ...interface{}) { + panic("don't call - testing only") +} +*/ + +// printf is used by the test so we must declare it. +func printf(format string, args ...interface{}) { + panic("don't call - testing only") +} + +/* +// Errorf is used by the test for a case in which the first parameter +// is not a format string. +func Errorf(i int, format string, args ...interface{}) { + panic("don't call - testing only") +} + +// errorf is used by the test for a case in which the function accepts multiple +// string parameters before variadic arguments +func errorf(level, format string, args ...interface{}) { + panic("don't call - testing only") +} +*/ + +// multi is used by the test. +func multi() []interface{} { + panic("don't call - testing only") +} + +type stringer float64 + +var stringerv stringer + +func (*stringer) String() string { + return "string" +} + +func (*stringer) Warn(int, ...interface{}) string { + return "warn" +} + +func (*stringer) Warnf(int, string, ...interface{}) string { + return "warnf" +} + +type embeddedStringer struct { + foo string + stringer + bar int +} + +var embeddedStringerv embeddedStringer + +type notstringer struct { + f float64 +} + +var notstringerv notstringer + +type stringerarray [4]float64 + +func (stringerarray) String() string { + return "string" +} + +var stringerarrayv stringerarray + +type notstringerarray [4]float64 + +var notstringerarrayv notstringerarray + +var nonemptyinterface = interface { + f() +}(nil) + +// A data type we can print with "%d". +type percentDStruct struct { + a int + b []byte + c *float64 +} + +var percentDV percentDStruct + +// A data type we cannot print correctly with "%d". +type notPercentDStruct struct { + a int + b []byte + c bool +} + +var notPercentDV notPercentDStruct + +// A data type we can print with "%s". +type percentSStruct struct { + a string + b []byte + C stringerarray +} + +var percentSV percentSStruct + +type recursiveStringer int + +func (s recursiveStringer) String() string { + _ = fmt.Sprintf("%d", s) + _ = fmt.Sprintf("%#v", s) + _ = fmt.Sprintf("%v", s) // ERROR "Sprintf format %v with arg s causes recursive String method call" + _ = fmt.Sprintf("%v", &s) // ERROR "Sprintf format %v with arg &s causes recursive String method call" + _ = fmt.Sprintf("%T", s) // ok; does not recursively call String + return fmt.Sprintln(s) // ERROR "Sprintln arg s causes recursive call to String method" +} + +type recursivePtrStringer int + +func (p *recursivePtrStringer) String() string { + _ = fmt.Sprintf("%v", *p) + return fmt.Sprintln(p) // ERROR "Sprintln arg p causes recursive call to String method" +} + +type BoolFormatter bool + +func (*BoolFormatter) Format(fmt.State, rune) { +} + +// Formatter with value receiver +type FormatterVal bool + +func (FormatterVal) Format(fmt.State, rune) { +} + +type RecursiveSlice []RecursiveSlice + +var recursiveSliceV = &RecursiveSlice{} + +type RecursiveMap map[int]RecursiveMap + +var recursiveMapV = make(RecursiveMap) + +type RecursiveStruct struct { + next *RecursiveStruct +} + +var recursiveStructV = &RecursiveStruct{} + +type RecursiveStruct1 struct { + next *RecursiveStruct2 +} + +type RecursiveStruct2 struct { + next *RecursiveStruct1 +} + +var recursiveStruct1V = &RecursiveStruct1{} + +// Issue 17798: unexported stringer cannot be formatted. +type unexportedStringer struct { + t stringer +} +type unexportedStringerOtherFields struct { + s string + t stringer + S string +} + +// Issue 17798: unexported error cannot be formatted. +type unexportedError struct { + e error +} +type unexportedErrorOtherFields struct { + s string + e error + S string +} + +type errorer struct{} + +func (e errorer) Error() string { return "errorer" } + +func UnexportedStringerOrError() { + us := unexportedStringer{} + fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type testdata.unexportedStringer" + fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]testdata.unexportedStringer" + + usf := unexportedStringerOtherFields{ + s: "foo", + S: "bar", + } + fmt.Printf("%s", usf) // ERROR "Printf format %s has arg usf of wrong type testdata.unexportedStringerOtherFields" + fmt.Printf("%s", &usf) // ERROR "Printf format %s has arg &usf of wrong type [*]testdata.unexportedStringerOtherFields" + + ue := unexportedError{ + e: &errorer{}, + } + fmt.Printf("%s", ue) // ERROR "Printf format %s has arg ue of wrong type testdata.unexportedError" + fmt.Printf("%s", &ue) // ERROR "Printf format %s has arg &ue of wrong type [*]testdata.unexportedError" + + uef := unexportedErrorOtherFields{ + s: "foo", + e: &errorer{}, + S: "bar", + } + fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type testdata.unexportedErrorOtherFields" + fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]testdata.unexportedErrorOtherFields" + + fmt.Println("foo\n", "bar") // not an error + fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline" + fmt.Println("foo\\n") // not an error + fmt.Println(`foo\n`) // not an error +} diff --git a/libgo/go/cmd/vet/testdata/rangeloop.go b/libgo/go/cmd/vet/testdata/rangeloop.go new file mode 100644 index 00000000000..cd3b4cbc452 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/rangeloop.go @@ -0,0 +1,90 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the rangeloop checker. + +package testdata + +func RangeLoopTests() { + var s []int + for i, v := range s { + go func() { + println(i) // ERROR "loop variable i captured by func literal" + println(v) // ERROR "loop variable v captured by func literal" + }() + } + for i, v := range s { + defer func() { + println(i) // ERROR "loop variable i captured by func literal" + println(v) // ERROR "loop variable v captured by func literal" + }() + } + for i := range s { + go func() { + println(i) // ERROR "loop variable i captured by func literal" + }() + } + for _, v := range s { + go func() { + println(v) // ERROR "loop variable v captured by func literal" + }() + } + for i, v := range s { + go func() { + println(i, v) + }() + println("unfortunately, we don't catch the error above because of this statement") + } + for i, v := range s { + go func(i, v int) { + println(i, v) + }(i, v) + } + for i, v := range s { + i, v := i, v + go func() { + println(i, v) + }() + } + // If the key of the range statement is not an identifier + // the code should not panic (it used to). + var x [2]int + var f int + for x[0], f = range s { + go func() { + _ = f // ERROR "loop variable f captured by func literal" + }() + } + type T struct { + v int + } + for _, v := range s { + go func() { + _ = T{v: 1} + _ = []int{v: 1} // ERROR "loop variable v captured by func literal" + }() + } + + // ordinary for-loops + for i := 0; i < 10; i++ { + go func() { + print(i) // ERROR "loop variable i captured by func literal" + }() + } + for i, j := 0, 1; i < 100; i, j = j, i+j { + go func() { + print(j) // ERROR "loop variable j captured by func literal" + }() + } + type cons struct { + car int + cdr *cons + } + var head *cons + for p := head; p != nil; p = p.next { + go func() { + print(p.car) // ERROR "loop variable p captured by func literal" + }() + } +} diff --git a/libgo/go/cmd/vet/testdata/shadow.go b/libgo/go/cmd/vet/testdata/shadow.go new file mode 100644 index 00000000000..3b61137b87c --- /dev/null +++ b/libgo/go/cmd/vet/testdata/shadow.go @@ -0,0 +1,59 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the shadowed variable checker. +// Some of these errors are caught by the compiler (shadowed return parameters for example) +// but are nonetheless useful tests. + +package testdata + +import "os" + +func ShadowRead(f *os.File, buf []byte) (err error) { + var x int + if f != nil { + err := 3 // OK - different type. + _ = err + } + if f != nil { + _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + if err != nil { + return err + } + i := 3 // OK + _ = i + } + if f != nil { + x := one() // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" + var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + if x == 1 && err != nil { + return err + } + } + for i := 0; i < 10; i++ { + i := i // OK: obviously intentional idiomatic redeclaration + go func() { + println(i) + }() + } + var shadowTemp interface{} + switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration + case int: + println("OK") + _ = shadowTemp + } + if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration + var f *os.File // OK because f is not mentioned later in the function. + // The declaration of x is a shadow because x is mentioned below. + var x int // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" + _, _, _ = x, f, shadowTemp + } + // Use a couple of variables to trigger shadowing errors. + _, _ = err, x + return +} + +func one() int { + return 1 +} diff --git a/libgo/go/cmd/vet/testdata/shift.go b/libgo/go/cmd/vet/testdata/shift.go new file mode 100644 index 00000000000..73cbaf88418 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/shift.go @@ -0,0 +1,162 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the suspicious shift checker. + +package testdata + +import ( + "fmt" + "unsafe" +) + +func ShiftTest() { + var i8 int8 + _ = i8 << 7 + _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8" + _ = i8 << (7 + 1) // ERROR "i8 .8 bits. too small for shift of 8" + _ = i8 >> 8 // ERROR "i8 .8 bits. too small for shift of 8" + i8 <<= 8 // ERROR "i8 .8 bits. too small for shift of 8" + i8 >>= 8 // ERROR "i8 .8 bits. too small for shift of 8" + var i16 int16 + _ = i16 << 15 + _ = i16 << 16 // ERROR "i16 .16 bits. too small for shift of 16" + _ = i16 >> 16 // ERROR "i16 .16 bits. too small for shift of 16" + i16 <<= 16 // ERROR "i16 .16 bits. too small for shift of 16" + i16 >>= 16 // ERROR "i16 .16 bits. too small for shift of 16" + var i32 int32 + _ = i32 << 31 + _ = i32 << 32 // ERROR "i32 .32 bits. too small for shift of 32" + _ = i32 >> 32 // ERROR "i32 .32 bits. too small for shift of 32" + i32 <<= 32 // ERROR "i32 .32 bits. too small for shift of 32" + i32 >>= 32 // ERROR "i32 .32 bits. too small for shift of 32" + var i64 int64 + _ = i64 << 63 + _ = i64 << 64 // ERROR "i64 .64 bits. too small for shift of 64" + _ = i64 >> 64 // ERROR "i64 .64 bits. too small for shift of 64" + i64 <<= 64 // ERROR "i64 .64 bits. too small for shift of 64" + i64 >>= 64 // ERROR "i64 .64 bits. too small for shift of 64" + var u8 uint8 + _ = u8 << 7 + _ = u8 << 8 // ERROR "u8 .8 bits. too small for shift of 8" + _ = u8 >> 8 // ERROR "u8 .8 bits. too small for shift of 8" + u8 <<= 8 // ERROR "u8 .8 bits. too small for shift of 8" + u8 >>= 8 // ERROR "u8 .8 bits. too small for shift of 8" + var u16 uint16 + _ = u16 << 15 + _ = u16 << 16 // ERROR "u16 .16 bits. too small for shift of 16" + _ = u16 >> 16 // ERROR "u16 .16 bits. too small for shift of 16" + u16 <<= 16 // ERROR "u16 .16 bits. too small for shift of 16" + u16 >>= 16 // ERROR "u16 .16 bits. too small for shift of 16" + var u32 uint32 + _ = u32 << 31 + _ = u32 << 32 // ERROR "u32 .32 bits. too small for shift of 32" + _ = u32 >> 32 // ERROR "u32 .32 bits. too small for shift of 32" + u32 <<= 32 // ERROR "u32 .32 bits. too small for shift of 32" + u32 >>= 32 // ERROR "u32 .32 bits. too small for shift of 32" + var u64 uint64 + _ = u64 << 63 + _ = u64 << 64 // ERROR "u64 .64 bits. too small for shift of 64" + _ = u64 >> 64 // ERROR "u64 .64 bits. too small for shift of 64" + u64 <<= 64 // ERROR "u64 .64 bits. too small for shift of 64" + u64 >>= 64 // ERROR "u64 .64 bits. too small for shift of 64" + _ = u64 << u64 // Non-constant shifts should succeed. + + var i int + _ = i << 31 + const in = 8 * unsafe.Sizeof(i) + _ = i << in // ERROR "too small for shift" + _ = i >> in // ERROR "too small for shift" + i <<= in // ERROR "too small for shift" + i >>= in // ERROR "too small for shift" + const ix = 8*unsafe.Sizeof(i) - 1 + _ = i << ix + _ = i >> ix + i <<= ix + i >>= ix + + var u uint + _ = u << 31 + const un = 8 * unsafe.Sizeof(u) + _ = u << un // ERROR "too small for shift" + _ = u >> un // ERROR "too small for shift" + u <<= un // ERROR "too small for shift" + u >>= un // ERROR "too small for shift" + const ux = 8*unsafe.Sizeof(u) - 1 + _ = u << ux + _ = u >> ux + u <<= ux + u >>= ux + + var p uintptr + _ = p << 31 + const pn = 8 * unsafe.Sizeof(p) + _ = p << pn // ERROR "too small for shift" + _ = p >> pn // ERROR "too small for shift" + p <<= pn // ERROR "too small for shift" + p >>= pn // ERROR "too small for shift" + const px = 8*unsafe.Sizeof(p) - 1 + _ = p << px + _ = p >> px + p <<= px + p >>= px + + const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks + + var h uintptr + h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) + h <<= 8 * unsafe.Sizeof(h) // ERROR "too small for shift" + h >>= 7 * unsafe.Alignof(h) + h >>= 8 * unsafe.Alignof(h) // ERROR "too small for shift" +} + +func ShiftDeadCode() { + var i int + const iBits = 8 * unsafe.Sizeof(i) + + if iBits <= 32 { + if iBits == 16 { + _ = i >> 8 + } else { + _ = i >> 16 + } + } else { + _ = i >> 32 + } + + if iBits >= 64 { + _ = i << 32 + if iBits == 128 { + _ = i << 64 + } + } else { + _ = i << 16 + } + + if iBits == 64 { + _ = i << 32 + } + + switch iBits { + case 128, 64: + _ = i << 32 + default: + _ = i << 16 + } + + switch { + case iBits < 32: + _ = i << 16 + case iBits > 64: + _ = i << 64 + default: + _ = i << 64 // ERROR "too small for shift" + } + + // Make sure other vet checks work in dead code. + if iBits == 1024 { + _ = i << 512 // OK + fmt.Printf("foo %s bar", 123) // ERROR "Printf" + } +} diff --git a/libgo/go/cmd/vet/testdata/structtag.go b/libgo/go/cmd/vet/testdata/structtag.go new file mode 100644 index 00000000000..c87e42f5d00 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/structtag.go @@ -0,0 +1,102 @@ +// 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. + +// This file contains the test for canonical struct tags. + +package testdata + +import "encoding/xml" + +type StructTagTest struct { + A int "hello" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" + B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key" + C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get" + D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" + E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" + F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key" + G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" + H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" + I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces" + J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces" + OK0 int `x:"y" u:"v" w:""` + OK1 int `x:"y:z" u:"v" w:""` // note multiple colons. + OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\"" + OK3 int `under_scores:"and" CAPS:"ARE_OK"` +} + +type UnexportedEncodingTagTest struct { + x int `json:"xx"` // ERROR "struct field x has json tag but is not exported" + y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported" + z int + A int `json:"aa" xml:"bb"` +} + +type unexp struct{} + +type JSONEmbeddedField struct { + UnexportedEncodingTagTest `is:"embedded"` + unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363 +} + +type AnonymousJSON struct{} +type AnonymousXML struct{} + +type DuplicateJSONFields struct { + JSON int `json:"a"` + DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46" + IgnoredJSON int `json:"-"` + OtherIgnoredJSON int `json:"-"` + OmitJSON int `json:",omitempty"` + OtherOmitJSON int `json:",omitempty"` + DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46" + NonJSON int `foo:"a"` + DuplicateNonJSON int `foo:"a"` + Embedded struct { + DuplicateJSON int `json:"a"` // OK because its not in the same struct type + } + AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46" + + XML int `xml:"a"` + DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60" + IgnoredXML int `xml:"-"` + OtherIgnoredXML int `xml:"-"` + OmitXML int `xml:",omitempty"` + OtherOmitXML int `xml:",omitempty"` + DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60" + NonXML int `foo:"a"` + DuplicateNonXML int `foo:"a"` + Embedded struct { + DuplicateXML int `xml:"a"` // OK because its not in the same struct type + } + AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60" + Attribute struct { + XMLName xml.Name `xml:"b"` + NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct. + Attr int `xml:"b,attr"` // OK because 0 is valid. + DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" + DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" + + AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76" + } +} + +type UnexpectedSpacetest struct { + A int `json:"a,omitempty"` + B int `json:"b, omitempty"` // ERROR "suspicious space in struct tag value" + C int `json:"c ,omitempty"` + D int `json:"d,omitempty, string"` // ERROR "suspicious space in struct tag value" + E int `xml:"e local"` + F int `xml:"f "` // ERROR "suspicious space in struct tag value" + G int `xml:" g"` // ERROR "suspicious space in struct tag value" + H int `xml:"h ,omitempty"` // ERROR "suspicious space in struct tag value" + I int `xml:"i, omitempty"` // ERROR "suspicious space in struct tag value" + J int `xml:"j local ,omitempty"` // ERROR "suspicious space in struct tag value" + K int `xml:"k local, omitempty"` // ERROR "suspicious space in struct tag value" + L int `xml:" l local,omitempty"` // ERROR "suspicious space in struct tag value" + M int `xml:"m local,omitempty"` // ERROR "suspicious space in struct tag value" + N int `xml:" "` // ERROR "suspicious space in struct tag value" + O int `xml:""` + P int `xml:","` + Q int `foo:" doesn't care "` +} diff --git a/libgo/go/cmd/vet/testdata/tagtest/file1.go b/libgo/go/cmd/vet/testdata/tagtest/file1.go new file mode 100644 index 00000000000..22a1509acc0 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/tagtest/file1.go @@ -0,0 +1,10 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build testtag + +package main + +func main() { +} diff --git a/libgo/go/cmd/vet/testdata/tagtest/file2.go b/libgo/go/cmd/vet/testdata/tagtest/file2.go new file mode 100644 index 00000000000..ba7dd91bbd8 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/tagtest/file2.go @@ -0,0 +1,10 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !testtag + +package main + +func ignore() { +} diff --git a/libgo/go/cmd/vet/testdata/testingpkg/tests.go b/libgo/go/cmd/vet/testdata/testingpkg/tests.go new file mode 100644 index 00000000000..69d29d3c6c6 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/testingpkg/tests.go @@ -0,0 +1 @@ +package testdata diff --git a/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go b/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go new file mode 100644 index 00000000000..f5bbc3922a9 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/testingpkg/tests_test.go @@ -0,0 +1,74 @@ +package testdata + +import ( + "testing" +) + +// Buf is a ... +type Buf []byte + +// Append ... +func (*Buf) Append([]byte) {} + +func (Buf) Reset() {} + +func (Buf) Len() int { return 0 } + +// DefaultBuf is a ... +var DefaultBuf Buf + +func Example() {} // OK because is package-level. + +func Example_goodSuffix() // OK because refers to suffix annotation. + +func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" + +func ExampleBuf() // OK because refers to known top-level type. + +func ExampleBuf_Append() {} // OK because refers to known method. + +func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear" + +func ExampleBuf_suffix() {} // OK because refers to suffix annotation. + +func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad" + +func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix. + +func ExampleDefaultBuf() {} // OK because refers to top-level identifier. + +func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing" + +func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" + +// "Puffer" is German for "Buffer". + +func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer" + +func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" + +func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" + +func nonTest() {} // OK because it doesn't start with "Test". + +func (Buf) TesthasReceiver() {} // OK because it has a receiver. + +func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase. + +func TestÜnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase. + +func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase" + +func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase" + +func Test(*testing.T) {} // OK "Test" on its own is considered a test. + +func Testify() {} // OK because it takes no parameters. + +func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters. + +func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names. + +func TestnoTParam(string) {} // OK because it doesn't take a *testing.T + +func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase" diff --git a/libgo/go/cmd/vet/testdata/unsafeptr.go b/libgo/go/cmd/vet/testdata/unsafeptr.go new file mode 100644 index 00000000000..ce852009ea7 --- /dev/null +++ b/libgo/go/cmd/vet/testdata/unsafeptr.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 testdata + +import ( + "reflect" + "unsafe" +) + +func f() { + var x unsafe.Pointer + var y uintptr + x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer" + y = uintptr(x) + + // only allowed pointer arithmetic is ptr +/-/&^ num. + // num+ptr is technically okay but still flagged: write ptr+num instead. + x = unsafe.Pointer(uintptr(x) + 1) + x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" + x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" + x = unsafe.Pointer(uintptr(x) - 1) + x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" + x = unsafe.Pointer(uintptr(x) &^ 3) + x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer" + + // certain uses of reflect are okay + var v reflect.Value + x = unsafe.Pointer(v.Pointer()) + x = unsafe.Pointer(v.UnsafeAddr()) + var s1 *reflect.StringHeader + x = unsafe.Pointer(s1.Data) + var s2 *reflect.SliceHeader + x = unsafe.Pointer(s2.Data) + var s3 reflect.StringHeader + x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer" + var s4 reflect.SliceHeader + x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer" + + // but only in reflect + var vv V + x = unsafe.Pointer(vv.Pointer()) // ERROR "possible misuse of unsafe.Pointer" + x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer" + var ss1 *StringHeader + x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer" + var ss2 *SliceHeader + x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer" + +} + +type V interface { + Pointer() uintptr + UnsafeAddr() uintptr +} + +type StringHeader struct { + Data uintptr +} + +type SliceHeader struct { + Data uintptr +} diff --git a/libgo/go/cmd/vet/testdata/unused.go b/libgo/go/cmd/vet/testdata/unused.go new file mode 100644 index 00000000000..d50f6594d9b --- /dev/null +++ b/libgo/go/cmd/vet/testdata/unused.go @@ -0,0 +1,29 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for the unusedresult checker. + +package testdata + +import ( + "bytes" + "errors" + "fmt" +) + +func _() { + fmt.Errorf("") // ERROR "result of fmt.Errorf call not used" + _ = fmt.Errorf("") + + errors.New("") // ERROR "result of errors.New call not used" + + err := errors.New("") + err.Error() // ERROR "result of \(error\).Error call not used" + + var buf bytes.Buffer + buf.String() // ERROR "result of \(bytes.Buffer\).String call not used" + + fmt.Sprint("") // ERROR "result of fmt.Sprint call not used" + fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used" +} diff --git a/libgo/go/cmd/vet/tests.go b/libgo/go/cmd/vet/tests.go new file mode 100644 index 00000000000..5b157084fa2 --- /dev/null +++ b/libgo/go/cmd/vet/tests.go @@ -0,0 +1,187 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" + "go/types" + "strings" + "unicode" + "unicode/utf8" +) + +func init() { + register("tests", + "check for common mistaken usages of tests/documentation examples", + checkTestFunctions, + funcDecl) +} + +func isExampleSuffix(s string) bool { + r, size := utf8.DecodeRuneInString(s) + return size > 0 && unicode.IsLower(r) +} + +func isTestSuffix(name string) bool { + if len(name) == 0 { + // "Test" is ok. + return true + } + r, _ := utf8.DecodeRuneInString(name) + return !unicode.IsLower(r) +} + +func isTestParam(typ ast.Expr, wantType string) bool { + ptr, ok := typ.(*ast.StarExpr) + if !ok { + // Not a pointer. + return false + } + // No easy way of making sure it's a *testing.T or *testing.B: + // ensure the name of the type matches. + if name, ok := ptr.X.(*ast.Ident); ok { + return name.Name == wantType + } + if sel, ok := ptr.X.(*ast.SelectorExpr); ok { + return sel.Sel.Name == wantType + } + return false +} + +func lookup(name string, scopes []*types.Scope) types.Object { + for _, scope := range scopes { + if o := scope.Lookup(name); o != nil { + return o + } + } + return nil +} + +func extendedScope(f *File) []*types.Scope { + scopes := []*types.Scope{f.pkg.typesPkg.Scope()} + if f.basePkg != nil { + scopes = append(scopes, f.basePkg.typesPkg.Scope()) + } else { + // If basePkg is not specified (e.g. when checking a single file) try to + // find it among imports. + pkgName := f.pkg.typesPkg.Name() + if strings.HasSuffix(pkgName, "_test") { + basePkgName := strings.TrimSuffix(pkgName, "_test") + for _, p := range f.pkg.typesPkg.Imports() { + if p.Name() == basePkgName { + scopes = append(scopes, p.Scope()) + break + } + } + } + } + return scopes +} + +func checkExample(fn *ast.FuncDecl, f *File, report reporter) { + fnName := fn.Name.Name + if params := fn.Type.Params; len(params.List) != 0 { + report("%s should be niladic", fnName) + } + if results := fn.Type.Results; results != nil && len(results.List) != 0 { + report("%s should return nothing", fnName) + } + + if filesRun && !includesNonTest { + // The coherence checks between a test and the package it tests + // will report false positives if no non-test files have + // been provided. + return + } + + if fnName == "Example" { + // Nothing more to do. + return + } + + var ( + exName = strings.TrimPrefix(fnName, "Example") + elems = strings.SplitN(exName, "_", 3) + ident = elems[0] + obj = lookup(ident, extendedScope(f)) + ) + if ident != "" && obj == nil { + // Check ExampleFoo and ExampleBadFoo. + report("%s refers to unknown identifier: %s", fnName, ident) + // Abort since obj is absent and no subsequent checks can be performed. + return + } + if len(elems) < 2 { + // Nothing more to do. + return + } + + if ident == "" { + // Check Example_suffix and Example_BadSuffix. + if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) { + report("%s has malformed example suffix: %s", fnName, residual) + } + return + } + + mmbr := elems[1] + if !isExampleSuffix(mmbr) { + // Check ExampleFoo_Method and ExampleFoo_BadMethod. + if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil { + report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr) + } + } + if len(elems) == 3 && !isExampleSuffix(elems[2]) { + // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix. + report("%s has malformed example suffix: %s", fnName, elems[2]) + } +} + +func checkTest(fn *ast.FuncDecl, prefix string, report reporter) { + // Want functions with 0 results and 1 parameter. + if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || + fn.Type.Params == nil || + len(fn.Type.Params.List) != 1 || + len(fn.Type.Params.List[0].Names) > 1 { + return + } + + // The param must look like a *testing.T or *testing.B. + if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) { + return + } + + if !isTestSuffix(fn.Name.Name[len(prefix):]) { + report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix) + } +} + +type reporter func(format string, args ...interface{}) + +// checkTestFunctions walks Test, Benchmark and Example functions checking +// malformed names, wrong signatures and examples documenting nonexistent +// identifiers. +func checkTestFunctions(f *File, node ast.Node) { + if !strings.HasSuffix(f.name, "_test.go") { + return + } + + fn, ok := node.(*ast.FuncDecl) + if !ok || fn.Recv != nil { + // Ignore non-functions or functions with receivers. + return + } + + report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) } + + switch { + case strings.HasPrefix(fn.Name.Name, "Example"): + checkExample(fn, f, report) + case strings.HasPrefix(fn.Name.Name, "Test"): + checkTest(fn, "Test", report) + case strings.HasPrefix(fn.Name.Name, "Benchmark"): + checkTest(fn, "Benchmark", report) + } +} diff --git a/libgo/go/cmd/vet/types.go b/libgo/go/cmd/vet/types.go new file mode 100644 index 00000000000..799dc655e60 --- /dev/null +++ b/libgo/go/cmd/vet/types.go @@ -0,0 +1,312 @@ +// 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. + +// This file contains the pieces of the tool that use typechecking from the go/types package. + +package main + +import ( + "go/ast" + "go/build" + "go/importer" + "go/token" + "go/types" +) + +// stdImporter is the importer we use to import packages. +// It is shared so that all packages are imported by the same importer. +var stdImporter types.Importer + +var ( + errorType *types.Interface + stringerType *types.Interface // possibly nil + formatterType *types.Interface // possibly nil +) + +func inittypes() { + errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + + if typ := importType("fmt", "Stringer"); typ != nil { + stringerType = typ.Underlying().(*types.Interface) + } + if typ := importType("fmt", "Formatter"); typ != nil { + formatterType = typ.Underlying().(*types.Interface) + } +} + +// isNamedType reports whether t is the named type path.name. +func isNamedType(t types.Type, path, name string) bool { + n, ok := t.(*types.Named) + if !ok { + return false + } + obj := n.Obj() + return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path +} + +// importType returns the type denoted by the qualified identifier +// path.name, and adds the respective package to the imports map +// as a side effect. In case of an error, importType returns nil. +func importType(path, name string) types.Type { + pkg, err := stdImporter.Import(path) + if err != nil { + // This can happen if the package at path hasn't been compiled yet. + warnf("import failed: %v", err) + return nil + } + if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok { + return obj.Type() + } + warnf("invalid type name %q", name) + return nil +} + +func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) []error { + if stdImporter == nil { + if *source { + stdImporter = importer.For("source", nil) + } else { + stdImporter = importer.Default() + } + inittypes() + } + pkg.defs = make(map[*ast.Ident]types.Object) + pkg.uses = make(map[*ast.Ident]types.Object) + pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection) + pkg.spans = make(map[types.Object]Span) + pkg.types = make(map[ast.Expr]types.TypeAndValue) + + var allErrors []error + config := types.Config{ + // We use the same importer for all imports to ensure that + // everybody sees identical packages for the given paths. + Importer: stdImporter, + // By providing a Config with our own error function, it will continue + // past the first error. We collect them all for printing later. + Error: func(e error) { + allErrors = append(allErrors, e) + }, + + Sizes: archSizes, + } + info := &types.Info{ + Selections: pkg.selectors, + Types: pkg.types, + Defs: pkg.defs, + Uses: pkg.uses, + } + typesPkg, err := config.Check(pkg.path, fs, astFiles, info) + if len(allErrors) == 0 && err != nil { + allErrors = append(allErrors, err) + } + pkg.typesPkg = typesPkg + // update spans + for id, obj := range pkg.defs { + pkg.growSpan(id, obj) + } + for id, obj := range pkg.uses { + pkg.growSpan(id, obj) + } + return allErrors +} + +// matchArgType reports an error if printf verb t is not appropriate +// for operand arg. +// +// typ is used only for recursive calls; external callers must supply nil. +// +// (Recursion arises from the compound types {map,chan,slice} which +// may be printed with %d etc. if that is appropriate for their element +// types.) +func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool { + return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool)) +} + +// matchArgTypeInternal is the internal version of matchArgType. It carries a map +// remembering what types are in progress so we don't recur when faced with recursive +// types or mutually recursive types. +func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool { + // %v, %T accept any argument type. + if t == anyType { + return true + } + if typ == nil { + // external call + typ = f.pkg.types[arg].Type + if typ == nil { + return true // probably a type check problem + } + } + // If the type implements fmt.Formatter, we have nothing to check. + if f.isFormatter(typ) { + return true + } + // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? + if t&argString != 0 && isConvertibleToString(typ) { + return true + } + + typ = typ.Underlying() + if inProgress[typ] { + // We're already looking at this type. The call that started it will take care of it. + return true + } + inProgress[typ] = true + + switch typ := typ.(type) { + case *types.Signature: + return t&argPointer != 0 + + case *types.Map: + // Recur: map[int]int matches %d. + return t&argPointer != 0 || + (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)) + + case *types.Chan: + return t&argPointer != 0 + + case *types.Array: + // Same as slice. + if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { + return true // %s matches []byte + } + // Recur: []int matches %d. + return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress) + + case *types.Slice: + // Same as array. + if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { + return true // %s matches []byte + } + // Recur: []int matches %d. But watch out for + // type T []T + // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below. + return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress) + + case *types.Pointer: + // Ugly, but dealing with an edge case: a known pointer to an invalid type, + // probably something from a failed import. + if typ.Elem().String() == "invalid type" { + if *verbose { + f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg)) + } + return true // special case + } + // If it's actually a pointer with %p, it prints as one. + if t == argPointer { + return true + } + // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct. + if str, ok := typ.Elem().Underlying().(*types.Struct); ok { + return f.matchStructArgType(t, str, arg, inProgress) + } + // The rest can print with %p as pointers, or as integers with %x etc. + return t&(argInt|argPointer) != 0 + + case *types.Struct: + return f.matchStructArgType(t, typ, arg, inProgress) + + case *types.Interface: + // There's little we can do. + // Whether any particular verb is valid depends on the argument. + // The user may have reasonable prior knowledge of the contents of the interface. + return true + + case *types.Basic: + switch typ.Kind() { + case types.UntypedBool, + types.Bool: + return t&argBool != 0 + + case types.UntypedInt, + types.Int, + types.Int8, + types.Int16, + types.Int32, + types.Int64, + types.Uint, + types.Uint8, + types.Uint16, + types.Uint32, + types.Uint64, + types.Uintptr: + return t&argInt != 0 + + case types.UntypedFloat, + types.Float32, + types.Float64: + return t&argFloat != 0 + + case types.UntypedComplex, + types.Complex64, + types.Complex128: + return t&argComplex != 0 + + case types.UntypedString, + types.String: + return t&argString != 0 + + case types.UnsafePointer: + return t&(argPointer|argInt) != 0 + + case types.UntypedRune: + return t&(argInt|argRune) != 0 + + case types.UntypedNil: + return t&argPointer != 0 // TODO? + + case types.Invalid: + if *verbose { + f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg)) + } + return true // Probably a type check problem. + } + panic("unreachable") + } + + return false +} + +func isConvertibleToString(typ types.Type) bool { + return types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) +} + +// hasBasicType reports whether x's type is a types.Basic with the given kind. +func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool { + t := f.pkg.types[x].Type + if t != nil { + t = t.Underlying() + } + b, ok := t.(*types.Basic) + return ok && b.Kind() == kind +} + +// matchStructArgType reports whether all the elements of the struct match the expected +// type. For instance, with "%d" all the elements must be printable with the "%d" format. +func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool { + for i := 0; i < typ.NumFields(); i++ { + typf := typ.Field(i) + if !f.matchArgTypeInternal(t, typf.Type(), arg, inProgress) { + return false + } + if t&argString != 0 && !typf.Exported() && isConvertibleToString(typf.Type()) { + // Issue #17798: unexported Stringer or error cannot be properly fomatted. + return false + } + } + return true +} + +// hasMethod reports whether the type contains a method with the given name. +// It is part of the workaround for Formatters and should be deleted when +// that workaround is no longer necessary. +// TODO: This could be better once issue 6259 is fixed. +func (f *File) hasMethod(typ types.Type, name string) bool { + // assume we have an addressable variable of type typ + obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name) + _, ok := obj.(*types.Func) + return ok +} + +var archSizes = types.SizesFor("gc", build.Default.GOARCH) diff --git a/libgo/go/cmd/vet/unsafeptr.go b/libgo/go/cmd/vet/unsafeptr.go new file mode 100644 index 00000000000..cb2cc818897 --- /dev/null +++ b/libgo/go/cmd/vet/unsafeptr.go @@ -0,0 +1,97 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check for invalid uintptr -> unsafe.Pointer conversions. + +package main + +import ( + "go/ast" + "go/token" + "go/types" +) + +func init() { + register("unsafeptr", + "check for misuse of unsafe.Pointer", + checkUnsafePointer, + callExpr) +} + +func checkUnsafePointer(f *File, node ast.Node) { + x := node.(*ast.CallExpr) + if len(x.Args) != 1 { + return + } + if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) { + f.Badf(x.Pos(), "possible misuse of unsafe.Pointer") + } +} + +// isSafeUintptr reports whether x - already known to be a uintptr - +// is safe to convert to unsafe.Pointer. It is safe if x is itself derived +// directly from an unsafe.Pointer via conversion and pointer arithmetic +// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr +// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader. +func (f *File) isSafeUintptr(x ast.Expr) bool { + switch x := x.(type) { + case *ast.ParenExpr: + return f.isSafeUintptr(x.X) + + case *ast.SelectorExpr: + switch x.Sel.Name { + case "Data": + // reflect.SliceHeader and reflect.StringHeader are okay, + // but only if they are pointing at a real slice or string. + // It's not okay to do: + // var x SliceHeader + // x.Data = uintptr(unsafe.Pointer(...)) + // ... use x ... + // p := unsafe.Pointer(x.Data) + // because in the middle the garbage collector doesn't + // see x.Data as a pointer and so x.Data may be dangling + // by the time we get to the conversion at the end. + // For now approximate by saying that *Header is okay + // but Header is not. + pt, ok := f.pkg.types[x.X].Type.(*types.Pointer) + if ok { + t, ok := pt.Elem().(*types.Named) + if ok && t.Obj().Pkg().Path() == "reflect" { + switch t.Obj().Name() { + case "StringHeader", "SliceHeader": + return true + } + } + } + } + + case *ast.CallExpr: + switch len(x.Args) { + case 0: + // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr. + sel, ok := x.Fun.(*ast.SelectorExpr) + if !ok { + break + } + switch sel.Sel.Name { + case "Pointer", "UnsafeAddr": + t, ok := f.pkg.types[sel.X].Type.(*types.Named) + if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" { + return true + } + } + + case 1: + // maybe conversion of uintptr to unsafe.Pointer + return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer) + } + + case *ast.BinaryExpr: + switch x.Op { + case token.ADD, token.SUB, token.AND_NOT: + return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y) + } + } + return false +} diff --git a/libgo/go/cmd/vet/unused.go b/libgo/go/cmd/vet/unused.go new file mode 100644 index 00000000000..02fcd841cd0 --- /dev/null +++ b/libgo/go/cmd/vet/unused.go @@ -0,0 +1,93 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file defines the check for unused results of calls to certain +// pure functions. + +package main + +import ( + "flag" + "go/ast" + "go/token" + "go/types" + "strings" +) + +var unusedFuncsFlag = flag.String("unusedfuncs", + "errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse", + "comma-separated list of functions whose results must be used") + +var unusedStringMethodsFlag = flag.String("unusedstringmethods", + "Error,String", + "comma-separated list of names of methods of type func() string whose results must be used") + +func init() { + register("unusedresult", + "check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list", + checkUnusedResult, + exprStmt) +} + +// func() string +var sigNoArgsStringResult = types.NewSignature(nil, nil, + types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])), + false) + +var unusedFuncs = make(map[string]bool) +var unusedStringMethods = make(map[string]bool) + +func initUnusedFlags() { + commaSplit := func(s string, m map[string]bool) { + if s != "" { + for _, name := range strings.Split(s, ",") { + if len(name) == 0 { + flag.Usage() + } + m[name] = true + } + } + } + commaSplit(*unusedFuncsFlag, unusedFuncs) + commaSplit(*unusedStringMethodsFlag, unusedStringMethods) +} + +func checkUnusedResult(f *File, n ast.Node) { + call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) + if !ok { + return // not a call statement + } + fun := unparen(call.Fun) + + if f.pkg.types[fun].IsType() { + return // a conversion, not a call + } + + selector, ok := fun.(*ast.SelectorExpr) + if !ok { + return // neither a method call nor a qualified ident + } + + sel, ok := f.pkg.selectors[selector] + if ok && sel.Kind() == types.MethodVal { + // method (e.g. foo.String()) + obj := sel.Obj().(*types.Func) + sig := sel.Type().(*types.Signature) + if types.Identical(sig, sigNoArgsStringResult) { + if unusedStringMethods[obj.Name()] { + f.Badf(call.Lparen, "result of (%s).%s call not used", + sig.Recv().Type(), obj.Name()) + } + } + } else if !ok { + // package-qualified function (e.g. fmt.Errorf) + obj := f.pkg.uses[selector.Sel] + if obj, ok := obj.(*types.Func); ok { + qname := obj.Pkg().Path() + "." + obj.Name() + if unusedFuncs[qname] { + f.Badf(call.Lparen, "result of %v call not used", qname) + } + } + } +} diff --git a/libgo/go/cmd/vet/vet_test.go b/libgo/go/cmd/vet/vet_test.go new file mode 100644 index 00000000000..116b77e971b --- /dev/null +++ b/libgo/go/cmd/vet/vet_test.go @@ -0,0 +1,249 @@ +// 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 main_test + +import ( + "bytes" + "fmt" + "internal/testenv" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" + "testing" +) + +const ( + dataDir = "testdata" + binary = "testvet.exe" +) + +// We implement TestMain so remove the test binary when all is done. +func TestMain(m *testing.M) { + result := m.Run() + os.Remove(binary) + os.Exit(result) +} + +func MustHavePerl(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("skipping test: perl not available on %s", runtime.GOOS) + } + if _, err := exec.LookPath("perl"); err != nil { + t.Skipf("skipping test: perl not found in path") + } +} + +var ( + buildMu sync.Mutex // guards following + built = false // We have built the binary. + failed = false // We have failed to build the binary, don't try again. +) + +func Build(t *testing.T) { + buildMu.Lock() + defer buildMu.Unlock() + if built { + return + } + if failed { + t.Skip("cannot run on this environment") + } + testenv.MustHaveGoBuild(t) + MustHavePerl(t) + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary) + output, err := cmd.CombinedOutput() + if err != nil { + failed = true + fmt.Fprintf(os.Stderr, "%s\n", output) + t.Fatal(err) + } + built = true +} + +func Vet(t *testing.T, files []string) { + errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") + if _, err := os.Stat(errchk); err != nil { + t.Skipf("skipping because no errchk: %v", err) + } + flags := []string{ + "./" + binary, + "-printfuncs=Warn:1,Warnf:1", + "-all", + "-shadow", + } + cmd := exec.Command(errchk, append(flags, files...)...) + if !run(cmd, t) { + t.Fatal("vet command failed") + } +} + +// Run this shell script, but do it in Go so it can be run by "go test". +// go build -o testvet +// $(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s +// rm testvet +// + +// TestVet tests self-contained files in testdata/*.go. +// +// If a file contains assembly or has inter-dependencies, it should be +// in its own test, like TestVetAsm, TestDivergentPackagesExamples, +// etc below. +func TestVet(t *testing.T) { + Build(t) + t.Parallel() + + // errchk ./testvet + gos, err := filepath.Glob(filepath.Join(dataDir, "*.go")) + if err != nil { + t.Fatal(err) + } + wide := runtime.GOMAXPROCS(0) + if wide > len(gos) { + wide = len(gos) + } + batch := make([][]string, wide) + for i, file := range gos { + // TODO: Remove print.go exception once we require type checking for everything, + // and then delete TestVetPrint. + if strings.HasSuffix(file, "print.go") { + continue + } + batch[i%wide] = append(batch[i%wide], file) + } + for i, files := range batch { + if len(files) == 0 { + continue + } + files := files + t.Run(fmt.Sprint(i), func(t *testing.T) { + t.Parallel() + t.Logf("files: %q", files) + Vet(t, files) + }) + } +} + +func TestVetPrint(t *testing.T) { + Build(t) + errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") + if _, err := os.Stat(errchk); err != nil { + t.Skipf("skipping because no errchk: %v", err) + } + cmd := exec.Command( + errchk, + "go", "vet", "-vettool=./"+binary, + "-printf", + "-printfuncs=Warn:1,Warnf:1", + "testdata/print.go", + ) + if !run(cmd, t) { + t.Fatal("vet command failed") + } +} + +func TestVetAsm(t *testing.T) { + Build(t) + + asmDir := filepath.Join(dataDir, "asm") + gos, err := filepath.Glob(filepath.Join(asmDir, "*.go")) + if err != nil { + t.Fatal(err) + } + asms, err := filepath.Glob(filepath.Join(asmDir, "*.s")) + if err != nil { + t.Fatal(err) + } + + t.Parallel() + // errchk ./testvet + Vet(t, append(gos, asms...)) +} + +func TestVetDirs(t *testing.T) { + t.Parallel() + Build(t) + for _, dir := range []string{ + "testingpkg", + "divergent", + "buildtag", + "incomplete", // incomplete examples + "cgo", + } { + dir := dir + t.Run(dir, func(t *testing.T) { + t.Parallel() + gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go")) + if err != nil { + t.Fatal(err) + } + Vet(t, gos) + }) + } +} + +func run(c *exec.Cmd, t *testing.T) bool { + output, err := c.CombinedOutput() + if err != nil { + t.Logf("vet output:\n%s", output) + t.Fatal(err) + } + // Errchk delights by not returning non-zero status if it finds errors, so we look at the output. + // It prints "BUG" if there is a failure. + if !c.ProcessState.Success() { + t.Logf("vet output:\n%s", output) + return false + } + ok := !bytes.Contains(output, []byte("BUG")) + if !ok { + t.Logf("vet output:\n%s", output) + } + return ok +} + +// TestTags verifies that the -tags argument controls which files to check. +func TestTags(t *testing.T) { + t.Parallel() + Build(t) + for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} { + tag := tag + t.Run(tag, func(t *testing.T) { + t.Parallel() + t.Logf("-tags=%s", tag) + args := []string{ + "-tags=" + tag, + "-v", // We're going to look at the files it examines. + "testdata/tagtest", + } + cmd := exec.Command("./"+binary, args...) + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(err) + } + // file1 has testtag and file2 has !testtag. + if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) { + t.Error("file1 was excluded, should be included") + } + if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) { + t.Error("file2 was included, should be excluded") + } + }) + } +} + +// Issue #21188. +func TestVetVerbose(t *testing.T) { + t.Parallel() + Build(t) + cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go") + out, err := cmd.CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Error(err) + } +} diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go index 42788443bcf..f07c7e81e87 100644 --- a/libgo/go/compress/bzip2/bzip2.go +++ b/libgo/go/compress/bzip2/bzip2.go @@ -163,7 +163,7 @@ func (bz2 *reader) readFromBlock(buf []byte) int { func (bz2 *reader) read(buf []byte) (int, error) { for { n := bz2.readFromBlock(buf) - if n > 0 { + if n > 0 || len(buf) == 0 { bz2.blockCRC = updateCRC(bz2.blockCRC, buf[:n]) return n, nil } diff --git a/libgo/go/compress/bzip2/bzip2_test.go b/libgo/go/compress/bzip2/bzip2_test.go index a6c3080db3e..3848603e0dd 100644 --- a/libgo/go/compress/bzip2/bzip2_test.go +++ b/libgo/go/compress/bzip2/bzip2_test.go @@ -204,6 +204,14 @@ func TestMTF(t *testing.T) { } } +func TestZeroRead(t *testing.T) { + b := mustDecodeHex("425a6839314159265359b5aa5098000000600040000004200021008283177245385090b5aa5098") + r := NewReader(bytes.NewReader(b)) + if n, err := r.Read(nil); n != 0 || err != nil { + t.Errorf("Read(nil) = (%d, %v), want (0, nil)", n, err) + } +} + var ( digits = mustLoadFile("testdata/e.txt.bz2") twain = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2") diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go index 6cd6281249b..f42a921e674 100644 --- a/libgo/go/compress/flate/huffman_bit_writer.go +++ b/libgo/go/compress/flate/huffman_bit_writer.go @@ -54,23 +54,15 @@ var offsetExtraBits = []int8{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, - /* extended window */ - 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, } var offsetBase = []uint32{ - /* normal deflate */ 0x000000, 0x000001, 0x000002, 0x000003, 0x000004, 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018, 0x000020, 0x000030, 0x000040, 0x000060, 0x000080, 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300, 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000, 0x001800, 0x002000, 0x003000, 0x004000, 0x006000, - - /* extended window */ - 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000, - 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000, - 0x100000, 0x180000, 0x200000, 0x300000, } // The odd order in which the codegen code sizes are written. diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go index 8bd750bd8b3..85d52e85009 100644 --- a/libgo/go/compress/gzip/gunzip.go +++ b/libgo/go/compress/gzip/gunzip.go @@ -66,7 +66,7 @@ type Header struct { // Only the first header is recorded in the Reader fields. // // Gzip files store a length and checksum of the uncompressed data. -// The Reader will return a ErrChecksum when Read +// The Reader will return an ErrChecksum when Read // reaches the end of the uncompressed data if it does not // have the expected length or checksum. Clients should treat data // returned by Read as tentative until they receive the io.EOF diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go index d41110422e9..f19f9cfa74b 100644 --- a/libgo/go/container/heap/heap_test.go +++ b/libgo/go/container/heap/heap_test.go @@ -33,6 +33,7 @@ func (h *myHeap) Push(v interface{}) { } func (h myHeap) verify(t *testing.T, i int) { + t.Helper() n := h.Len() j1 := 2*i + 1 j2 := 2*i + 2 diff --git a/libgo/go/container/ring/example_test.go b/libgo/go/container/ring/example_test.go new file mode 100644 index 00000000000..d8f16390eef --- /dev/null +++ b/libgo/go/container/ring/example_test.go @@ -0,0 +1,195 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package ring_test + +import ( + "container/ring" + "fmt" +) + +func ExampleRing_Len() { + // Create a new ring of size 4 + r := ring.New(4) + + // Print out its length + fmt.Println(r.Len()) + + // Output: + // 4 +} + +func ExampleRing_Next() { + // Create a new ring of size 5 + r := ring.New(5) + + // Get the length of the ring + n := r.Len() + + // Initialize the ring with some integer values + for i := 0; i < n; i++ { + r.Value = i + r = r.Next() + } + + // Iterate through the ring and print its contents + for j := 0; j < n; j++ { + fmt.Println(r.Value) + r = r.Next() + } + + // Output: + // 0 + // 1 + // 2 + // 3 + // 4 +} + +func ExampleRing_Prev() { + // Create a new ring of size 5 + r := ring.New(5) + + // Get the length of the ring + n := r.Len() + + // Initialize the ring with some integer values + for i := 0; i < n; i++ { + r.Value = i + r = r.Next() + } + + // Iterate through the ring backwards and print its contents + for j := 0; j < n; j++ { + r = r.Prev() + fmt.Println(r.Value) + } + + // Output: + // 4 + // 3 + // 2 + // 1 + // 0 +} + +func ExampleRing_Do() { + // Create a new ring of size 5 + r := ring.New(5) + + // Get the length of the ring + n := r.Len() + + // Initialize the ring with some integer values + for i := 0; i < n; i++ { + r.Value = i + r = r.Next() + } + + // Iterate through the ring and print its contents + r.Do(func(p interface{}) { + fmt.Println(p.(int)) + }) + + // Output: + // 0 + // 1 + // 2 + // 3 + // 4 +} + +func ExampleRing_Move() { + // Create a new ring of size 5 + r := ring.New(5) + + // Get the length of the ring + n := r.Len() + + // Initialize the ring with some integer values + for i := 0; i < n; i++ { + r.Value = i + r = r.Next() + } + + // Move the pointer forward by three steps + r = r.Move(3) + + // Iterate through the ring and print its contents + r.Do(func(p interface{}) { + fmt.Println(p.(int)) + }) + + // Output: + // 3 + // 4 + // 0 + // 1 + // 2 +} + +func ExampleRing_Link() { + // Create two rings, r and s, of size 2 + r := ring.New(2) + s := ring.New(2) + + // Get the length of the ring + lr := r.Len() + ls := s.Len() + + // Initialize r with 0s + for i := 0; i < lr; i++ { + r.Value = 0 + r = r.Next() + } + + // Initialize s with 1s + for j := 0; j < ls; j++ { + s.Value = 1 + s = s.Next() + } + + // Link ring r and ring s + rs := r.Link(s) + + // Iterate through the combined ring and print its contents + rs.Do(func(p interface{}) { + fmt.Println(p.(int)) + }) + + // Output: + // 0 + // 0 + // 1 + // 1 +} + +func ExampleRing_Unlink() { + // Create a new ring of size 6 + r := ring.New(6) + + // Get the length of the ring + n := r.Len() + + // Initialize the ring with some integer values + for i := 0; i < n; i++ { + r.Value = i + r = r.Next() + } + + // Unlink three elements from r, starting from r.Next() + r.Unlink(3) + + // Iterate through the remaining ring and print its contents + r.Do(func(p interface{}) { + fmt.Println(p.(int)) + }) + + // Output: + // 0 + // 4 + // 5 +} diff --git a/libgo/go/context/benchmark_test.go b/libgo/go/context/benchmark_test.go index b79232704eb..3c526dd1069 100644 --- a/libgo/go/context/benchmark_test.go +++ b/libgo/go/context/benchmark_test.go @@ -7,10 +7,64 @@ package context_test import ( . "context" "fmt" + "runtime" + "sync" "testing" + "time" ) -func BenchmarkContextCancelTree(b *testing.B) { +func BenchmarkWithTimeout(b *testing.B) { + for concurrency := 40; concurrency <= 4e5; concurrency *= 100 { + name := fmt.Sprintf("concurrency=%d", concurrency) + b.Run(name, func(b *testing.B) { + benchmarkWithTimeout(b, concurrency) + }) + } +} + +func benchmarkWithTimeout(b *testing.B, concurrentContexts int) { + gomaxprocs := runtime.GOMAXPROCS(0) + perPContexts := concurrentContexts / gomaxprocs + root := Background() + + // Generate concurrent contexts. + var wg sync.WaitGroup + ccf := make([][]CancelFunc, gomaxprocs) + for i := range ccf { + wg.Add(1) + go func(i int) { + defer wg.Done() + cf := make([]CancelFunc, perPContexts) + for j := range cf { + _, cf[j] = WithTimeout(root, time.Hour) + } + ccf[i] = cf + }(i) + } + wg.Wait() + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + wcf := make([]CancelFunc, 10) + for pb.Next() { + for i := range wcf { + _, wcf[i] = WithTimeout(root, time.Hour) + } + for _, f := range wcf { + f() + } + } + }) + b.StopTimer() + + for _, cf := range ccf { + for _, f := range cf { + f() + } + } +} + +func BenchmarkCancelTree(b *testing.B) { depths := []int{1, 10, 100, 1000} for _, d := range depths { b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) { diff --git a/libgo/go/context/context.go b/libgo/go/context/context.go index 892ff27c653..06580e0465a 100644 --- a/libgo/go/context/context.go +++ b/libgo/go/context/context.go @@ -136,7 +136,7 @@ type Context interface { // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. - // var userKey key = 0 + // var userKey key // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { @@ -380,25 +380,25 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) { // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { +func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { + if cur, ok := parent.Deadline(); ok && cur.Before(d) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), - deadline: deadline, + deadline: d, } propagateCancel(parent, c) - d := time.Until(deadline) - if d <= 0 { + dur := time.Until(d) + if dur <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { - c.timer = time.AfterFunc(d, func() { + c.timer = time.AfterFunc(dur, func() { c.cancel(true, DeadlineExceeded) }) } diff --git a/libgo/go/context/example_test.go b/libgo/go/context/example_test.go index 2d48d4e82bb..b2c2aa921da 100644 --- a/libgo/go/context/example_test.go +++ b/libgo/go/context/example_test.go @@ -52,7 +52,7 @@ func ExampleWithCancel() { // 5 } -// This example passes a context with a arbitrary deadline to tell a blocking +// This example passes a context with an arbitrary deadline to tell a blocking // function that it should abandon its work as soon as it gets to it. func ExampleWithDeadline() { d := time.Now().Add(50 * time.Millisecond) diff --git a/libgo/go/crypto/aes/ctr_s390x.go b/libgo/go/crypto/aes/ctr_s390x.go index ae09dbadaf4..7892f79d243 100644 --- a/libgo/go/crypto/aes/ctr_s390x.go +++ b/libgo/go/crypto/aes/ctr_s390x.go @@ -66,6 +66,10 @@ func (c *aesctr) refill() { } func (c *aesctr) XORKeyStream(dst, src []byte) { + if len(src) > 0 { + // Assert len(dst) >= len(src) + _ = dst[len(src)-1] + } for len(src) > 0 { if len(c.buffer) == 0 { c.refill() diff --git a/libgo/go/crypto/aes/gcm_s390x.go b/libgo/go/crypto/aes/gcm_s390x.go index ca7f6a778dc..ba6d7ce7665 100644 --- a/libgo/go/crypto/aes/gcm_s390x.go +++ b/libgo/go/crypto/aes/gcm_s390x.go @@ -12,6 +12,11 @@ import ( "errors" ) +// This file contains two implementations of AES-GCM. The first implementation +// (gcmAsm) uses the KMCTR instruction to encrypt using AES in counter mode and +// the KIMD instruction for GHASH. The second implementation (gcmKMA) uses the +// newer KMA instruction which performs both operations. + // gcmCount represents a 16-byte big-endian count value. type gcmCount [16]byte @@ -73,12 +78,16 @@ var _ gcmAble = (*aesCipherAsm)(nil) func (c *aesCipherAsm) NewGCM(nonceSize int) (cipher.AEAD, error) { var hk gcmHashKey c.Encrypt(hk[:], hk[:]) - g := &gcmAsm{ + g := gcmAsm{ block: c, hashKey: hk, nonceSize: nonceSize, } - return g, nil + if hasKMA { + g := gcmKMA{g} + return &g, nil + } + return &g, nil } func (g *gcmAsm) NonceSize() int { @@ -270,3 +279,90 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { g.counterCrypt(out, ciphertext, &counter) return ret, nil } + +// supportsKMA reports whether the message-security-assist 8 facility is available. +// This function call may be expensive so hasKMA should be queried instead. +func supportsKMA() bool + +// hasKMA contains the result of supportsKMA. +var hasKMA = supportsKMA() + +// gcmKMA implements the cipher.AEAD interface using the KMA instruction. It should +// only be used if hasKMA is true. +type gcmKMA struct { + gcmAsm +} + +// flags for the KMA instruction +const ( + kmaHS = 1 << 10 // hash subkey supplied + kmaLAAD = 1 << 9 // last series of additional authenticated data + kmaLPC = 1 << 8 // last series of plaintext or ciphertext blocks + kmaDecrypt = 1 << 7 // decrypt +) + +// kmaGCM executes the encryption or decryption operation given by fn. The tag +// will be calculated and written to tag. cnt should contain the current +// counter state and will be overwritten with the updated counter state. +// TODO(mundaym): could pass in hash subkey +//go:noescape +func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount) + +// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for +// details. +func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { + panic("cipher: message too large for GCM") + } + + ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) + + counter := g.deriveCounter(nonce) + fc := g.block.function | kmaLAAD | kmaLPC + + var tag [gcmTagSize]byte + kmaGCM(fc, g.block.key, out[:len(plaintext)], plaintext, data, &tag, &counter) + copy(out[len(plaintext):], tag[:]) + + return ret +} + +// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface +// for details. +func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { + if len(nonce) != g.nonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + if len(ciphertext) < gcmTagSize { + return nil, errOpen + } + if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize { + return nil, errOpen + } + + tag := ciphertext[len(ciphertext)-gcmTagSize:] + ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] + ret, out := sliceForAppend(dst, len(ciphertext)) + + counter := g.deriveCounter(nonce) + fc := g.block.function | kmaLAAD | kmaLPC | kmaDecrypt + + var expectedTag [gcmTagSize]byte + kmaGCM(fc, g.block.key, out[:len(ciphertext)], ciphertext, data, &expectedTag, &counter) + + if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 { + // The AESNI code decrypts and authenticates concurrently, and + // so overwrites dst in the event of a tag mismatch. That + // behavior is mimicked here in order to be consistent across + // platforms. + for i := range out { + out[i] = 0 + } + return nil, errOpen + } + + return ret, nil +} diff --git a/libgo/go/crypto/cipher/benchmark_test.go b/libgo/go/crypto/cipher/benchmark_test.go index 93c40d0f466..1a3f1bdfaca 100644 --- a/libgo/go/crypto/cipher/benchmark_test.go +++ b/libgo/go/crypto/cipher/benchmark_test.go @@ -10,6 +10,21 @@ import ( "testing" ) +func benchmarkAESGCMSign(b *testing.B, buf []byte) { + 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[:], nil, buf) + } +} + func benchmarkAESGCMSeal(b *testing.B, buf []byte) { b.SetBytes(int64(len(buf))) @@ -54,6 +69,10 @@ func BenchmarkAESGCMOpen1K(b *testing.B) { benchmarkAESGCMOpen(b, make([]byte, 1024)) } +func BenchmarkAESGCMSign8K(b *testing.B) { + benchmarkAESGCMSign(b, make([]byte, 8*1024)) +} + func BenchmarkAESGCMSeal8K(b *testing.B) { benchmarkAESGCMSeal(b, make([]byte, 8*1024)) } diff --git a/libgo/go/crypto/cipher/cipher.go b/libgo/go/crypto/cipher/cipher.go index 531ecad9ac0..31c14d7f914 100644 --- a/libgo/go/crypto/cipher/cipher.go +++ b/libgo/go/crypto/cipher/cipher.go @@ -17,21 +17,26 @@ type Block interface { BlockSize() int // Encrypt encrypts the first block in src into dst. - // Dst and src may point at the same memory. + // Dst and src must overlap entirely or not at all. Encrypt(dst, src []byte) // Decrypt decrypts the first block in src into dst. - // Dst and src may point at the same memory. + // Dst and src must overlap entirely or not at all. Decrypt(dst, src []byte) } // A Stream represents a stream cipher. type Stream interface { // XORKeyStream XORs each byte in the given slice with a byte from the - // cipher's key stream. Dst and src may point to the same memory. + // cipher's key stream. Dst and src must overlap entirely or not at all. + // // If len(dst) < len(src), XORKeyStream should panic. It is acceptable // to pass a dst bigger than src, and in that case, XORKeyStream will // only update dst[:len(src)] and will not touch the rest of dst. + // + // Multiple calls to XORKeyStream behave as if the concatenation of + // the src buffers was passed in a single run. That is, Stream + // maintains state and does not reset at each XORKeyStream call. XORKeyStream(dst, src []byte) } @@ -42,8 +47,16 @@ type BlockMode interface { BlockSize() int // CryptBlocks encrypts or decrypts a number of blocks. The length of - // src must be a multiple of the block size. Dst and src may point to - // the same memory. + // src must be a multiple of the block size. Dst and src must overlap + // entirely or not at all. + // + // If len(dst) < len(src), CryptBlocks should panic. It is acceptable + // to pass a dst bigger than src, and in that case, CryptBlocks will + // only update dst[:len(src)] and will not touch the rest of dst. + // + // Multiple calls to CryptBlocks behave as if the concatenation of + // the src buffers was passed in a single run. That is, BlockMode + // maintains state and does not reset at each CryptBlocks call. CryptBlocks(dst, src []byte) } diff --git a/libgo/go/crypto/cipher/example_test.go b/libgo/go/crypto/cipher/example_test.go index 956cc2eaca6..6e050a9c0da 100644 --- a/libgo/go/crypto/cipher/example_test.go +++ b/libgo/go/crypto/cipher/example_test.go @@ -15,9 +15,12 @@ import ( ) func ExampleNewGCM_encrypt() { - // The key argument should be the AES key, either 16 or 32 bytes - // to select AES-128 or AES-256. - key := []byte("AES256Key-32Characters1234567890") + // Load your secret key from a safe place and reuse it across multiple + // Seal/Open calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). + key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") plaintext := []byte("exampleplaintext") block, err := aes.NewCipher(key) @@ -41,12 +44,14 @@ func ExampleNewGCM_encrypt() { } func ExampleNewGCM_decrypt() { - // The key argument should be the AES key, either 16 or 32 bytes - // to select AES-128 or AES-256. - key := []byte("AES256Key-32Characters1234567890") - ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260") - - nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d") + // Load your secret key from a safe place and reuse it across multiple + // Seal/Open calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). + key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") + ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471") + nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda") block, err := aes.NewCipher(key) if err != nil { @@ -68,8 +73,12 @@ func ExampleNewGCM_decrypt() { } func ExampleNewCBCDecrypter() { - key := []byte("example key 1234") - ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b") block, err := aes.NewCipher(key) if err != nil { @@ -107,7 +116,11 @@ func ExampleNewCBCDecrypter() { } func ExampleNewCBCEncrypter() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") plaintext := []byte("exampleplaintext") // CBC mode works on blocks so plaintexts may need to be padded to the @@ -142,8 +155,12 @@ func ExampleNewCBCEncrypter() { } func ExampleNewCFBDecrypter() { - key := []byte("example key 1234") - ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad") block, err := aes.NewCipher(key) if err != nil { @@ -167,7 +184,11 @@ func ExampleNewCFBDecrypter() { } func ExampleNewCFBEncrypter() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") plaintext := []byte("some plaintext") block, err := aes.NewCipher(key) @@ -189,10 +210,15 @@ func ExampleNewCFBEncrypter() { // It's important to remember that ciphertexts must be authenticated // (i.e. by using crypto/hmac) as well as being encrypted in order to // be secure. + fmt.Printf("%x\n", ciphertext) } func ExampleNewCTR() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") plaintext := []byte("some plaintext") block, err := aes.NewCipher(key) @@ -227,7 +253,11 @@ func ExampleNewCTR() { } func ExampleNewOFB() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") plaintext := []byte("some plaintext") block, err := aes.NewCipher(key) @@ -262,7 +292,11 @@ func ExampleNewOFB() { } func ExampleStreamReader() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") inFile, err := os.Open("encrypted-file") if err != nil { @@ -299,7 +333,11 @@ func ExampleStreamReader() { } func ExampleStreamWriter() { - key := []byte("example key 1234") + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") inFile, err := os.Open("plaintext-file") if err != nil { diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go index 62085aac0fe..28f3ddd6e63 100644 --- a/libgo/go/crypto/cipher/gcm.go +++ b/libgo/go/crypto/cipher/gcm.go @@ -26,7 +26,7 @@ type AEAD interface { // slice. The nonce must be NonceSize() bytes long and unique for all // time, for a given key. // - // The plaintext and dst may alias exactly or not at all. To reuse + // The plaintext and dst must overlap exactly or not at all. To reuse // plaintext's storage for the encrypted output, use plaintext[:0] as dst. Seal(dst, nonce, plaintext, additionalData []byte) []byte @@ -36,7 +36,7 @@ type AEAD interface { // 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. To reuse + // The ciphertext and dst must overlap exactly or not at all. To reuse // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. // // Even if the function fails, the contents of dst, up to its capacity, diff --git a/libgo/go/crypto/cipher/io.go b/libgo/go/crypto/cipher/io.go index 3938c0a4c88..0974ac748e5 100644 --- a/libgo/go/crypto/cipher/io.go +++ b/libgo/go/crypto/cipher/io.go @@ -37,10 +37,8 @@ func (w StreamWriter) Write(src []byte) (n int, err error) { c := make([]byte, len(src)) w.S.XORKeyStream(c, src) n, err = w.W.Write(c) - if n != len(src) { - if err == nil { // should never happen - err = io.ErrShortWrite - } + if n != len(src) && err == nil { // should never happen + err = io.ErrShortWrite } return } diff --git a/libgo/go/crypto/cipher/ofb.go b/libgo/go/crypto/cipher/ofb.go index e86ebcb237e..7b35f8995c8 100644 --- a/libgo/go/crypto/cipher/ofb.go +++ b/libgo/go/crypto/cipher/ofb.go @@ -19,7 +19,7 @@ type ofb struct { func NewOFB(b Block, iv []byte) Stream { blockSize := b.BlockSize() if len(iv) != blockSize { - return nil + panic("cipher.NewOFB: IV length must equal block size") } bufSize := streamBufferSize if bufSize < blockSize { diff --git a/libgo/go/crypto/cipher/xor.go b/libgo/go/crypto/cipher/xor.go index 01ca0a9f086..5b26eace09d 100644 --- a/libgo/go/crypto/cipher/xor.go +++ b/libgo/go/crypto/cipher/xor.go @@ -19,6 +19,11 @@ func fastXORBytes(dst, a, b []byte) int { if len(b) < n { n = len(b) } + if n == 0 { + return 0 + } + // Assert dst has enough space + _ = dst[n-1] w := n / wordSize if w > 0 { @@ -48,8 +53,8 @@ func safeXORBytes(dst, a, b []byte) int { 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. +// xorBytes xors the bytes in a and b. The destination should have enough +// space, otherwise xorBytes will panic. Returns the number of bytes xor'd. func xorBytes(dst, a, b []byte) int { if supportsUnaligned { return fastXORBytes(dst, a, b) diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go index bc0c3e34629..e94585579eb 100644 --- a/libgo/go/crypto/dsa/dsa.go +++ b/libgo/go/crypto/dsa/dsa.go @@ -37,7 +37,7 @@ type PrivateKey struct { // this error must be handled. var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key") -// ParameterSizes is a enumeration of the acceptable bit lengths of the primes +// ParameterSizes is an enumeration of the acceptable bit lengths of the primes // in a set of DSA parameters. See FIPS 186-3, section 4.2. type ParameterSizes int diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index 02848fd5954..755ed284a91 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -49,7 +49,7 @@ type PublicKey struct { X, Y *big.Int } -// PrivateKey represents a ECDSA private key. +// PrivateKey represents an ECDSA private key. type PrivateKey struct { PublicKey D *big.Int @@ -64,12 +64,15 @@ func (priv *PrivateKey) Public() crypto.PublicKey { return &priv.PublicKey } -// Sign signs msg with priv, reading randomness from rand. This method is -// intended to support keys where the private part is kept in, for example, a -// hardware module. Common uses should use the Sign function in this package -// directly. -func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - r, s, err := Sign(rand, priv, msg) +// Sign signs digest with priv, reading randomness from rand. The opts argument +// is not currently used but, in keeping with the crypto.Signer interface, +// should be the hash function used to digest the message. +// +// This method implements crypto.Signer, which is an interface to support keys +// where the private part is kept in, for example, a hardware module. Common +// uses should use the Sign function in this package directly. +func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { + r, s, err := Sign(rand, priv, digest) if err != nil { return nil, err } diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 9546f67c68b..9224a039f3f 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -48,10 +48,13 @@ func BenchmarkSignP256(b *testing.B) { hashed := []byte("testing") priv, _ := GenerateKey(p256, rand.Reader) + b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _, _ = Sign(rand.Reader, priv, hashed) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _, _, _ = Sign(rand.Reader, priv, hashed) + } + }) } func BenchmarkSignP384(b *testing.B) { @@ -60,10 +63,13 @@ func BenchmarkSignP384(b *testing.B) { hashed := []byte("testing") priv, _ := GenerateKey(p384, rand.Reader) + b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _, _ = Sign(rand.Reader, priv, hashed) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _, _, _ = Sign(rand.Reader, priv, hashed) + } + }) } func BenchmarkVerifyP256(b *testing.B) { @@ -73,20 +79,26 @@ func BenchmarkVerifyP256(b *testing.B) { priv, _ := GenerateKey(p256, rand.Reader) r, s, _ := Sign(rand.Reader, priv, hashed) + b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i++ { - Verify(&priv.PublicKey, hashed, r, s) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Verify(&priv.PublicKey, hashed, r, s) + } + }) } func BenchmarkKeyGeneration(b *testing.B) { b.ResetTimer() p256 := elliptic.P256() + b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i++ { - GenerateKey(p256, rand.Reader) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + GenerateKey(p256, rand.Reader) + } + }) } func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) { @@ -331,3 +343,25 @@ func TestNegativeInputs(t *testing.T) { testNegativeInputs(t, elliptic.P384(), "p384") testNegativeInputs(t, elliptic.P521(), "p521") } + +func TestZeroHashSignature(t *testing.T) { + zeroHash := make([]byte, 64) + + for _, curve := range []elliptic.Curve{elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521()} { + privKey, err := GenerateKey(curve, rand.Reader) + if err != nil { + panic(err) + } + + // Sign a hash consisting of all zeros. + r, s, err := Sign(rand.Reader, privKey, zeroHash) + if err != nil { + panic(err) + } + + // Confirm that it can be verified. + if !Verify(&privKey.PublicKey, zeroHash, r, s) { + t.Errorf("zero hash signature verify failed for %T", curve) + } + } +} diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go index d3527243e78..35aacf24e51 100644 --- a/libgo/go/crypto/elliptic/elliptic.go +++ b/libgo/go/crypto/elliptic/elliptic.go @@ -301,7 +301,7 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e return } -// Marshal converts a point into the form specified in section 4.3.6 of ANSI X9.62. +// Marshal converts a point into the uncompressed form specified in section 4.3.6 of ANSI X9.62. func Marshal(curve Curve, x, y *big.Int) []byte { byteLen := (curve.Params().BitSize + 7) >> 3 @@ -316,7 +316,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte { } // Unmarshal converts a point, serialized by Marshal, into an x, y pair. -// It is an error if the point is not on the curve. On error, x = nil. +// It is an error if the point is not in uncompressed form or is not on the curve. +// On error, x = nil. func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { byteLen := (curve.Params().BitSize + 7) >> 3 if len(data) != 1+2*byteLen { @@ -325,10 +326,14 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { if data[0] != 4 { // uncompressed form return } + p := curve.Params().P x = new(big.Int).SetBytes(data[1 : 1+byteLen]) y = new(big.Int).SetBytes(data[1+byteLen:]) + if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 { + return nil, nil + } if !curve.IsOnCurve(x, y) { - x, y = nil, nil + return nil, nil } return } diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index c3e4c17d250..f661359c358 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/crypto/elliptic/elliptic_test.go @@ -455,15 +455,81 @@ func TestInfinity(t *testing.T) { } } +type synthCombinedMult struct { + Curve +} + +func (s synthCombinedMult) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) { + x1, y1 := s.ScalarBaseMult(baseScalar) + x2, y2 := s.ScalarMult(bigX, bigY, scalar) + return s.Add(x1, y1, x2, y2) +} + +func TestCombinedMult(t *testing.T) { + type combinedMult interface { + Curve + CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) + } + + p256, ok := P256().(combinedMult) + if !ok { + p256 = &synthCombinedMult{P256()} + } + + gx := p256.Params().Gx + gy := p256.Params().Gy + + zero := make([]byte, 32) + one := make([]byte, 32) + one[31] = 1 + two := make([]byte, 32) + two[31] = 2 + + // 0×G + 0×G = ∞ + x, y := p256.CombinedMult(gx, gy, zero, zero) + if x.Sign() != 0 || y.Sign() != 0 { + t.Errorf("0×G + 0×G = (%d, %d), should be ∞", x, y) + } + + // 1×G + 0×G = G + x, y = p256.CombinedMult(gx, gy, one, zero) + if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 { + t.Errorf("1×G + 0×G = (%d, %d), should be (%d, %d)", x, y, gx, gy) + } + + // 0×G + 1×G = G + x, y = p256.CombinedMult(gx, gy, zero, one) + if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 { + t.Errorf("0×G + 1×G = (%d, %d), should be (%d, %d)", x, y, gx, gy) + } + + // 1×G + 1×G = 2×G + x, y = p256.CombinedMult(gx, gy, one, one) + ggx, ggy := p256.ScalarBaseMult(two) + if x.Cmp(ggx) != 0 || y.Cmp(ggy) != 0 { + t.Errorf("1×G + 1×G = (%d, %d), should be (%d, %d)", x, y, ggx, ggy) + } + + minusOne := new(big.Int).Sub(p256.Params().N, big.NewInt(1)) + // 1×G + (-1)×G = ∞ + x, y = p256.CombinedMult(gx, gy, one, minusOne.Bytes()) + if x.Sign() != 0 || y.Sign() != 0 { + t.Errorf("1×G + (-1)×G = (%d, %d), should be ∞", x, y) + } +} + func BenchmarkBaseMult(b *testing.B) { b.ResetTimer() p224 := P224() e := p224BaseMultTests[25] k, _ := new(big.Int).SetString(e.k, 10) + b.ReportAllocs() b.StartTimer() - for i := 0; i < b.N; i++ { - p224.ScalarBaseMult(k.Bytes()) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p224.ScalarBaseMult(k.Bytes()) + } + }) } func BenchmarkBaseMultP256(b *testing.B) { @@ -471,10 +537,13 @@ func BenchmarkBaseMultP256(b *testing.B) { p256 := P256() e := p224BaseMultTests[25] k, _ := new(big.Int).SetString(e.k, 10) + b.ReportAllocs() b.StartTimer() - for i := 0; i < b.N; i++ { - p256.ScalarBaseMult(k.Bytes()) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p256.ScalarBaseMult(k.Bytes()) + } + }) } func BenchmarkScalarMultP256(b *testing.B) { @@ -483,10 +552,13 @@ func BenchmarkScalarMultP256(b *testing.B) { _, x, y, _ := GenerateKey(p256, rand.Reader) priv, _, _, _ := GenerateKey(p256, rand.Reader) + b.ReportAllocs() b.StartTimer() - for i := 0; i < b.N; i++ { - p256.ScalarMult(x, y, priv) - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p256.ScalarMult(x, y, priv) + } + }) } func TestMarshal(t *testing.T) { @@ -517,3 +589,42 @@ func TestP224Overflow(t *testing.T) { t.Error("P224 failed to validate a correct point") } } + +// See https://golang.org/issues/20482 +func TestUnmarshalToLargeCoordinates(t *testing.T) { + curve := P256() + p := curve.Params().P + + invalidX, invalidY := make([]byte, 65), make([]byte, 65) + invalidX[0], invalidY[0] = 4, 4 // uncompressed encoding + + // Set x to be greater than curve's parameter P – specifically, to P+5. + // Set y to mod_sqrt(x^3 - 3x + B)) so that (x mod P = 5 , y) is on the + // curve. + x := new(big.Int).Add(p, big.NewInt(5)) + y, _ := new(big.Int).SetString("31468013646237722594854082025316614106172411895747863909393730389177298123724", 10) + + copy(invalidX[1:], x.Bytes()) + copy(invalidX[33:], y.Bytes()) + + if X, Y := Unmarshal(curve, invalidX); X != nil || Y != nil { + t.Errorf("Unmarshal accpets invalid X coordinate") + } + + // This is a point on the curve with a small y value, small enough that we can add p and still be within 32 bytes. + x, _ = new(big.Int).SetString("31931927535157963707678568152204072984517581467226068221761862915403492091210", 10) + y, _ = new(big.Int).SetString("5208467867388784005506817585327037698770365050895731383201516607147", 10) + y.Add(y, p) + + if p.Cmp(y) > 0 || y.BitLen() != 256 { + t.Fatal("y not within expected range") + } + + // marshal + copy(invalidY[1:], x.Bytes()) + copy(invalidY[33:], y.Bytes()) + + if X, Y := Unmarshal(curve, invalidY); X != nil || Y != nil { + t.Errorf("Unmarshal accpets invalid Y coordinate") + } +} diff --git a/libgo/go/crypto/elliptic/p256_amd64.go b/libgo/go/crypto/elliptic/p256_amd64.go index 8f3db0718b3..f108e737e02 100644 --- a/libgo/go/crypto/elliptic/p256_amd64.go +++ b/libgo/go/crypto/elliptic/p256_amd64.go @@ -53,44 +53,62 @@ func (curve p256Curve) Params() *CurveParams { // Functions implemented in p256_asm_amd64.s // Montgomery multiplication modulo P256 +//go:noescape func p256Mul(res, in1, in2 []uint64) // Montgomery square modulo P256 +//go:noescape func p256Sqr(res, in []uint64) // Montgomery multiplication by 1 +//go:noescape func p256FromMont(res, in []uint64) // iff cond == 1 val <- -val +//go:noescape func p256NegCond(val []uint64, cond int) // if cond == 0 res <- b; else res <- a +//go:noescape func p256MovCond(res, a, b []uint64, cond int) // Endianness swap +//go:noescape func p256BigToLittle(res []uint64, in []byte) + +//go:noescape func p256LittleToBig(res []byte, in []uint64) // Constant time table access +//go:noescape func p256Select(point, table []uint64, idx int) + +//go:noescape func p256SelectBase(point, table []uint64, idx int) // Montgomery multiplication modulo Ord(G) +//go:noescape func p256OrdMul(res, in1, in2 []uint64) // Montgomery square modulo Ord(G), repeated n times +//go:noescape func p256OrdSqr(res, in []uint64, n int) // Point add with in2 being affine point // If sign == 1 -> in2 = -in2 // If sel == 0 -> res = in1 // if zero == 0 -> res = in2 +//go:noescape func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int) -// Point add -func p256PointAddAsm(res, in1, in2 []uint64) +// Point add. Returns one if the two input points were equal and zero +// otherwise. (Note that, due to the way that the equations work out, some +// representations of ∞ are considered equal to everything by this function.) +//go:noescape +func p256PointAddAsm(res, in1, in2 []uint64) int // Point double +//go:noescape func p256PointDoubleAsm(res, in []uint64) func (curve p256Curve) Inverse(k *big.Int) *big.Int { @@ -214,9 +232,11 @@ func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []by scalarReversed := make([]uint64, 4) var r1, r2 p256Point p256GetScalar(scalarReversed, baseScalar) + r1IsInfinity := scalarIsZero(scalarReversed) r1.p256BaseMult(scalarReversed) p256GetScalar(scalarReversed, scalar) + r2IsInfinity := scalarIsZero(scalarReversed) fromBig(r2.xyz[0:4], maybeReduceModP(bigX)) fromBig(r2.xyz[4:8], maybeReduceModP(bigY)) p256Mul(r2.xyz[0:4], r2.xyz[0:4], rr[:]) @@ -229,8 +249,15 @@ func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []by r2.xyz[11] = 0x00000000fffffffe r2.p256ScalarMult(scalarReversed) - p256PointAddAsm(r1.xyz[:], r1.xyz[:], r2.xyz[:]) - return r1.p256PointToAffine() + + var sum, double p256Point + pointsEqual := p256PointAddAsm(sum.xyz[:], r1.xyz[:], r2.xyz[:]) + p256PointDoubleAsm(double.xyz[:], r1.xyz[:]) + sum.CopyConditional(&double, pointsEqual) + sum.CopyConditional(&r1, r2IsInfinity) + sum.CopyConditional(&r2, r1IsInfinity) + + return sum.p256PointToAffine() } func (curve p256Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { @@ -261,6 +288,24 @@ func (curve p256Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big return r.p256PointToAffine() } +// uint64IsZero returns 1 if x is zero and zero otherwise. +func uint64IsZero(x uint64) int { + x = ^x + x &= x >> 32 + x &= x >> 16 + x &= x >> 8 + x &= x >> 4 + x &= x >> 2 + x &= x >> 1 + return int(x & 1) +} + +// scalarIsZero returns 1 if scalar represents the zero value, and zero +// otherwise. +func scalarIsZero(scalar []uint64) int { + return uint64IsZero(scalar[0] | scalar[1] | scalar[2] | scalar[3]) +} + func (p *p256Point) p256PointToAffine() (x, y *big.Int) { zInv := make([]uint64, 4) zInvSq := make([]uint64, 4) @@ -282,6 +327,17 @@ func (p *p256Point) p256PointToAffine() (x, y *big.Int) { return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut) } +// CopyConditional copies overwrites p with src if v == 1, and leaves p +// unchanged if v == 0. +func (p *p256Point) CopyConditional(src *p256Point, v int) { + pMask := uint64(v) - 1 + srcMask := ^pMask + + for i, n := range p.xyz { + p.xyz[i] = (n & pMask) | (src.xyz[i] & srcMask) + } +} + // p256Inverse sets out to in^-1 mod p. func p256Inverse(out, in []uint64) { var stack [6 * 4]uint64 diff --git a/libgo/go/crypto/elliptic/p256_s390x.go b/libgo/go/crypto/elliptic/p256_s390x.go index 5f99e71e5d6..43e19e93274 100644 --- a/libgo/go/crypto/elliptic/p256_s390x.go +++ b/libgo/go/crypto/elliptic/p256_s390x.go @@ -8,6 +8,7 @@ package elliptic import ( + "crypto/subtle" "math/big" ) @@ -50,6 +51,8 @@ func (curve p256CurveFast) Params() *CurveParams { // Functions implemented in p256_asm_s390x.s // Montgomery multiplication modulo P256 +// +//go:noescape func p256MulAsm(res, in1, in2 []byte) // Montgomery square modulo P256 @@ -58,19 +61,31 @@ func p256Sqr(res, in []byte) { } // Montgomery multiplication by 1 +// +//go:noescape func p256FromMont(res, in []byte) // iff cond == 1 val <- -val +// +//go:noescape func p256NegCond(val *p256Point, cond int) // if cond == 0 res <- b; else res <- a +// +//go:noescape func p256MovCond(res, a, b *p256Point, cond int) // Constant time table access +// +//go:noescape func p256Select(point *p256Point, table []p256Point, idx int) + +//go:noescape func p256SelectBase(point *p256Point, table []p256Point, idx int) // Montgomery multiplication modulo Ord(G) +// +//go:noescape func p256OrdMul(res, in1, in2 []byte) // Montgomery square modulo Ord(G), repeated n times @@ -85,10 +100,16 @@ func p256OrdSqr(res, in []byte, n int) { // If sign == 1 -> P2 = -P2 // If sel == 0 -> P3 = P1 // if zero == 0 -> P3 = P2 +// +//go:noescape func p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int) // Point add -func p256PointAddAsm(P3, P1, P2 *p256Point) +// +//go:noescape +func p256PointAddAsm(P3, P1, P2 *p256Point) int + +//go:noescape func p256PointDoubleAsm(P3, P1 *p256Point) func (curve p256CurveFast) Inverse(k *big.Int) *big.Int { @@ -203,7 +224,9 @@ func maybeReduceModP(in *big.Int) *big.Int { func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) { var r1, r2 p256Point - r1.p256BaseMult(p256GetMultiplier(baseScalar)) + scalarReduced := p256GetMultiplier(baseScalar) + r1IsInfinity := scalarIsZero(scalarReduced) + r1.p256BaseMult(scalarReduced) copy(r2.x[:], fromBig(maybeReduceModP(bigX))) copy(r2.y[:], fromBig(maybeReduceModP(bigY))) @@ -211,9 +234,17 @@ func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar p256MulAsm(r2.x[:], r2.x[:], rr[:]) p256MulAsm(r2.y[:], r2.y[:], rr[:]) + scalarReduced = p256GetMultiplier(scalar) + r2IsInfinity := scalarIsZero(scalarReduced) r2.p256ScalarMult(p256GetMultiplier(scalar)) - p256PointAddAsm(&r1, &r1, &r2) - return r1.p256PointToAffine() + + var sum, double p256Point + pointsEqual := p256PointAddAsm(&sum, &r1, &r2) + p256PointDoubleAsm(&double, &r1) + p256MovCond(&sum, &double, &sum, pointsEqual) + p256MovCond(&sum, &r1, &sum, r2IsInfinity) + p256MovCond(&sum, &r2, &sum, r1IsInfinity) + return sum.p256PointToAffine() } func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) { @@ -233,6 +264,16 @@ func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y return r.p256PointToAffine() } +// scalarIsZero returns 1 if scalar represents the zero value, and zero +// otherwise. +func scalarIsZero(scalar []byte) int { + b := byte(0) + for _, s := range scalar { + b |= s + } + return subtle.ConstantTimeByteEq(b, 0) +} + func (p *p256Point) p256PointToAffine() (x, y *big.Int) { zInv := make([]byte, 32) zInvSq := make([]byte, 32) diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go index 9ef9c448ee2..3c8e727bc8c 100644 --- a/libgo/go/crypto/hmac/hmac.go +++ b/libgo/go/crypto/hmac/hmac.go @@ -64,6 +64,9 @@ func (h *hmac) Reset() { } // New returns a new HMAC hash using the given hash.Hash type and key. +// Note that unlike other hash implementations in the standard library, +// the returned Hash does not implement encoding.BinaryMarshaler +// or encoding.BinaryUnmarshaler. func New(h func() hash.Hash, key []byte) hash.Hash { hm := new(hmac) hm.outer = h() diff --git a/libgo/go/crypto/issue21104_test.go b/libgo/go/crypto/issue21104_test.go new file mode 100644 index 00000000000..b4276df4e11 --- /dev/null +++ b/libgo/go/crypto/issue21104_test.go @@ -0,0 +1,61 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rc4" + "testing" +) + +func TestRC4OutOfBoundsWrite(t *testing.T) { + // This cipherText is encrypted "0123456789" + cipherText := []byte{238, 41, 187, 114, 151, 2, 107, 13, 178, 63} + cipher, err := rc4.NewCipher([]byte{0}) + if err != nil { + panic(err) + } + test(t, "RC4", cipherText, cipher.XORKeyStream) +} +func TestCTROutOfBoundsWrite(t *testing.T) { + testBlock(t, "CTR", cipher.NewCTR) +} +func TestOFBOutOfBoundsWrite(t *testing.T) { + testBlock(t, "OFB", cipher.NewOFB) +} +func TestCFBEncryptOutOfBoundsWrite(t *testing.T) { + testBlock(t, "CFB Encrypt", cipher.NewCFBEncrypter) +} +func TestCFBDecryptOutOfBoundsWrite(t *testing.T) { + testBlock(t, "CFB Decrypt", cipher.NewCFBDecrypter) +} +func testBlock(t *testing.T, name string, newCipher func(cipher.Block, []byte) cipher.Stream) { + // This cipherText is encrypted "0123456789" + cipherText := []byte{86, 216, 121, 231, 219, 191, 26, 12, 176, 117} + var iv, key [16]byte + block, err := aes.NewCipher(key[:]) + if err != nil { + panic(err) + } + stream := newCipher(block, iv[:]) + test(t, name, cipherText, stream.XORKeyStream) +} +func test(t *testing.T, name string, cipherText []byte, xor func([]byte, []byte)) { + want := "abcdefghij" + plainText := []byte(want) + shorterLen := len(cipherText) / 2 + defer func() { + err := recover() + if err == nil { + t.Errorf("%v XORKeyStream expected to panic on len(dst) < len(src), but didn't", name) + } + const plain = "0123456789" + if plainText[shorterLen] == plain[shorterLen] { + t.Errorf("%v XORKeyStream did out of bounds write, want %v, got %v", name, want, string(plainText)) + } + }() + xor(plainText[:shorterLen], cipherText) +} diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go index b682f008942..7aeee603f70 100644 --- a/libgo/go/crypto/md5/md5.go +++ b/libgo/go/crypto/md5/md5.go @@ -12,6 +12,7 @@ package md5 import ( "crypto" + "errors" "hash" ) @@ -50,7 +51,82 @@ func (d *digest) Reset() { d.len = 0 } -// New returns a new hash.Hash computing the MD5 checksum. +const ( + magic = "md5\x01" + marshaledSize = len(magic) + 4*4 + chunk + 8 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, d.s[0]) + b = appendUint32(b, d.s[1]) + b = appendUint32(b, d.s[2]) + b = appendUint32(b, d.s[3]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.len) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/md5: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/md5: invalid hash state size") + } + b = b[len(magic):] + b, d.s[0] = consumeUint32(b) + b, d.s[1] = consumeUint32(b) + b, d.s[2] = consumeUint32(b) + b, d.s[3] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, d.len = consumeUint64(b) + d.nx = int(d.len) % chunk + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + a := [8]byte{ + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + _ = b[7] + x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + _ = b[3] + x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + return b[4:], x +} + +// New returns a new hash.Hash computing the MD5 checksum. The Hash also +// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. func New() hash.Hash { d := new(digest) d.Reset() diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go index e7faf4961e4..64a62e47305 100644 --- a/libgo/go/crypto/md5/md5_test.go +++ b/libgo/go/crypto/md5/md5_test.go @@ -5,7 +5,9 @@ package md5 import ( + "bytes" "crypto/rand" + "encoding" "fmt" "io" "testing" @@ -13,42 +15,43 @@ import ( ) type md5Test struct { - out string - in string + out string + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []md5Test{ - {"d41d8cd98f00b204e9800998ecf8427e", ""}, - {"0cc175b9c0f1b6a831c399e269772661", "a"}, - {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"}, - {"900150983cd24fb0d6963f7d28e17f72", "abc"}, - {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"}, - {"ab56b4d92b40713acc5af89985d4b786", "abcde"}, - {"e80b5017098950fc58aad83c8c14978e", "abcdef"}, - {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"}, - {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"}, - {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"}, - {"a925576942e94b2ef57a066101b48876", "abcdefghij"}, - {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."}, - {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."}, - {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."}, - {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"}, - {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."}, - {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."}, - {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."}, - {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"}, - {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"}, - {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."}, - {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."}, - {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."}, - {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"}, - {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"}, + {"d41d8cd98f00b204e9800998ecf8427e", "", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, + {"0cc175b9c0f1b6a831c399e269772661", "a", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, + {"187ef4436122d1cc2f40dc2b92f0eba0", "ab", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tva\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"}, + {"900150983cd24fb0d6963f7d28e17f72", "abc", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tva\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"}, + {"e2fc714c4727ee9395f324cd2e7f331f", "abcd", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"}, + {"ab56b4d92b40713acc5af89985d4b786", "abcde", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"}, + {"e80b5017098950fc58aad83c8c14978e", "abcdef", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"}, + {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"}, + {"e8dc4081b13434b45189a720b77b6818", "abcdefgh", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"}, + {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"}, + {"a925576942e94b2ef57a066101b48876", "abcdefghij", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvabcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"}, + {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvDiscard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"}, + {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvHe who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvI wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"}, + {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvFree! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvThe days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"}, + {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvNepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"}, + {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvFor every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"}, + {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvHis money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvThere is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"}, + {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvIt's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"}, + {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102Tvsize: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"}, + {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvThe major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"}, + {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvGive me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"}, + {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvIf the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"}, + {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvIt's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"}, + {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway.", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvYou remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""}, + {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvC is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"}, + {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvEven if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"}, + {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "md5\x01\xa7\xc9\x18\x9b\xc3E\x18\xf2\x82\xfd\xf3$\x9d_\v\nem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"}, + {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick", "md5\x01gE#\x01\xefÍ«\x89\x98\xba\xdc\xfe\x102TvHow can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, } func TestGolden(t *testing.T) { @@ -82,6 +85,38 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + for _, g := range golden { + h := New() + h2 := New() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("md5(%q) state = %q, want %q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) { + t.Errorf("md5(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2) + } + } +} + func TestLarge(t *testing.T) { const N = 10000 ok := "2bb571599a4180e1d542f76904adc3df" // md5sum of "0123456789" * 1000 diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go index 8a4c7572363..dbd038cc582 100644 --- a/libgo/go/crypto/rand/rand_linux.go +++ b/libgo/go/crypto/rand/rand_linux.go @@ -9,7 +9,30 @@ import ( ) func init() { - altGetRandom = getRandomLinux + altGetRandom = batched(getRandomLinux, maxGetRandomRead) +} + +// maxGetRandomRead is the maximum number of bytes to ask for in one call to the +// getrandom() syscall. In linux at most 2^25-1 bytes will be returned per call. +// From the manpage +// +// * When reading from the urandom source, a maximum of 33554431 bytes +// is returned by a single call to getrandom() on systems where int +// has a size of 32 bits. +const maxGetRandomRead = (1 << 25) - 1 + +// batched returns a function that calls f to populate a []byte by chunking it +// into subslices of, at most, readMax bytes. +func batched(f func([]byte) bool, readMax int) func([]byte) bool { + return func(buf []byte) bool { + for len(buf) > readMax { + if !f(buf[:readMax]) { + return false + } + buf = buf[readMax:] + } + return len(buf) == 0 || f(buf) + } } // If the kernel is too old (before 3.17) to support the getrandom syscall(), diff --git a/libgo/go/crypto/rand/rand_linux_test.go b/libgo/go/crypto/rand/rand_linux_test.go new file mode 100644 index 00000000000..77b7b6ebd7a --- /dev/null +++ b/libgo/go/crypto/rand/rand_linux_test.go @@ -0,0 +1,42 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import ( + "bytes" + "testing" +) + +func TestBatched(t *testing.T) { + fillBatched := batched(func(p []byte) bool { + for i := range p { + p[i] = byte(i) + } + return true + }, 5) + + p := make([]byte, 13) + if !fillBatched(p) { + t.Fatal("batched function returned false") + } + expected := []byte{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2} + if !bytes.Equal(expected, p) { + t.Errorf("incorrect batch result: got %x, want %x", p, expected) + } +} + +func TestBatchedError(t *testing.T) { + b := batched(func(p []byte) bool { return false }, 5) + if b(make([]byte, 13)) { + t.Fatal("batched function should have returned false") + } +} + +func TestBatchedEmpty(t *testing.T) { + b := batched(func(p []byte) bool { return false }, 5) + if !b(make([]byte, 0)) { + t.Fatal("empty slice should always return true") + } +} diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go index 772af0e7e0d..8274325c81a 100644 --- a/libgo/go/crypto/rc4/rc4.go +++ b/libgo/go/crypto/rc4/rc4.go @@ -52,8 +52,7 @@ func (c *Cipher) Reset() { } // 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. +// key stream. Dst and src must overlap entirely or not at all. // // This is the pure Go version. rc4_{amd64,386,arm}* contain assembly // implementations. This is here for tests and to prevent bitrot. diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go index 687ea237fcd..aea1939597a 100644 --- a/libgo/go/crypto/rc4/rc4_asm.go +++ b/libgo/go/crypto/rc4/rc4_asm.go @@ -11,10 +11,12 @@ package rc4 func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) // 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. +// Dst and src must overlap entirely or not at all. func (c *Cipher) XORKeyStream(dst, src []byte) { if len(src) == 0 { return } + // Assert len(dst) >= len(src) + _ = dst[len(src)-1] xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j) } diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go index bf56b51db9a..d20dbb14a38 100644 --- a/libgo/go/crypto/rc4/rc4_ref.go +++ b/libgo/go/crypto/rc4/rc4_ref.go @@ -7,7 +7,7 @@ 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. +// Dst and src must overlap entirely or not at all. func (c *Cipher) XORKeyStream(dst, src []byte) { c.xorKeyStreamGeneric(dst, src) } diff --git a/libgo/go/crypto/rsa/pss.go b/libgo/go/crypto/rsa/pss.go index 1ba194a4ad2..75558a92cf1 100644 --- a/libgo/go/crypto/rsa/pss.go +++ b/libgo/go/crypto/rsa/pss.go @@ -6,7 +6,7 @@ package rsa // 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 +// [1] https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf import ( "bytes" diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index 1de4fcb473e..0faca43e430 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/crypto/rsa/rsa.go @@ -92,17 +92,19 @@ func (priv *PrivateKey) Public() crypto.PublicKey { return &priv.PublicKey } -// Sign signs msg with priv, reading randomness from rand. If opts is a +// Sign signs digest with priv, reading randomness from rand. If opts is a // *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will -// be used. This method is intended to support keys where the private part is -// kept in, for example, a hardware module. Common uses should use the Sign* -// functions in this package. -func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { +// be used. +// +// This method implements crypto.Signer, which is an interface to support keys +// where the private part is kept in, for example, a hardware module. Common +// uses should use the Sign* functions in this package directly. +func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { if pssOpts, ok := opts.(*PSSOptions); ok { - return SignPSS(rand, priv, pssOpts.Hash, msg, pssOpts) + return SignPSS(rand, priv, pssOpts.Hash, digest, pssOpts) } - return SignPKCS1v15(rand, priv, opts.HashFunc(), msg) + return SignPKCS1v15(rand, priv, opts.HashFunc(), digest) } // Decrypt decrypts ciphertext with priv. If opts is nil or of type @@ -424,8 +426,7 @@ var ErrVerification = errors.New("crypto/rsa: verification error") func modInverse(a, n *big.Int) (ia *big.Int, ok bool) { g := new(big.Int) x := new(big.Int) - y := new(big.Int) - g.GCD(x, y, a, n) + g.GCD(x, nil, a, n) if g.Cmp(bigOne) != 0 { // In this case, a and n aren't coprime and we cannot calculate // the inverse. This happens because the values of n are nearly diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go index 6b1721470b2..ae4896fc328 100644 --- a/libgo/go/crypto/sha1/sha1.go +++ b/libgo/go/crypto/sha1/sha1.go @@ -10,6 +10,7 @@ package sha1 import ( "crypto" + "errors" "hash" ) @@ -40,6 +41,69 @@ type digest struct { len uint64 } +const ( + magic = "sha\x01" + marshaledSize = len(magic) + 5*4 + chunk + 8 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.len) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/sha1: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/sha1: invalid hash state size") + } + b = b[len(magic):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, d.len = consumeUint64(b) + d.nx = int(d.len) % chunk + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + putUint64(a[:], x) + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + putUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + _ = b[7] + x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + _ = b[3] + x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + return b[4:], x +} + func (d *digest) Reset() { d.h[0] = init0 d.h[1] = init1 @@ -50,7 +114,9 @@ func (d *digest) Reset() { d.len = 0 } -// New returns a new hash.Hash computing the SHA1 checksum. +// New returns a new hash.Hash computing the SHA1 checksum. The Hash also +// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. func New() hash.Hash { d := new(digest) d.Reset() @@ -104,9 +170,7 @@ func (d *digest) checkSum() [Size]byte { // Length in bits. len <<= 3 - for i := uint(0); i < 8; i++ { - tmp[i] = byte(len >> (56 - 8*i)) - } + putUint64(tmp[:], len) d.Write(tmp[0:8]) if d.nx != 0 { @@ -114,12 +178,12 @@ func (d *digest) checkSum() [Size]byte { } var digest [Size]byte - for i, s := range d.h { - digest[i*4] = byte(s >> 24) - digest[i*4+1] = byte(s >> 16) - digest[i*4+2] = byte(s >> 8) - digest[i*4+3] = byte(s) - } + + putUint32(digest[0:], d.h[0]) + putUint32(digest[4:], d.h[1]) + putUint32(digest[8:], d.h[2]) + putUint32(digest[12:], d.h[3]) + putUint32(digest[16:], d.h[4]) return digest } @@ -199,3 +263,23 @@ func Sum(data []byte) [Size]byte { d.Write(data) return d.checkSum() } + +func putUint64(x []byte, s uint64) { + _ = x[7] + x[0] = byte(s >> 56) + x[1] = byte(s >> 48) + x[2] = byte(s >> 40) + x[3] = byte(s >> 32) + x[4] = byte(s >> 24) + x[5] = byte(s >> 16) + x[6] = byte(s >> 8) + x[7] = byte(s) +} + +func putUint32(x []byte, s uint32) { + _ = x[3] + x[0] = byte(s >> 24) + x[1] = byte(s >> 16) + x[2] = byte(s >> 8) + x[3] = byte(s) +} diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go index faa9916bc06..4f229262adb 100644 --- a/libgo/go/crypto/sha1/sha1_test.go +++ b/libgo/go/crypto/sha1/sha1_test.go @@ -7,50 +7,53 @@ package sha1 import ( + "bytes" "crypto/rand" + "encoding" "fmt" "io" "testing" ) type sha1Test struct { - out string - in string + out string + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []sha1Test{ - {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"}, - {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, - {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, - {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"}, - {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, - {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"}, - {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"}, - {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"}, - {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"}, - {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"}, - {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"}, - {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"}, - {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."}, - {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."}, - {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."}, - {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"}, - {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."}, - {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."}, - {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."}, - {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"}, - {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"}, - {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."}, - {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."}, - {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."}, - {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"}, - {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"}, + {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", "sha\x01\v\xa0)I\xdeq(8h\x9ev\xe5\x88[\xf8\x81\x17\xba4Daaaaaaaaaaaaaaaaaaaaaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96"}, + {"da39a3ee5e6b4b0d3255bfef95601890afd80709", "", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, + {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, + {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"}, + {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"}, + {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"}, + {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"}, + {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"}, + {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"}, + {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"}, + {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"}, + {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"}, + {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"}, + {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"}, + {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"}, + {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"}, + {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"}, + {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, + {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"}, + {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"}, + {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"}, + {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"}, + {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"}, + {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"}, + {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"}, + {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""}, + {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"}, + {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"}, + {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "sha\x01x}\xf4\r\xeb\xf2\x10\x87\xe8[\xb2JA$D\xb7\u063ax8em\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"}, + {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"}, } func TestGolden(t *testing.T) { @@ -87,6 +90,40 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + h := New() + h2 := New() + for _, g := range golden { + h.Reset() + h2.Reset() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("sha1(%q) state = %+q, want %+q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) { + t.Errorf("sha1(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2) + } + } +} + func TestSize(t *testing.T) { c := New() if got := c.Size(); got != Size { diff --git a/libgo/go/crypto/sha1/sha1block_arm64.go b/libgo/go/crypto/sha1/sha1block_arm64.go new file mode 100644 index 00000000000..9e944392165 --- /dev/null +++ b/libgo/go/crypto/sha1/sha1block_arm64.go @@ -0,0 +1,30 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package sha1 + +import "internal/cpu" + +var k = []uint32{ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6, +} + +var hasSHA1 = cpu.ARM64.HasSHA1 + +//go:noescape +func sha1block(h []uint32, p []byte, k []uint32) + +func block(dig *digest, p []byte) { + if !hasSHA1 { + blockGeneric(dig, p) + } else { + h := dig.h[:] + sha1block(h, p, k) + } +} diff --git a/libgo/go/crypto/sha1/sha1block_generic.go b/libgo/go/crypto/sha1/sha1block_generic.go index e7515c915a7..b14c42cae43 100644 --- a/libgo/go/crypto/sha1/sha1block_generic.go +++ b/libgo/go/crypto/sha1/sha1block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -build !amd64,!amd64p32,!386,!arm,!s390x +// -build !amd64,!amd64p32,!386,!arm,!s390x,!arm64 package sha1 diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go index 74b05b92d77..b8ddaf43bbb 100644 --- a/libgo/go/crypto/sha256/sha256.go +++ b/libgo/go/crypto/sha256/sha256.go @@ -8,6 +8,7 @@ package sha256 import ( "crypto" + "errors" "hash" ) @@ -54,6 +55,92 @@ type digest struct { is224 bool // mark if this digest is SHA-224 } +const ( + magic224 = "sha\x02" + magic256 = "sha\x03" + marshaledSize = len(magic256) + 8*4 + chunk + 8 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + if d.is224 { + b = append(b, magic224...) + } else { + b = append(b, magic256...) + } + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = appendUint32(b, d.h[5]) + b = appendUint32(b, d.h[6]) + b = appendUint32(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.len) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) { + return errors.New("crypto/sha256: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/sha256: invalid hash state size") + } + b = b[len(magic224):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b, d.h[5] = consumeUint32(b) + b, d.h[6] = consumeUint32(b) + b, d.h[7] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, d.len = consumeUint64(b) + d.nx = int(d.len) % chunk + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + a := [8]byte{ + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + _ = b[7] + x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + _ = b[3] + x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + return b[4:], x +} + func (d *digest) Reset() { if !d.is224 { d.h[0] = init0 @@ -78,7 +165,10 @@ func (d *digest) Reset() { d.len = 0 } -// New returns a new hash.Hash computing the SHA256 checksum. +// New returns a new hash.Hash computing the SHA256 checksum. The Hash +// also implements encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler to marshal and unmarshal the internal +// state of the hash. func New() hash.Hash { d := new(digest) d.Reset() diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go index 279cf5ad407..cd402864e52 100644 --- a/libgo/go/crypto/sha256/sha256_test.go +++ b/libgo/go/crypto/sha256/sha256_test.go @@ -7,83 +7,87 @@ package sha256 import ( + "bytes" "crypto/rand" + "encoding" "fmt" + "hash" "io" "testing" ) type sha256Test struct { - out string - in string + out string + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []sha256Test{ - {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, - {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"}, - {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"}, - {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, - {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"}, - {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"}, - {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"}, - {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"}, - {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"}, - {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"}, - {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"}, - {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."}, - {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."}, - {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."}, - {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"}, - {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."}, - {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."}, - {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."}, - {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"}, - {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"}, - {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."}, - {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."}, - {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."}, - {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"}, - {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"}, + {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "", "sha\x03j\t\xe6g\xbbg\xae\x85> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + _ = b[7] + x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return b[8:], x +} + // New returns a new hash.Hash computing the SHA-512 checksum. func New() hash.Hash { d := &digest{function: crypto.SHA512} diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go index a3a136a19f8..4423cf5f189 100644 --- a/libgo/go/crypto/sha512/sha512_test.go +++ b/libgo/go/crypto/sha512/sha512_test.go @@ -7,7 +7,9 @@ package sha512 import ( + "bytes" "crypto/rand" + "encoding" "encoding/hex" "hash" "io" @@ -15,230 +17,640 @@ import ( ) type sha512Test struct { - in string - out224 string - out256 string - out384 string - out512 string + out string + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } -var golden = []sha512Test{ +var golden224 = []sha512Test{ { - "", "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4", + "", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", + "a", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5", + "ab", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa", + "abc", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534", + "abcd", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515", + "abcde", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8", + "abcdef", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf", + "abcdefg", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab", + "abcdefgh", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539", + "abcdefghi", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116", + "abcdefghij", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05", + }, + { + "4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac", + "Discard medicine more than two years old.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14", + }, + { + "cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e", + "He who has a shady past knows that nice guys finish last.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b", + "I wouldn't marry him with a ten foot pole.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15", + }, + { + "981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904", + "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99", + "The days of the digital watch are numbered. -Tom Stoppard", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d", + }, + { + "6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f", + "Nepal premier won't resign.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r", + }, + { + "7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35", + "For every action there is an equal and opposite government program.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!", + }, + { + "45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378", + "His money is twice tainted: 'taint yours and 'taint mine.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880", + "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993", + "It's a tiny change to the code and not completely disgusting. - Bob Manchek", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%", + }, + { + "6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881", + "size: a.out: bad magic", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f", + }, + { + "a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f", + "The major problem is with sendmail. -Mark Horton", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18", + }, + { + "76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1", + "Give me a rock, paper and scissors and I will move the world. CCFestoon", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$", + }, + { + "4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c", + "If the enemy is within range, then so are you.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17", + }, + { + "6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8", + "It's well we cannot hear the screams/That we create in others' dreams.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#", + }, + { + "6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e", + "You remind me of a TV show, but that's all right: I watch it anyway.", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"", + }, + { + "db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938", + "C is as portable as Stonehedge!!", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", + }, + { + "05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0", + "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d", + "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B", + }, + { + "e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c", + "How can you write a big system without C++? -Paul Glick", + "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, +} + +var golden256 = []sha512Test{ + { "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", + "", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", + "a", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14", + "ab", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", + "abc", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9", + "abcd", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363", + "abcde", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84", + "abcdef", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3", + "abcdefg", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe", + "abcdefgh", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f", + "abcdefghi", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d", + "abcdefghij", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05", + }, + { + "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b", + "Discard medicine more than two years old.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14", + }, + { + "25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b", + "He who has a shady past knows that nice guys finish last.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65", + "I wouldn't marry him with a ten foot pole.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15", + }, + { + "839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8", + "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e", + "The days of the digital watch are numbered. -Tom Stoppard", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d", + }, + { + "9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2", + "Nepal premier won't resign.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r", + }, + { + "08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9", + "For every action there is an equal and opposite government program.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!", + }, + { + "4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e", + "His money is twice tainted: 'taint yours and 'taint mine.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b", + "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944", + "It's a tiny change to the code and not completely disgusting. - Bob Manchek", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%", + }, + { + "d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443", + "size: a.out: bad magic", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f", + }, + { + "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607", + "The major problem is with sendmail. -Mark Horton", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18", + }, + { + "5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0", + "Give me a rock, paper and scissors and I will move the world. CCFestoon", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$", + }, + { + "1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a", + "If the enemy is within range, then so are you.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17", + }, + { + "105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51", + "It's well we cannot hear the screams/That we create in others' dreams.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#", + }, + { + "74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3", + "You remind me of a TV show, but that's all right: I watch it anyway.", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"", + }, + { + "50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6", + "C is as portable as Stonehedge!!", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", + }, + { + "a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0", + "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69", + "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B", + }, + { + "3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485", + "How can you write a big system without C++? -Paul Glick", + "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, +} + +var golden384 = []sha512Test{ + { "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + "", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", + "a", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + }, + { + "c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", + "ab", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + "abc", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + }, + { + "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", + "abcd", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", + "abcde", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", + }, + { + "c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", + "abcdef", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", + "abcdefg", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", + }, + { + "9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", + "abcdefgh", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", + "abcdefghi", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", + }, + { + "a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", + "abcdefghij", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05", + }, + { + "86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", + "Discard medicine more than two years old.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14", + }, + { + "ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", + "He who has a shady past knows that nice guys finish last.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", + "I wouldn't marry him with a ten foot pole.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15", + }, + { + "e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", + "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", + "The days of the digital watch are numbered. -Tom Stoppard", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d", + }, + { + "a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", + "Nepal premier won't resign.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r", + }, + { + "5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", + "For every action there is an equal and opposite government program.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!", + }, + { + "ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", + "His money is twice tainted: 'taint yours and 'taint mine.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, + { + "722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", + "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", + "It's a tiny change to the code and not completely disgusting. - Bob Manchek", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%", + }, + { + "1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", + "size: a.out: bad magic", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f", + }, + { + "5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", + "The major problem is with sendmail. -Mark Horton", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18", + }, + { + "5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", + "Give me a rock, paper and scissors and I will move the world. CCFestoon", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$", + }, + { + "1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", + "If the enemy is within range, then so are you.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17", + }, + { + "76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", + "It's well we cannot hear the screams/That we create in others' dreams.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#", + }, + { + "12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", + "You remind me of a TV show, but that's all right: I watch it anyway.", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"", + }, + { + "0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", + "C is as portable as Stonehedge!!", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", + }, + { + "bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", + "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", + }, + { + "b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", + "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B", + }, + { + "1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", + "How can you write a big system without C++? -Paul Glick", + "sha\x04Ë»\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", + }, +} + +var golden512 = []sha512Test{ + { "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", }, { - "a", - "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", - "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", - "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "a", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", }, { - "ab", - "b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5", - "22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14", - "c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", + "ab", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!ya\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", }, { - "abc", - "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa", - "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", - "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + "abc", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!ya\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", }, { - "abcd", - "0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534", - "d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9", - "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", + "abcd", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", }, { - "abcde", - "880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515", - "de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363", - "4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", + "abcde", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02", }, { - "abcdef", - "236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8", - "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84", - "c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", + "abcdef", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", }, { - "abcdefg", - "4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf", - "a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3", - "9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", + "abcdefg", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", }, { - "abcdefgh", - "792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab", - "a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe", - "9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", + "abcdefgh", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", }, { - "abcdefghi", - "56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539", - "b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f", - "ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", + "abcdefghi", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04", }, { - "abcdefghij", - "f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116", - "550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d", - "a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", + "abcdefghij", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05", }, { - "Discard medicine more than two years old.", - "4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac", - "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b", - "86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", + "Discard medicine more than two years old.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yDiscard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14", }, { - "He who has a shady past knows that nice guys finish last.", - "cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e", - "25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b", - "ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", + "He who has a shady past knows that nice guys finish last.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yHe who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", }, { - "I wouldn't marry him with a ten foot pole.", - "6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b", - "698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65", - "40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", + "I wouldn't marry him with a ten foot pole.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yI wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15", }, { - "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", - "981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904", - "839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8", - "e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", + "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yFree! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", }, { - "The days of the digital watch are numbered. -Tom Stoppard", - "e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99", - "5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e", - "c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", + "The days of the digital watch are numbered. -Tom Stoppard", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d", }, { - "Nepal premier won't resign.", - "6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f", - "9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2", - "a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", + "Nepal premier won't resign.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yNepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r", }, { - "For every action there is an equal and opposite government program.", - "7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35", - "08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9", - "5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", + "For every action there is an equal and opposite government program.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yFor every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!", }, { - "His money is twice tainted: 'taint yours and 'taint mine.", - "45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378", - "4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e", - "ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", + "His money is twice tainted: 'taint yours and 'taint mine.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yHis money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", }, { - "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", - "51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880", - "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b", - "722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", + "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yThere is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", }, { - "It's a tiny change to the code and not completely disgusting. - Bob Manchek", - "3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993", - "7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944", - "dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", + "It's a tiny change to the code and not completely disgusting. - Bob Manchek", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yIt's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%", }, { - "size: a.out: bad magic", - "6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881", - "d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443", - "1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", + "size: a.out: bad magic", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!ysize: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f", }, { - "The major problem is with sendmail. -Mark Horton", - "a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f", - "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607", - "5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", + "The major problem is with sendmail. -Mark Horton", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18", }, { - "Give me a rock, paper and scissors and I will move the world. CCFestoon", - "76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1", - "5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0", - "5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", + "Give me a rock, paper and scissors and I will move the world. CCFestoon", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yGive me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$", }, { - "If the enemy is within range, then so are you.", - "4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c", - "1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a", - "1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", + "If the enemy is within range, then so are you.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yIf the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17", }, { - "It's well we cannot hear the screams/That we create in others' dreams.", - "6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8", - "105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51", - "76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", + "It's well we cannot hear the screams/That we create in others' dreams.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yIt's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#", }, { - "You remind me of a TV show, but that's all right: I watch it anyway.", - "6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e", - "74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3", - "12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", + "You remind me of a TV show, but that's all right: I watch it anyway.", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yYou remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"", }, { - "C is as portable as Stonehedge!!", - "db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938", - "50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6", - "0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", + "C is as portable as Stonehedge!!", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yC is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", }, { - "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", - "05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0", - "a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0", - "bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", + "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yEven if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,", }, { - "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", - "3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d", - "688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69", - "b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", + "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B", }, { - "How can you write a big system without C++? -Paul Glick", - "e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c", - "3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485", - "1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", + "How can you write a big system without C++? -Paul Glick", + "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;l\x1f\x1f\x83Ù«\xfbA\xbdk[\xe0\xcd\x19\x13~!yHow can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c", }, } @@ -265,17 +677,119 @@ func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, diges } func TestGolden(t *testing.T) { - for _, test := range golden { - in := []byte(test.in) - - sum224 := Sum512_224(in) - sum256 := Sum512_256(in) - sum384 := Sum384(in) - sum512 := Sum512(in) - testHash(t, "SHA512/224", test.in, test.out224, sum224[:], New512_224()) - testHash(t, "SHA512/256", test.in, test.out256, sum256[:], New512_256()) - testHash(t, "SHA384", test.in, test.out384, sum384[:], New384()) - testHash(t, "SHA512", test.in, test.out512, sum512[:], New()) + tests := []struct { + name string + oneShotHash func(in []byte) []byte + digest hash.Hash + golden []sha512Test + }{ + { + "SHA512/224", + func(in []byte) []byte { a := Sum512_224(in); return a[:] }, + New512_224(), + golden224, + }, + { + "SHA512/256", + func(in []byte) []byte { a := Sum512_256(in); return a[:] }, + New512_256(), + golden256, + }, + { + "SHA384", + func(in []byte) []byte { a := Sum384(in); return a[:] }, + New384(), + golden384, + }, + { + "SHA512", + func(in []byte) []byte { a := Sum512(in); return a[:] }, + New(), + golden512, + }, + } + for _, tt := range tests { + for _, test := range tt.golden { + in := []byte(test.in) + testHash(t, tt.name, test.in, test.out, tt.oneShotHash(in), tt.digest) + } + } +} + +func TestGoldenMarshal(t *testing.T) { + tests := []struct { + name string + newHash func() hash.Hash + golden []sha512Test + }{ + {"512/224", New512_224, golden224}, + {"512/256", New512_256, golden256}, + {"384", New384, golden384}, + {"512", New, golden512}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, test := range tt.golden { + h := tt.newHash() + h2 := tt.newHash() + + io.WriteString(h, test.in[:len(test.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + return + } + + if string(state) != test.halfState { + t.Errorf("New%s(%q) state = %q, want %q", tt.name, test.in, state, test.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + return + } + + io.WriteString(h, test.in[len(test.in)/2:]) + io.WriteString(h2, test.in[len(test.in)/2:]) + + if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) { + t.Errorf("New%s(%q) = 0x%x != marshaled 0x%x", tt.name, test.in, actual, actual2) + } + } + }) + } +} + +func TestMarshalMismatch(t *testing.T) { + h := []func() hash.Hash{ + New, + New384, + New512_224, + New512_256, + } + + for i, fn1 := range h { + for j, fn2 := range h { + if i == j { + continue + } + + h1 := fn1() + h2 := fn2() + + state, err := h1.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("i=%d: could not marshal: %v", i, err) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err == nil { + t.Errorf("i=%d, j=%d: got no error , expected one: %v", i, j, err) + } + } } } diff --git a/libgo/go/crypto/subtle/constant_time.go b/libgo/go/crypto/subtle/constant_time.go index 11312b8dd44..9f5fee87e3f 100644 --- a/libgo/go/crypto/subtle/constant_time.go +++ b/libgo/go/crypto/subtle/constant_time.go @@ -29,24 +29,12 @@ func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y } // ConstantTimeByteEq returns 1 if x == y and 0 otherwise. func ConstantTimeByteEq(x, y uint8) int { - z := ^(x ^ y) - z &= z >> 4 - z &= z >> 2 - z &= z >> 1 - - return int(z) + return int((uint32(x^y) - 1) >> 31) } // ConstantTimeEq returns 1 if x == y and 0 otherwise. func ConstantTimeEq(x, y int32) int { - z := ^(x ^ y) - z &= z >> 16 - z &= z >> 8 - z &= z >> 4 - z &= z >> 2 - z &= z >> 1 - - return int(z & 1) + return int((uint64(uint32(x^y)) - 1) >> 63) } // ConstantTimeCopy copies the contents of y into x (a slice of equal length) diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go index 619a454441d..033301a6e4a 100644 --- a/libgo/go/crypto/subtle/constant_time_test.go +++ b/libgo/go/crypto/subtle/constant_time_test.go @@ -125,3 +125,35 @@ func TestConstantTimeLessOrEq(t *testing.T) { } } } + +var benchmarkGlobal uint8 + +func BenchmarkConstantTimeByteEq(b *testing.B) { + var x, y uint8 + + for i := 0; i < b.N; i++ { + x, y = uint8(ConstantTimeByteEq(x, y)), x + } + + benchmarkGlobal = x +} + +func BenchmarkConstantTimeEq(b *testing.B) { + var x, y int + + for i := 0; i < b.N; i++ { + x, y = ConstantTimeEq(int32(x), int32(y)), x + } + + benchmarkGlobal = uint8(x) +} + +func BenchmarkConstantTimeLessOrEq(b *testing.B) { + var x, y int + + for i := 0; i < b.N; i++ { + x, y = ConstantTimeLessOrEq(x, y), x + } + + benchmarkGlobal = uint8(x) +} diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 5860838dd25..d4b0286b853 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -29,10 +29,11 @@ const ( ) const ( - maxPlaintext = 16384 // maximum plaintext payload length - maxCiphertext = 16384 + 2048 // maximum ciphertext payload length - recordHeaderLen = 5 // record header length - maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + maxPlaintext = 16384 // maximum plaintext payload length + maxCiphertext = 16384 + 2048 // maximum ciphertext payload length + recordHeaderLen = 5 // record header length + maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + maxWarnAlertCount = 5 // maximum number of consecutive warning alerts minVersion = VersionTLS10 maxVersion = VersionTLS12 @@ -126,35 +127,25 @@ const ( // Rest of these are reserved by the TLS spec ) -// Hash functions for TLS 1.2 (See RFC 5246, section A.4.1) -const ( - hashSHA1 uint8 = 2 - hashSHA256 uint8 = 4 - hashSHA384 uint8 = 5 -) - // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) const ( signatureRSA uint8 = 1 signatureECDSA uint8 = 3 ) -// signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See -// RFC 5246, section A.4.1. -type signatureAndHash struct { - hash, signature uint8 -} - // supportedSignatureAlgorithms contains the signature and hash algorithms that // the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 -// CertificateRequest. -var supportedSignatureAlgorithms = []signatureAndHash{ - {hashSHA256, signatureRSA}, - {hashSHA256, signatureECDSA}, - {hashSHA384, signatureRSA}, - {hashSHA384, signatureECDSA}, - {hashSHA1, signatureRSA}, - {hashSHA1, signatureECDSA}, +// CertificateRequest. The two fields are merged to match with TLS 1.3. +// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. +var supportedSignatureAlgorithms = []SignatureScheme{ + PKCS1WithSHA256, + ECDSAWithP256AndSHA256, + PKCS1WithSHA384, + ECDSAWithP384AndSHA384, + PKCS1WithSHA512, + ECDSAWithP521AndSHA512, + PKCS1WithSHA1, + ECDSAWithSHA1, } // ConnectionState records basic TLS details about the connection. @@ -234,6 +225,9 @@ const ( ECDSAWithP256AndSHA256 SignatureScheme = 0x0403 ECDSAWithP384AndSHA384 SignatureScheme = 0x0503 ECDSAWithP521AndSHA512 SignatureScheme = 0x0603 + + // Legacy signature and hash algorithms for TLS 1.2. + ECDSAWithSHA1 SignatureScheme = 0x0203 ) // ClientHelloInfo contains information from a ClientHello message in order to @@ -471,8 +465,8 @@ type Config struct { // connections using that key are compromised. SessionTicketKey [32]byte - // SessionCache is a cache of ClientSessionState entries for TLS session - // resumption. + // ClientSessionCache is a cache of ClientSessionState entries for TLS + // session resumption. ClientSessionCache ClientSessionCache // MinVersion contains the minimum SSL/TLS version that is acceptable. @@ -961,11 +955,24 @@ func unexpectedMessageError(wanted, got interface{}) error { return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) } -func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool { - for _, s := range sigHashes { - if s == sigHash { +func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { + for _, s := range supportedSignatureAlgorithms { + if s == sigAlg { return true } } return false } + +// signatureFromSignatureScheme maps a signature algorithm to the underlying +// signature method (without hash function). +func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 { + switch signatureAlgorithm { + case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: + return signatureRSA + case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: + return signatureECDSA + default: + return 0 + } +} diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index e6d85aa2639..31c50538703 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -94,6 +94,10 @@ type Conn struct { bytesSent int64 packetsSent int64 + // warnCount counts the number of consecutive warning alerts received + // by Conn.readRecord. Protected by in.Mutex. + warnCount int + // activeCall is an atomic int32; the low bit is whether Close has // been called. the rest of the bits are the number of goroutines // in Conn.Write. @@ -213,10 +217,11 @@ func extractPadding(payload []byte) (toRemove int, good byte) { // if len(payload) >= (paddingLen - 1) then the MSB of t is zero good = byte(int32(^t) >> 31) - toCheck := 255 // the maximum possible padding length + // The maximum possible padding length plus the actual length field + toCheck := 256 // The length of the padded data is public, so we can use an if here - if toCheck+1 > len(payload) { - toCheck = len(payload) - 1 + if toCheck > len(payload) { + toCheck = len(payload) } for i := 0; i < toCheck; i++ { @@ -657,6 +662,11 @@ Again: return c.in.setErrorLocked(err) } + if typ != recordTypeAlert && len(data) > 0 { + // this is a valid non-alert message: reset the count of alerts + c.warnCount = 0 + } + switch typ { default: c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) @@ -674,6 +684,13 @@ Again: case alertLevelWarning: // drop on the floor c.in.freeBlock(b) + + c.warnCount++ + if c.warnCount > maxWarnAlertCount { + c.sendAlert(alertUnexpectedMessage) + return c.in.setErrorLocked(errors.New("tls: too many warn alerts")) + } + goto Again case alertLevelError: c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) @@ -686,6 +703,11 @@ Again: c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } + // Handshake messages are not allowed to fragment across the CCS + if c.hand.Len() > 0 { + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + break + } err := c.in.changeCipherSpec() if err != nil { c.in.setErrorLocked(c.sendAlert(err.(alert))) diff --git a/libgo/go/crypto/tls/conn_test.go b/libgo/go/crypto/tls/conn_test.go index e27c5414b22..5c7f7ce2bb7 100644 --- a/libgo/go/crypto/tls/conn_test.go +++ b/libgo/go/crypto/tls/conn_test.go @@ -21,6 +21,12 @@ func TestRoundUp(t *testing.T) { } } +// will be initialized with {0, 255, 255, ..., 255} +var padding255Bad = [256]byte{} + +// will be initialized with {255, 255, 255, ..., 255} +var padding255Good = [256]byte{255} + var paddingTests = []struct { in []byte good bool @@ -36,9 +42,15 @@ var paddingTests = []struct { {[]byte{1, 4, 4, 4, 4, 4}, true, 1}, {[]byte{5, 5, 5, 5, 5, 5}, true, 0}, {[]byte{6, 6, 6, 6, 6, 6}, false, 0}, + {padding255Bad[:], false, 0}, + {padding255Good[:], true, 0}, } func TestRemovePadding(t *testing.T) { + for i := 1; i < len(padding255Bad); i++ { + padding255Bad[i] = 255 + padding255Good[i] = 255 + } for i, test := range paddingTests { paddingLen, good := extractPadding(test.in) expectedGood := byte(255) diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index a4ca5d34fb8..dc529c96d65 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -29,51 +29,38 @@ type clientHandshakeState struct { session *ClientSessionState } -// c.out.Mutex <= L; c.handshakeMutex <= L. -func (c *Conn) clientHandshake() error { - if c.config == nil { - c.config = defaultConfig() - } - - // This may be a renegotiation handshake, in which case some fields - // need to be reset. - c.didResume = false - - if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify { - return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") +func makeClientHello(config *Config) (*clientHelloMsg, error) { + if len(config.ServerName) == 0 && !config.InsecureSkipVerify { + return nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") } nextProtosLength := 0 - for _, proto := range c.config.NextProtos { + for _, proto := range config.NextProtos { if l := len(proto); l == 0 || l > 255 { - return errors.New("tls: invalid NextProtos value") + return nil, errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l } } + if nextProtosLength > 0xffff { - return errors.New("tls: NextProtos values too large") + return nil, errors.New("tls: NextProtos values too large") } hello := &clientHelloMsg{ - vers: c.config.maxVersion(), + vers: config.maxVersion(), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, scts: true, - serverName: hostnameInSNI(c.config.ServerName), - supportedCurves: c.config.curvePreferences(), + serverName: hostnameInSNI(config.ServerName), + supportedCurves: config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, - nextProtoNeg: len(c.config.NextProtos) > 0, + nextProtoNeg: len(config.NextProtos) > 0, secureRenegotiationSupported: true, - alpnProtocols: c.config.NextProtos, + alpnProtocols: config.NextProtos, } - - if c.handshakes > 0 { - hello.secureRenegotiation = c.clientFinished[:] - } - - possibleCipherSuites := c.config.cipherSuites() + possibleCipherSuites := config.cipherSuites() hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) NextCipherSuite: @@ -92,14 +79,35 @@ NextCipherSuite: } } - _, err := io.ReadFull(c.config.rand(), hello.random) + _, err := io.ReadFull(config.rand(), hello.random) if err != nil { - c.sendAlert(alertInternalError) - return errors.New("tls: short read from Rand: " + err.Error()) + return nil, errors.New("tls: short read from Rand: " + err.Error()) } if hello.vers >= VersionTLS12 { - hello.signatureAndHashes = supportedSignatureAlgorithms + hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms + } + + return hello, nil +} + +// c.out.Mutex <= L; c.handshakeMutex <= L. +func (c *Conn) clientHandshake() error { + if c.config == nil { + c.config = defaultConfig() + } + + // This may be a renegotiation handshake, in which case some fields + // need to be reset. + c.didResume = false + + hello, err := makeClientHello(c.config) + if err != nil { + return err + } + + if c.handshakes > 0 { + hello.secureRenegotiation = c.clientFinished[:] } var session *ClientSessionState @@ -147,12 +155,36 @@ NextCipherSuite: // (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()) } } - if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil { + hs := &clientHandshakeState{ + c: c, + hello: hello, + session: session, + } + + if err = hs.handshake(); err != nil { + return err + } + + // If we had a successful handshake and hs.session is different from + // the one already cached - cache a new one + if sessionCache != nil && hs.session != nil && session != hs.session { + sessionCache.Put(cacheKey, hs.session) + } + + return nil +} + +// Does the handshake, either a full one or resumes old session. +// Requires hs.c, hs.hello, and, optionally, hs.session to be set. +func (hs *clientHandshakeState) handshake() error { + c := hs.c + + // send ClientHello + if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { return err } @@ -160,34 +192,19 @@ NextCipherSuite: if err != nil { return err } - serverHello, ok := msg.(*serverHelloMsg) - if !ok { - 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. - c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers) + var ok bool + if hs.serverHello, ok = msg.(*serverHelloMsg); !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(hs.serverHello, msg) } - c.vers = vers - c.haveVers = true - suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite) - if suite == nil { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server chose an unconfigured cipher suite") + if err = hs.pickTLSVersion(); err != nil { + return err } - hs := &clientHandshakeState{ - c: c, - serverHello: serverHello, - hello: hello, - suite: suite, - finishedHash: newFinishedHash(c.vers, suite), - session: session, + if err = hs.pickCipherSuite(); err != nil { + return err } isResume, err := hs.processServerHello() @@ -195,6 +212,8 @@ NextCipherSuite: return err } + hs.finishedHash = newFinishedHash(c.vers, hs.suite) + // No signatures of the handshake are needed in a resumption. // Otherwise, in a full handshake, if we don't have any certificates // configured then we will never send a CertificateVerify message and @@ -246,13 +265,33 @@ NextCipherSuite: } } - 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) pickTLSVersion() error { + vers, ok := hs.c.config.mutualVersion(hs.serverHello.vers) + if !ok || vers < VersionTLS10 { + // TLS 1.0 is the minimum version supported as a client. + hs.c.sendAlert(alertProtocolVersion) + return fmt.Errorf("tls: server selected unsupported protocol version %x", hs.serverHello.vers) + } + + hs.c.vers = vers + hs.c.haveVers = true + + return nil +} + +func (hs *clientHandshakeState) pickCipherSuite() error { + if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil { + hs.c.sendAlert(alertHandshakeFailure) + return errors.New("tls: server chose an unconfigured cipher suite") + } + + hs.c.cipherSuite = hs.suite.id return nil } @@ -443,12 +482,15 @@ func (hs *clientHandshakeState) doFullHandshake() error { return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key) } - certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType) - if err != nil { - c.sendAlert(alertInternalError) - return err + // SignatureAndHashAlgorithm was introduced in TLS 1.2. + if certVerify.hasSignatureAndHash { + certVerify.signatureAlgorithm, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.supportedSignatureAlgorithms, signatureType) + if err != nil { + c.sendAlert(alertInternalError) + return err + } } - digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) + digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(signatureType, certVerify.signatureAlgorithm, hs.masterSecret) if err != nil { c.sendAlert(alertInternalError) return err @@ -707,10 +749,7 @@ func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) ( signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA] } } else { - signatureSchemes = make([]SignatureScheme, 0, len(certReq.signatureAndHashes)) - for _, sah := range certReq.signatureAndHashes { - signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature)) - } + signatureSchemes = certReq.supportedSignatureAlgorithms } return c.config.GetClientCertificate(&CertificateRequestInfo{ diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go index 5851f897f96..cc3ab714a63 100644 --- a/libgo/go/crypto/tls/handshake_client_test.go +++ b/libgo/go/crypto/tls/handshake_client_test.go @@ -85,7 +85,7 @@ func (o *opensslOutputSink) Write(data []byte) (n int, err error) { o.all = append(o.all, data...) for { - i := bytes.Index(o.line, []byte{'\n'}) + i := bytes.IndexByte(o.line, '\n') if i < 0 { break } @@ -1189,7 +1189,7 @@ func TestVerifyPeerCertificate(t *testing.T) { // callback should still be called but // validatedChains must be empty. if l := len(validatedChains); l != 0 { - return errors.New("got len(validatedChains) = 0, wanted zero") + return fmt.Errorf("got len(validatedChains) = %d, wanted zero", l) } *called = true return nil @@ -1438,19 +1438,23 @@ func TestTLS11SignatureSchemes(t *testing.T) { } var getClientCertificateTests = []struct { - setup func(*Config) + setup func(*Config, *Config) expectedClientError string verify func(*testing.T, int, *ConnectionState) }{ { - func(clientConfig *Config) { + func(clientConfig, serverConfig *Config) { // Returning a Certificate with no certificate data // should result in an empty message being sent to the // server. + serverConfig.ClientCAs = nil clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) { if len(cri.SignatureSchemes) == 0 { panic("empty SignatureSchemes") } + if len(cri.AcceptableCAs) != 0 { + panic("AcceptableCAs should have been empty") + } return new(Certificate), nil } }, @@ -1462,7 +1466,7 @@ var getClientCertificateTests = []struct { }, }, { - func(clientConfig *Config) { + func(clientConfig, serverConfig *Config) { // With TLS 1.1, the SignatureSchemes should be // synthesised from the supported certificate types. clientConfig.MaxVersion = VersionTLS11 @@ -1481,7 +1485,7 @@ var getClientCertificateTests = []struct { }, }, { - func(clientConfig *Config) { + func(clientConfig, serverConfig *Config) { // Returning an error should abort the handshake with // that error. clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) { @@ -1493,14 +1497,21 @@ var getClientCertificateTests = []struct { }, }, { - func(clientConfig *Config) { + func(clientConfig, serverConfig *Config) { clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) { - return &testConfig.Certificates[0], nil + if len(cri.AcceptableCAs) == 0 { + panic("empty AcceptableCAs") + } + cert := &Certificate{ + Certificate: [][]byte{testRSACertificate}, + PrivateKey: testRSAPrivateKey, + } + return cert, nil } }, "", func(t *testing.T, testNum int, cs *ConnectionState) { - if l := len(cs.VerifiedChains); l != 0 { + if len(cs.VerifiedChains) == 0 { t.Errorf("#%d: expected some verified chains, but found none", testNum) } }, @@ -1515,13 +1526,15 @@ func TestGetClientCertificate(t *testing.T) { for i, test := range getClientCertificateTests { serverConfig := testConfig.Clone() - serverConfig.ClientAuth = RequestClientCert + serverConfig.ClientAuth = VerifyClientCertIfGiven serverConfig.RootCAs = x509.NewCertPool() serverConfig.RootCAs.AddCert(issuer) + serverConfig.ClientCAs = serverConfig.RootCAs + serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) } clientConfig := testConfig.Clone() - test.setup(clientConfig) + test.setup(clientConfig, serverConfig) type serverResult struct { cs ConnectionState @@ -1553,6 +1566,8 @@ func TestGetClientCertificate(t *testing.T) { t.Errorf("#%d: client error: %v", i, clientErr) } else if got := clientErr.Error(); got != test.expectedClientError { t.Errorf("#%d: expected client error %q, but got %q", i, test.expectedClientError, got) + } else { + test.verify(t, i, &result.cs) } } else if len(test.expectedClientError) > 0 { t.Errorf("#%d: expected client error %q, but got no error", i, test.expectedClientError) diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go index 0c7581f3e36..f8c8d571ccd 100644 --- a/libgo/go/crypto/tls/handshake_messages.go +++ b/libgo/go/crypto/tls/handshake_messages.go @@ -24,7 +24,7 @@ type clientHelloMsg struct { supportedPoints []uint8 ticketSupported bool sessionTicket []uint8 - signatureAndHashes []signatureAndHash + supportedSignatureAlgorithms []SignatureScheme secureRenegotiation []byte secureRenegotiationSupported bool alpnProtocols []string @@ -50,7 +50,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool { bytes.Equal(m.supportedPoints, m1.supportedPoints) && m.ticketSupported == m1.ticketSupported && bytes.Equal(m.sessionTicket, m1.sessionTicket) && - eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) && + eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) && m.secureRenegotiationSupported == m1.secureRenegotiationSupported && bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && eqStrings(m.alpnProtocols, m1.alpnProtocols) @@ -87,8 +87,8 @@ func (m *clientHelloMsg) marshal() []byte { extensionsLength += len(m.sessionTicket) numExtensions++ } - if len(m.signatureAndHashes) > 0 { - extensionsLength += 2 + 2*len(m.signatureAndHashes) + if len(m.supportedSignatureAlgorithms) > 0 { + extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms) numExtensions++ } if m.secureRenegotiationSupported { @@ -234,11 +234,11 @@ func (m *clientHelloMsg) marshal() []byte { copy(z, m.sessionTicket) z = z[len(m.sessionTicket):] } - if len(m.signatureAndHashes) > 0 { + if len(m.supportedSignatureAlgorithms) > 0 { // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 z[0] = byte(extensionSignatureAlgorithms >> 8) z[1] = byte(extensionSignatureAlgorithms) - l := 2 + 2*len(m.signatureAndHashes) + l := 2 + 2*len(m.supportedSignatureAlgorithms) z[2] = byte(l >> 8) z[3] = byte(l) z = z[4:] @@ -247,9 +247,9 @@ func (m *clientHelloMsg) marshal() []byte { z[0] = byte(l >> 8) z[1] = byte(l) z = z[2:] - for _, sigAndHash := range m.signatureAndHashes { - z[0] = sigAndHash.hash - z[1] = sigAndHash.signature + for _, sigAlgo := range m.supportedSignatureAlgorithms { + z[0] = byte(sigAlgo >> 8) + z[1] = byte(sigAlgo) z = z[2:] } } @@ -344,7 +344,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.ocspStapling = false m.ticketSupported = false m.sessionTicket = nil - m.signatureAndHashes = nil + m.supportedSignatureAlgorithms = nil m.alpnProtocols = nil m.scts = false @@ -455,10 +455,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } n := l / 2 d := data[2:] - m.signatureAndHashes = make([]signatureAndHash, n) - for i := range m.signatureAndHashes { - m.signatureAndHashes[i].hash = d[0] - m.signatureAndHashes[i].signature = d[1] + m.supportedSignatureAlgorithms = make([]SignatureScheme, n) + for i := range m.supportedSignatureAlgorithms { + m.supportedSignatureAlgorithms[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1]) d = d[2:] } case extensionRenegotiationInfo: @@ -1203,9 +1202,9 @@ type certificateRequestMsg struct { // 1.2. hasSignatureAndHash bool - certificateTypes []byte - signatureAndHashes []signatureAndHash - certificateAuthorities [][]byte + certificateTypes []byte + supportedSignatureAlgorithms []SignatureScheme + certificateAuthorities [][]byte } func (m *certificateRequestMsg) equal(i interface{}) bool { @@ -1217,7 +1216,7 @@ func (m *certificateRequestMsg) equal(i interface{}) bool { return bytes.Equal(m.raw, m1.raw) && bytes.Equal(m.certificateTypes, m1.certificateTypes) && eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) && - eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) + eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) } func (m *certificateRequestMsg) marshal() (x []byte) { @@ -1234,7 +1233,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) { length += casLength if m.hasSignatureAndHash { - length += 2 + 2*len(m.signatureAndHashes) + length += 2 + 2*len(m.supportedSignatureAlgorithms) } x = make([]byte, 4+length) @@ -1249,13 +1248,13 @@ func (m *certificateRequestMsg) marshal() (x []byte) { y := x[5+len(m.certificateTypes):] if m.hasSignatureAndHash { - n := len(m.signatureAndHashes) * 2 + n := len(m.supportedSignatureAlgorithms) * 2 y[0] = uint8(n >> 8) y[1] = uint8(n) y = y[2:] - for _, sigAndHash := range m.signatureAndHashes { - y[0] = sigAndHash.hash - y[1] = sigAndHash.signature + for _, sigAlgo := range m.supportedSignatureAlgorithms { + y[0] = uint8(sigAlgo >> 8) + y[1] = uint8(sigAlgo) y = y[2:] } } @@ -1312,11 +1311,10 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool { if len(data) < int(sigAndHashLen) { return false } - numSigAndHash := sigAndHashLen / 2 - m.signatureAndHashes = make([]signatureAndHash, numSigAndHash) - for i := range m.signatureAndHashes { - m.signatureAndHashes[i].hash = data[0] - m.signatureAndHashes[i].signature = data[1] + numSigAlgos := sigAndHashLen / 2 + m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos) + for i := range m.supportedSignatureAlgorithms { + m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) data = data[2:] } } @@ -1355,7 +1353,7 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool { type certificateVerifyMsg struct { raw []byte hasSignatureAndHash bool - signatureAndHash signatureAndHash + signatureAlgorithm SignatureScheme signature []byte } @@ -1367,8 +1365,7 @@ func (m *certificateVerifyMsg) equal(i interface{}) bool { return bytes.Equal(m.raw, m1.raw) && m.hasSignatureAndHash == m1.hasSignatureAndHash && - m.signatureAndHash.hash == m1.signatureAndHash.hash && - m.signatureAndHash.signature == m1.signatureAndHash.signature && + m.signatureAlgorithm == m1.signatureAlgorithm && bytes.Equal(m.signature, m1.signature) } @@ -1390,8 +1387,8 @@ func (m *certificateVerifyMsg) marshal() (x []byte) { x[3] = uint8(length) y := x[4:] if m.hasSignatureAndHash { - y[0] = m.signatureAndHash.hash - y[1] = m.signatureAndHash.signature + y[0] = uint8(m.signatureAlgorithm >> 8) + y[1] = uint8(m.signatureAlgorithm) y = y[2:] } y[0] = uint8(siglength >> 8) @@ -1417,8 +1414,7 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool { data = data[4:] if m.hasSignatureAndHash { - m.signatureAndHash.hash = data[0] - m.signatureAndHash.signature = data[1] + m.signatureAlgorithm = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) data = data[2:] } @@ -1554,13 +1550,12 @@ func eqByteSlices(x, y [][]byte) bool { return true } -func eqSignatureAndHashes(x, y []signatureAndHash) bool { +func eqSignatureAlgorithms(x, y []SignatureScheme) bool { if len(x) != len(y) { return false } for i, v := range x { - v2 := y[i] - if v.hash != v2.hash || v.signature != v2.signature { + if v != y[i] { return false } } diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index 7add97c32c1..37eb748eea7 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/crypto/tls/handshake_messages_test.go @@ -98,8 +98,8 @@ func TestFuzz(t *testing.T) { func randomBytes(n int, rand *rand.Rand) []byte { r := make([]byte, n) - for i := 0; i < n; i++ { - r[i] = byte(rand.Int31()) + if _, err := rand.Read(r); err != nil { + panic("rand.Read failed: " + err.Error()) } return r } @@ -116,7 +116,11 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { m.sessionId = randomBytes(rand.Intn(32), rand) m.cipherSuites = make([]uint16, rand.Intn(63)+1) for i := 0; i < len(m.cipherSuites); i++ { - m.cipherSuites[i] = uint16(rand.Int31()) + cs := uint16(rand.Int31()) + if cs == scsvRenegotiation { + cs += 1 + } + m.cipherSuites[i] = cs } m.compressionMethods = randomBytes(rand.Intn(63)+1, rand) if rand.Intn(10) > 5 { @@ -141,7 +145,7 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { } } if rand.Intn(10) > 5 { - m.signatureAndHashes = supportedSignatureAlgorithms + m.supportedSignatureAlgorithms = supportedSignatureAlgorithms } m.alpnProtocols = make([]string, rand.Intn(5)) for i := range m.alpnProtocols { diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index ae328487088..991b4e9e621 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -418,7 +418,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { } if c.vers >= VersionTLS12 { certReq.hasSignatureAndHash = true - certReq.signatureAndHashes = supportedSignatureAlgorithms + certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms } // An empty list of certificateAuthorities signals to @@ -519,27 +519,30 @@ func (hs *serverHandshakeState) doFullHandshake() error { } // Determine the signature type. - var signatureAndHash signatureAndHash + var signatureAlgorithm SignatureScheme + var sigType uint8 if certVerify.hasSignatureAndHash { - signatureAndHash = certVerify.signatureAndHash - if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) { + signatureAlgorithm = certVerify.signatureAlgorithm + if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) { return errors.New("tls: unsupported hash function for client certificate") } + sigType = signatureFromSignatureScheme(signatureAlgorithm) } else { // Before TLS 1.2 the signature algorithm was implicit // from the key type, and only one hash per signature - // algorithm was possible. Leave the hash as zero. + // algorithm was possible. Leave signatureAlgorithm + // unset. switch pub.(type) { case *ecdsa.PublicKey: - signatureAndHash.signature = signatureECDSA + sigType = signatureECDSA case *rsa.PublicKey: - signatureAndHash.signature = signatureRSA + sigType = signatureRSA } } switch key := pub.(type) { case *ecdsa.PublicKey: - if signatureAndHash.signature != signatureECDSA { + if sigType != signatureECDSA { err = errors.New("tls: bad signature type for client's ECDSA certificate") break } @@ -552,20 +555,20 @@ func (hs *serverHandshakeState) doFullHandshake() error { break } var digest []byte - if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + if digest, _, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { break } if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { err = errors.New("tls: ECDSA verification failure") } case *rsa.PublicKey: - if signatureAndHash.signature != signatureRSA { + if sigType != signatureRSA { err = errors.New("tls: bad signature type for client's RSA certificate") break } var digest []byte var hashFunc crypto.Hash - if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { break } err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) @@ -818,17 +821,12 @@ func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo { supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:] } - signatureSchemes := make([]SignatureScheme, 0, len(hs.clientHello.signatureAndHashes)) - for _, sah := range hs.clientHello.signatureAndHashes { - signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature)) - } - hs.cachedClientHelloInfo = &ClientHelloInfo{ CipherSuites: hs.clientHello.cipherSuites, ServerName: hs.clientHello.serverName, SupportedCurves: hs.clientHello.supportedCurves, SupportedPoints: hs.clientHello.supportedPoints, - SignatureSchemes: signatureSchemes, + SignatureSchemes: hs.clientHello.supportedSignatureAlgorithms, SupportedProtos: hs.clientHello.alpnProtocols, SupportedVersions: supportedVersions, Conn: hs.c.conn, diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index 63845c170d7..67160213fbe 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -6,9 +6,11 @@ package tls import ( "bytes" + "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" + "crypto/x509" "encoding/hex" "encoding/pem" "errors" @@ -996,6 +998,87 @@ func TestFallbackSCSV(t *testing.T) { runServerTestTLS11(t, test) } +func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, cert []byte, key crypto.PrivateKey) { + config := testConfig.Clone() + config.CipherSuites = []uint16{cipherSuite} + config.CurvePreferences = []CurveID{curve} + config.Certificates = make([]Certificate, 1) + config.Certificates[0].Certificate = [][]byte{cert} + config.Certificates[0].PrivateKey = key + config.BuildNameToCertificate() + + clientConn, serverConn := net.Pipe() + serverConn = &recordingConn{Conn: serverConn} + go func() { + client := Client(clientConn, testConfig) + client.Handshake() + }() + server := Server(serverConn, config) + if err := server.Handshake(); err != nil { + b.Fatalf("handshake failed: %v", err) + } + serverConn.Close() + flows := serverConn.(*recordingConn).flows + + feeder := make(chan struct{}) + clientConn, serverConn = net.Pipe() + + go func() { + for range feeder { + for i, f := range flows { + if i%2 == 0 { + clientConn.Write(f) + continue + } + ff := make([]byte, len(f)) + n, err := io.ReadFull(clientConn, ff) + if err != nil { + b.Fatalf("#%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", i+1, err, n, len(ff), ff[:n], f) + } + if !bytes.Equal(f, ff) { + b.Fatalf("#%d: mismatch on read: got:%x want:%x", i+1, ff, f) + } + } + } + }() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + feeder <- struct{}{} + server := Server(serverConn, config) + if err := server.Handshake(); err != nil { + b.Fatalf("handshake failed: %v", err) + } + } + close(feeder) +} + +func BenchmarkHandshakeServer(b *testing.B) { + b.Run("RSA", func(b *testing.B) { + benchmarkHandshakeServer(b, TLS_RSA_WITH_AES_128_GCM_SHA256, + 0, testRSACertificate, testRSAPrivateKey) + }) + b.Run("ECDHE-P256-RSA", func(b *testing.B) { + benchmarkHandshakeServer(b, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + CurveP256, testRSACertificate, testRSAPrivateKey) + }) + b.Run("ECDHE-P256-ECDSA-P256", func(b *testing.B) { + benchmarkHandshakeServer(b, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + CurveP256, testP256Certificate, testP256PrivateKey) + }) + b.Run("ECDHE-X25519-ECDSA-P256", func(b *testing.B) { + benchmarkHandshakeServer(b, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + X25519, testP256Certificate, testP256PrivateKey) + }) + b.Run("ECDHE-P521-ECDSA-P521", func(b *testing.B) { + if testECDSAPrivateKey.PublicKey.Curve != elliptic.P521() { + b.Fatal("test ECDSA key doesn't use curve P-521") + } + benchmarkHandshakeServer(b, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + CurveP521, testECDSACertificate, testECDSAPrivateKey) + }) +} + // clientCertificatePEM and clientKeyPEM were generated with generate_cert.go // Thus, they have no ExtKeyUsage fields and trigger an error when verification // is turned on. @@ -1296,6 +1379,8 @@ var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906 var testSNICertificate = fromHex("0441883421114c81480804c430820237308201a0a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a3023310b3009060355040a1302476f311430120603550403130b736e69746573742e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a3773075300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b0500038181007beeecff0230dbb2e7a334af65430b7116e09f327c3bbf918107fc9c66cb497493207ae9b4dbb045cb63d605ec1b5dd485bb69124d68fa298dc776699b47632fd6d73cab57042acb26f083c4087459bc5a3bb3ca4d878d7fe31016b7bc9a627438666566e3389bfaeebe6becc9a0093ceed18d0f9ac79d56f3a73f18188988ed") +var testP256Certificate = fromHex("308201693082010ea00302010202105012dc24e1124ade4f3e153326ff27bf300a06082a8648ce3d04030230123110300e060355040a130741636d6520436f301e170d3137303533313232343934375a170d3138303533313232343934375a30123110300e060355040a130741636d6520436f3059301306072a8648ce3d020106082a8648ce3d03010703420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75a3463044300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000300f0603551d1104083006820474657374300a06082a8648ce3d0403020349003046022100963712d6226c7b2bef41512d47e1434131aaca3ba585d666c924df71ac0448b3022100f4d05c725064741aef125f243cdbccaa2a5d485927831f221c43023bd5ae471a") + var testRSAPrivateKey = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: bigFromString("153980389784927331788354528594524332344709972855165340650588877572729725338415474372475094155672066328274535240275856844648695200875763869073572078279316458648124537905600131008790701752441155668003033945258023841165089852359980273279085783159654751552359397986180318708491098942831252291841441726305535546071"), @@ -1316,3 +1401,5 @@ var testECDSAPrivateKey = &ecdsa.PrivateKey{ }, D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"), } + +var testP256PrivateKey, _ = x509.ParseECPrivateKey(fromHex("30770201010420012f3b52bc54c36ba3577ad45034e2e8efe1e6999851284cb848725cfe029991a00a06082a8648ce3d030107a14403420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75")) diff --git a/libgo/go/crypto/tls/handshake_test.go b/libgo/go/crypto/tls/handshake_test.go index 8e5410a17de..4b3fa238f4a 100644 --- a/libgo/go/crypto/tls/handshake_test.go +++ b/libgo/go/crypto/tls/handshake_test.go @@ -32,10 +32,10 @@ import ( // 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. +// the test files to be regenerated. 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") diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go index 1b27c049ed3..3f570b66c69 100644 --- a/libgo/go/crypto/tls/key_agreement.go +++ b/libgo/go/crypto/tls/key_agreement.go @@ -110,14 +110,14 @@ func md5SHA1Hash(slices [][]byte) []byte { } // hashForServerKeyExchange hashes the given slices and returns their digest -// and the identifier of the hash function used. The sigAndHash argument is -// only used for >= TLS 1.2 and precisely identifies the hash function to use. -func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { +// and the identifier of the hash function used. The signatureAlgorithm argument +// is only used for >= TLS 1.2 and identifies the hash function to use. +func hashForServerKeyExchange(sigType uint8, signatureAlgorithm SignatureScheme, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { if version >= VersionTLS12 { - if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { + if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) { return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer") } - hashFunc, err := lookupTLSHash(sigAndHash.hash) + hashFunc, err := lookupTLSHash(signatureAlgorithm) if err != nil { return nil, crypto.Hash(0), err } @@ -128,7 +128,7 @@ func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slice digest := h.Sum(nil) return digest, hashFunc, nil } - if sigAndHash.signature == signatureECDSA { + if sigType == signatureECDSA { return sha1Hash(slices), crypto.SHA1, nil } return md5SHA1Hash(slices), crypto.MD5SHA1, nil @@ -137,20 +137,27 @@ func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slice // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a // ServerKeyExchange given the signature type being used and the client's // advertised list of supported signature and hash combinations. -func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) { +func pickTLS12HashForSignature(sigType uint8, clientList []SignatureScheme) (SignatureScheme, error) { if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 - return hashSHA1, nil + switch sigType { + case signatureRSA: + return PKCS1WithSHA1, nil + case signatureECDSA: + return ECDSAWithSHA1, nil + default: + return 0, errors.New("tls: unknown signature algorithm") + } } - for _, sigAndHash := range clientList { - if sigAndHash.signature != sigType { + for _, sigAlg := range clientList { + if signatureFromSignatureScheme(sigAlg) != sigType { continue } - if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { - return sigAndHash.hash, nil + if isSupportedSignatureAlgorithm(sigAlg, supportedSignatureAlgorithms) { + return sigAlg, nil } } @@ -172,7 +179,7 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) { } // ecdheRSAKeyAgreement implements a TLS key agreement where the server -// generates a ephemeral EC public/private key pair and signs it. The +// generates an ephemeral EC public/private key pair and signs it. The // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { @@ -240,16 +247,17 @@ NextCandidate: serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - sigAndHash := signatureAndHash{signature: ka.sigType} + var signatureAlgorithm SignatureScheme if ka.version >= VersionTLS12 { var err error - if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { + signatureAlgorithm, err = pickTLS12HashForSignature(ka.sigType, clientHello.supportedSignatureAlgorithms) + if err != nil { return nil, err } } - digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams) + digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, hello.random, serverECDHParams) if err != nil { return nil, err } @@ -287,8 +295,8 @@ NextCandidate: copy(skx.key, serverECDHParams) k := skx.key[len(serverECDHParams):] if ka.version >= VersionTLS12 { - k[0] = sigAndHash.hash - k[1] = sigAndHash.signature + k[0] = byte(signatureAlgorithm >> 8) + k[1] = byte(signatureAlgorithm) k = k[2:] } k[0] = byte(len(sig) >> 8) @@ -319,13 +327,10 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert if !ok { panic("internal error") } - x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:]) + x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:]) // Unmarshal also checks whether the given point is on the curve if x == nil { return nil, errClientKeyExchange } - if !curve.IsOnCurve(x, y) { - return nil, errClientKeyExchange - } x, _ = curve.ScalarMult(x, y, ka.privateKey) preMasterSecret := make([]byte, (curve.Params().BitSize+7)>>3) xBytes := x.Bytes() @@ -365,21 +370,17 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell if !ok { return errors.New("tls: server selected unsupported curve") } - - ka.x, ka.y = elliptic.Unmarshal(curve, publicKey) + ka.x, ka.y = elliptic.Unmarshal(curve, publicKey) // Unmarshal also checks whether the given point is on the curve if ka.x == nil { return errServerKeyExchange } - if !curve.IsOnCurve(ka.x, ka.y) { - return errServerKeyExchange - } } - sigAndHash := signatureAndHash{signature: ka.sigType} + var signatureAlgorithm SignatureScheme if ka.version >= VersionTLS12 { // handle SignatureAndHashAlgorithm - sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]} - if sigAndHash.signature != ka.sigType { + signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) + if signatureFromSignatureScheme(signatureAlgorithm) != ka.sigType { return errServerKeyExchange } sig = sig[2:] @@ -393,7 +394,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell } sig = sig[2:] - digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams) + digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, serverHello.random, serverECDHParams) if err != nil { return err } diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go index 5833fc19631..74438f8bc84 100644 --- a/libgo/go/crypto/tls/prf.go +++ b/libgo/go/crypto/tls/prf.go @@ -12,6 +12,7 @@ import ( "crypto/sha256" "crypto/sha512" "errors" + "fmt" "hash" ) @@ -34,12 +35,8 @@ func pHash(result, secret, seed []byte, hash func() hash.Hash) { h.Write(a) h.Write(seed) b := h.Sum(nil) - todo := len(b) - if j+todo > len(result) { - todo = len(result) - j - } - copy(result[j:j+todo], b) - j += todo + copy(result[j:], b) + j += len(b) h.Reset() h.Write(a) @@ -180,17 +177,19 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie } // lookupTLSHash looks up the corresponding crypto.Hash for a given -// TLS hash identifier. -func lookupTLSHash(hash uint8) (crypto.Hash, error) { - switch hash { - case hashSHA1: +// hash from a TLS SignatureScheme. +func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) { + switch signatureAlgorithm { + case PKCS1WithSHA1, ECDSAWithSHA1: return crypto.SHA1, nil - case hashSHA256: + case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256: return crypto.SHA256, nil - case hashSHA384: + case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384: return crypto.SHA384, nil + case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512: + return crypto.SHA512, nil default: - return 0, errors.New("tls: unsupported hash algorithm") + return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm) } } @@ -310,31 +309,26 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { return out } -// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a +// selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a // client's CertificateVerify with, or an error if none can be found. -func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) { - if h.version < VersionTLS12 { - // Nothing to negotiate before TLS 1.2. - return signatureAndHash{signature: sigType}, nil - } - +func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) { for _, v := range serverList { - if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) { + if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms) { return v, nil } } - return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate") + return 0, errors.New("tls: no supported signature algorithm found for signing client certificate") } // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash // id suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) { +func (h finishedHash) hashForClientCertificate(sigType uint8, signatureAlgorithm SignatureScheme, masterSecret []byte) ([]byte, crypto.Hash, error) { if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") } if h.version == VersionSSL30 { - if signatureAndHash.signature != signatureRSA { + if sigType != signatureRSA { return nil, 0, errors.New("tls: unsupported signature type for client certificate") } @@ -345,7 +339,7 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil } if h.version >= VersionTLS12 { - hashAlg, err := lookupTLSHash(signatureAndHash.hash) + hashAlg, err := lookupTLSHash(signatureAlgorithm) if err != nil { return nil, 0, err } @@ -354,7 +348,7 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash return hash.Sum(nil), hashAlg, nil } - if signatureAndHash.signature == signatureECDSA { + if sigType == signatureECDSA { return h.server.Sum(nil), crypto.SHA1, nil } diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA index 099cef4ba9a..f7b661223f5 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 4f 5d 09 43 37 |....Y...U..O].C7| -00000010 70 c6 d9 8b 07 ca 1a f0 fb a7 05 51 53 67 7a 7e |p..........QSgz~| -00000020 c9 c6 68 10 10 2a 69 bd 47 db 8e 20 f2 13 5b 26 |..h..*i.G.. ..[&| -00000030 e6 8e 19 b0 bc b5 ee 1f ca 44 5d 32 11 37 b0 78 |.........D]2.7.x| -00000040 49 16 6e c2 44 86 52 3f 9f 05 15 aa c0 09 00 00 |I.n.D.R?........| +00000000 16 03 01 00 59 02 00 00 55 03 01 37 4c 3d 48 47 |....Y...U..7L=HG| +00000010 2c b1 fb 63 1d 94 a6 b7 57 87 72 ec 4d 29 f9 4e |,..c....W.r.M).N| +00000020 81 d1 b6 27 8c 6a 27 c0 d3 c5 32 20 2d 80 95 68 |...'.j'...2 -..h| +00000030 a9 f9 2a 79 af be 9f d3 ce 4f 6a 2c 6b b3 dd 9e |..*y.....Oj,k...| +00000040 62 e2 08 b9 24 a3 fe 23 11 f8 cd ab c0 09 00 00 |b...$..#........| 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....| @@ -49,18 +49,18 @@ 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 b5 0c 00 00 b1 03 00 1d 20 56 b4 |*............ V.| -00000280 39 d4 8f 18 79 87 89 d0 04 ee 12 54 20 2b be c1 |9...y......T +..| -00000290 94 99 40 a2 73 df 1e 92 66 0b d1 f1 d6 38 00 8b |..@.s...f....8..| -000002a0 30 81 88 02 42 01 38 12 59 bd ea 44 59 f4 6f a9 |0...B.8.Y..DY.o.| -000002b0 8e 9e a0 85 b5 b3 55 3e 76 49 b7 75 98 6e 81 30 |......U>vI.u.n.0| -000002c0 c4 73 bd 54 78 39 f7 e2 22 49 4c 93 0d c1 26 89 |.s.Tx9.."IL...&.| -000002d0 08 b9 9c 8b 86 3e 81 2c a5 50 7c e9 88 ec c0 ad |.....>.,.P|.....| -000002e0 9e e0 40 ac 4e 0a fd 02 42 01 2e 0d 37 73 6a 0d |..@.N...B...7sj.| -000002f0 a4 60 08 a0 2b 32 0f 87 8d f8 9b c7 68 cf 50 79 |.`..+2......h.Py| -00000300 73 f7 cf 93 aa 75 57 20 58 3d 13 c0 f3 66 7d 59 |s....uW X=...f}Y| -00000310 15 73 d4 29 03 34 df 33 00 c0 b5 71 bc 2a 90 ef |.s.).4.3...q.*..| -00000320 3c 02 5e ea 9d 29 93 1c 18 db 04 16 03 01 00 0a |<.^..)..........| +00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 14 a7 |*............ ..| +00000280 f5 4f 06 cf f6 92 3d 98 59 e2 36 72 2c 45 ce 98 |.O....=.Y.6r,E..| +00000290 a2 97 c3 3c ba 67 b3 6a fe 0a 2c f7 ae 03 00 8b |...<.g.j..,.....| +000002a0 30 81 88 02 42 00 cd a1 a2 cc 81 c9 7a c5 a9 54 |0...B.......z..T| +000002b0 19 61 0a d3 23 7a cb f8 52 54 16 c3 38 b6 9e f2 |.a..#z..RT..8...| +000002c0 a6 7f 5a 5c e7 3f ae c8 85 c1 01 6f 90 94 c4 e1 |..Z\.?.....o....| +000002d0 c3 56 b3 da 4c 92 9c 11 0f 4d 06 31 3f d9 a4 77 |.V..L....M.1?..w| +000002e0 1e 99 f6 3d ef 5e 06 02 42 01 4c f6 ac 3b 87 7b |...=.^..B.L..;.{| +000002f0 a1 3b 59 28 ab 00 dd 06 e7 9c 8a 8b 0e 50 48 49 |.;Y(.........PHI| +00000300 4d b8 56 34 94 6a 7f 7a 6c 17 b0 2a 29 42 18 aa |M.V4.j.zl..*)B..| +00000310 a6 86 ce e0 d7 77 c1 e0 ea 40 96 50 79 ee e0 3c |.....w...@.Py..<| +00000320 6b 4e c1 07 b3 05 f5 9a 71 aa 9d 16 03 01 00 0a |kN......q.......| 00000330 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........| 00000340 00 00 00 |...| >>> Flow 3 (client to server) @@ -99,30 +99,30 @@ 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| -00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......| -00000240 00 8d 00 8b 30 81 88 02 42 01 53 2c a8 59 57 d2 |....0...B.S,.YW.| -00000250 fc 0b 12 27 6f 9a f7 4e a0 dd 2c af 1b 4c 81 0b |...'o..N..,..L..| -00000260 97 79 7e 6f dd a1 cf cb e2 14 4d af 76 99 d8 06 |.y~o......M.v...| -00000270 4f 8d 4f 86 d3 25 04 ea 80 02 ae 25 10 9d 2d 59 |O.O..%.....%..-Y| -00000280 11 39 65 6b 83 d0 16 7d bf a8 a4 02 42 01 f2 16 |.9ek...}....B...| -00000290 6c f1 e6 3b b1 af fb 3f 99 f0 8a e3 c8 62 ba 71 |l..;...?.....b.q| -000002a0 12 a1 2c 1e 15 74 d5 98 b5 ae 9f 50 a2 15 9b 73 |..,..t.....P...s| -000002b0 9a 5f 2c 90 d4 9d 20 6f 35 b6 32 3e f4 b7 dd 50 |._,... o5.2>...P| -000002c0 64 42 e3 4e 51 f3 11 4b b4 9e a3 92 a2 10 59 14 |dB.NQ..K......Y.| -000002d0 03 01 00 01 01 16 03 01 00 30 78 8c 7c 31 ce 16 |.........0x.|1..| -000002e0 8f 1f 2a b9 ee cb 72 7f 1e 59 5b ad c2 58 32 77 |..*...r..Y[..X2w| -000002f0 fa 46 83 b9 67 0c 5f 41 25 6a 38 ec 20 d2 80 e6 |.F..g._A%j8. ...| -00000300 be 85 ce 94 b1 89 5f 8d 17 9b |......_...| +00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 90 0f 00 |...._X.;t.......| +00000240 00 8c 00 8a 30 81 87 02 41 69 90 2d 22 89 47 af |....0...Ai.-".G.| +00000250 7e ab 99 d8 fc 71 00 e0 03 d8 03 36 2c 9f 5d 59 |~....q.....6,.]Y| +00000260 27 2e c8 88 6f ba 7f 61 5a 86 8e 87 fd 3e 92 23 |'...o..aZ....>.#| +00000270 e3 4e 49 af fe 2b 34 80 63 dd e3 e4 6b ca bd 08 |.NI..+4.c...k...| +00000280 31 c8 54 27 d2 31 75 68 56 5d 02 42 01 1c 80 ed |1.T'.1uhV].B....| +00000290 fc 67 1a e1 cd c0 dc 9d 22 2b 7f 9b 0a 6d 3e 3b |.g......"+...m>;| +000002a0 ac 37 90 20 67 50 a1 e0 16 3c 3c 8c a1 46 2b 81 |.7. gP...<<..F+.| +000002b0 48 b3 c3 c7 57 3b 26 17 51 4e d7 30 08 9c 2e d9 |H...W;&.QN.0....| +000002c0 87 41 93 21 94 fe 47 34 16 a1 e3 dc 68 a7 14 03 |.A.!..G4....h...| +000002d0 01 00 01 01 16 03 01 00 30 68 22 41 51 d1 f0 15 |........0h"AQ...| +000002e0 e5 19 86 95 89 c2 a1 65 23 b2 61 44 fa 7e 07 9e |.......e#.aD.~..| +000002f0 f9 91 4b 17 a5 3b 7c 6e e5 ee bf 06 4c 91 00 f5 |..K..;|n....L...| +00000300 be b7 d5 b5 7c 88 21 0d ae |....|.!..| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 95 d6 f2 a2 75 |..........0....u| -00000010 0e f8 c7 7c f9 1d 65 b4 82 08 c9 62 aa 93 24 8f |...|..e....b..$.| -00000020 4d 11 c7 b0 17 04 f1 0a 8b be 64 06 f9 07 20 0b |M.........d... .| -00000030 f0 3b 92 db 62 ba 63 91 a1 58 fe |.;..b.c..X.| +00000000 14 03 01 00 01 01 16 03 01 00 30 22 37 a1 e7 52 |..........0"7..R| +00000010 94 4a e6 d8 e2 0a 96 37 9e 3e f2 a1 96 42 0f c9 |.J.....7.>...B..| +00000020 ba 95 15 27 3e 9c 01 04 0e 41 01 e5 a6 c7 b4 c7 |...'>....A......| +00000030 c6 54 b2 0e 96 52 6c cd 73 11 d3 |.T...Rl.s..| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 3e a4 b5 b5 2f 4f c8 e0 08 cf 8a |.... >.../O.....| -00000010 9c f6 69 94 a9 91 0f 5d c5 06 ee 71 e2 42 11 b4 |..i....]...q.B..| -00000020 a8 17 54 19 3d 17 03 01 00 20 ce d2 8d 8a 78 e4 |..T.=.... ....x.| -00000030 15 a4 ab 83 0d 9c fa 47 1c 8f 2d 87 a8 55 65 9d |.......G..-..Ue.| -00000040 7f 03 75 11 62 83 0b 44 0b f1 15 03 01 00 20 eb |..u.b..D...... .| -00000050 1a 46 95 1e 1b 10 b7 25 a8 c4 5b db 8b 3c 61 c9 |.F.....%..[..>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 32 7c 5c ac bd |....Y...U..2|\..| -00000010 77 70 c2 f8 f0 20 37 e4 e8 45 db be 97 22 e4 f3 |wp... 7..E..."..| -00000020 24 1c c1 29 8f 02 e1 bc ba 4a 1e 20 81 6f b5 12 |$..).....J. .o..| -00000030 c0 9d 9e de 2f b6 04 b2 74 34 da 2b 04 55 2c 4f |..../...t4.+.U,O| -00000040 dd 01 8a 30 d9 67 45 9f f1 31 f1 78 c0 13 00 00 |...0.gE..1.x....| +00000000 16 03 01 00 59 02 00 00 55 03 01 af af 0f 49 f7 |....Y...U.....I.| +00000010 fa 29 30 cb 90 30 b4 70 d2 94 96 db 99 f9 4d 10 |.)0..0.p......M.| +00000020 4c 14 67 a0 2f ac cc e6 7f 89 c2 20 d8 e0 15 ba |L.g./...... ....| +00000030 55 99 b7 20 04 e2 84 e4 5d 97 4b ea 6e d5 6b db |U.. ....].K.n.k.| +00000040 dc 23 2a a1 76 4c fd c0 5f a6 4a e1 c0 13 00 00 |.#*.vL.._.J.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,17 +54,17 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......| -000002c0 aa 0c 00 00 a6 03 00 1d 20 2f f7 3b 44 1a 47 85 |........ /.;D.G.| -000002d0 d7 db 40 28 4e 6a f1 2f 1e b5 cc b0 58 0d 92 93 |..@(Nj./....X...| -000002e0 30 41 65 08 05 f7 51 23 57 00 80 87 0d c3 22 ff |0Ae...Q#W.....".| -000002f0 aa d1 3f 55 09 cf 98 dc 91 f8 d0 63 58 da dc 52 |..?U.......cX..R| -00000300 03 f0 06 a6 4e 7e 5b 96 a1 3b d7 8e 1e 68 50 ef |....N~[..;...hP.| -00000310 59 3f 78 06 eb 9a 33 c5 01 3c e0 fb c6 f1 b6 bc |Y?x...3..<......| -00000320 5a bc 95 e8 43 d9 ab 36 05 26 13 c5 a6 68 9b e2 |Z...C..6.&...h..| -00000330 b1 42 6e 89 60 5c b3 91 02 c5 8b ab 53 d1 d9 79 |.Bn.`\......S..y| -00000340 d0 37 b5 5e 2c 16 72 29 f8 9c d0 4a 46 87 46 f4 |.7.^,.r)...JF.F.| -00000350 01 2b e8 6a 4f 59 d1 2d 3d de 4b 3b 0e c7 cd 42 |.+.jOY.-=.K;...B| -00000360 ae d2 94 e9 a6 6b 65 ad 3f 77 57 16 03 01 00 0a |.....ke.?wW.....| +000002c0 aa 0c 00 00 a6 03 00 1d 20 b7 12 77 ce bd 55 19 |........ ..w..U.| +000002d0 d6 16 92 11 72 ad dc b4 9c fd 7a cd dc 31 53 0f |....r.....z..1S.| +000002e0 bc bf 12 0a 9f 32 c9 e3 09 00 80 6e 49 99 f1 c2 |.....2.....nI...| +000002f0 6c 4e cd c1 bb cc b1 db fd e5 3a 12 c9 94 dd 11 |lN........:.....| +00000300 84 b3 5f 43 15 7c f5 05 a0 13 90 05 0e bb 13 60 |.._C.|.........`| +00000310 c5 ef 30 e6 cb 5d b2 50 10 99 1f 01 13 43 37 e8 |..0..].P.....C7.| +00000320 6c 95 aa ae 3e f6 53 25 92 48 d1 f6 e1 7d 88 0e |l...>.S%.H...}..| +00000330 23 fb ee 72 e8 84 83 6b bc d6 96 3c 1d 62 98 3e |#..r...k...<.b.>| +00000340 89 c7 19 cc cd 08 d3 cb b2 fe 39 51 f0 62 89 71 |..........9Q.b.q| +00000350 d7 83 78 33 0d de f8 81 5a e4 f3 ea 55 e9 58 41 |..x3....Z...U.XA| +00000360 94 b2 1b b9 1f 3b 52 f1 d3 d0 51 16 03 01 00 0a |.....;R...Q.....| 00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........| 00000380 00 00 00 |...| >>> Flow 3 (client to server) @@ -104,29 +104,29 @@ 00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| 00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......| -00000240 00 8d 00 8b 30 81 88 02 42 01 b3 df 59 06 71 e6 |....0...B...Y.q.| -00000250 74 c9 9d d5 2c b0 a7 f8 1e ac bc f3 5a e2 ed 0b |t...,.......Z...| -00000260 f2 e9 37 82 c6 fe 7c 23 b9 63 6e 88 1d 63 31 ad |..7...|#.cn..c1.| -00000270 d3 29 48 eb f3 5d 52 f5 76 ab fc 16 9e 09 4f 49 |.)H..]R.v.....OI| -00000280 cf b4 03 6a ed db e5 13 ea 67 74 02 42 01 8e 2f |...j.....gt.B../| -00000290 b8 12 38 c9 a6 8c 77 40 85 89 ef d8 ac 08 00 c0 |..8...w@........| -000002a0 ee 70 68 a6 88 1f d1 67 0d 1b 7b 1f be e0 a7 b9 |.ph....g..{.....| -000002b0 c3 7d ff 6a 39 3c b9 aa f6 78 ac 9a ca 67 55 0c |.}.j9<...x...gU.| -000002c0 38 23 cc ab 18 c0 b9 ea 9c 84 61 32 0a 0d f3 14 |8#........a2....| -000002d0 03 01 00 01 01 16 03 01 00 30 73 12 76 94 30 37 |.........0s.v.07| -000002e0 e5 e3 30 59 88 2f 5f e9 f2 7b 3d 02 88 65 09 14 |..0Y./_..{=..e..| -000002f0 68 23 02 d0 ae e5 7f 7f 8d 95 3b 1c 75 f5 1f 24 |h#........;.u..$| -00000300 43 60 29 bb 0e 69 88 36 a9 68 |C`)..i.6.h| +00000240 00 8d 00 8b 30 81 88 02 42 01 8b 84 b3 ac 64 4e |....0...B.....dN| +00000250 77 d2 47 77 13 2f 45 ec 0b 3f 92 ef 55 cc 78 8e |w.Gw./E..?..U.x.| +00000260 d9 c1 ae 4b c5 6f 01 d0 55 ca 0b 12 cf 3c ac c8 |...K.o..U....<..| +00000270 46 7b 6a c4 22 f3 16 85 1a 2a ea 4f f6 65 1c c9 |F{j."....*.O.e..| +00000280 90 7b d1 c5 9f c8 59 73 43 47 bd 02 42 00 93 a3 |.{....YsCG..B...| +00000290 35 0a 1f 14 de 23 fa 92 a4 d6 5e dc fd c0 85 87 |5....#....^.....| +000002a0 fb 23 12 bd 8e d7 f3 98 33 49 fc 88 92 13 8a 7d |.#......3I.....}| +000002b0 ee 12 e5 d6 b3 ff bf 04 7e 48 ff 83 6b 76 70 b8 |........~H..kvp.| +000002c0 8c 1f f5 44 4b a7 fb 48 81 87 a0 6b 66 45 15 14 |...DK..H...kfE..| +000002d0 03 01 00 01 01 16 03 01 00 30 83 d6 1c 9f e9 ef |.........0......| +000002e0 49 45 e4 97 17 2c af 6f 4e 59 0e 4d 43 69 88 fd |IE...,.oNY.MCi..| +000002f0 3d 99 00 9e 02 3c 33 78 d6 37 6e f9 55 43 ac 16 |=....<3x.7n.UC..| +00000300 2e 14 0e 0e 44 a1 f7 1e fc 09 |....D.....| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 a0 5f 7f 59 e0 |..........0._.Y.| -00000010 b1 7e ed ad de 6a 47 94 21 e5 1b 77 a7 d0 88 fd |.~...jG.!..w....| -00000020 9e 4e 48 87 1d cf 40 e4 b9 38 a3 2e e4 00 c3 94 |.NH...@..8......| -00000030 95 20 1c 97 d2 a9 3a 11 86 30 5f |. ....:..0_| +00000000 14 03 01 00 01 01 16 03 01 00 30 75 1b 70 70 73 |..........0u.pps| +00000010 c3 2d d5 7a a5 ca 63 b3 b7 b1 57 a8 bc fd 5c 95 |.-.z..c...W...\.| +00000020 ed e7 88 26 b3 9b a6 8d c7 3f 02 70 a7 98 1c 33 |...&.....?.p...3| +00000030 86 67 f7 ca 76 42 53 99 3b 17 ef |.g..vBS.;..| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 ca 4c f5 cb 81 66 2f 97 e3 5d 8b |.... .L...f/..].| -00000010 dd 7d dd fa fe 8c 98 45 3f 3d 16 17 98 4d b5 15 |.}.....E?=...M..| -00000020 6c 91 8a 79 7a 17 03 01 00 20 96 ec 30 cb d3 78 |l..yz.... ..0..x| -00000030 b9 0a a1 ab fd 12 25 d5 82 7b 7a 3c 17 56 7b b7 |......%..{z<.V{.| -00000040 c4 6e ea a2 5b d7 6b b6 22 a9 15 03 01 00 20 ba |.n..[.k."..... .| -00000050 ff fe 2b 60 83 34 ad 45 75 15 d5 95 b3 27 92 46 |..+`.4.Eu....'.F| -00000060 47 ae f1 d4 a4 9d 63 ef db d9 b5 37 0f f1 74 |G.....c....7..t| +00000000 17 03 01 00 20 61 40 b2 4d fe 8d 3c a1 d2 4b 36 |.... a@.M..<..K6| +00000010 bb 5d 6c 77 65 6e 66 55 57 12 a5 62 9d 56 f6 53 |.]lwenfUW..b.V.S| +00000020 dd a6 38 7c 32 17 03 01 00 20 e5 98 82 47 a0 cc |..8|2.... ...G..| +00000030 a7 02 98 71 01 00 d7 ee 1c 35 16 d6 7a 03 80 95 |...q.....5..z...| +00000040 d0 69 9a e9 bb 4c 9c 0a 92 59 15 03 01 00 20 a2 |.i...L...Y.... .| +00000050 96 8a 21 a9 a4 28 83 f8 fb 3c aa 6e 53 fb 23 7e |..!..(...<.nS.#~| +00000060 a1 08 4f 16 8f 34 02 27 34 e2 c2 71 1e a2 c7 |..O..4.'4..q...| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA index 67772e174aa..65bc2783347 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 ed 13 de 15 cc |....Y...U.......| -00000010 90 4f f3 72 5a d4 7a 01 26 fa 7a ae 38 92 a0 d6 |.O.rZ.z.&.z.8...| -00000020 70 4a 20 f6 7e 11 f7 ac e6 94 87 20 9f 37 0f 8f |pJ .~...... .7..| -00000030 55 a6 6a 97 b8 0f 56 aa 2d 69 c5 79 01 d5 c0 01 |U.j...V.-i.y....| -00000040 2c 2b 0e 16 d8 79 a3 f3 44 99 7c 01 c0 09 00 00 |,+...y..D.|.....| +00000000 16 03 01 00 59 02 00 00 55 03 01 3b ff d1 3d 27 |....Y...U..;..='| +00000010 af 29 b4 e8 d8 71 40 08 5c 7b 8b a9 23 8a 70 1a |.)...q@.\{..#.p.| +00000020 c8 a4 19 11 71 7b 92 58 03 af 99 20 c8 18 fc 7d |....q{.X... ...}| +00000030 e6 ed 7b d7 1c 2a 5e d5 5b 22 d9 dc 9e b1 aa 88 |..{..*^.["......| +00000040 0a 9f fb 4a 8a d7 27 d9 65 df 76 3a c0 09 00 00 |...J..'.e.v:....| 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....| @@ -49,18 +49,18 @@ 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 b4 0c 00 00 b0 03 00 1d 20 ca e8 |*............ ..| -00000280 ef 79 56 cd aa eb 12 8f e1 89 d1 3c 63 1f c8 54 |.yV........>> Flow 3 (client to server) @@ -99,29 +99,29 @@ 00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.| 00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...| 00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....| -00000230 86 0f 00 00 82 00 80 8f 6f 77 5d d5 99 28 0c 7a |........ow]..(.z| -00000240 36 f2 50 ec 9a e6 eb 88 ac 45 f7 9b 6f 98 84 ba |6.P......E..o...| -00000250 fb 3c b8 d6 54 61 b8 87 25 50 3c 31 5a d2 c1 54 |.<..Ta..%P<1Z..T| -00000260 e8 ed c3 93 cc 98 b1 c3 d4 84 11 d8 a0 c7 ae 67 |...............g| -00000270 67 35 6a 0f 93 18 bb 18 52 f8 25 88 1f d2 19 4d |g5j.....R.%....M| -00000280 3b 4c f2 0f f7 06 68 57 cf 45 20 e0 57 75 37 e9 |;L....hW.E .Wu7.| -00000290 cd 86 1f e5 d2 90 1e cf 3a 18 fd 45 bc a1 84 63 |........:..E...c| -000002a0 36 d8 ac 6b 09 41 da 0a 87 7f ab ce 8e 49 e6 c8 |6..k.A.......I..| -000002b0 bf fb 2c 3b 7b e9 ae 14 03 01 00 01 01 16 03 01 |..,;{...........| -000002c0 00 30 7d 65 9c c1 25 e4 85 d7 39 d4 67 cf eb f1 |.0}e..%...9.g...| -000002d0 b7 c2 4d e6 5d bd 13 74 55 22 f0 8a 7e a6 a2 eb |..M.]..tU"..~...| -000002e0 93 cc b7 fa 86 b1 b5 e0 a3 ef ee 56 f0 cd f7 a5 |...........V....| -000002f0 d8 9e |..| +00000230 86 0f 00 00 82 00 80 35 95 c1 44 9d 66 18 82 91 |.......5..D.f...| +00000240 5b 25 68 80 9c 07 78 c6 ed da 98 25 07 9a c4 08 |[%h...x....%....| +00000250 b3 10 a2 67 b0 5b 0e c2 3d 25 af ea bc e1 5f a7 |...g.[..=%...._.| +00000260 d2 58 e9 a7 0c c8 c4 10 d0 44 a4 a1 a6 07 12 b1 |.X.......D......| +00000270 7f 22 6c 54 4e 97 ad b5 55 a0 58 ed c7 52 7a d6 |."lTN...U.X..Rz.| +00000280 5a 23 4f 6b b2 41 0f 01 2b 97 93 02 6f ce bd 32 |Z#Ok.A..+...o..2| +00000290 12 d3 af 32 09 0c a8 1a 16 58 f3 d8 d6 fe ba 84 |...2.....X......| +000002a0 57 b0 18 5c 86 35 83 54 6e f7 04 21 29 62 1c 76 |W..\.5.Tn..!)b.v| +000002b0 dc 44 03 5c 3a 1a 41 14 03 01 00 01 01 16 03 01 |.D.\:.A.........| +000002c0 00 30 2e 3f d7 4c 32 5f 13 48 47 46 b0 30 c1 00 |.0.?.L2_.HGF.0..| +000002d0 49 5d 6d 58 b6 1c ea f4 f9 1c 48 b9 01 9c 9c 94 |I]mX......H.....| +000002e0 7f 83 5a e7 c3 10 92 ad 9f fa a8 c6 57 49 ae 3a |..Z.........WI.:| +000002f0 3a 2a |:*| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 ff 13 14 c5 ad |..........0.....| -00000010 88 ec a1 cf cc 0d 3f 7b ec 50 4a 25 69 1f 18 dc |......?{.PJ%i...| -00000020 b1 99 1f 3b 78 60 e0 83 c0 cd 9a b3 0d 59 0b f8 |...;x`.......Y..| -00000030 8a b7 7c 2c b4 2c e4 d0 49 82 82 |..|,.,..I..| +00000000 14 03 01 00 01 01 16 03 01 00 30 29 fc da 17 09 |..........0)....| +00000010 5a 69 1b 4f 2e 4f 40 1d 9e 69 6c 62 ee 8b f9 53 |Zi.O.O@..ilb...S| +00000020 48 6a ae b6 85 df ab f3 89 8d f3 6e df f0 8f 14 |Hj.........n....| +00000030 79 a3 d8 d5 e4 3c 6b dd fb 77 24 |y....>> Flow 5 (client to server) -00000000 17 03 01 00 20 51 91 74 f6 31 07 15 6b 9e 0b 28 |.... Q.t.1..k..(| -00000010 02 b8 ec 9d c6 e3 15 24 d3 ea 4b 27 d0 fa 9f c2 |.......$..K'....| -00000020 c4 8d 37 b3 d9 17 03 01 00 20 7d 97 75 fe de 3f |..7...... }.u..?| -00000030 ae ab e6 a8 1d 76 1c 06 9c 02 61 cc f5 1d fe c8 |.....v....a.....| -00000040 a2 dc ae 97 7f 1c 05 19 e5 14 15 03 01 00 20 4a |.............. J| -00000050 bc 45 97 6b 09 8e 47 5f d5 a0 97 78 79 67 09 8d |.E.k..G_...xyg..| -00000060 d3 80 38 58 5c cc ae 8e d4 67 1d 93 2b 20 79 |..8X\....g..+ y| +00000000 17 03 01 00 20 89 6b 03 b2 9d cc f2 6f 8f 27 6c |.... .k.....o.'l| +00000010 d4 49 61 4f 88 c1 6c b6 ef 2e 75 b9 0d d4 06 b0 |.IaO..l...u.....| +00000020 cb 6f 80 70 f6 17 03 01 00 20 ab 92 7f df 5f 38 |.o.p..... ...._8| +00000030 87 d7 7e ff 9c 17 14 cc 41 8d 28 98 7d 6a 59 78 |..~.....A.(.}jYx| +00000040 f0 9f d1 f1 f1 5a 75 27 fa 57 15 03 01 00 20 a3 |.....Zu'.W.... .| +00000050 3b 0c 84 bc d7 5d f6 87 b1 14 bd c4 6e a8 14 ae |;....]......n...| +00000060 e8 fd f2 50 67 b9 fa 6c 86 d8 6d 84 87 5e fe |...Pg..l..m..^.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA index e585894db7e..fef2ac07113 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 61 6b 2e 41 7f |....Y...U..ak.A.| -00000010 af 26 6f a2 8b 63 ee e4 b1 76 19 3a 6d a3 c2 30 |.&o..c...v.:m..0| -00000020 37 e8 47 c2 90 10 7e e8 c5 b2 eb 20 00 1c 8f 70 |7.G...~.... ...p| -00000030 0d 15 4a c7 7d ab ca 79 a7 d8 c2 01 62 6e 6f aa |..J.}..y....bno.| -00000040 df a2 1c 8f 7c 27 d9 e6 fe e9 c8 ab c0 13 00 00 |....|'..........| +00000000 16 03 01 00 59 02 00 00 55 03 01 58 89 71 77 b1 |....Y...U..X.qw.| +00000010 c2 2a 4e e4 5a 4f bb 76 8a b5 9b f3 b1 c6 fc 30 |.*N.ZO.v.......0| +00000020 a8 ca 7e 5c d6 29 41 7d 17 04 5d 20 86 f6 c6 6f |..~\.)A}..] ...o| +00000030 5f 48 2c 43 07 ea d1 b3 81 da 6d 2f 70 aa 4c 2e |_H,C......m/p.L.| +00000040 d4 87 bb 4c 38 c9 67 bc 80 38 d0 c3 c0 13 00 00 |...L8.g..8......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,17 +54,17 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......| -000002c0 aa 0c 00 00 a6 03 00 1d 20 29 0b ca 37 f3 a1 52 |........ )..7..R| -000002d0 49 1c 84 9a e4 74 6b 4b 2d 1f e6 e9 83 1d 5d 59 |I....tkK-.....]Y| -000002e0 5a 2f 09 9f bc a4 30 af 71 00 80 d9 bb 6d 09 a7 |Z/....0.q....m..| -000002f0 ab 47 6f e8 a6 1a da fb 66 7d a5 f0 c9 c3 24 4c |.Go.....f}....$L| -00000300 99 56 c6 29 71 27 08 0b c1 60 44 cc 6d 42 1b 5e |.V.)q'...`D.mB.^| -00000310 cd 9f 82 24 38 23 ec d9 fa 32 49 2f 16 5d d2 9d |...$8#...2I/.]..| -00000320 e9 13 4e 66 3d f8 bf 30 2e 8c eb 35 4c e8 81 86 |..Nf=..0...5L...| -00000330 c0 de c7 0d a9 60 7e 7c 4a c4 1d a0 89 70 de 82 |.....`~|J....p..| -00000340 1b 37 a0 ea 7f 20 a5 fe d4 20 1d 6f 1a 84 dd a4 |.7... ... .o....| -00000350 13 46 18 c6 31 14 81 4b a4 bb 43 5c c4 49 1c 5a |.F..1..K..C\.I.Z| -00000360 8d 12 57 e0 1d 9a b6 cd f1 39 ff 16 03 01 00 0a |..W......9......| +000002c0 aa 0c 00 00 a6 03 00 1d 20 0c 12 68 b0 30 bb 4b |........ ..h.0.K| +000002d0 b0 c2 38 4d fa 65 f1 43 4a f1 47 dc 6e 6d ae 6b |..8M.e.CJ.G.nm.k| +000002e0 35 f5 4a 3c fa bc a6 6e 27 00 80 38 ef 5d 08 06 |5.J<...n'..8.]..| +000002f0 e5 f9 86 86 2e f3 6d b6 d4 12 94 5d 18 6b 11 67 |......m....].k.g| +00000300 17 65 d3 5c 0b fe 09 2d bb ca a6 2d c4 d7 fc b9 |.e.\...-...-....| +00000310 71 c1 4a 38 bb 14 bf dc 1b 4d 61 38 c6 76 3e 24 |q.J8.....Ma8.v>$| +00000320 ff e6 c5 7e f8 5d 5f 80 3d 8a 4e 5f bb 91 b7 c5 |...~.]_.=.N_....| +00000330 59 f8 b7 a1 7b d5 c3 72 57 83 de 52 40 75 1c ec |Y...{..rW..R@u..| +00000340 77 e9 0e a6 3a ad e4 57 ae d4 92 44 40 00 74 fa |w...:..W...D@.t.| +00000350 ae 16 b9 82 0d 9e 2a 43 12 1b a6 bb a1 89 6a 99 |......*C......j.| +00000360 09 80 d1 ad b6 9c 92 01 60 14 bb 16 03 01 00 0a |........`.......| 00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........| 00000380 00 00 00 |...| >>> Flow 3 (client to server) @@ -103,29 +103,29 @@ 00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.| 00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...| 00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....| -00000230 86 0f 00 00 82 00 80 12 76 af 25 e4 e7 ff d6 e4 |........v.%.....| -00000240 27 58 31 0f 6b 1e 84 13 2f d0 60 80 18 c3 f8 c1 |'X1.k.../.`.....| -00000250 f8 04 39 d4 07 05 d3 96 e2 b2 10 de 1f 68 88 67 |..9..........h.g| -00000260 1d dd 0a 11 52 9d 16 0e af 07 de cb f1 7c f4 b4 |....R........|..| -00000270 5d 0f 4f 43 5b 3c 25 07 32 13 f2 ab 9b 2d d0 a8 |].OC[<%.2....-..| -00000280 28 90 cb 04 48 c3 43 bd 2b b4 ef b9 7b cd bd d5 |(...H.C.+...{...| -00000290 bc d1 cc 00 17 46 fa 9b 1f 44 58 b7 6c de 1b 7a |.....F...DX.l..z| -000002a0 e0 d7 12 38 a3 09 f8 7a 9b 26 0b ee 37 bc 79 1b |...8...z.&..7.y.| -000002b0 51 9f 9a 1f f9 a9 51 14 03 01 00 01 01 16 03 01 |Q.....Q.........| -000002c0 00 30 97 df fb 79 78 a8 27 fd 2b 68 6b ec 4d 29 |.0...yx.'.+hk.M)| -000002d0 a1 02 59 ae 18 0b 46 62 af 61 53 2f 95 50 f2 ac |..Y...Fb.aS/.P..| -000002e0 c8 c3 5e 78 ca b0 e2 5d ff d7 1b 9b 00 30 f6 da |..^x...].....0..| -000002f0 d7 91 |..| +00000230 86 0f 00 00 82 00 80 1d 64 73 05 fa f9 5e ef eb |........ds...^..| +00000240 c7 1b 07 99 0e d1 52 83 9e 19 ba 62 11 14 0a c2 |......R....b....| +00000250 11 e0 ff 6e 43 03 85 1d ef 73 f8 c2 4d b0 c6 5a |...nC....s..M..Z| +00000260 ba 14 14 1e 95 d1 f8 1a 3f 7f c3 08 f4 86 e6 2c |........?......,| +00000270 43 2f 00 fd d7 e1 4e 07 45 09 19 98 33 ad 6e e2 |C/....N.E...3.n.| +00000280 17 21 3b 8c a4 5e 50 6c 5a a3 75 68 93 a5 ee 42 |.!;..^PlZ.uh...B| +00000290 a9 88 6d c4 4e 9c 3f ce ee e1 a1 9b c4 c6 8e f7 |..m.N.?.........| +000002a0 65 b8 7f 10 a9 5f b8 07 70 8a 4f 89 2c 59 a1 46 |e...._..p.O.,Y.F| +000002b0 f9 a2 05 bc 01 45 7e 14 03 01 00 01 01 16 03 01 |.....E~.........| +000002c0 00 30 43 ec 90 51 04 0a 70 f7 8b a4 15 63 df 1b |.0C..Q..p....c..| +000002d0 70 eb 59 63 d1 54 41 4e 7e 82 e4 fb fe ca 87 6e |p.Yc.TAN~......n| +000002e0 86 2d c6 d2 ee 1c 7b 9e 72 2d d6 d6 12 15 a8 8b |.-....{.r-......| +000002f0 b2 9d |..| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 f9 e9 d7 8c 4a |..........0....J| -00000010 6b f4 c9 88 d6 98 70 53 13 fc 51 9c 81 14 cf 71 |k.....pS..Q....q| -00000020 d9 30 7a d9 2c 34 96 00 a4 a0 2b 1e 7d ff d0 f2 |.0z.,4....+.}...| -00000030 b7 81 ed 86 c5 e1 09 16 82 47 20 |.........G | +00000000 14 03 01 00 01 01 16 03 01 00 30 d2 8f 01 3c 0e |..........0...<.| +00000010 0d 9e 0d bb 92 0b e8 90 b8 39 53 b8 50 7a b0 c1 |.........9S.Pz..| +00000020 f3 89 3d 5c 1c a0 e8 97 21 c5 30 0f f1 14 11 6b |..=\....!.0....k| +00000030 ec 6e 8f 75 c8 7f 89 dd 3e 19 44 |.n.u....>.D| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 db b5 66 4e fb b1 47 8a 8e 6b a8 |.... ..fN..G..k.| -00000010 03 53 1a 51 22 8e 47 a3 3a 74 ed a4 6a aa 79 fd |.S.Q".G.:t..j.y.| -00000020 55 0f ac 35 a9 17 03 01 00 20 3e 0b 39 f5 5a 03 |U..5..... >.9.Z.| -00000030 43 d9 e2 7d 1c dc 3b 42 82 2a 2d d4 04 0a 76 97 |C..}..;B.*-...v.| -00000040 70 ed ee 99 58 15 40 c1 3a d5 15 03 01 00 20 bf |p...X.@.:..... .| -00000050 ea e8 93 67 a4 91 1a b5 f5 03 a5 94 50 95 41 16 |...g........P.A.| -00000060 b0 2a 74 d9 32 65 94 35 45 b9 0f 2e 80 87 fd |.*t.2e.5E......| +00000000 17 03 01 00 20 19 f5 38 97 ac a5 5a 25 d4 1e 3a |.... ..8...Z%..:| +00000010 8c e6 89 36 88 80 f9 95 09 b2 f5 1d a8 09 02 b6 |...6............| +00000020 ec aa 8e aa c6 17 03 01 00 20 3e ee df 1b 09 ff |......... >.....| +00000030 88 77 4a da 5c 74 cf 64 3d 92 a0 08 1c 7b 12 db |.wJ.\t.d=....{..| +00000040 72 99 0f d4 4e 20 55 17 1d d3 15 03 01 00 20 19 |r...N U....... .| +00000050 ee bc fc da 0b 15 72 da 43 bc 0b 0a 49 4d 67 63 |......r.C...IMgc| +00000060 3d 04 78 00 c3 9d 66 a5 16 96 68 80 88 27 47 |=.x...f...h..'G| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES index 529b7cef48b..ca39d9b5b26 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 b0 ec 4b 2e 9e |....Y...U....K..| -00000010 19 7d 7b 7e 7c 52 8a d2 2e 8a 97 05 8a c6 ae aa |.}{~|R..........| -00000020 c5 62 bd 6f bd 7e fe 6b c6 9f d4 20 74 db 02 b1 |.b.o.~.k... t...| -00000030 65 88 41 bb 9a 55 22 f3 01 c4 5c ca 39 86 b1 77 |e.A..U"...\.9..w| -00000040 c4 b3 45 16 eb 55 d8 15 b8 4d ac 12 c0 09 00 00 |..E..U...M......| +00000000 16 03 01 00 59 02 00 00 55 03 01 b2 70 62 50 ad |....Y...U...pbP.| +00000010 93 c5 c2 a6 66 60 f0 ed 9a 44 56 1a 9a 9c c0 00 |....f`...DV.....| +00000020 a4 5b 59 ee d5 b5 91 c2 04 c8 7d 20 d3 a3 00 df |.[Y.......} ....| +00000030 93 72 69 c9 d6 dd 3b ba 45 5c d2 7a cc 0e 10 3b |.ri...;.E\.z...;| +00000040 6b 6f eb 6a 7a d3 55 d6 eb e9 0a 8a c0 09 00 00 |ko.jz.U.........| 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....| @@ -49,37 +49,37 @@ 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 b5 0c 00 00 b1 03 00 1d 20 7d 74 |*............ }t| -00000280 bf aa a8 b6 c0 1f 78 0c 1a ee c5 b7 56 ff 5c aa |......x.....V.\.| -00000290 f4 e3 a5 0c f7 64 31 eb 85 8a c9 bd 05 1b 00 8b |.....d1.........| -000002a0 30 81 88 02 42 00 f8 5d e5 bf 2e 70 79 f4 36 90 |0...B..]...py.6.| -000002b0 fc 6e 9a cc f1 c4 01 50 8c b9 92 4e bd e0 82 2d |.n.....P...N...-| -000002c0 1b ab 30 71 d1 db 76 af 50 75 08 fb cb 50 5b 00 |..0q..v.Pu...P[.| -000002d0 49 72 f5 d7 d9 44 48 94 ac 1d 8d 2e 50 90 ad a3 |Ir...DH.....P...| -000002e0 42 2b 5f 57 48 5e 9e 02 42 00 bb 0b 9a d7 25 53 |B+_WH^..B.....%S| -000002f0 04 5c 58 01 07 8e 3d ee f5 4f 0b 80 bd 02 07 3e |.\X...=..O.....>| -00000300 ff b9 01 ac 7a 49 be 94 fa cf 58 5c 59 91 b5 5d |....zI....X\Y..]| -00000310 cc 61 b9 e3 2f 53 7d 3c 3f 41 c5 31 1a 90 fc fa |.a../S}..| +000002c0 06 ad e6 1e 2f 31 75 90 f1 22 28 39 d3 af 96 73 |..../1u.."(9...s| +000002d0 52 76 34 9b cd 7c 5d 46 6b 48 30 9a d9 b7 63 23 |Rv4..|]FkH0...c#| +000002e0 f8 7f c2 80 22 55 02 41 6c bb 0c 49 c3 a3 57 a7 |...."U.Al..I..W.| +000002f0 cf 2b 3e 96 a1 53 01 72 d0 5a e4 af 54 8f 23 6c |.+>..S.r.Z..T.#l| +00000300 2d 60 91 f2 4a 93 1f 75 0f cc a4 0a 5c 2d 40 7b |-`..J..u....\-@{| +00000310 11 8c a1 96 fb 2b ad 6f eb 07 78 e5 70 26 37 7b |.....+.o..x.p&7{| +00000320 f4 19 1c d7 98 43 11 be 88 16 03 01 00 04 0e 00 |.....C..........| +00000330 00 00 |..| >>> Flow 3 (client to server) 00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......| -00000030 16 03 01 00 30 f5 d0 86 ef 96 7e b9 94 cc 19 62 |....0.....~....b| -00000040 cc 3a 14 f1 74 a2 0d c8 b9 4c 5d 8a c5 80 60 23 |.:..t....L]...`#| -00000050 d5 f5 04 06 16 e2 69 ca 4d 99 1b a0 b5 3b 7d 62 |......i.M....;}b| -00000060 51 62 ee d9 60 |Qb..`| +00000030 16 03 01 00 30 7a cf 24 f7 f6 69 1a ab 34 31 d5 |....0z.$..i..41.| +00000040 af ed 37 9f 1d 8d 3a 6b 72 a3 b0 fc b9 49 fb bc |..7...:kr....I..| +00000050 c5 94 9e 37 ce b0 87 8f ed 52 25 eb 2d 53 b9 39 |...7.....R%.-S.9| +00000060 d2 d3 f0 d6 97 |.....| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 4d f9 c2 63 4f |..........0M..cO| -00000010 98 1b 02 ce df ca d1 15 a2 4f 6f 4c 2c b8 1a 88 |.........OoL,...| -00000020 11 c9 b3 45 e6 1d cf e8 6b dd 8c 89 c6 1d 0b 66 |...E....k......f| -00000030 82 d5 1d c6 55 14 1c 56 59 3e 69 |....U..VY>i| +00000000 14 03 01 00 01 01 16 03 01 00 30 92 72 cc c3 1f |..........0.r...| +00000010 4b a5 c4 d7 6f d1 17 4b 4e 27 b7 f5 72 fd c2 a0 |K...o..KN'..r...| +00000020 30 cb 4c cf 82 1f 0a 49 3d 23 bc 47 f1 e8 a7 b5 |0.L....I=#.G....| +00000030 c7 6a 92 25 55 3a f0 0f b0 30 74 |.j.%U:...0t| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 12 be 42 b4 31 07 55 8e f9 a1 64 |.... ..B.1.U...d| -00000010 96 70 46 68 3e fd 4e 4f 9c af b3 11 de fc 80 f1 |.pFh>.NO........| -00000020 c8 11 84 ba ae 17 03 01 00 20 2f f9 ec dd 50 97 |......... /...P.| -00000030 1e a4 f1 66 fe 28 e3 c1 51 8d c0 f6 c3 d8 b3 ad |...f.(..Q.......| -00000040 7d dc a5 98 87 90 34 71 b4 73 15 03 01 00 20 d1 |}.....4q.s.... .| -00000050 6f 91 91 01 68 c4 11 6a e5 a2 ed 20 3f 3a 3d b7 |o...h..j... ?:=.| -00000060 d9 7f c3 b3 29 c3 df 3e 17 69 76 9f 04 f8 58 |....)..>.iv...X| +00000000 17 03 01 00 20 85 49 7a 58 80 e9 59 63 d0 74 a1 |.... .IzX..Yc.t.| +00000010 b7 d9 1b 46 41 5f 51 c0 66 4a 10 e1 ad dd 9f 9a |...FA_Q.fJ......| +00000020 c3 cf 32 77 72 17 03 01 00 20 05 7d 08 38 3d f0 |..2wr.... .}.8=.| +00000030 02 f7 17 71 b7 1c 29 c3 a6 c8 ff 7a 82 36 1e 42 |...q..)....z.6.B| +00000040 00 1e 6c d8 b1 39 22 ec 62 43 15 03 01 00 20 0d |..l..9".bC.... .| +00000050 80 5b da 89 4d 42 ab 95 17 11 0f 9b 79 2f c8 3f |.[..MB......y/.?| +00000060 f2 fd 54 2e ea 4a f9 de fc 5d 7f 75 51 86 e5 |..T..J...].uQ..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES index 78947ace0e8..2cae0876a4e 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 45 04 14 a2 70 |....Y...U..E...p| -00000010 3e 1e d9 2c d4 bd f3 e8 9c f3 e0 08 d8 0f 7f 82 |>..,............| -00000020 2b 07 a0 bd 47 56 a0 e1 06 0d 36 20 fc 0f 5b 85 |+...GV....6 ..[.| -00000030 8e 17 20 f1 f6 1e 80 c3 79 1a e1 86 c3 ed e9 24 |.. .....y......$| -00000040 6d bb 24 3c 0c 8d 2c 79 f2 03 27 b0 c0 13 00 00 |m.$<..,y..'.....| +00000000 16 03 01 00 59 02 00 00 55 03 01 f8 80 7d dd cc |....Y...U....}..| +00000010 ab 8c 66 56 c7 e9 18 88 87 44 39 67 57 91 e8 ee |..fV.....D9gW...| +00000020 3a c0 bc 2e bf 50 54 5e 8d c2 61 20 da b0 2d 85 |:....PT^..a ..-.| +00000030 e2 ed f5 5f 2b af 14 87 e6 26 6b af a4 4a 24 2d |..._+....&k..J$-| +00000040 1a bc 15 96 11 c8 c0 8b e9 0c 27 91 c0 13 00 00 |..........'.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,36 +54,36 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......| -000002c0 aa 0c 00 00 a6 03 00 1d 20 85 05 5f e3 a2 b2 12 |........ .._....| -000002d0 c8 82 53 2b c2 38 e1 a8 08 87 a7 d5 b3 98 6f 81 |..S+.8........o.| -000002e0 ce 81 6b 78 3e 3a b7 1d 71 00 80 43 81 fb 47 5e |..kx>:..q..C..G^| -000002f0 08 16 39 35 d3 c2 f3 ea bb 2c 7d bc 01 9b 35 5d |..95.....,}...5]| -00000300 63 7e c3 38 f3 04 96 eb d7 3f d1 df 71 97 ec 22 |c~.8.....?..q.."| -00000310 1b 4a 89 14 4d e5 44 08 87 52 69 ea 28 f8 6a ea |.J..M.D..Ri.(.j.| -00000320 3e ff 17 de 4d 20 95 e3 6e 3f af 05 20 9b a3 ac |>...M ..n?.. ...| -00000330 70 1b 1c bf f9 52 d6 11 6d d9 85 90 08 4d 64 1f |p....R..m....Md.| -00000340 c5 35 34 37 11 b8 44 a3 ef 93 a6 b6 87 58 0b c4 |.547..D......X..| -00000350 8e 94 d8 67 4d 09 7a 2a aa 95 db e6 af 29 21 a2 |...gM.z*.....)!.| -00000360 ee c3 90 ef c6 53 46 12 fb 87 06 16 03 01 00 04 |.....SF.........| +000002c0 aa 0c 00 00 a6 03 00 1d 20 0a d4 a1 84 63 ba 2d |........ ....c.-| +000002d0 23 89 b1 37 eb 97 d3 a7 09 36 3d ac 2a 30 7c f9 |#..7.....6=.*0|.| +000002e0 f6 87 67 86 22 fa f5 f9 06 00 80 c9 ea 8a 76 f2 |..g.".........v.| +000002f0 a5 1b e8 14 2c 2a 2f 2e a0 78 ac 06 9b 48 a8 d9 |....,*/..x...H..| +00000300 03 91 e7 c1 e5 e6 a3 9e 5e 33 73 0a f4 b3 d7 64 |........^3s....d| +00000310 5f 86 d6 36 e5 88 25 90 3c a2 d6 3f d6 07 7a 5c |_..6..%.<..?..z\| +00000320 64 c4 0f ac a9 3e c9 f6 b6 35 2a df a3 a3 79 8f |d....>...5*...y.| +00000330 b3 a6 f4 d8 e4 0a 4f 5f 11 3a 85 9a 0c 48 7b 3b |......O_.:...H{;| +00000340 a2 24 ec c0 44 7e eb b5 f3 f8 52 e6 83 bf 45 91 |.$..D~....R...E.| +00000350 9a 7c a4 e3 29 97 ea 9c 94 28 66 73 45 ed 52 2f |.|..)....(fsE.R/| +00000360 df a8 44 8b a5 0b 7a 31 92 eb 72 16 03 01 00 04 |..D...z1..r.....| 00000370 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......| -00000030 16 03 01 00 30 50 f5 a9 34 25 ed a2 fb c8 7f 35 |....0P..4%.....5| -00000040 08 57 59 da 54 c1 8d 92 ec 23 73 af f3 92 8d 19 |.WY.T....#s.....| -00000050 03 ce ab 5b eb dc 5b 81 3f 51 a1 20 31 3f 33 da |...[..[.?Q. 1?3.| -00000060 27 c5 c3 9c fd |'....| +00000030 16 03 01 00 30 19 34 cf 68 d1 8f ea be 56 24 71 |....0.4.h....V$q| +00000040 e4 ad ad f8 b3 dd 57 43 46 d5 8d f3 1c 0c df 4f |......WCF......O| +00000050 1c af 3b 2a 24 e4 8a 98 b5 b7 61 6f 5f 48 68 20 |..;*$.....ao_Hh | +00000060 b7 6a 9c ee 80 |.j...| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 b1 61 9b 63 4e |..........0.a.cN| -00000010 43 96 80 49 ac 2d 93 7d b9 f2 bb 81 79 5e 94 bf |C..I.-.}....y^..| -00000020 06 d0 a6 14 46 91 cd 90 b0 8a 85 ee fe 41 a7 4d |....F........A.M| -00000030 97 d7 4d 40 5e f4 5b bd d3 0c db |..M@^.[....| +00000000 14 03 01 00 01 01 16 03 01 00 30 fc 42 2b 0f 86 |..........0.B+..| +00000010 73 e1 a1 1a 09 1e 78 7d 61 f1 7c a4 94 14 26 53 |s.....x}a.|...&S| +00000020 de 28 f3 63 63 c3 65 7b e4 fd 10 2d 66 ed f7 dd |.(.cc.e{...-f...| +00000030 f9 9e 13 5c c1 e8 94 6a 32 c0 db |...\...j2..| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 49 21 bc a5 4c 96 41 3f 22 87 0a |.... I!..L.A?"..| -00000010 c0 4e 0e 54 cb c2 27 8a 4f b0 37 fb b4 1f c1 4e |.N.T..'.O.7....N| -00000020 77 e1 09 57 23 17 03 01 00 20 f0 f0 3b 78 a8 ae |w..W#.... ..;x..| -00000030 ef b1 e0 f4 29 0f 90 4a 0f e5 48 34 84 5e 4f d8 |....)..J..H4.^O.| -00000040 53 46 f8 29 64 2b 8e 87 79 0a 15 03 01 00 20 71 |SF.)d+..y..... q| -00000050 32 6c 08 2a f7 18 c8 d5 48 a8 c7 d1 68 7a 65 ec |2l.*....H...hze.| -00000060 3e fa 4b fe ff 76 1a 57 64 22 61 27 a0 5d b6 |>.K..v.Wd"a'.].| +00000000 17 03 01 00 20 36 9a 1b 7f 79 a7 ff 31 92 36 5f |.... 6...y..1.6_| +00000010 7c d2 21 69 01 b6 24 da ea b4 b2 42 81 b5 55 94 ||.!i..$....B..U.| +00000020 8e b8 25 83 35 17 03 01 00 20 27 28 1c 8a fa 21 |..%.5.... '(...!| +00000030 57 39 77 57 5b bd ef 05 5b 39 e2 07 1b c9 3c f7 |W9wW[...[9....<.| +00000040 b9 ac be ce 7e 16 87 6d 5b a7 15 03 01 00 20 c0 |....~..m[..... .| +00000050 9b 05 b5 eb ac 65 08 ae 12 c7 18 be 00 a4 d6 30 |.....e.........0| +00000060 15 dd 90 5d d7 25 89 37 be 3d 56 d3 8c a9 3d |...].%.7.=V...=| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 index 7ecfbde86a4..2e10537999b 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 4c 98 ce a5 80 |....Q...M..L....| -00000010 84 dc d3 70 de 75 bf 26 5c 15 8b b7 2c 78 30 a7 |...p.u.&\...,x0.| -00000020 65 1a 0c f7 1a e5 51 91 7c cb ca 20 83 2c 90 3b |e.....Q.|.. .,.;| -00000030 cf dd 4e 51 8b 27 98 95 aa d9 1d da 4d 3d e1 18 |..NQ.'......M=..| -00000040 f5 58 fd 85 c5 ed c9 5f 12 2f 4b b3 00 05 00 00 |.X....._./K.....| +00000000 16 03 01 00 51 02 00 00 4d 03 01 ba 66 88 b5 b3 |....Q...M...f...| +00000010 17 e1 9a c1 b6 27 e0 3f 1c 80 73 b6 6c 16 c9 4e |.....'.?..s.l..N| +00000020 33 c4 8c 75 26 46 01 1b 31 dc a3 20 e3 57 4f 91 |3..u&F..1.. .WO.| +00000030 3e 5b 91 cf 75 77 71 66 2f be 84 20 1c 7f 02 dd |>[..uwqf/.. ....| +00000040 8b 63 43 6c 4d 1d a4 7a da 89 35 5a 00 05 00 00 |.cClM..z..5Z....| 00000050 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.| 00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......| 00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..| @@ -64,15 +64,15 @@ 00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..| 00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..| 00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 01 00 01 |.Y(.....ia5.....| -00000090 01 16 03 01 00 24 0e 4d ff 2c 39 80 ba a5 96 18 |.....$.M.,9.....| -000000a0 56 15 94 9f e2 1e 7d 13 62 51 d5 e1 05 f8 d8 b3 |V.....}.bQ......| -000000b0 bd 77 58 38 95 b4 7d 37 66 8a |.wX8..}7f.| +00000090 01 16 03 01 00 24 b6 4b 4c 75 2d d9 8d 1c 85 df |.....$.KLu-.....| +000000a0 f1 8d ff 7a 24 6b 02 3f fa 80 d7 f4 71 76 77 97 |...z$k.?....qvw.| +000000b0 fd b3 59 d7 91 9f 3a e9 ec 3b |..Y...:..;| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 dc 6f da 57 0d |..........$.o.W.| -00000010 f8 b8 aa d5 e5 0a 2e 81 ed 2a b7 f8 0e 2a f1 05 |.........*...*..| -00000020 76 8d 4f b0 0e db 16 c5 d7 c8 5e f9 fb 9e e0 |v.O.......^....| +00000000 14 03 01 00 01 01 16 03 01 00 24 b6 51 7e 95 65 |..........$.Q~.e| +00000010 c5 85 08 c3 31 5c ae 2e e9 9e 6e bb 3d e8 68 c5 |....1\....n.=.h.| +00000020 26 a0 8c 61 a8 96 09 3c ec c7 9a 80 ff a2 5d |&..a...<......]| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a 47 97 4d e6 59 d4 2f bb 60 56 69 |.....G.M.Y./.`Vi| -00000010 d8 bc 8d 91 44 7c cd 85 7e c5 18 5f 57 8e 08 15 |....D|..~.._W...| -00000020 03 01 00 16 f7 79 56 72 e6 77 8d af 94 55 d7 0e |.....yVr.w...U..| -00000030 96 c8 3b 35 52 ea f7 e7 b8 d6 |..;5R.....| +00000000 17 03 01 00 1a 0b 83 3a 24 a0 b4 7f cc 86 6c 4f |.......:$.....lO| +00000010 db 19 1b 09 23 77 a6 91 c6 09 db aa 3c 1a f3 15 |....#w......<...| +00000020 03 01 00 16 80 dc 14 9b a7 ff 08 af 25 5e 67 8c |............%^g.| +00000030 2d 2a 8e c9 bc 17 5a 29 48 99 |-*....Z)H.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES index 5232ad57df8..2ef4407b08e 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 30 f8 f6 b2 af |....Y...U..0....| -00000010 99 b0 e0 f6 9a eb 47 6f 2f ad 2f 45 18 56 b3 dd |......Go/./E.V..| -00000020 b6 b9 20 fb af 97 43 1f 0e 51 c0 20 fe 6c 12 64 |.. ...C..Q. .l.d| -00000030 8e cc a4 24 d6 e6 80 cf f2 9e 74 3f a7 1e 8b da |...$......t?....| -00000040 0e 3c 58 74 f4 8f be 1f 60 86 57 c6 c0 09 00 00 |.....P.&...64...| -000002a0 30 81 86 02 41 24 90 6f 3e 1a 2c a5 7f 08 dc b2 |0...A$.o>.,.....| -000002b0 d3 46 27 5e cb 1f 2a 6d 92 ba 1b fe e3 c5 64 79 |.F'^..*m......dy| -000002c0 31 50 8c 43 4b b1 ee 0d 6f 53 ad 6f e9 db 86 e7 |1P.CK...oS.o....| -000002d0 1f e3 77 f1 8d a8 ab 81 2a d6 fa e7 98 d5 bc 0d |..w.....*.......| -000002e0 ec af ea 84 c4 f8 02 41 6a d2 66 32 e1 d7 46 1a |.......Aj.f2..F.| -000002f0 95 5a 91 c3 76 82 20 c2 a3 a2 32 f5 fd eb a2 0e |.Z..v. ...2.....| -00000300 0f d8 a9 31 7a ef a8 05 6c 5d bf 27 d0 2d 94 ca |...1z...l].'.-..| -00000310 fb d6 62 7a 1c 6a 46 20 fe ed a6 60 a3 db b1 bd |..bz.jF ...`....| -00000320 11 82 05 c3 db 0c 4a 2d 6c 16 03 02 00 04 0e 00 |......J-l.......| +00000270 2a 16 03 02 00 b3 0c 00 00 af 03 00 1d 20 63 d9 |*............ c.| +00000280 4a 4e 6b ef 1c 95 89 ab f8 93 20 46 3f 51 40 a3 |JNk....... F?Q@.| +00000290 2a d5 e7 6b 18 04 01 55 6f d7 3f de 6f 20 00 89 |*..k...Uo.?.o ..| +000002a0 30 81 86 02 41 72 0a a5 28 94 81 35 17 04 6b 6c |0...Ar..(..5..kl| +000002b0 9b 66 0f 31 2e 83 55 bb af 97 87 8b 41 cd eb 2c |.f.1..U.....A..,| +000002c0 d0 71 87 4f d8 80 33 ec d2 57 6e 16 20 7a a7 aa |.q.O..3..Wn. z..| +000002d0 93 9a 14 5b 56 cb df ff b6 bc 5f 98 64 3c e2 cb |...[V....._.d<..| +000002e0 e3 45 0c ac 94 a5 02 41 41 97 c8 5e 64 74 93 ee |.E.....AA..^dt..| +000002f0 2e 56 fb 8a 0b ca f8 e7 5e 80 c7 8c 78 89 37 1b |.V......^...x.7.| +00000300 f2 ff de a0 df 54 9b 58 32 26 c7 cf ad af 5d 06 |.....T.X2&....].| +00000310 d9 7e 0b 96 a0 e0 64 64 e7 f4 04 08 40 b2 d6 a5 |.~....dd....@...| +00000320 bd 75 f4 7c 33 cd 3f 34 02 16 03 02 00 04 0e 00 |.u.|3.?4........| 00000330 00 00 |..| >>> Flow 3 (client to server) 00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......| 00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000040 00 00 00 00 00 22 71 28 3d 07 73 61 5e 84 72 36 |....."q(=.sa^.r6| -00000050 c0 87 37 4a 5b c2 d9 40 96 a2 01 20 b2 04 23 2f |..7J[..@... ..#/| -00000060 c1 6f 1e 7c a1 77 20 0f 87 46 98 a2 5c aa 35 37 |.o.|.w ..F..\.57| -00000070 37 87 5a 75 33 |7.Zu3| +00000040 00 00 00 00 00 e8 63 07 7b aa d4 3b ce 03 91 f7 |......c.{..;....| +00000050 4e 28 74 df 52 5f 3e 80 81 30 9d 4e e3 a5 f5 11 |N(t.R_>..0.N....| +00000060 57 80 db 52 1d 4c c4 f3 38 c0 62 3d 84 57 1b 5d |W..R.L..8.b=.W.]| +00000070 1a 51 b3 bb c3 |.Q...| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 21 b5 1f 8d 4b |..........@!...K| -00000010 1c a7 28 4e 73 3e d7 c5 75 6e eb e4 b3 95 02 4e |..(Ns>..un.....N| -00000020 a3 47 03 44 97 69 c9 89 f5 ac e2 29 5e 22 e7 2c |.G.D.i.....)^".,| -00000030 a2 2d e3 ac 64 45 ae 9d 07 9e fe f8 c6 85 47 4d |.-..dE........GM| -00000040 59 be 72 8d e6 50 da c7 83 91 14 |Y.r..P.....| +00000000 14 03 02 00 01 01 16 03 02 00 40 25 b2 b4 08 64 |..........@%...d| +00000010 e0 09 4f 9a 25 35 7a 29 d8 0f 6d c6 39 3e 9e 17 |..O.%5z)..m.9>..| +00000020 9f bb a2 cc e5 17 5c 76 36 b2 10 13 a2 c5 e9 ba |......\v6.......| +00000030 08 5b f5 ff 8e 64 cc 3a 72 54 22 84 e9 d5 15 8e |.[...d.:rT".....| +00000040 85 44 f4 d3 e2 a8 48 46 32 9d b5 |.D....HF2..| >>> 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 57 45 25 4c 1b 90 d3 28 e1 69 43 |.....WE%L...(.iC| -00000020 c5 28 d9 d5 15 35 cf 41 bb 38 f2 12 c6 18 a5 a2 |.(...5.A.8......| -00000030 f5 e4 64 1d 59 15 03 02 00 30 00 00 00 00 00 00 |..d.Y....0......| -00000040 00 00 00 00 00 00 00 00 00 00 35 06 5f e3 ff e7 |..........5._...| -00000050 f0 f1 0c d5 b1 59 42 80 19 8d 67 1b 18 18 5c 18 |.....YB...g...\.| -00000060 42 38 67 85 c3 ab e2 dc 60 d4 |B8g.....`.| +00000010 00 00 00 00 00 29 6a 84 08 a0 1e eb 43 8e c2 c7 |.....)j.....C...| +00000020 db 45 cc ee 39 0d a7 17 5f da e4 f5 70 d4 10 73 |.E..9..._...p..s| +00000030 40 94 f4 81 4c 15 03 02 00 30 00 00 00 00 00 00 |@...L....0......| +00000040 00 00 00 00 00 00 00 00 00 00 17 41 90 a8 d4 70 |...........A...p| +00000050 c2 5e 89 b6 4e d9 49 83 31 58 c1 ca 59 ec 55 a7 |.^..N.I.1X..Y.U.| +00000060 78 83 63 d0 97 32 a0 78 f5 61 |x.c..2.x.a| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES index 48ff7bce320..ccf30011207 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 10 ca d9 1b 83 |....Y...U.......| -00000010 59 c8 a5 a5 6a 89 65 6e 1c 0a 49 98 69 05 49 27 |Y...j.en..I.i.I'| -00000020 96 72 74 5f 6e 5b 66 26 3b fd f8 20 23 b5 d6 c5 |.rt_n[f&;.. #...| -00000030 09 f1 66 02 27 5c 5a 15 17 83 c5 11 a4 32 cf d8 |..f.'\Z......2..| -00000040 1e a0 e7 93 83 35 6e aa 61 ae 97 77 c0 13 00 00 |.....5n.a..w....| +00000000 16 03 02 00 59 02 00 00 55 03 02 25 c4 bc bf ab |....Y...U..%....| +00000010 16 38 05 55 b8 78 a8 b6 e4 0c cb 70 f9 72 a9 5f |.8.U.x.....p.r._| +00000020 f3 59 86 32 ca 92 b6 dd 66 83 42 20 e8 b9 6d 35 |.Y.2....f.B ..m5| +00000030 25 ec e2 37 91 f1 9e 8b 0b 7f 15 cf fd 34 16 9e |%..7.........4..| +00000040 ff 44 67 72 df bd 95 75 d3 fd 89 a5 c0 13 00 00 |.Dgr...u........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,38 +54,38 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 02 00 |.=.`.\!.;.......| -000002c0 aa 0c 00 00 a6 03 00 1d 20 97 a4 91 6b cd ca 44 |........ ...k..D| -000002d0 7e ac fd a5 b1 c0 ce 88 07 f3 a2 d9 93 2b a8 d9 |~............+..| -000002e0 0b 65 0b 47 c0 2e 4f 3b 26 00 80 00 18 01 a1 29 |.e.G..O;&......)| -000002f0 0b 84 c9 09 5e 8c 58 5f 62 b6 22 8b 94 6e 72 26 |....^.X_b."..nr&| -00000300 44 27 32 b9 22 12 67 58 34 a1 ce 6f 87 19 a0 5c |D'2.".gX4..o...\| -00000310 5d 58 dc 91 fb c7 e6 31 33 76 6d 1f 8e 4f 46 55 |]X.....13vm..OFU| -00000320 f1 08 57 9b bb fe 8d c7 6c 0b cd 8b ad b7 51 28 |..W.....l.....Q(| -00000330 f8 5b 75 97 fe a0 d4 a1 2e 9a d3 d5 45 62 f8 19 |.[u.........Eb..| -00000340 f6 73 d0 f6 6d e8 43 49 a2 f5 71 66 c5 29 1a 99 |.s..m.CI..qf.)..| -00000350 e6 c0 cc f9 a5 cd a5 b7 58 08 4d cc 17 46 91 4c |........X.M..F.L| -00000360 29 99 b4 05 78 af e7 b0 d1 2d 38 16 03 02 00 04 |)...x....-8.....| +000002c0 aa 0c 00 00 a6 03 00 1d 20 07 e7 bf ce 93 eb a9 |........ .......| +000002d0 c7 5d 78 3f bc 62 d4 d3 88 10 98 5e 6e 90 3e b5 |.]x?.b.....^n.>.| +000002e0 11 cb 3d ed 42 1a d8 ac 2b 00 80 17 fa bd aa a4 |..=.B...+.......| +000002f0 9c 14 78 9f d8 e7 65 3f 1f 54 b8 37 fc 2f a4 61 |..x...e?.T.7./.a| +00000300 aa 47 ce ca 0f 59 f0 22 8c 5a e6 c8 ed 4e aa 91 |.G...Y.".Z...N..| +00000310 c3 ce a8 08 21 7d d7 ef 88 c6 fc 04 6b b2 c8 d6 |....!}......k...| +00000320 f0 3e aa dc 25 8c bd e7 fd 35 ea 44 7f 6d 2f bb |.>..%....5.D.m/.| +00000330 f4 8d a2 39 f9 a1 69 9e 8e bc 08 50 1b 3d fe a9 |...9..i....P.=..| +00000340 91 bd ab 67 2f 7a 71 a2 85 b2 3e ef 3f a5 45 c7 |...g/zq...>.?.E.| +00000350 b1 2c 69 a0 ae 50 f8 12 73 c2 26 6a f0 7d 1f 28 |.,i..P..s.&j.}.(| +00000360 49 1b c0 96 45 d8 e9 19 bd 47 af 16 03 02 00 04 |I...E....G......| 00000370 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......| 00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000040 00 00 00 00 00 f2 fb 8f ab ae 46 f2 6a 18 1b 77 |..........F.j..w| -00000050 f3 ce 0c b6 83 9c d6 34 54 82 76 db 5c 79 5d cf |.......4T.v.\y].| -00000060 24 f3 26 6d 9d f0 af d3 fc e0 96 69 0a 04 f7 ba |$.&m.......i....| -00000070 78 54 af 37 a5 |xT.7.| +00000040 00 00 00 00 00 f4 1e 67 b5 2c 02 b9 fc 49 44 f1 |.......g.,...ID.| +00000050 85 9f df bd 47 03 f5 68 a4 54 68 ea 13 c8 4c f8 |....G..h.Th...L.| +00000060 81 5e 06 c3 df 2c bb f9 9c a6 99 36 26 60 e0 ac |.^...,.....6&`..| +00000070 5f 82 0a c1 ea |_....| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 e7 d9 0e af 0c |..........@.....| -00000010 06 55 85 ab b0 0a 5e d9 11 81 7a 53 c0 f6 3f 84 |.U....^...zS..?.| -00000020 06 7d 9c 20 05 e9 0d 1d df 9b 48 11 d9 df 0c e6 |.}. ......H.....| -00000030 6b c2 a8 8f f4 d9 e8 8e f6 1a 3e db 7c e5 97 ac |k.........>.|...| -00000040 5d 63 08 b2 3a 54 91 62 fc 2e a5 |]c..:T.b...| +00000000 14 03 02 00 01 01 16 03 02 00 40 82 b5 a3 75 27 |..........@...u'| +00000010 3d 41 d0 00 f7 7d 1a e8 97 98 f6 f1 df f7 00 37 |=A...}.........7| +00000020 a7 2e 29 e6 5a 26 ca ef 94 2c 05 06 c4 94 66 01 |..).Z&...,....f.| +00000030 94 65 e3 45 50 7d 7a f4 78 ab 24 f6 9b 84 4b 7d |.e.EP}z.x.$...K}| +00000040 a7 02 9c 32 f7 90 39 ac a6 61 47 |...2..9..aG| >>> 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 3f ef e9 bc 10 07 75 99 67 8f 99 |.....?.....u.g..| -00000020 bb c0 15 94 86 a2 80 cc 15 97 54 f8 4e 1a d1 9a |..........T.N...| -00000030 33 80 aa da ec 15 03 02 00 30 00 00 00 00 00 00 |3........0......| -00000040 00 00 00 00 00 00 00 00 00 00 6f 78 7b d2 80 62 |..........ox{..b| -00000050 5c cf 34 d6 5a 72 d8 63 95 24 c6 ff 69 d0 6d 90 |\.4.Zr.c.$..i.m.| -00000060 8d a2 9f 37 e8 7b b1 d4 68 04 |...7.{..h.| +00000010 00 00 00 00 00 76 c0 94 ff b2 5a f4 4a 17 47 43 |.....v....Z.J.GC| +00000020 94 d0 b3 7a 77 c0 e6 5d 0e 92 6d 6b 72 b9 d4 58 |...zw..]..mkr..X| +00000030 d3 d5 be 50 95 15 03 02 00 30 00 00 00 00 00 00 |...P.....0......| +00000040 00 00 00 00 00 00 00 00 00 00 25 f0 64 c9 b4 f7 |..........%.d...| +00000050 3c 36 ea e2 df 8c 47 aa 1d a9 ba 5e d0 ce 10 6b |<6....G....^...k| +00000060 a3 4b 08 04 10 60 ce 75 a1 5b |.K...`.u.[| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 index 2e9c49e27ad..0c8ae3518f7 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 51 02 00 00 4d 03 02 36 8f 18 79 0f |....Q...M..6..y.| -00000010 99 6b 3d 1d f4 19 aa ff 79 7c 50 15 52 db 9d c5 |.k=.....y|P.R...| -00000020 62 40 2d 5b de 45 0c 66 b1 cb be 20 9e 00 c3 00 |b@-[.E.f... ....| -00000030 22 2f b5 c6 79 c1 f7 72 8f 4b 94 f4 ac fe a9 53 |"/..y..r.K.....S| -00000040 97 4e fb 00 df 34 b6 24 8f ff 89 db 00 05 00 00 |.N...4.$........| +00000000 16 03 02 00 51 02 00 00 4d 03 02 17 49 a0 13 8a |....Q...M...I...| +00000010 1d 7a e5 dd dd f3 ba 71 8c 9f b9 16 55 98 4e 56 |.z.....q....U.NV| +00000020 74 da 97 99 09 b7 5a cb 16 17 a8 20 b4 67 96 70 |t.....Z.... .g.p| +00000030 f5 7c 25 f3 5e 47 6b 38 fb 2a 18 67 a7 35 b6 93 |.|%.^Gk8.*.g.5..| +00000040 88 26 c7 da 67 7c d7 d9 4d 23 46 15 00 05 00 00 |.&..g|..M#F.....| 00000050 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.| 00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......| 00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..| @@ -64,15 +64,15 @@ 00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..| 00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..| 00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 02 00 01 |.Y(.....ia5.....| -00000090 01 16 03 02 00 24 92 fa 9a bb 9b a3 39 3f 6b 0c |.....$......9?k.| -000000a0 70 b5 48 4a fc cf 79 86 c7 90 e8 db ca 6a ff 95 |p.HJ..y......j..| -000000b0 11 9b 65 b2 07 61 00 a8 dc 14 |..e..a....| +00000090 01 16 03 02 00 24 57 25 f5 73 5b e7 e4 e5 41 29 |.....$W%.s[...A)| +000000a0 0f 6f c5 92 93 17 17 fe 3f 84 cb 62 c0 69 ef ae |.o......?..b.i..| +000000b0 c4 96 c7 32 76 b9 fb 2a 01 03 |...2v..*..| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 24 47 d5 78 31 32 |..........$G.x12| -00000010 db db 2b f4 2f e6 a4 fa fa 04 31 ba c0 bc 86 38 |..+./.....1....8| -00000020 29 70 53 c6 8c 28 e5 75 90 ed 0f 4f 3e cb 06 |)pS..(.u...O>..| +00000000 14 03 02 00 01 01 16 03 02 00 24 74 40 46 d2 01 |..........$t@F..| +00000010 85 de 99 2e 04 b7 c4 a6 50 61 22 01 23 fd 77 be |........Pa".#.w.| +00000020 55 6a 6d 1a 79 17 c7 3d 75 64 99 fc bb 42 a7 |Ujm.y..=ud...B.| >>> Flow 5 (client to server) -00000000 17 03 02 00 1a f3 e7 6c 01 c5 70 c6 69 dd 4f 40 |.......l..p.i.O@| -00000010 38 c1 b2 d2 28 69 2f 99 b1 bd 71 d0 c2 00 08 15 |8...(i/...q.....| -00000020 03 02 00 16 4c 44 14 02 8e 46 f8 84 40 f1 3d 6d |....LD...F..@.=m| -00000030 f2 01 f6 9d 7a 0b 18 ee 9d 41 |....z....A| +00000000 17 03 02 00 1a d0 cc 3e 2e f5 09 1d 14 b6 ec f4 |.......>........| +00000010 19 64 30 40 eb 86 31 8b 61 fd 94 b5 3a 0c d5 15 |.d0@..1.a...:...| +00000020 03 02 00 16 f2 d9 24 a4 f7 65 0e 26 1e c0 c9 7d |......$..e.&...}| +00000030 5c 57 59 fb 80 fd ab ab 83 e4 |\WY.......| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 index c20dcc658f3..c63e71a4bb0 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 65 9c b1 7a 5c |....Q...M..e..z\| -00000010 84 e5 a5 12 ba 54 1f 4c ec 95 0b 8f ea 5c cc 3b |.....T.L.....\.;| -00000020 de b8 18 23 8e c4 95 59 d7 7f 8f 20 36 fe ec 27 |...#...Y... 6..'| -00000030 10 85 43 fb 9c 68 3f 69 d0 08 a6 57 10 a6 29 a4 |..C..h?i...W..).| -00000040 f6 0c 2e 05 6e 0d e5 44 61 e1 2e 07 00 9c 00 00 |....n..Da.......| +00000000 16 03 03 00 51 02 00 00 4d 03 03 49 4c e7 e2 d1 |....Q...M..IL...| +00000010 f6 48 5a 9c 53 86 a7 b4 43 a2 35 a1 6a cd 40 8d |.HZ.S...C.5.j.@.| +00000020 db 5a 93 d2 66 1a 9e b3 cd ab 8b 20 52 21 cc 8d |.Z..f...... R!..| +00000030 24 23 ed 26 f1 c0 44 17 74 1a ef 01 5c c5 8e 79 |$#.&..D.t...\..y| +00000040 f6 e5 00 e8 b3 71 72 99 a5 2d 4d cf 00 9c 00 00 |.....qr..-M.....| 00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.| 00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......| 00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..| @@ -64,17 +64,17 @@ 00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..| 00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..| 00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....| -00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 f1 |.....(..........| -000000a0 fe 34 f7 de 76 9b 56 27 e6 9f 36 48 30 a6 de 78 |.4..v.V'..6H0..x| -000000b0 10 6a ef bf 92 8a 6e 99 21 2f 1b 7b 48 80 |.j....n.!/.{H.| +00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 c5 41 |.....(.........A| +000000a0 79 78 69 d0 e6 8f 11 e0 19 7a a2 51 0f b4 1f 8f |yxi......z.Q....| +000000b0 8a a5 d9 48 1a b8 cd 2f ea e2 04 9b e8 9f |...H.../......| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 23 9d a2 ae a1 |..........(#....| -00000010 7d dd 92 1f 42 18 68 f6 fb 31 56 7b e4 58 a4 e9 |}...B.h..1V{.X..| -00000020 c2 1c e7 67 1b 40 b1 b9 63 9d 05 fb c7 44 9e f6 |...g.@..c....D..| -00000030 7a 14 bb |z..| +00000000 14 03 03 00 01 01 16 03 03 00 28 f3 72 0c 34 0f |..........(.r.4.| +00000010 59 fa 8d 0f d1 37 6d 3b 9c e6 41 66 8b 30 4a d0 |Y....7m;..Af.0J.| +00000020 ef 21 f1 42 79 f0 55 0e a1 43 d5 d7 b1 d6 45 aa |.!.By.U..C....E.| +00000030 5a 3a 69 |Z:i| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d7 31 70 |..............1p| -00000010 c8 11 3f bd 83 fc 6e f8 3b e0 ee 45 c5 1a c8 41 |..?...n.;..E...A| -00000020 80 22 d4 15 03 03 00 1a 00 00 00 00 00 00 00 02 |."..............| -00000030 7a fe 3a 11 7c c0 26 30 55 24 85 0b 43 cb 7c ac |z.:.|.&0U$..C.|.| -00000040 ef 2c |.,| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 7d bd ac |.............}..| +00000010 69 1a 3c b3 4d 0f 1b 25 40 95 34 f0 b1 97 60 39 |i.<.M..%@.4...`9| +00000020 93 42 10 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.B..............| +00000030 a0 65 f5 b0 94 a5 2e 1a c4 a5 97 76 12 8f 82 70 |.e.........v...p| +00000040 49 0c |I.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 index 774481e84a7..17826d300a4 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 26 31 ba 4a 56 |....Q...M..&1.JV| -00000010 16 83 15 47 b9 c4 7e 10 ca 92 31 4d 77 af cc cd |...G..~...1Mw...| -00000020 70 f4 cc 82 6e b9 ac 1b 0d 17 25 20 e9 08 ec 95 |p...n.....% ....| -00000030 ea 84 a4 bd 8f 9d 8e d3 58 a7 5e 72 42 e4 19 8f |........X.^rB...| -00000040 46 c3 d9 be 16 3c d4 53 5a 02 8f a1 00 3c 00 00 |F....<.SZ....<..| +00000000 16 03 03 00 51 02 00 00 4d 03 03 89 90 c7 c5 d0 |....Q...M.......| +00000010 21 e2 50 ac 35 a7 b1 10 8a 32 45 b8 48 02 0e 19 |!.P.5....2E.H...| +00000020 45 58 31 81 a4 db 0f 19 21 53 80 20 ca a7 7f 02 |EX1.....!S. ....| +00000030 5a f4 9b cc 70 72 fa e8 ed 4f 0c 1b c7 7a b2 58 |Z...pr...O...z.X| +00000040 e1 c1 b3 c8 3e a1 82 8e 78 3b c6 02 00 3c 00 00 |....>...x;...<..| 00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.| 00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......| 00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..| @@ -65,25 +65,25 @@ 00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..| 00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....| 00000090 01 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 |.....P..........| -000000a0 00 00 00 00 00 00 46 91 40 e2 65 40 fe 42 c3 34 |......F.@.e@.B.4| -000000b0 98 65 89 d0 96 7e 7b 67 8e c4 d5 e6 37 f5 96 04 |.e...~{g....7...| -000000c0 b7 c8 63 83 76 5c ca 9d 89 18 d4 97 8b 3f f6 75 |..c.v\.......?.u| -000000d0 1d 51 0b b9 90 1c 85 8f 83 20 9e 9a 21 d9 db 14 |.Q....... ..!...| -000000e0 1e 02 d4 ab aa c4 |......| +000000a0 00 00 00 00 00 00 e0 31 66 d7 3b a5 a2 cd 61 c5 |.......1f.;...a.| +000000b0 76 26 ce b4 a7 a3 86 8b 68 98 8a 0c 14 df 71 39 |v&......h.....q9| +000000c0 29 b0 29 05 97 87 2f d5 81 25 0b 46 e7 91 2a fc |).).../..%.F..*.| +000000d0 bb 76 d3 19 31 37 ad 8b 01 f0 66 1f 0f 7f 7a 0f |.v..17....f...z.| +000000e0 bd 2b 76 3f 84 2b |.+v?.+| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 50 6d 34 72 de 79 |..........Pm4r.y| -00000010 ad 96 d0 92 5f d7 01 de 90 f4 5d 0f de 02 ae 19 |...._.....].....| -00000020 61 a3 ee 29 ab 18 f1 09 2e 5b bc e0 73 9a 68 19 |a..).....[..s.h.| -00000030 17 dd c8 d9 63 b4 28 c8 da 1a 81 40 ca d3 5a 99 |....c.(....@..Z.| -00000040 17 67 fe e9 dd 1a 52 c4 6e 70 0a 0e cf e8 c0 f8 |.g....R.np......| -00000050 6c 1f ee d2 70 97 dc ee b8 95 35 |l...p.....5| +00000000 14 03 03 00 01 01 16 03 03 00 50 b7 1d 0b ad 4a |..........P....J| +00000010 05 27 59 4e 95 11 58 6e 90 02 12 52 40 b2 0e 1d |.'YN..Xn...R@...| +00000020 ca 82 a6 85 2f 01 ad 9c 29 41 f9 a0 3d b2 39 be |..../...)A..=.9.| +00000030 9f 76 72 3e de db 17 de d7 9e 4e 0a 89 be 27 9c |.vr>......N...'.| +00000040 37 88 46 87 8c a9 a9 41 70 01 72 60 18 4a 3b ac |7.F....Ap.r`.J;.| +00000050 97 8e 4f 2c 4b 4e 87 0b bd e4 89 |..O,KN.....| >>> Flow 5 (client to server) 00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000010 00 00 00 00 00 ee 03 cc 04 97 17 f0 04 85 02 b7 |................| -00000020 5c 24 ca 9f c2 25 e0 76 f4 72 e5 71 2b ac f4 a5 |\$...%.v.r.q+...| -00000030 c4 62 08 9a da b7 ab 30 2f 34 b0 70 20 a3 b9 b3 |.b.....0/4.p ...| -00000040 df 90 9b 01 0b 15 03 03 00 40 00 00 00 00 00 00 |.........@......| -00000050 00 00 00 00 00 00 00 00 00 00 3b ca fc 0e 08 f2 |..........;.....| -00000060 c8 b7 22 61 43 24 b3 54 1b ca 58 c6 bd 27 f3 3d |.."aC$.T..X..'.=| -00000070 ac a0 d8 fe 0e b5 15 7c 1f 98 32 f0 6b 28 bc 61 |.......|..2.k(.a| -00000080 6c c7 ba 66 54 19 92 a9 6f 43 |l..fT...oC| +00000010 00 00 00 00 00 b6 0c c1 ab 01 1a 69 8f 48 80 5e |...........i.H.^| +00000020 f8 d6 b7 b9 7c 9e 30 01 ff 4d 27 94 ef 3e 05 c3 |....|.0..M'..>..| +00000030 64 fd 38 f9 b9 29 fe 49 bf 6a fc 6f ac 1e 6d ee |d.8..).I.j.o..m.| +00000040 42 a2 2f 05 e5 15 03 03 00 40 00 00 00 00 00 00 |B./......@......| +00000050 00 00 00 00 00 00 00 00 00 00 37 ca 1c 12 fd 31 |..........7....1| +00000060 2b 9e 56 51 a7 f5 3e 37 48 fe 08 b9 a3 8d 4c 26 |+.VQ..>7H.....L&| +00000070 7d c2 9d 04 f8 7f b9 47 00 87 bd 86 51 36 83 a7 |}......G....Q6..| +00000080 98 cf de ac 76 d6 78 ac bd 95 |....v.x...| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 index 6d2674639a2..598430dae22 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 98 b0 4a 9a c8 |....Q...M....J..| -00000010 8f f9 1f f9 70 03 d9 1a ee 7c 29 30 6a 71 7c 6c |....p....|)0jq|l| -00000020 ea 2c de 84 f9 ee 4d 2c d7 58 12 20 a4 e2 1b f3 |.,....M,.X. ....| -00000030 42 b8 9a 0b 71 8c 27 57 61 98 c5 c5 1b 04 01 5b |B...q.'Wa......[| -00000040 a0 bc 88 64 d9 ce 5a a1 b2 7b 6c 4e 00 9d 00 00 |...d..Z..{lN....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 de 31 eb 89 cf |....Q...M...1...| +00000010 06 df 45 b2 68 3c 70 8e ef ec 11 14 d1 f3 8c 95 |..E.h>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 42 49 9c 67 4f |..........(BI.gO| -00000010 36 75 b8 34 0e ee 00 98 1a ba 52 d5 96 7b 91 d7 |6u.4......R..{..| -00000020 ba ec e4 5e 2e 42 e3 72 a0 ea 60 24 31 30 3d a2 |...^.B.r..`$10=.| -00000030 c5 6c 8f |.l.| +00000000 14 03 03 00 01 01 16 03 03 00 28 f0 52 59 4b c1 |..........(.RYK.| +00000010 54 7c 0d 0c 4a 82 96 0a 50 d2 6d ce 7c 2f e9 3c |T|..J...P.m.|/.<| +00000020 55 ea da ea 8a 1a 6f 1d fe 96 01 0f 42 61 61 45 |U.....o.....BaaE| +00000030 ef 31 97 |.1.| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 42 9f da |.............B..| -00000010 a1 e6 98 48 a8 6c 78 a0 f7 fd e7 0f bc df 97 ef |...H.lx.........| -00000020 b8 62 4c 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.bL.............| -00000030 99 ac 35 a4 d9 1f 58 26 51 c6 6a b9 1f 53 ec 19 |..5...X&Q.j..S..| -00000040 90 78 |.x| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 cb 28 8f |..............(.| +00000010 dd 5d cf 29 ef 92 72 71 43 85 c1 1b fe 41 a4 f8 |.].)..rqC....A..| +00000020 07 f7 96 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 25 52 2c d6 5a f4 95 ea 21 bb 35 70 d1 78 cc 15 |%R,.Z...!.5p.x..| +00000040 d5 79 |.y| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN index 9f90ff269ad..05c4afb1b5f 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN @@ -1,21 +1,22 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 a9 01 00 00 a5 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 ad 01 00 00 a9 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 50 33 74 |.............P3t| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 54 33 74 |.............T3t| 00000060 00 00 00 05 00 05 01 00 00 00 00 00 0a 00 0a 00 |................| 00000070 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| -00000080 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| -00000090 03 ff 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f |.............pro| -000000a0 74 6f 32 06 70 72 6f 74 6f 31 00 12 00 00 |to2.proto1....| +00000080 0d 00 12 00 10 04 01 04 03 05 01 05 03 06 01 06 |................| +00000090 03 02 01 02 03 ff 01 00 01 00 00 10 00 10 00 0e |................| +000000a0 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 12 |.proto2.proto1..| +000000b0 00 00 |..| >>> Flow 2 (server to client) -00000000 16 03 03 00 66 02 00 00 62 03 03 8d 70 c6 03 ad |....f...b...p...| -00000010 2f 20 b3 c2 ab e0 fc 80 74 c4 23 9e 82 65 61 a1 |/ ......t.#..ea.| -00000020 26 97 14 a0 9b 9c d5 e0 92 43 ee 20 ec 84 cf 78 |&........C. ...x| -00000030 44 16 7d f3 ad 94 a9 f8 c3 e0 c6 e1 b6 c5 e3 3d |D.}............=| -00000040 77 ea 76 1d 58 cc 94 3a ad 1a 1a 6c cc a8 00 00 |w.v.X..:...l....| +00000000 16 03 03 00 66 02 00 00 62 03 03 cb 8e 3f a0 07 |....f...b....?..| +00000010 c3 0e b3 b2 07 39 e2 2d b9 5f 03 31 05 b0 0d b6 |.....9.-._.1....| +00000020 c7 c5 4d 39 2b 3f 1a d7 38 43 69 20 f5 35 e2 93 |..M9+?..8Ci .5..| +00000030 75 c4 eb b3 eb a3 ad cd 9f e3 c6 dc b8 ea 20 7c |u............. || +00000040 94 1b 9c 73 bd 2e af f1 4d 97 6d eb cc a8 00 00 |...s....M.m.....| 00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................| 00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 59 |.....proto1....Y| 00000070 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.| @@ -56,31 +57,31 @@ 000002a0 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F| 000002b0 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.| 000002c0 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........| -000002d0 00 a8 03 00 1d 20 84 de 31 92 b6 a5 d8 a4 88 a2 |..... ..1.......| -000002e0 54 67 e6 61 40 f2 5a 87 0f ce 15 b1 d6 af f3 5d |Tg.a@.Z........]| -000002f0 99 71 d6 04 f5 52 04 01 00 80 a8 1d 8b 8c e9 a3 |.q...R..........| -00000300 af 2d 31 e4 0f f0 26 74 c2 e5 1b ae ac 47 9c 6e |.-1...&t.....G.n| -00000310 6c 5f 45 7d b1 b3 2a af 36 68 42 13 95 0d 33 1c |l_E}..*.6hB...3.| -00000320 8d 6c 72 48 4a 94 f0 fb 82 20 cc 76 21 7f 62 e7 |.lrHJ.... .v!.b.| -00000330 23 a3 c8 4e 3a ce f1 5c c3 60 73 26 59 4c 94 f3 |#..N:..\.`s&YL..| -00000340 07 36 f6 a0 b3 60 03 d5 72 1e bf c8 d9 1d 61 01 |.6...`..r.....a.| -00000350 9a 18 57 a3 b4 de 36 1f e1 7d dc 69 c0 fb c0 71 |..W...6..}.i...q| -00000360 45 1f 73 0d 50 69 d3 18 97 23 60 1c 5a 9a 93 b4 |E.s.Pi...#`.Z...| -00000370 67 cc e5 80 3b 25 d0 6c 50 c8 16 03 03 00 04 0e |g...;%.lP.......| +000002d0 00 a8 03 00 1d 20 4c d6 65 c1 74 2c 78 ab 45 87 |..... L.e.t,x.E.| +000002e0 bc 6e 9a cd 6c d4 2f 1e ed 1b ed 68 e0 20 3b 13 |.n..l./....h. ;.| +000002f0 7b b9 45 a1 38 78 04 01 00 80 31 26 2b b6 f8 fe |{.E.8x....1&+...| +00000300 bf 3c c6 8e ec 30 87 09 18 87 27 ec 9f 4f 93 74 |.<...0....'..O.t| +00000310 6b 65 94 12 3e 4d 5e a8 f7 0f ec 9e 60 c5 d5 a0 |ke..>M^.....`...| +00000320 c1 53 10 1d 8a 5b 82 2e 64 07 59 2e 0c b8 e3 90 |.S...[..d.Y.....| +00000330 20 a5 0a 88 3e 7e d6 b9 85 58 78 f1 58 56 a6 d8 | ...>~...Xx.XV..| +00000340 ee 60 52 59 d1 5b 16 58 de ce bc 09 79 99 65 e0 |.`RY.[.X....y.e.| +00000350 6b 0b 4e 3d fb 80 35 6b 56 48 33 b3 17 4e 61 cf |k.N=..5kVH3..Na.| +00000360 88 78 41 14 c8 fa 41 32 f9 2b 87 27 40 d7 2b 51 |.xA...A2.+.'@.+Q| +00000370 bd 16 54 cd f3 79 3a 7d c9 f0 16 03 03 00 04 0e |..T..y:}........| 00000380 00 00 00 |...| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 5c c5 3e 7a 14 97 1b 55 88 25 08 |.... \.>z...U.%.| -00000040 ad 86 48 ac f0 43 8c 17 5b 58 93 6c 7a 95 69 a8 |..H..C..[X.lz.i.| -00000050 ad 0c b3 61 4d |...aM| +00000030 16 03 03 00 20 40 b0 f2 80 ce 38 b3 98 fd 34 ba |.... @....8...4.| +00000040 84 d3 f7 30 dc 9f 09 4b 0e 44 0b 79 b1 28 39 53 |...0...K.D.y.(9S| +00000050 94 03 db c8 2b |....+| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 dd 1b 80 da d9 |.......... .....| -00000010 73 da 7d 15 9b 92 82 01 a7 8f fe 4a 75 97 8f f4 |s.}........Ju...| -00000020 64 1b bf cf c3 40 78 f2 52 f5 7a |d....@x.R.z| +00000000 14 03 03 00 01 01 16 03 03 00 20 6f 6c ec 1a 29 |.......... ol..)| +00000010 d8 29 6c 10 67 12 4f 45 d3 64 85 e4 bc 28 5b 52 |.)l.g.OE.d...([R| +00000020 d0 46 45 3c ac bc fa 51 c1 00 84 |.FE<...Q...| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 4e fa 7c 37 80 48 19 a6 03 25 7c |.....N.|7.H...%|| -00000010 65 56 43 af 9a e8 e2 aa e5 79 98 15 03 03 00 12 |eVC......y......| -00000020 f9 b7 01 e8 2e 85 33 89 60 44 84 93 26 4c ec ac |......3.`D..&L..| -00000030 2e 6f |.o| +00000000 17 03 03 00 16 7d 3e 49 f0 a6 61 18 fc 10 f4 7f |.....}>I..a.....| +00000010 e2 df b7 58 7d ad 31 84 de 60 e0 15 03 03 00 12 |...X}.1..`......| +00000020 08 cd 3f b6 58 d8 72 12 e0 f5 c6 8f f7 76 d5 29 |..?.X.r......v.)| +00000030 4f b2 |O.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA index 336e10da83a..6fc1b1bd18e 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 cf 28 2c 3e 4f |....Y...U...(,>O| -00000010 da 6b ae 24 74 a9 91 c3 c5 55 4b ab ec 07 f8 cd |.k.$t....UK.....| -00000020 65 f8 fe 08 f6 9a 23 da 99 6c 5d 20 af 4a 1e 32 |e.....#..l] .J.2| -00000030 7b bd 3c 0b b1 14 66 a3 b7 2f a4 2a c3 43 c4 e0 |{.<...f../.*.C..| -00000040 c2 ad 78 b1 28 ab 51 06 1b 87 d2 75 c0 09 00 00 |..x.(.Q....u....| +00000000 16 03 03 00 59 02 00 00 55 03 03 3d c4 44 53 fd |....Y...U..=.DS.| +00000010 1d ce 32 ba 0a ba 77 43 7a ba d1 e1 5b 7d 78 d4 |..2...wCz...[}x.| +00000020 d3 29 5f e2 2b ab a1 e0 20 70 bd 20 4c 6b 28 a6 |.)_.+... p. Lk(.| +00000030 f0 d0 51 92 3d ed 65 5c bd 26 8f 81 93 14 b0 93 |..Q.=.e\.&......| +00000040 80 af ae f6 3c 59 1f 1c 65 45 f0 13 c0 09 00 00 |.....| -000002c0 f7 e0 5d 64 47 5a d1 d9 ed d2 1c 6b 13 3e e7 83 |..]dGZ.....k.>..| -000002d0 6e bb 53 33 03 7d 69 c6 8f 9d 98 d7 96 9c 73 e3 |n.S3.}i.......s.| -000002e0 12 bd 69 1f b1 d3 f4 25 d7 02 42 01 11 6d c8 53 |..i....%..B..m.S| -000002f0 9b bf f4 db ff 8a 00 82 93 f7 b5 bf c9 bb cd ec |................| -00000300 64 f8 d9 6d 36 0d f8 db ce 9d 65 a0 5e 5a e0 13 |d..m6.....e.^Z..| -00000310 ec 08 73 2c 3f 8c c6 5b 08 cc 0f 4a 7d 6b 5e 89 |..s,?..[...J}k^.| -00000320 bf 4a 4e db 51 5a 9f 51 3e 9d 9a c5 84 16 03 03 |.JN.QZ.Q>.......| +00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 b4 47 |*............ .G| +00000280 68 85 aa c9 1b 4f ac c6 c6 08 39 e2 91 a8 0f a7 |h....O....9.....| +00000290 26 d0 60 1a 68 62 7d 22 61 d2 66 1f 42 71 04 03 |&.`.hb}"a.f.Bq..| +000002a0 00 8b 30 81 88 02 42 00 86 22 15 eb 04 d8 98 69 |..0...B..".....i| +000002b0 71 75 c9 d7 17 61 d2 dc a7 2f 21 22 fd b9 da 6e |qu...a.../!"...n| +000002c0 b2 36 65 22 1a 20 c8 49 3e a6 2a e4 4e a1 93 8d |.6e". .I>.*.N...| +000002d0 47 59 42 4f 54 51 3f dd fc b9 b0 b4 fe d2 77 28 |GYBOTQ?.......w(| +000002e0 15 58 4f b5 f5 56 da b2 02 02 42 00 cb 0b 69 b7 |.XO..V....B...i.| +000002f0 1b 48 85 7e e3 bf be 27 64 c7 38 4d dc a1 49 73 |.H.~...'d.8M..Is| +00000300 ba f9 45 6b cc 95 d1 72 d8 45 9c 39 3d 3a 93 85 |..Ek...r.E.9=:..| +00000310 a7 22 20 c3 ce 48 e3 0d 31 9c f4 cf 2c dc d7 9d |." ..H..1...,...| +00000320 d3 b4 6a fe 98 31 d9 32 dc 37 1a c0 fa 16 03 03 |..j..1.2.7......| 00000330 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......| 00000340 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000350 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................| @@ -101,32 +101,32 @@ 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| -00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......| -00000240 00 8f 05 03 00 8b 30 81 88 02 42 01 32 6d 32 38 |......0...B.2m28| -00000250 d6 bd 1b b6 c5 80 f2 ea 60 b8 bf 3f b6 76 68 1b |........`..?.vh.| -00000260 66 fb 5d 69 0b 25 09 7f 2d 73 ad 7e cd 98 cb b5 |f.]i.%..-s.~....| -00000270 93 4e 4f 1c 4e 3f a1 39 cf a0 70 a6 3d 29 36 27 |.NO.N?.9..p.=)6'| -00000280 51 e0 55 95 11 df 00 88 6c 38 d6 de 36 02 42 01 |Q.U.....l8..6.B.| -00000290 67 50 81 90 a7 ae b5 e2 34 75 81 41 c2 71 8d 0c |gP......4u.A.q..| -000002a0 9a 20 e7 33 af 0e 61 48 85 51 a1 f7 90 17 d1 ad |. .3..aH.Q......| -000002b0 b3 e1 cf 3e 12 fc ce 39 16 a8 78 3b 69 0d 79 76 |...>...9..x;i.yv| -000002c0 03 17 75 c2 a0 63 5e dc 0a a7 c9 aa 15 2a 83 65 |..u..c^......*.e| -000002d0 df 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |...........@....| -000002e0 00 00 00 00 00 00 00 00 00 00 00 00 27 da 48 f6 |............'.H.| -000002f0 d3 00 98 b9 a6 b7 41 0b eb e6 d1 d7 82 9a 0c 59 |......A........Y| -00000300 8a 42 1c 99 59 af da a7 5b 88 ab b6 7d 01 bc 0f |.B..Y...[...}...| -00000310 45 08 c4 05 0d 2a 4a 83 bf eb b1 b6 |E....*J.....| +00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 92 0f 00 |...._X.;t.......| +00000240 00 8e 06 03 00 8a 30 81 87 02 42 00 cb 61 7d bc |......0...B..a}.| +00000250 af 48 88 32 98 9b 34 a0 71 0e 3a 33 bd da 73 16 |.H.2..4.q.:3..s.| +00000260 05 f4 8e d8 30 11 c8 da dd 7a 84 80 57 a1 76 d8 |....0....z..W.v.| +00000270 af 3d 90 d7 e2 44 85 78 c4 12 ed 8d dc 4e 82 08 |.=...D.x.....N..| +00000280 51 20 59 d7 38 26 29 c9 2b 5b 77 fc d2 02 41 3b |Q Y.8&).+[w...A;| +00000290 70 99 7c 46 bf 8e 85 40 d7 75 c5 43 36 f8 e3 30 |p.|F...@.u.C6..0| +000002a0 28 ac 20 1e 79 43 b2 f3 6d b1 ae 6e cf 41 b5 ed |(. .yC..m..n.A..| +000002b0 76 2b d5 17 78 2c fa 91 75 ba 63 8f e9 1c c8 c0 |v+..x,..u.c.....| +000002c0 1e 02 63 70 53 41 e0 98 77 a5 ae 54 6a 74 c0 91 |..cpSA..w..Tjt..| +000002d0 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| +000002e0 00 00 00 00 00 00 00 00 00 00 00 7d 12 bc ba f4 |...........}....| +000002f0 34 59 b7 c2 a9 5d 11 88 38 cc bc cc 1c 14 b7 5a |4Y...]..8......Z| +00000300 ae d8 0a 45 bc 61 b5 bc d6 8e c4 69 80 10 7a ea |...E.a.....i..z.| +00000310 07 f4 dc 1a c9 dc b8 90 66 6c bc |........fl.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 73 7c e6 43 b9 |..........@s|.C.| -00000010 47 85 1c 50 f1 cb a1 29 79 02 dd 13 85 2a d9 a2 |G..P...)y....*..| -00000020 07 50 e4 80 c4 7e 66 ee f2 1a 21 1d cd e4 ff 4a |.P...~f...!....J| -00000030 a4 61 9d b4 a1 26 88 72 20 2b 06 77 c3 8b 3b 21 |.a...&.r +.w..;!| -00000040 53 33 02 3d a2 06 77 3b a5 a6 0b |S3.=..w;...| +00000000 14 03 03 00 01 01 16 03 03 00 40 df ff fd 43 0b |..........@...C.| +00000010 d1 28 4b db ce 29 8b 01 56 e7 44 9d 69 92 e7 11 |.(K..)..V.D.i...| +00000020 7c 57 f2 a1 cf 35 d4 3a 8f 90 69 ce 80 4e 8b 6c ||W...5.:..i..N.l| +00000030 e9 eb 90 65 0e 89 49 20 41 ae 32 62 66 f4 aa 85 |...e..I A.2bf...| +00000040 cd ca f7 a2 37 8f ef 22 ab b6 7b |....7.."..{| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 1a 45 68 03 9b f0 42 e4 21 5e d8 |......Eh...B.!^.| -00000020 98 d6 46 67 2b 93 80 92 1f 91 60 a3 05 04 1c a0 |..Fg+.....`.....| -00000030 1b a9 ce 45 03 15 03 03 00 30 00 00 00 00 00 00 |...E.....0......| -00000040 00 00 00 00 00 00 00 00 00 00 6b 23 42 c8 5c 29 |..........k#B.\)| -00000050 f5 1f 7c d5 80 c4 9f 6f 12 77 95 71 8f 82 f9 63 |..|....o.w.q...c| -00000060 07 2c 6d ed 6d c6 4f 90 50 a3 |.,m.m.O.P.| +00000010 00 00 00 00 00 76 a4 88 f6 fb 0a 0f 8d a6 1f e0 |.....v..........| +00000020 96 4d d0 93 30 c9 b6 27 1e 3c 87 d7 98 f9 d6 e9 |.M..0..'.<......| +00000030 96 f7 e0 af b6 15 03 03 00 30 00 00 00 00 00 00 |.........0......| +00000040 00 00 00 00 00 00 00 00 00 00 82 01 3b 93 6f 78 |............;.ox| +00000050 1b e8 b6 ed 45 11 85 26 0f 40 63 2a a6 c9 f8 7b |....E..&.@c*...{| +00000060 7f 01 42 6b c1 8b 4f c0 a6 b5 |..Bk..O...| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA index fb6c940a5f9..47c083e494a 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 2e d2 1c 3f f8 |....Y...U.....?.| -00000010 3a dc be 78 0b fa 03 00 e0 9a b9 62 34 45 f8 34 |:..x.......b4E.4| -00000020 54 21 4c c0 76 a6 e1 5a a1 67 c2 20 1b 98 25 34 |T!L.v..Z.g. ..%4| -00000030 79 ac 59 b5 39 c8 93 10 a9 ea 9d 25 3d 2c d8 69 |y.Y.9......%=,.i| -00000040 da d8 33 75 ef 44 4c 76 92 2b 3b b4 c0 2f 00 00 |..3u.DLv.+;../..| +00000000 16 03 03 00 59 02 00 00 55 03 03 b1 01 db c2 3f |....Y...U......?| +00000010 11 0c d0 d2 fd 1d 5f 54 f6 62 4a 47 f9 62 e6 88 |......_T.bJG.b..| +00000020 72 d7 f5 91 78 73 99 94 72 26 ed 20 51 91 b2 bf |r...xs..r&. Q...| +00000030 78 94 0c 1f bb 7b ff a2 b6 8f 57 5d 03 f2 97 b8 |x....{....W]....| +00000040 c2 20 99 cd 48 f3 14 fc 63 38 97 44 c0 2f 00 00 |. ..H...c8.D./..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,17 +54,17 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 06 be 1b 0b d8 95 59 |........ ......Y| -000002d0 b2 13 1c 4a 06 b8 36 3e 4f 98 3f 81 11 3e 7d 21 |...J..6>O.?..>}!| -000002e0 fa d9 f0 db 1b 41 4a d0 14 04 01 00 80 ca 57 f5 |.....AJ.......W.| -000002f0 e7 b6 72 7e 3f b0 67 f2 a2 d0 84 d5 7f 7d 83 ff |..r~?.g......}..| -00000300 92 73 4f 19 f7 94 b6 d7 95 f4 1b 56 2a fc fa 24 |.sO........V*..$| -00000310 3e fe 00 65 52 76 c8 30 8a bf ae fe b5 c9 f2 47 |>..eRv.0.......G| -00000320 0a 71 ad c1 6a 61 8c b5 ab 59 09 12 92 b2 b4 ad |.q..ja...Y......| -00000330 cb cc ac c4 30 e9 a4 8a 82 4e 2e d6 1d 16 46 dd |....0....N....F.| -00000340 60 37 50 b8 ae 83 c1 e6 1d ba 8c c7 18 f7 5e d7 |`7P...........^.| -00000350 23 e5 8a 14 ba e4 8e a1 77 8a b6 41 03 61 8a 25 |#.......w..A.a.%| -00000360 8a 27 f8 cb 2e 4a e0 07 aa bf 03 32 98 16 03 03 |.'...J.....2....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 22 78 15 4f d2 33 df |........ "x.O.3.| +000002d0 3e 82 b7 10 ca 8b 5c d6 f2 84 8f e7 cb cf 3e 2f |>.....\.......>/| +000002e0 65 dd 5b 5c 0a 48 f4 f6 1e 04 01 00 80 40 08 09 |e.[\.H.......@..| +000002f0 e5 bc a2 e3 27 a9 7e 2d e2 1d 47 7c 8c 95 44 28 |....'.~-..G|..D(| +00000300 f8 3d 00 5d f7 38 26 31 8f f3 61 27 f6 c0 a0 12 |.=.].8&1..a'....| +00000310 ed 3b 59 18 ed aa 4c 4a 54 8a 23 0a 13 7a 7d 1c |.;Y...LJT.#..z}.| +00000320 26 5e 7a f1 55 d5 68 dc f9 97 ef 6d 98 0f 87 41 |&^z.U.h....m...A| +00000330 31 e5 a0 f1 84 19 3a 19 cf b3 f7 9d 34 13 05 ab |1.....:.....4...| +00000340 85 2e 6f 4e 8f fd c3 37 63 3e c9 3d 48 87 6a 9b |..oN...7c>.=H.j.| +00000350 c1 21 d1 4f 89 7d a1 dc 23 bb cf d8 b1 d9 91 e0 |.!.O.}..#.......| +00000360 f6 48 f0 20 64 8b f8 f1 86 5c b3 6c 70 16 03 03 |.H. d....\.lp...| 00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......| 00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................| @@ -105,28 +105,28 @@ 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| -00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 92 0f 00 |...._X.;t.......| -00000240 00 8e 05 03 00 8a 30 81 87 02 41 19 c6 1e f0 f4 |......0...A.....| -00000250 ca 79 d7 8c 36 0f 56 9a 9d 07 55 31 fe 63 f1 ec |.y..6.V...U1.c..| -00000260 20 80 6f 12 ed 7f bb c0 87 0a 0d 68 81 89 bd 8b | .o........h....| -00000270 19 04 5e c0 19 8a d2 0f 6d 71 83 59 ee a7 be be |..^.....mq.Y....| -00000280 1d bb 2f 12 53 9b ca 58 0e a6 8d ae 02 42 00 d0 |../.S..X.....B..| -00000290 4c 69 75 30 86 d1 da 73 1b 8e 3e e1 82 9b f3 58 |Liu0...s..>....X| -000002a0 8f 6d 0a 10 86 72 5f 90 17 d1 ac 34 8a b5 60 d0 |.m...r_....4..`.| -000002b0 b8 54 0f 05 7f cd 6a c0 62 b5 04 d9 3a 98 95 b6 |.T....j.b...:...| -000002c0 b3 00 1d 94 6e 79 35 57 d2 78 a4 7a 4a 45 89 d1 |....ny5W.x.zJE..| -000002d0 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| -000002e0 00 00 00 cf b5 3c cf 0a b7 6b 51 cb fe 06 4c df |.....<...kQ...L.| -000002f0 2c 79 a6 5e a8 75 8b 4c 44 7b ae ff 64 d7 67 dc |,y.^.u.LD{..d.g.| -00000300 af ef 54 |..T| +00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......| +00000240 00 8f 06 03 00 8b 30 81 88 02 42 01 9e be 18 6a |......0...B....j| +00000250 b3 8d c4 2f b9 ed db b9 89 cf 2f e5 d6 13 64 68 |.../....../...dh| +00000260 72 e4 51 01 12 a9 83 08 d7 2e fa cc 64 09 80 79 |r.Q.........d..y| +00000270 ce 3d 51 a1 e1 f7 3c 5c 2c dd 97 a2 f9 61 c3 7a |.=Q...<\,....a.z| +00000280 bc 25 ad c1 04 a1 cf bf 06 f5 e2 b5 15 02 42 00 |.%............B.| +00000290 bf 72 20 6f 0e 49 f2 07 bd 07 ef f3 e8 9c 1a 61 |.r o.I.........a| +000002a0 b0 7a 6c b0 14 71 4a aa 76 05 9f d1 ef 5b 41 be |.zl..qJ.v....[A.| +000002b0 4c 20 7b 5c 31 86 da e3 3b 54 0f af 79 6b 54 84 |L {\1...;T..ykT.| +000002c0 72 0b 0a e4 ea 33 48 a2 1a e8 8d dd 16 45 80 d1 |r....3H......E..| +000002d0 88 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 |...........(....| +000002e0 00 00 00 00 4d 58 00 50 6d 12 ea c2 6c f8 1c 51 |....MX.Pm...l..Q| +000002f0 e8 91 8c 24 dd c2 28 af c7 c7 ed 28 29 34 62 2c |...$..(....()4b,| +00000300 c0 d3 06 7d |...}| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 1c 12 5e 29 ba |..........(..^).| -00000010 34 b3 d8 ae f7 2a 83 0d 3e 21 ec 91 c9 fa 7f d1 |4....*..>!......| -00000020 42 7e 8d d9 e5 ed 4e f9 ae 95 66 27 85 cc 44 2d |B~....N...f'..D-| -00000030 cd a3 26 |..&| +00000000 14 03 03 00 01 01 16 03 03 00 28 b3 71 11 c5 31 |..........(.q..1| +00000010 7b 22 87 23 7b 71 05 ca 95 fc d1 7d 0e fd 68 d3 |{".#{q.....}..h.| +00000020 7f 08 af 41 16 ff cf 87 a4 5a 6b fb b1 5e 89 e0 |...A.....Zk..^..| +00000030 8e 0c 88 |...| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 8b 4c 36 |..............L6| -00000010 6f b8 69 16 0a 40 67 05 5e a8 e6 48 cc ad 7b 29 |o.i..@g.^..H..{)| -00000020 95 3d 02 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.=..............| -00000030 58 e3 b5 8e 30 e7 5d 02 cd e5 c0 11 95 3a ef a9 |X...0.]......:..| -00000040 d7 86 |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 3b 83 10 |.............;..| +00000010 ee 6d c5 a9 6a 9e 61 7f df 00 c4 03 39 6a b8 4a |.m..j.a.....9j.J| +00000020 0f 0c e6 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 35 b9 7d a7 29 d0 ba e1 5e 4e f1 67 4a 81 12 e7 |5.}.)...^N.gJ...| +00000040 62 72 |br| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 index 17fc8f8e118..892db8accfc 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 31 df 35 e4 36 |....Y...U..1.5.6| -00000010 c5 f1 b4 9f e7 5d fa e1 e0 23 04 54 bd 2b fb ab |.....]...#.T.+..| -00000020 a2 37 8f 35 eb 79 47 e6 f8 2b cb 20 ba d8 db 26 |.7.5.yG..+. ...&| -00000030 ce 6b 4a e9 1e 0c 46 9f 4d 85 cb d7 b0 e2 3d 20 |.kJ...F.M.....= | -00000040 58 43 83 37 e1 53 ac 3b d9 b3 fd 0a c0 30 00 00 |XC.7.S.;.....0..| +00000000 16 03 03 00 59 02 00 00 55 03 03 76 09 a7 74 97 |....Y...U..v..t.| +00000010 df 92 1b 14 fb 0f 5c 82 a9 04 22 5f 32 1f 04 50 |......\..."_2..P| +00000020 52 8c ec 30 c1 5e 73 51 8a 0d 22 20 12 f5 11 b3 |R..0.^sQ.." ....| +00000030 3b 8e 49 9a 0b 79 3e 0a a8 7f a8 01 eb b0 ea 4e |;.I..y>........N| +00000040 d5 19 0d 4e c5 7d d7 a0 ff 6e 75 a1 c0 30 00 00 |...N.}...nu..0..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,17 +54,17 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 9a 18 f9 2e 33 f7 bb |........ ....3..| -000002d0 ca 60 0b 51 ad 5c 01 e2 61 82 0b 3f 09 8f 78 9d |.`.Q.\..a..?..x.| -000002e0 3b 11 8b e0 4a 35 2e d5 54 04 01 00 80 90 94 0e |;...J5..T.......| -000002f0 bf 3a b7 95 d3 58 cc 65 c3 79 5e 1e bb d9 21 56 |.:...X.e.y^...!V| -00000300 06 93 6c 2b 6e 26 55 ee 26 c3 02 44 7e db 35 9b |..l+n&U.&..D~.5.| -00000310 d4 d4 1a a0 65 35 41 a4 6c ce de 1f 94 ff b4 1b |....e5A.l.......| -00000320 1e 9c 28 0b 4c 8d 55 d0 d8 be f1 df e0 d1 1a b5 |..(.L.U.........| -00000330 c8 be 2c 5a 2c c3 3f ea 4f e6 d5 b4 6b e1 ff eb |..,Z,.?.O...k...| -00000340 f3 f3 40 54 d5 62 1f a0 fc b2 34 66 ee c5 27 a6 |..@T.b....4f..'.| -00000350 2b 2a b9 5d 3f 36 28 eb 39 99 25 e5 04 d2 18 13 |+*.]?6(.9.%.....| -00000360 3c 23 93 d0 04 37 85 b0 4d 6e 9b 32 9a 16 03 03 |<#...7..Mn.2....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 24 0d ab 23 1c 61 5d |........ $..#.a]| +000002d0 26 01 04 dd ea 32 2d e4 a1 95 28 fc a7 17 93 6f |&....2-...(....o| +000002e0 ce b8 ef 0a 74 cf 28 ca 33 04 01 00 80 1e e1 03 |....t.(.3.......| +000002f0 e6 a7 bd 38 7b 32 52 01 47 b3 fa 0a 8f 29 2c 98 |...8{2R.G....),.| +00000300 58 37 21 3d 9e 78 48 dc 74 a9 ec d2 9a cb 56 8e |X7!=.xH.t.....V.| +00000310 4a 90 d6 b6 87 82 03 b8 60 04 bf 73 b2 61 e6 ab |J.......`..s.a..| +00000320 7d cd eb ba cf e8 16 86 db 38 7e 96 6b 14 c4 4f |}........8~.k..O| +00000330 05 fb 2b b5 6e 50 9a f5 02 f3 a2 84 95 8d a6 91 |..+.nP..........| +00000340 d2 16 33 98 16 c0 61 55 fe a8 70 02 d1 db 86 d1 |..3...aU..p.....| +00000350 37 0c 02 36 cf b2 10 6d 63 94 f6 18 29 a7 6b 1b |7..6...mc...).k.| +00000360 8f 7c 51 8e 8f e4 ef a8 2b 99 0b ae 1b 16 03 03 |.|Q.....+.......| 00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......| 00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................| @@ -105,26 +105,26 @@ 00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.| 00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...| 00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....| -00000230 88 0f 00 00 84 05 01 00 80 ad f7 ff a0 cb d0 6e |...............n| -00000240 8f 19 0c 40 2a 1f bb dd 11 52 81 84 f1 7b 3f cf |...@*....R...{?.| -00000250 75 72 83 a4 4c 0a 9c 70 95 98 d5 51 a2 28 0c 8c |ur..L..p...Q.(..| -00000260 20 08 d7 2a a5 3e 0c cf 6c a2 1d 32 bd cc a1 b4 | ..*.>..l..2....| -00000270 61 e0 6d 9a 61 16 03 5c 7a b8 fa 15 ea cd e4 de |a.m.a..\z.......| -00000280 d6 16 93 b2 e0 d2 55 b9 03 e0 67 04 27 64 8c e2 |......U...g.'d..| -00000290 01 ee 8f f7 59 3e 12 16 51 f2 07 20 fe 03 e2 3e |....Y>..Q.. ...>| -000002a0 09 1f 96 24 c5 73 0e 69 ac 57 ff 43 2b 6a c6 20 |...$.s.i.W.C+j. | -000002b0 2f e4 ef 7e bc b3 38 57 06 14 03 03 00 01 01 16 |/..~..8W........| -000002c0 03 03 00 28 00 00 00 00 00 00 00 00 fd 71 f5 ca |...(.........q..| -000002d0 91 26 67 54 a5 e6 f3 06 c8 40 24 9d a9 bd b1 9a |.&gT.....@$.....| -000002e0 63 c4 c2 53 56 ba af c0 16 bc 06 5c |c..SV......\| +00000230 88 0f 00 00 84 06 01 00 80 9f 32 29 c2 47 12 3b |..........2).G.;| +00000240 c1 2a f5 02 2b be 51 88 68 ed d6 f6 06 72 b8 02 |.*..+.Q.h....r..| +00000250 32 5f f6 c6 a0 72 d1 df d4 01 8c f7 37 ca 3a 8f |2_...r......7.:.| +00000260 cb ee d8 1d 7b 8a 80 0b 21 30 14 55 32 19 ba 8e |....{...!0.U2...| +00000270 a0 6a 0a 8b 53 01 71 09 d2 1c 19 b2 50 4f a4 35 |.j..S.q.....PO.5| +00000280 4d 22 71 74 62 fb 24 8d d1 b2 0e d7 60 ae 9e a9 |M"qtb.$.....`...| +00000290 07 60 84 99 da c9 a4 04 09 35 da c3 98 4e ab fe |.`.......5...N..| +000002a0 41 68 f2 0c 8a 94 b3 26 af 2c 19 52 48 08 8d 00 |Ah.....&.,.RH...| +000002b0 05 69 d8 9f 35 b5 9e 00 2e 14 03 03 00 01 01 16 |.i..5...........| +000002c0 03 03 00 28 00 00 00 00 00 00 00 00 bf fd 71 87 |...(..........q.| +000002d0 c2 8c 1e 69 59 95 8a 75 da 56 7e db e6 5c fd 6c |...iY..u.V~..\.l| +000002e0 74 97 46 66 37 23 3f 39 91 23 c0 d1 |t.Ff7#?9.#..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 92 8f bd c5 97 |..........(.....| -00000010 94 76 70 f4 0a f9 9a 79 69 31 27 0e c0 c5 0b 3c |.vp....yi1'....<| -00000020 9f 4f c2 2f cb 6c 56 62 80 3b e5 72 6a 05 9e 4b |.O./.lVb.;.rj..K| -00000030 34 b9 66 |4.f| +00000000 14 03 03 00 01 01 16 03 03 00 28 16 d9 d6 d4 2f |..........(..../| +00000010 8c 6f 50 8d e6 6f ea eb 6a 55 6a 12 10 d2 dc aa |.oP..o..jUj.....| +00000020 83 7a 38 6a bc 10 aa da 62 ab 94 7b ac f2 03 1a |.z8j....b..{....| +00000030 2f 95 6d |/.m| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 43 fb 43 |.............C.C| -00000010 3d 96 63 dd 25 94 9d 7a fb 9e 15 6f 62 5e ed 34 |=.c.%..z...ob^.4| -00000020 19 89 b8 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| -00000030 53 c2 2d 6c b7 91 6c 62 84 09 a2 1c 9b 3d 9e 89 |S.-l..lb.....=..| -00000040 6a 3d |j=| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 36 84 d7 |.............6..| +00000010 5c ef b0 3e 11 86 a9 a1 2c 0c 05 2f fa 86 3b dc |\..>....,../..;.| +00000020 fb 8c 94 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 86 fb 4d dd 33 11 53 9c c2 9f e6 48 79 19 69 f3 |..M.3.S....Hy.i.| +00000040 db 3b |.;| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA index 1ff91986d28..9f717b1548b 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 84 4b ff a4 2a |....Y...U...K..*| -00000010 a4 76 c0 26 f6 05 72 94 01 15 44 f2 c6 7d b0 4b |.v.&..r...D..}.K| -00000020 1b fa da 51 54 45 78 66 e6 0a dd 20 17 df d2 0c |...QTExf... ....| -00000030 2f d6 55 b9 ae 82 ce 2f 2f 07 67 54 5e 02 bd 2f |/.U....//.gT^../| -00000040 48 f6 fb 3d 9c fa 4f a8 66 15 08 da c0 09 00 00 |H..=..O.f.......| +00000000 16 03 03 00 59 02 00 00 55 03 03 63 c7 66 ed 90 |....Y...U..c.f..| +00000010 6f f2 a3 65 32 55 e2 00 ce 15 46 33 22 ad 1a 6f |o..e2U....F3"..o| +00000020 ac 21 89 0e b0 66 a8 04 98 f2 99 20 02 7c 4f 57 |.!...f..... .|OW| +00000030 f4 69 17 6f 23 f5 a6 db 8f a6 ef eb 83 70 53 5d |.i.o#........pS]| +00000040 0e 85 b9 d7 53 01 10 9b 65 97 c0 c1 c0 09 00 00 |....S...e.......| 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....| @@ -49,22 +49,22 @@ 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 b7 0c 00 00 b3 03 00 1d 20 5d 4e |*............ ]N| -00000280 0c 9e ad 7b f1 48 0c db 03 96 26 2e 16 87 2c e2 |...{.H....&...,.| -00000290 ce a2 47 5a 57 30 e8 e1 7e b2 53 5b c6 7b 04 03 |..GZW0..~.S[.{..| -000002a0 00 8b 30 81 88 02 42 00 e8 8e 68 a8 e3 b5 b4 fe |..0...B...h.....| -000002b0 b9 91 aa 4f 96 3d 97 8d b2 ef 23 a4 3d 16 db 2b |...O.=....#.=..+| -000002c0 50 6d 52 cd a5 e7 79 ae 65 10 d6 36 e0 ba c3 6b |PmR...y.e..6...k| -000002d0 53 61 14 bb 05 47 5a df 26 2f cb 3a 95 c6 6b dc |Sa...GZ.&/.:..k.| -000002e0 88 fd 2e 22 b5 ef ff 31 0e 02 42 01 be ce 6e 53 |..."...1..B...nS| -000002f0 42 43 1c 1c d8 83 7f 45 c4 16 ee d2 7b 66 a0 f4 |BC.....E....{f..| -00000300 f3 14 da 5c 14 e8 fc bc 86 7d 18 43 b9 7b 90 8c |...\.....}.C.{..| -00000310 af f1 05 95 c6 53 0b 0b 0d 10 a1 e9 bb 89 35 c2 |.....S........5.| -00000320 b2 e1 d7 dd 99 7c bf 85 19 3c 4e 8e 8f 16 03 03 |.....|...>> Flow 3 (client to server) 00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0| 00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.| @@ -101,31 +101,31 @@ 00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.| 00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...| 00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....| -00000230 88 0f 00 00 84 05 01 00 80 98 58 a8 77 3d db 0b |..........X.w=..| -00000240 04 36 78 51 8b 23 48 fc 70 2b c9 94 1f ee 32 ae |.6xQ.#H.p+....2.| -00000250 41 c0 42 20 19 51 67 e7 fa c0 fd 15 a1 5f 55 4f |A.B .Qg......_UO| -00000260 aa be 29 77 f5 47 71 b9 6c 51 89 18 df 25 98 fd |..)w.Gq.lQ...%..| -00000270 c8 6e ae e3 fd 99 63 ca 2c d2 fb ca bc 57 b7 7f |.n....c.,....W..| -00000280 a2 90 a6 6f b7 2e b7 2a 52 29 e6 75 57 86 cc b1 |...o...*R).uW...| -00000290 d8 6c f3 4e 49 ab 4b 66 0a 72 aa ec c2 f7 6e 57 |.l.NI.Kf.r....nW| -000002a0 15 26 79 1a a4 24 c2 ba 76 9e dd b9 f9 d4 da 1b |.&y..$..v.......| -000002b0 c9 29 66 eb 64 1b 68 66 66 14 03 03 00 01 01 16 |.)f.d.hff.......| +00000230 88 0f 00 00 84 06 01 00 80 0a d6 0d 0a 0f 6b 18 |..............k.| +00000240 f4 e3 3a b7 84 cd 56 53 ae 81 3f e8 50 a4 6a ab |..:...VS..?.P.j.| +00000250 4e f7 f5 8f e6 c5 6f e1 88 47 a9 ba 35 07 a3 5d |N.....o..G..5..]| +00000260 d0 e3 f3 b9 2a 33 33 1c af d5 91 4b 92 3d da eb |....*33....K.=..| +00000270 96 3f 4c 0e ac 55 3e 32 8c 56 f9 3e 64 d1 51 03 |.?L..U>2.V.>d.Q.| +00000280 a1 46 2a 47 0b d6 fd 0c 94 15 de 66 22 24 11 06 |.F*G.......f"$..| +00000290 ed 17 ab f0 c5 5b 39 7d f2 ce 02 3f 3a 16 b4 14 |.....[9}...?:...| +000002a0 81 f7 4f 38 a9 46 ee 09 bf ed 14 b5 d8 3c d6 32 |..O8.F.......<.2| +000002b0 26 48 6d 9d 49 70 12 a0 f3 14 03 03 00 01 01 16 |&Hm.Ip..........| 000002c0 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 |...@............| -000002d0 00 00 00 00 70 2b 69 27 05 9a 96 e6 e8 52 ea 0f |....p+i'.....R..| -000002e0 3a d6 40 b5 e2 89 5b bf aa 95 6c c1 7d 53 09 89 |:.@...[...l.}S..| -000002f0 23 38 6b 83 85 84 fa f4 2e fb cd b3 57 4e 79 8a |#8k.........WNy.| -00000300 92 74 03 22 |.t."| +000002d0 00 00 00 00 d5 b2 cc f7 6b 74 c0 77 c3 05 7f 09 |........kt.w....| +000002e0 28 54 fe 44 ef b1 4c 40 ff 47 00 59 ae 22 96 53 |(T.D..L@.G.Y.".S| +000002f0 6d db b1 5b fd af 24 10 ca 0d f6 8b 24 7a c0 38 |m..[..$.....$z.8| +00000300 d7 92 7c c2 |..|.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 8f 91 f1 f5 6b |..........@....k| -00000010 cc 52 9d db 35 1f db b4 64 fe 33 a5 83 08 24 2f |.R..5...d.3...$/| -00000020 57 18 0e 60 4e 18 54 bb 80 31 37 fe 26 14 b8 c8 |W..`N.T..17.&...| -00000030 dd c4 8c 07 42 0b 80 0b 41 82 40 f6 9b b8 60 4f |....B...A.@...`O| -00000040 cb 7b 43 ea 1a 6e 31 8d 9f 82 f7 |.{C..n1....| +00000000 14 03 03 00 01 01 16 03 03 00 40 c3 48 00 56 17 |..........@.H.V.| +00000010 16 d1 dd 17 a2 c7 48 c9 d6 3e 6a 1e 4c cc 0a a2 |......H..>j.L...| +00000020 40 3e 31 2e 50 69 d6 06 15 48 87 45 2f f0 a1 04 |@>1.Pi...H.E/...| +00000030 38 b2 81 15 b9 0d ac f4 9e 51 9f b0 9c 79 20 57 |8........Q...y W| +00000040 ab 8a 56 08 97 2b d0 62 12 7d b3 |..V..+.b.}.| >>> 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 70 e7 c8 03 9c e2 58 73 68 ab 9b |.....p.....Xsh..| -00000020 5c bf 32 57 f8 f1 13 97 02 59 de 99 d3 3e 16 3d |\.2W.....Y...>.=| -00000030 87 11 d4 b4 63 15 03 03 00 30 00 00 00 00 00 00 |....c....0......| -00000040 00 00 00 00 00 00 00 00 00 00 9b 99 45 f3 0d f1 |............E...| -00000050 c5 36 07 8c 81 94 b7 0a dc 7c ee 0c 22 1b 36 fd |.6.......|..".6.| -00000060 d4 fc 7d f1 98 8b 87 be 5f c6 |..}....._.| +00000010 00 00 00 00 00 27 df 11 a5 71 1a f9 c9 fb d3 a8 |.....'...q......| +00000020 cd f1 5f 88 e4 db ca 2f ec c7 26 e2 c9 69 11 c5 |.._..../..&..i..| +00000030 a4 ba 6f 58 69 15 03 03 00 30 00 00 00 00 00 00 |..oXi....0......| +00000040 00 00 00 00 00 00 00 00 00 00 e8 9d f0 1d f8 4b |...............K| +00000050 fc d1 7e ac 10 b2 5d af ea 87 b9 d8 4b 0d 24 d6 |..~...].....K.$.| +00000060 ff 44 9f 93 bf 51 9d 21 9d 1d |.D...Q.!..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA index 76f0c2511ba..656281cfa65 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 92 93 45 4c f9 |....Y...U....EL.| -00000010 93 bf ee 78 58 e0 42 b6 df 32 c2 63 6d ec 89 66 |...xX.B..2.cm..f| -00000020 5a 11 7c 0d 31 2f b5 90 22 ab 3d 20 65 f3 40 c4 |Z.|.1/..".= e.@.| -00000030 f8 31 fa 80 f3 fb a7 f6 9e dc 0c 94 67 48 d9 2b |.1..........gH.+| -00000040 cb 94 82 5f 4e 8b 41 5e c6 63 27 da c0 2f 00 00 |..._N.A^.c'../..| +00000000 16 03 03 00 59 02 00 00 55 03 03 cd 8e 54 03 73 |....Y...U....T.s| +00000010 80 fb 7a 0a 38 a0 cd d3 5c 1a 84 a2 66 43 47 68 |..z.8...\...fCGh| +00000020 7b d9 c0 5b c3 14 2f 51 45 12 62 20 9e 32 b0 17 |{..[../QE.b .2..| +00000030 85 6e 8a de ae 7a f7 09 76 79 5f 74 eb b1 3c e9 |.n...z..vy_t..<.| +00000040 4f 36 09 ef b2 f9 8f 25 c1 db 37 46 c0 2f 00 00 |O6.....%..7F./..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,17 +54,17 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 66 49 44 2b 04 fe f5 |........ fID+...| -000002d0 41 68 60 09 81 0e 24 c4 46 68 33 87 41 dd 48 69 |Ah`...$.Fh3.A.Hi| -000002e0 4c be c8 22 2d 4e ff 80 20 04 01 00 80 30 85 40 |L.."-N.. ....0.@| -000002f0 30 56 d5 1d 41 14 9d e8 27 39 a2 18 d5 eb 92 27 |0V..A...'9.....'| -00000300 63 4b 05 85 1a 9e 5f 60 2c 80 a3 20 9f 9c 57 29 |cK...._`,.. ..W)| -00000310 ba 5f ac 0a aa 89 98 fc ca 8e 37 6b 44 bc 0f 33 |._........7kD..3| -00000320 5d 47 91 46 55 d4 f9 4f 76 73 51 c4 f6 a9 90 e4 |]G.FU..OvsQ.....| -00000330 95 10 92 94 f1 33 11 3d 83 0a eb 5d ff e6 9d 9c |.....3.=...]....| -00000340 19 ec e1 65 11 ad d7 7b 6a a4 f9 d8 b6 0c 53 8a |...e...{j.....S.| -00000350 16 d5 1f a7 0b 80 6f c5 d8 6a 57 11 2f b1 84 65 |......o..jW./..e| -00000360 24 8a 02 de aa 10 40 bd 9b 68 a2 b7 b6 16 03 03 |$.....@..h......| +000002c0 ac 0c 00 00 a8 03 00 1d 20 57 b6 34 6b 1c 97 1f |........ W.4k...| +000002d0 51 f1 d5 38 68 a2 2f 69 fb 9e 94 cf 7e c3 25 97 |Q..8h./i....~.%.| +000002e0 82 e9 32 c0 0e 99 0c 7c 50 04 01 00 80 2d 08 85 |..2....|P....-..| +000002f0 c5 bc d6 3b 94 c5 7e 26 80 bc 0d 63 50 84 d0 77 |...;..~&...cP..w| +00000300 f8 4b cd 2c d4 cb e0 f2 7c 63 dc 9e 42 4e 3f 3c |.K.,....|c..BN?<| +00000310 a3 b7 c7 41 e6 e9 2c da ff 06 6d ec b5 f3 57 22 |...A..,...m...W"| +00000320 3a 6b cc 6b 00 d0 53 6e b1 89 7c 09 cc db 8e f1 |:k.k..Sn..|.....| +00000330 00 32 d1 68 2f ae 7a 83 00 71 a8 81 e6 66 c2 e7 |.2.h/.z..q...f..| +00000340 13 94 bf 9b 30 84 23 3d 95 03 11 4d 3a e7 4c 0a |....0.#=...M:.L.| +00000350 43 c7 6d 31 c1 92 b1 ab 7d 11 a1 2f 4a 2d bd fe |C.m1....}../J-..| +00000360 f5 d4 b1 ab ef 2d e3 79 ee 2f 6b 44 29 16 03 03 |.....-.y./kD)...| 00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&...@......| 00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................| @@ -105,26 +105,26 @@ 00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.| 00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...| 00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....| -00000230 88 0f 00 00 84 05 01 00 80 05 9b 97 90 30 0b 21 |.............0.!| -00000240 ed 52 16 19 e0 54 7d 59 42 17 94 81 9b 2c b6 5b |.R...T}YB....,.[| -00000250 7f 7c 8e a5 bf 27 a9 25 14 74 f0 37 fa 6e 2b 84 |.|...'.%.t.7.n+.| -00000260 80 a4 cd ae a6 8a 1b 62 2d 5e 03 ff 70 55 d7 99 |.......b-^..pU..| -00000270 68 3c b3 0e 03 41 ae af c6 3e 09 d4 16 8e 06 71 |h<...A...>.....q| -00000280 14 f8 90 97 cd f6 eb 7d 90 3c d1 f3 95 db 35 3c |.......}.<....5<| -00000290 c9 7d dc 30 55 e1 a0 66 8e 26 20 4f 43 89 08 6f |.}.0U..f.& OC..o| -000002a0 95 58 42 ae e8 6c b6 77 45 c6 8c c7 ad e5 ed ff |.XB..l.wE.......| -000002b0 09 6f 2e 7e b0 e4 5c f2 db 14 03 03 00 01 01 16 |.o.~..\.........| -000002c0 03 03 00 28 00 00 00 00 00 00 00 00 c0 2c cc 32 |...(.........,.2| -000002d0 78 5e 6c 3e e9 a3 83 65 b4 bb 4e 79 b2 04 08 30 |x^l>...e..Ny...0| -000002e0 09 e9 04 99 70 48 44 95 26 b0 37 c9 |....pHD.&.7.| +00000230 88 0f 00 00 84 06 01 00 80 72 5e f2 3f d2 7d 33 |.........r^.?.}3| +00000240 ec 01 70 e5 91 5b 71 ac 48 88 99 5a af ad 40 82 |..p..[q.H..Z..@.| +00000250 a7 de 2f 25 16 67 e1 e3 7d e6 d5 0f 79 63 63 56 |../%.g..}...yccV| +00000260 1b 45 da 38 f7 99 4d a2 8e 6f 70 02 92 21 da 69 |.E.8..M..op..!.i| +00000270 ba 2d 95 ea e5 5a f1 be 23 bb d2 8c 8b 36 b8 bf |.-...Z..#....6..| +00000280 c3 b5 c8 48 3c 27 26 c8 52 9c a4 53 d0 4e a6 7e |...H<'&.R..S.N.~| +00000290 cf 95 01 20 62 e1 47 59 82 b0 f1 64 e7 8e f4 f4 |... b.GY...d....| +000002a0 c7 50 67 83 ec 56 10 9d 0b 54 60 5a 1a 0f 0d 31 |.Pg..V...T`Z...1| +000002b0 31 c6 2d 12 e6 e4 22 77 6a 14 03 03 00 01 01 16 |1.-..."wj.......| +000002c0 03 03 00 28 00 00 00 00 00 00 00 00 91 d6 08 d4 |...(............| +000002d0 74 3f 02 78 ed c3 9d 0b a7 f0 10 c7 e8 4a a3 a7 |t?.x.........J..| +000002e0 d7 b7 c1 ca d4 fc e9 dc b5 ca 35 39 |..........59| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 5f 80 e2 f1 78 |..........(_...x| -00000010 0f cb 58 5c 3c 50 4c 1e 33 8a 1f b7 89 92 37 11 |..X\>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 75 dc 54 |.............u.T| -00000010 d9 c5 b1 c2 c9 64 9a ea 20 e5 76 61 6c 05 af 33 |.....d.. .val..3| -00000020 6b bc d7 15 03 03 00 1a 00 00 00 00 00 00 00 02 |k...............| -00000030 24 6b 03 76 d3 da d0 ee a6 32 c3 58 a1 5e a5 21 |$k.v.....2.X.^.!| -00000040 b8 3a |.:| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 3e 3d cd |.............>=.| +00000010 9b 8c 53 b7 86 e1 60 bc 3c 3a 7b b1 cf a5 d1 c8 |..S...`.<:{.....| +00000020 1b d1 92 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 83 58 15 c4 87 a3 bf 7b cf e6 e0 b4 10 37 ad 3b |.X.....{.....7.;| +00000040 d9 9a |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES index 5d795e791f0..3403023b6b6 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 c3 2f 08 30 ba |....Y...U.../.0.| -00000010 5d 9e 55 ef 23 f9 8a 0d 2f b4 25 02 5f c0 d2 c2 |].U.#.../.%._...| -00000020 50 7c da db a4 ee 7c 18 df af aa 20 f3 a5 02 de |P|....|.... ....| -00000030 54 9f ce b9 6d 69 66 5d 57 76 ff 18 91 d3 93 ab |T...mif]Wv......| -00000040 39 13 29 4c b9 a7 3c db 7f 4d 97 fc c0 09 00 00 |9.)L..<..M......| +00000000 16 03 03 00 59 02 00 00 55 03 03 78 e9 9b 0c e1 |....Y...U..x....| +00000010 45 f0 55 05 58 ef 80 4f 22 88 e4 7d eb af a5 b2 |E.U.X..O"..}....| +00000020 75 36 9f a2 cc 6d 51 27 ca 7e 38 20 c8 89 89 e7 |u6...mQ'.~8 ....| +00000030 95 70 01 01 67 b0 9a 1a 7a 54 d8 bb 22 72 c6 9c |.p..g...zT.."r..| +00000040 09 ff d4 2c 0a 94 86 bc 51 cb 56 7d c0 09 00 00 |...,....Q.V}....| 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....| @@ -49,39 +49,39 @@ 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 b6 0c 00 00 b2 03 00 1d 20 46 07 |*............ F.| -00000280 78 fd 3b 0c e0 2c 96 f8 44 b9 e9 06 e9 66 17 35 |x.;..,..D....f.5| -00000290 c0 92 87 51 f6 e3 d7 f5 09 50 56 c6 e9 3b 04 03 |...Q.....PV..;..| -000002a0 00 8a 30 81 87 02 41 5d 88 4b fe eb 45 ee 5e 9f |..0...A].K..E.^.| -000002b0 ec 20 90 1f 41 aa 47 87 f7 ae 46 71 dc 55 8b 2c |. ..A.G...Fq.U.,| -000002c0 ce 70 5f ad 3e fa 3c c3 cb 77 d2 69 67 25 27 08 |.p_.>.<..w.ig%'.| -000002d0 23 de 52 3c 0e 6c ca 8f 86 8f 61 cd 5b cf d8 42 |#.R<.l....a.[..B| -000002e0 aa 5a 95 aa 4b d4 d9 f3 02 42 01 81 78 53 9c bd |.Z..K....B..xS..| -000002f0 af 7e d9 be 26 07 24 11 ca 4b 1d dd 2b 49 ec 35 |.~..&.$..K..+I.5| -00000300 25 8d 58 87 ad 80 4f 90 c7 f8 a4 b9 c2 75 b5 12 |%.X...O......u..| -00000310 a7 2c 49 82 76 e8 ce c4 a7 23 68 75 fc 88 82 13 |.,I.v....#hu....| -00000320 27 55 a7 50 3c d6 d0 ae e3 88 94 b4 16 03 03 00 |'U.P<...........| +00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 0f 61 |*............ .a| +00000280 6e 56 ec 74 54 e2 24 09 61 64 45 89 44 aa cb 79 |nV.tT.$.adE.D..y| +00000290 18 37 12 42 07 f8 d7 a3 42 b8 d7 06 21 28 04 03 |.7.B....B...!(..| +000002a0 00 8a 30 81 87 02 42 00 af 5c 33 04 e8 e1 fa b7 |..0...B..\3.....| +000002b0 98 38 96 ea c1 ee 7d 2c 45 85 ab 41 bd d8 88 af |.8....},E..A....| +000002c0 a6 0b e4 22 56 7d 3a e6 a6 8e 0d b5 81 cb 38 43 |..."V}:.......8C| +000002d0 e7 b6 94 ee 20 e7 61 89 00 99 69 18 b3 06 d0 15 |.... .a...i.....| +000002e0 0e f4 10 e9 5a dd 74 10 d1 02 41 27 4c dc 89 d4 |....Z.t...A'L...| +000002f0 75 56 d4 c2 82 7d 53 a0 61 c5 ba 6a 9a ca fa 36 |uV...}S.a..j...6| +00000300 16 db 82 5d 5e b7 9b 6a b8 13 0b 69 2f b5 c9 8e |...]^..j...i/...| +00000310 53 18 03 24 b3 31 b1 48 8c b9 e0 16 96 cc e2 5d |S..$.1.H.......]| +00000320 71 6a 1d 70 8c 1b 57 8e 5d 9a f2 e1 16 03 03 00 |qj.p..W.].......| 00000330 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| 00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000040 00 00 00 00 00 04 f4 cc a8 9f 48 44 ca 19 e6 4c |..........HD...L| -00000050 3d 51 f2 29 40 0b 70 06 09 f0 69 5c 51 78 51 1e |=Q.)@.p...i\QxQ.| -00000060 2b d1 47 22 8d d6 fb f5 41 bd e4 fd 3d f4 1b 48 |+.G"....A...=..H| -00000070 44 96 2d 97 b9 |D.-..| +00000040 00 00 00 00 00 c1 47 dc 05 80 89 9f 04 e8 88 58 |......G........X| +00000050 bc 59 78 df ce bb d4 f7 cf 45 e2 2a ff ce 09 9c |.Yx......E.*....| +00000060 07 f3 90 49 ad 4d 07 b4 21 46 e3 37 e9 54 82 4d |...I.M..!F.7.T.M| +00000070 a2 05 ad 83 fa |.....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 f1 a2 70 ba 50 |..........@..p.P| -00000010 9d 7a 9f 8f c6 fb 7e 83 75 bd 94 cf e6 c1 4a f0 |.z....~.u.....J.| -00000020 e6 54 e9 2c 30 23 a2 5c c2 09 32 d4 06 f7 54 e7 |.T.,0#.\..2...T.| -00000030 ab 27 a6 66 ab 86 e6 2c 20 12 cf 61 4d ef 12 20 |.'.f..., ..aM.. | -00000040 ba b6 42 39 b7 76 b9 1b fc f4 44 |..B9.v....D| +00000000 14 03 03 00 01 01 16 03 03 00 40 a6 27 61 cd 85 |..........@.'a..| +00000010 3a 7c 35 bb 33 61 ed 4b 0f 0c 42 bd 25 a5 5a a8 |:|5.3a.K..B.%.Z.| +00000020 ef 27 b3 d7 d2 38 64 c7 46 51 5c f2 4b 32 a1 eb |.'...8d.FQ\.K2..| +00000030 b2 6a ba af fc d0 2d 7a 9d 72 d5 23 ae 15 2a fc |.j....-z.r.#..*.| +00000040 1c 03 cd 99 dd ac b0 31 83 0a 1e |.......1...| >>> 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 0b 5b d0 ab 14 3f ae 1f 4b 12 25 |......[...?..K.%| -00000020 05 2a 67 11 0c 17 42 1b b6 d2 af 16 40 26 fd 7b |.*g...B.....@&.{| -00000030 d7 57 10 2a f8 15 03 03 00 30 00 00 00 00 00 00 |.W.*.....0......| -00000040 00 00 00 00 00 00 00 00 00 00 83 54 64 d6 31 32 |...........Td.12| -00000050 55 62 32 49 b9 54 7b e3 34 02 1c 75 e3 1b 5a 41 |Ub2I.T{.4..u..ZA| -00000060 a2 cd 47 26 f0 ed c2 d5 41 34 |..G&....A4| +00000010 00 00 00 00 00 a7 0f 50 52 17 a2 5b 19 33 4e 97 |.......PR..[.3N.| +00000020 33 4e 56 2e 1e bf 93 ca ae fa 4c ca ff 47 08 7b |3NV.......L..G.{| +00000030 d2 f8 e1 29 29 15 03 03 00 30 00 00 00 00 00 00 |...))....0......| +00000040 00 00 00 00 00 00 00 00 00 00 a5 ac 57 1c ca 5f |............W.._| +00000050 f2 39 b2 85 a5 4a 06 11 a2 8f e5 1d 55 1d 4f 89 |.9...J......U.O.| +00000060 6c d9 47 bd a2 8b d3 d0 eb d6 |l.G.......| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM index 28a9ef7c659..3ae5fac30c1 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 72 81 c3 91 37 |....Y...U..r...7| -00000010 54 37 fb 0f 2b 16 3b 7b bc a6 d9 2e e2 83 23 83 |T7..+.;{......#.| -00000020 b3 67 cf 36 dc 65 8d a6 3d cb 72 20 ac b9 b9 48 |.g.6.e..=.r ...H| -00000030 30 9d fe 67 09 39 f5 47 d2 9a c8 3e 22 02 50 5e |0..g.9.G...>".P^| -00000040 fd 02 c9 ff c1 84 2e 2e ab 78 ef c6 c0 2b 00 00 |.........x...+..| +00000000 16 03 03 00 59 02 00 00 55 03 03 e1 a8 35 92 15 |....Y...U....5..| +00000010 b2 f2 02 ae 4f 1b c5 1c 46 04 d1 bf 60 d6 bd 66 |....O...F...`..f| +00000020 d0 c4 d5 18 26 10 6d 53 19 35 d2 20 15 d3 4b 3f |....&.mS.5. ..K?| +00000030 de 5a f3 8d f7 02 c4 71 8b 4f c2 b6 69 49 f1 2a |.Z.....q.O..iI.*| +00000040 79 66 40 45 ee 9d 1b d8 72 7e b0 23 c0 2b 00 00 |yf@E....r~.#.+..| 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....| @@ -49,34 +49,34 @@ 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 b6 0c 00 00 b2 03 00 1d 20 b7 1c |*............ ..| -00000280 2f 05 5e c8 ae 68 6b 54 c5 88 19 cf 7c 04 b2 ed |/.^..hkT....|...| -00000290 8d 5a e9 7e 6b 50 8a ee 12 66 2d 6f e4 7a 04 03 |.Z.~kP...f-o.z..| -000002a0 00 8a 30 81 87 02 42 01 8d 7e 23 bc d7 a7 ad 73 |..0...B..~#....s| -000002b0 5f 45 9e 04 da 6e c0 34 a8 09 59 e3 bc ab 80 e1 |_E...n.4..Y.....| -000002c0 d4 84 79 7d de 90 c1 f2 ea 95 ed fc 7e d3 f0 31 |..y}........~..1| -000002d0 4c 9b da 82 a0 97 ed e6 c9 f2 b9 2a 0a 1e 0a 2c |L..........*...,| -000002e0 7f 1d 62 ea 11 a9 77 5e 2f 02 41 09 88 2b eb 84 |..b...w^/.A..+..| -000002f0 4f 62 9a c9 8a 0b a2 c6 88 0e 3e d9 29 f0 2b ba |Ob........>.).+.| -00000300 08 40 b0 9c 17 70 d9 84 1e d3 39 ad 70 fc df 63 |.@...p....9.p..c| -00000310 a0 f6 69 3c 19 ce 0b a5 95 d2 6a b1 46 b1 e5 ba |..i<......j.F...| -00000320 fd d2 67 4b 76 e3 eb b9 21 d0 7c 85 16 03 03 00 |..gKv...!.|.....| +00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 2e b4 |*............ ..| +00000280 dd 41 46 08 4d c2 c9 37 b8 50 0b 50 6f c7 bd 13 |.AF.M..7.P.Po...| +00000290 de 59 d4 9f d0 2b 44 2a 8c 6f 2a f9 67 7a 04 03 |.Y...+D*.o*.gz..| +000002a0 00 8a 30 81 87 02 41 7c 9a e0 93 cc 65 a2 af 0e |..0...A|....e...| +000002b0 32 9c 37 b7 39 9a 45 95 fb 2e b2 a9 34 f8 ab 47 |2.7.9.E.....4..G| +000002c0 d8 3b 6f 7d b8 03 32 a9 d0 30 1a 37 cc fd 4a 16 |.;o}..2..0.7..J.| +000002d0 94 f9 23 ce b7 8a e6 91 d7 33 00 25 d3 c7 88 d8 |..#......3.%....| +000002e0 49 2c 81 73 e2 b1 b8 78 02 42 01 c8 58 dc 43 96 |I,.s...x.B..X.C.| +000002f0 40 00 c3 4c 9c a1 ba ef 4a 20 e6 ee 53 28 6e 82 |@..L....J ..S(n.| +00000300 97 ba f3 0b 71 5c f9 4f 05 1e 61 a7 ba 03 60 5c |....q\.O..a...`\| +00000310 f5 61 1e fd 53 c1 74 30 5c 92 b4 4c 6e d2 9f 05 |.a..S.t0\..Ln...| +00000320 6b ad 92 e5 14 b8 a9 07 a0 f3 34 71 16 03 03 00 |k.........4q....| 00000330 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 32 49 7e |....(........2I~| -00000040 8f d6 2e 81 d7 03 a6 61 a3 04 98 81 95 84 58 d1 |.......a......X.| -00000050 a2 33 fe 4a 5d cd 96 76 64 1e 1a 62 03 |.3.J]..vd..b.| +00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 71 c9 39 |....(........q.9| +00000040 50 b8 91 9e eb f6 48 c6 04 d0 ae 99 dc 63 14 1b |P.....H......c..| +00000050 e9 4f 6b c0 18 46 b6 ca 38 bc 58 c3 85 |.Ok..F..8.X..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 28 14 2d ae 7c |..........((.-.|| -00000010 b8 7d dc 27 b2 18 39 57 c8 be 5c 3d a3 ab fa 5a |.}.'..9W..\=...Z| -00000020 3d 55 1b 3d 31 77 95 af 42 86 af 2b e7 5a 98 40 |=U.=1w..B..+.Z.@| -00000030 18 77 d1 |.w.| +00000000 14 03 03 00 01 01 16 03 03 00 28 e3 f3 fe 51 7c |..........(...Q|| +00000010 7c f9 ad fe 85 6c 37 fd 8f e2 76 2f 10 38 62 b0 ||....l7...v/.8b.| +00000020 37 7c cf 6e e6 65 c6 f4 5e 67 33 03 10 62 14 29 |7|.n.e..^g3..b.)| +00000030 8a ca 2e |...| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 30 50 2f |.............0P/| -00000010 36 4a 7c ee e6 f0 b9 b8 bf 4d e3 63 4d 5e 58 08 |6J|......M.cM^X.| -00000020 ac ac 82 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| -00000030 80 e2 42 ca 91 65 04 4e ca a8 6f 81 7c 30 c0 1f |..B..e.N..o.|0..| -00000040 aa 7b |.{| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5a 2d fa |.............Z-.| +00000010 9d 55 ff 55 ee 77 9e c0 60 3d 37 aa 82 14 a9 8c |.U.U.w..`=7.....| +00000020 7b d3 92 15 03 03 00 1a 00 00 00 00 00 00 00 02 |{...............| +00000030 8a 69 ad 03 ec 4f 06 55 e6 0c 3a 59 ea 15 26 e7 |.i...O.U..:Y..&.| +00000040 17 de |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 index 831fa2101fe..9d79b14dae0 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 be c0 b6 d7 fe |....Y...U.......| -00000010 43 9d 21 1f 89 27 bd db 0a 9a 5a 44 dd 79 d1 f2 |C.!..'....ZD.y..| -00000020 18 9a 2a 04 8c eb e6 a9 93 ef ee 20 35 48 44 08 |..*........ 5HD.| -00000030 8c 7a 3e f6 0f d7 5f 33 54 60 0b c9 65 4e 17 8d |.z>..._3T`..eN..| -00000040 d2 69 b7 20 0b c5 ba 9a d4 b7 40 39 c0 23 00 00 |.i. ......@9.#..| +00000000 16 03 03 00 59 02 00 00 55 03 03 c7 69 06 a9 64 |....Y...U...i..d| +00000010 53 1a 6c 7b 39 f3 2e e3 01 5e ef e0 ac 69 a6 2e |S.l{9....^...i..| +00000020 39 59 c4 a8 06 60 9c 5b 0a 93 f2 20 b1 ba 93 61 |9Y...`.[... ...a| +00000030 3f c3 a8 d0 e7 22 60 8a 0b c2 68 14 69 c5 8a 9c |?...."`...h.i...| +00000040 35 b2 ba 8a d2 9b a4 e0 13 d8 fc bb c0 23 00 00 |5............#..| 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....| @@ -49,43 +49,43 @@ 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 b7 0c 00 00 b3 03 00 1d 20 0e 53 |*............ .S| -00000280 82 54 1a ba f8 a4 52 1d 6d b8 70 18 41 e8 67 f9 |.T....R.m.p.A.g.| -00000290 38 1e fb fa b8 89 2d d6 4d 1b ae 67 fe 75 04 03 |8.....-.M..g.u..| -000002a0 00 8b 30 81 88 02 42 01 68 0e d4 92 a6 1a d9 66 |..0...B.h......f| -000002b0 ff 0e ca 4c 32 b8 78 d3 52 d1 ad a2 32 83 f0 3c |...L2.x.R...2..<| -000002c0 43 e0 7e 92 94 e9 c6 99 00 d9 f7 06 c0 2c 72 c0 |C.~..........,r.| -000002d0 9b f7 c0 ec 1f 23 8f b5 e5 74 9d ff 89 17 12 b4 |.....#...t......| -000002e0 f1 f5 25 f7 2e 0d 78 f6 1c 02 42 01 fc da dd c8 |..%...x...B.....| -000002f0 65 30 67 a3 ff 42 e3 37 19 ba 7c 04 6b a1 b3 97 |e0g..B.7..|.k...| -00000300 b0 ca 8c 2d fc b0 40 1c a1 d8 c9 64 fe df 48 3b |...-..@....d..H;| -00000310 07 57 1f 81 a2 3e a4 84 96 00 fb 55 29 1c 94 9d |.W...>.....U)...| -00000320 f9 0d a4 71 4f 5f fd c3 22 e2 88 07 21 16 03 03 |...qO_.."...!...| -00000330 00 04 0e 00 00 00 |......| +00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 bd cd |*............ ..| +00000280 69 00 ff 76 9e 27 f5 4d cb f2 be 87 ec f3 c6 08 |i..v.'.M........| +00000290 79 fa cc 4e a5 db e6 dd 19 cb b1 66 e5 2b 04 03 |y..N.......f.+..| +000002a0 00 8a 30 81 87 02 41 33 72 4b 8e 13 f1 3c 7b 9b |..0...A3rK...<{.| +000002b0 4e 63 e0 28 1c 62 b0 a9 bf 70 96 68 93 52 4b 64 |Nc.(.b...p.h.RKd| +000002c0 02 4b 79 0b 50 7c 16 df 21 8f e4 8b c2 c6 4b cc |.Ky.P|..!.....K.| +000002d0 96 b8 bb 4a cc 89 f6 a5 6d c2 a3 70 b6 5a 25 26 |...J....m..p.Z%&| +000002e0 ad aa 56 95 72 fa d6 13 02 42 01 de 8a 1f 83 51 |..V.r....B.....Q| +000002f0 ce 3e 37 ff 3e ba 0e ed bd f3 95 0c 1b 69 8f f3 |.>7.>........i..| +00000300 f4 a9 26 cb c6 f4 70 79 da 93 5b 25 76 89 e8 3d |..&...py..[%v..=| +00000310 94 7f a9 5b 4f 25 83 63 a2 cb 71 27 41 5e 41 a1 |...[O%.c..q'A^A.| +00000320 5c 65 f2 2d a4 81 91 ca 79 bc 45 d3 16 03 03 00 |\e.-....y.E.....| +00000330 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| 00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........| -00000040 00 00 00 00 00 7c e9 97 4b 98 8a 4c 59 95 3e 31 |.....|..K..LY.>1| -00000050 c4 b6 e2 79 10 de bc 8e aa 1e 52 07 b2 e1 52 bc |...y......R...R.| -00000060 3b da 8d 5f 12 6a 18 d1 0a 5d 93 1c ad bb f9 b7 |;.._.j...]......| -00000070 6b 58 49 39 ea 3a 9e 20 47 69 43 b4 b4 d8 16 d0 |kXI9.:. GiC.....| -00000080 f0 9d 36 74 04 |..6t.| +00000040 00 00 00 00 00 fe 52 a2 0a 9f de 8c 45 36 c5 0e |......R.....E6..| +00000050 a0 b5 f6 06 80 9f 2b 0e 72 4b 86 a7 4c 2a 37 0c |......+.rK..L*7.| +00000060 a0 a3 4c 2c 32 32 cf ed 45 ee e3 a2 1c 17 7d 4f |..L,22..E.....}O| +00000070 d8 60 d6 79 08 01 d7 35 0c 40 c8 85 f1 3e 73 b5 |.`.y...5.@...>s.| +00000080 5d 89 c9 db 03 |]....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 50 60 d5 ac 39 b6 |..........P`..9.| -00000010 58 50 03 90 9f c9 78 f1 45 43 b1 34 bd c8 29 65 |XP....x.EC.4..)e| -00000020 54 38 7a 88 46 15 e8 a4 fb 9d 80 4e d6 45 e1 8d |T8z.F......N.E..| -00000030 27 d6 09 66 1d ee 46 6d dd 8e 89 34 0f 4a fb fd |'..f..Fm...4.J..| -00000040 bc 85 08 07 f0 5b 1c 24 e2 11 1b e2 a4 94 f5 80 |.....[.$........| -00000050 fa 47 f4 62 0e b9 1c 31 cb 7b bf |.G.b...1.{.| +00000000 14 03 03 00 01 01 16 03 03 00 50 99 8b 66 fc b2 |..........P..f..| +00000010 0c 18 de 47 7b 72 a2 9b 47 64 58 45 00 70 b6 d3 |...G{r..GdXE.p..| +00000020 33 62 c2 c6 41 da 5d 08 37 16 5c 24 50 06 e0 e6 |3b..A.].7.\$P...| +00000030 7c 90 5e 32 5e 3f 2e bc 70 d2 77 b5 29 d8 d4 fb ||.^2^?..p.w.)...| +00000040 38 8c 05 40 e1 42 1a 25 44 79 fa a6 cc f6 50 5a |8..@.B.%Dy....PZ| +00000050 da e0 85 99 30 20 7d ee 04 fe ca |....0 }....| >>> Flow 5 (client to server) 00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000010 00 00 00 00 00 37 b7 23 a2 06 97 f3 60 9a f0 7e |.....7.#....`..~| -00000020 b7 11 6d 0d 66 0e db 38 1a eb cd 72 80 c8 54 ef |..m.f..8...r..T.| -00000030 cf 90 6d 22 68 41 63 03 46 b9 28 4f 2f d6 fe fa |..m"hAc.F.(O/...| -00000040 b2 91 07 36 71 15 03 03 00 40 00 00 00 00 00 00 |...6q....@......| -00000050 00 00 00 00 00 00 00 00 00 00 ca 17 d9 fd 1a 0e |................| -00000060 21 db a4 92 dc 92 e8 89 9d 14 6b 8a d3 ee a7 95 |!.........k.....| -00000070 c0 91 8d 3c af 5a 48 d5 c6 2f 66 b8 b8 d4 ce f9 |...<.ZH../f.....| -00000080 59 e5 e0 e2 df e5 7e ea 94 03 |Y.....~...| +00000010 00 00 00 00 00 cb cb 98 55 3f 17 18 42 7b 52 0c |........U?..B{R.| +00000020 6f 6c 50 87 b1 af ef 25 ac a5 24 4a d2 bc 39 33 |olP....%..$J..93| +00000030 29 81 c0 4f cf 20 8f 0c 4c a8 64 5f 97 4d da f4 |)..O. ..L.d_.M..| +00000040 89 7c 28 f3 d4 15 03 03 00 40 00 00 00 00 00 00 |.|(......@......| +00000050 00 00 00 00 00 00 00 00 00 00 6b c5 03 a6 9b 87 |..........k.....| +00000060 ac df 05 8d 79 3c 46 12 70 3a 1d a0 d0 29 7c 2a |....y>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 e6 0e 27 a7 58 |....Y...U....'.X| -00000010 1d a3 1d 1d 21 64 31 f6 1e bc 28 b4 46 7e 26 be |....!d1...(.F~&.| -00000020 de 0a 65 eb f0 18 dc 7f 3e 1b 55 20 fe 66 50 20 |..e.....>.U .fP | -00000030 f0 f0 48 a8 db 0a ff ee 60 ea 3d 7f 07 5e b9 65 |..H.....`.=..^.e| -00000040 c3 e4 2a 19 9c bd 57 36 ca e3 a7 2d c0 2c 00 00 |..*...W6...-.,..| +00000000 16 03 03 00 59 02 00 00 55 03 03 93 2e 79 54 e7 |....Y...U....yT.| +00000010 e4 ce 82 cd 46 2b d1 99 d2 ba c7 37 1e f5 86 2f |....F+.....7.../| +00000020 6c 7d b1 10 e1 98 03 b1 93 a9 d9 20 c2 b6 55 f9 |l}......... ..U.| +00000030 d0 b3 65 3e 99 33 4c a4 5d a3 58 8b b4 ee c3 91 |..e>.3L.].X.....| +00000040 80 34 1c 07 c2 b9 9c bf e4 c0 bd f2 c0 2c 00 00 |.4...........,..| 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....| @@ -49,34 +49,34 @@ 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 b7 0c 00 00 b3 03 00 1d 20 17 21 |*............ .!| -00000280 a9 b8 65 8b aa 41 d2 d1 45 45 e5 ce 39 60 54 b6 |..e..A..EE..9`T.| -00000290 43 9f c4 19 a4 aa ec 71 08 b0 d1 22 f7 46 04 03 |C......q...".F..| -000002a0 00 8b 30 81 88 02 42 00 8b a5 d9 d3 8f a1 72 48 |..0...B.......rH| -000002b0 06 42 25 c3 f6 c8 46 8d 88 30 36 7d d8 18 a9 cc |.B%...F..06}....| -000002c0 de e4 c8 3f e9 d2 f0 88 18 cc c6 fb 14 e0 05 b1 |...?............| -000002d0 ec 50 3d 57 b4 e9 83 57 55 4b 0d 2c 89 69 ff b1 |.P=W...WUK.,.i..| -000002e0 58 0b 01 89 48 97 ee 88 7e 02 42 01 e1 6f 9c 36 |X...H...~.B..o.6| -000002f0 6a 6c 86 24 d6 b3 45 f1 6c 03 d8 fd da d8 cc 52 |jl.$..E.l......R| -00000300 04 41 7a c5 f9 b5 91 a5 6c d8 5a 03 ad de e3 da |.Az.....l.Z.....| -00000310 de f8 db b0 bc 75 38 03 ab 84 ac 3f b2 c2 7e 6d |.....u8....?..~m| -00000320 a7 2e c0 d9 bd 85 e2 7b 36 11 2b 12 14 16 03 03 |.......{6.+.....| +00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 d2 39 |*............ .9| +00000280 f6 fc 9c 40 cb ba 04 7c 37 ac df 95 5f 46 44 f4 |...@...|7..._FD.| +00000290 2b 0c 63 24 4e 95 1d 35 b3 68 ab 27 d1 5a 04 03 |+.c$N..5.h.'.Z..| +000002a0 00 8b 30 81 88 02 42 01 3e ff 73 74 01 f5 c8 32 |..0...B.>.st...2| +000002b0 31 f1 d5 0b 26 db 0c ef d0 c9 a7 aa 21 c8 0f 50 |1...&.......!..P| +000002c0 2f ce eb 41 ce 1e de 5d 29 8d c1 20 f2 d9 5d 39 |/..A...]).. ..]9| +000002d0 9d 1d c1 10 b1 a8 35 33 cc 58 f3 fd df 5d 7e fc |......53.X...]~.| +000002e0 ee 8b 15 02 03 2e b0 2b b1 02 42 00 e0 f1 cf e9 |.......+..B.....| +000002f0 e7 e2 1a a7 e1 3c 47 40 c4 fb b2 0d 15 47 4e 26 |.....>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 4b a3 cc |....(........K..| -00000040 a1 5b 04 d4 1e 6c 2c 26 56 23 62 50 bc d6 90 0b |.[...l,&V#bP....| -00000050 67 41 d9 7c 79 a5 53 54 73 0a 93 e2 73 |gA.|y.STs...s| +00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 5c 78 1d |....(........\x.| +00000040 a7 00 de 4e 5e 13 6a 1d 1d 82 28 f6 b6 8a 88 fe |...N^.j...(.....| +00000050 00 81 fe 04 95 a0 4e 93 e0 01 19 a3 6d |......N.....m| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 e3 19 7b 8c 8a |..........(..{..| -00000010 52 35 82 cc 70 50 83 22 88 8b 0a 54 bc eb ff 57 |R5..pP."...T...W| -00000020 2c df 0d 50 d6 21 2f d2 d9 e8 15 27 b9 d7 01 a3 |,..P.!/....'....| -00000030 f2 62 0b |.b.| +00000000 14 03 03 00 01 01 16 03 03 00 28 0a 61 1d 77 66 |..........(.a.wf| +00000010 67 ca 17 5a 94 fc bf 36 07 33 f8 7e 34 bc 65 aa |g..Z...6.3.~4.e.| +00000020 0f 28 7d 40 80 6e 33 99 83 09 02 78 b7 d1 cd 56 |.(}@.n3....x...V| +00000030 a7 f7 e5 |...| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 cc cf 92 |................| -00000010 4d 25 58 96 1d dc df fb d9 1f a5 49 87 45 dd 73 |M%X........I.E.s| -00000020 1a 17 ae 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| -00000030 fb b5 c5 e4 aa ea e7 7e ff dd f7 11 63 c0 e4 a3 |.......~....c...| -00000040 86 fc |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 56 48 af |.............VH.| +00000010 45 e1 76 a8 67 ef 80 cc 92 03 aa b5 88 fc 48 84 |E.v.g.........H.| +00000020 1b 81 39 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..9.............| +00000030 5a 53 90 c9 25 a6 99 ce e7 09 74 97 63 68 fe 0c |ZS..%.....t.ch..| +00000040 5e 89 |^.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 index 61e665721a2..4d3fbfe8e6f 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 @@ -1,17 +1,17 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......| +00000000 16 03 01 00 6b 01 00 00 67 03 03 00 00 00 00 00 |....k...g.......| 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 02 cc a9 |................| -00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............| +00000030 01 00 00 3c 00 05 00 05 01 00 00 00 00 00 0a 00 |...<............| 00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................| -00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................| -00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............| +00000050 00 00 0d 00 12 00 10 04 01 04 03 05 01 05 03 06 |................| +00000060 01 06 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 |................| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 d6 47 27 38 fc |....Y...U...G'8.| -00000010 16 92 2c 1f a6 53 a9 31 85 65 a7 83 0a 8f cb 4d |..,..S.1.e.....M| -00000020 7d 5b df c1 2e b9 b1 08 e3 b9 96 20 16 0c e5 07 |}[......... ....| -00000030 27 cc 4f 7d 11 ef 1a 14 c6 42 bf e9 c1 b7 a5 89 |'.O}.....B......| -00000040 ca 2b 4c 30 4f c7 c8 10 13 b0 b1 6b cc a9 00 00 |.+L0O......k....| +00000000 16 03 03 00 59 02 00 00 55 03 03 3c 9c e9 fb 22 |....Y...U..<..."| +00000010 8b 32 cb 0d 56 1d a7 a2 c7 c5 d4 41 3d 9f 84 1b |.2..V......A=...| +00000020 26 50 b6 a3 fa f2 c5 20 0d f9 a6 20 38 86 ba 26 |&P..... ... 8..&| +00000030 db 6e d9 ab 3c 73 ec d8 34 56 d1 f2 d3 60 42 9a |.n..KjA..=}?Y....| -00000320 f7 c7 7f 63 49 2f e4 4e d9 8f 2d e5 98 16 03 03 |...cI/.N..-.....| -00000330 00 04 0e 00 00 00 |......| +00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 ef e6 |*............ ..| +00000280 9e e3 b7 29 0e db 15 72 e8 a8 14 db 99 9c 81 05 |...)...r........| +00000290 29 a0 52 3d 4b a8 76 a3 6d 45 9a 19 72 50 04 03 |).R=K.v.mE..rP..| +000002a0 00 8a 30 81 87 02 41 59 79 0e 40 7d ee 88 af a4 |..0...AYy.@}....| +000002b0 23 dd 4e 18 6a 15 20 af 98 d9 f7 4f 0a ff 7a c6 |#.N.j. ....O..z.| +000002c0 a7 36 53 f0 1e 1a a7 90 25 e6 bd 82 69 cc bc aa |.6S.....%...i...| +000002d0 5d dd c5 0d 01 ed f8 75 57 18 3b d9 52 9d e2 3b |]......uW.;.R..;| +000002e0 a2 fb 7a 71 ea 61 7c 34 02 42 01 f3 ed 1f 6d e8 |..zq.a|4.B....m.| +000002f0 15 ce a1 af ff f5 2f fb e4 6f 83 9c ac f4 05 e2 |....../..o......| +00000300 27 15 bb dd 63 9c ea ac 06 a1 08 4c 5f ad 1a 80 |'...c......L_...| +00000310 cd ee d6 b7 d0 96 6d 42 54 ff cb 42 9b 48 24 0c |......mBT..B.H$.| +00000320 fe fa 07 2a 0a 7a d3 c0 58 4b cd 79 16 03 03 00 |...*.z..XK.y....| +00000330 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 7c 89 36 36 77 8c 09 31 e4 48 01 |.... |.66w..1.H.| -00000040 6f 08 27 a8 bb 1b 1c a6 0c 09 ec 0b f6 a3 be bd |o.'.............| -00000050 76 70 fb f8 e5 |vp...| +00000030 16 03 03 00 20 6e 2a ec f4 3a e8 88 99 f1 77 94 |.... n*..:....w.| +00000040 b3 a2 c5 3a 59 c2 9a f5 4a fb 89 e4 51 1a 54 a4 |...:Y...J...Q.T.| +00000050 72 d9 54 99 c3 |r.T..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 a0 db 6c df b1 |.......... ..l..| -00000010 87 77 78 ad 22 b2 98 77 e8 57 aa 13 a8 98 35 63 |.wx."..w.W....5c| -00000020 00 c5 13 b9 88 5d ca bf bc c5 c3 |.....].....| +00000000 14 03 03 00 01 01 16 03 03 00 20 be 1a 60 4e 4a |.......... ..`NJ| +00000010 2d 81 19 6b 7c f2 80 15 18 9c 38 70 6d a3 49 88 |-..k|.....8pm.I.| +00000020 93 4b e8 cc 9f b2 0e cc ed 29 64 |.K.......)d| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 16 00 c8 c6 25 ae 11 9d a5 10 75 |.........%.....u| -00000010 e4 4c e3 69 12 2b d9 9e 8e 40 88 15 03 03 00 12 |.L.i.+...@......| -00000020 cf ab ac d4 c4 8e 9c 92 c4 2f 1f c6 96 0b 36 c9 |........./....6.| -00000030 f5 22 |."| +00000000 17 03 03 00 16 bd 4c d9 d3 ea d0 d3 4e db dc ea |......L.....N...| +00000010 ad e7 20 17 ec 36 04 29 a5 7c ab 15 03 03 00 12 |.. ..6.).|......| +00000020 7b e1 b6 9b fc f9 18 83 87 31 b3 02 e7 b2 e3 c6 |{........1......| +00000030 37 d8 |7.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES index 45728cfbe73..9cc3e8ffaa8 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 2f 51 e0 81 eb |....Y...U../Q...| -00000010 d2 db 4f 22 fa 11 d2 56 f3 06 d6 a0 97 d2 f3 74 |..O"...V.......t| -00000020 fc a9 a7 73 ba a8 ee f2 05 89 15 20 0f 96 70 60 |...s....... ..p`| -00000030 6f 78 aa 56 fa 92 5e e3 bc e7 f0 40 00 48 8b 84 |ox.V..^....@.H..| -00000040 57 b8 49 e9 f9 00 99 ff 73 29 f6 e7 c0 13 00 00 |W.I.....s)......| +00000000 16 03 03 00 59 02 00 00 55 03 03 66 3d ff 45 dc |....Y...U..f=.E.| +00000010 ea f8 4c 56 5d 55 71 63 c1 64 33 9f f5 09 aa 38 |..LV]Uqc.d3....8| +00000020 bd 13 27 d7 85 ed 0a b4 68 83 9a 20 98 69 c4 d9 |..'.....h.. .i..| +00000030 a1 46 f4 30 ed 4d ae 31 7b 3c 18 23 fa b5 b4 a1 |.F.0.M.1{<.#....| +00000040 74 98 34 7f b8 d0 00 e5 22 35 eb 4f c0 13 00 00 |t.4....."5.O....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,38 +54,38 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 48 77 87 3e 04 c9 14 |........ Hw.>...| -000002d0 56 9d 1b 41 4b d0 eb 65 8d 56 56 97 fd 73 97 cd |V..AK..e.VV..s..| -000002e0 c6 88 8f 8e 79 99 09 65 53 04 01 00 80 98 c2 ff |....y..eS.......| -000002f0 49 aa 41 ce 0e 7b 03 99 39 c0 b5 ac 72 16 1c 5e |I.A..{..9...r..^| -00000300 a0 92 f1 07 0c 93 dc f6 25 2b 5c be e3 65 41 a9 |........%+\..eA.| -00000310 1e 57 6d 9f 28 50 ca 87 2f c7 b0 15 2e 15 d2 cc |.Wm.(P../.......| -00000320 4d 0e 42 4c 0a 01 4d 1b 9c d1 17 e7 22 9a 6a a9 |M.BL..M.....".j.| -00000330 27 0b 7a a7 32 e3 c7 5a d1 7f f2 1c 45 61 91 a8 |'.z.2..Z....Ea..| -00000340 e0 e0 49 de b7 2f a6 89 63 94 ed 0e 63 15 6b 4f |..I../..c...c.kO| -00000350 fb 62 c4 35 cb 98 89 c2 d1 bc f6 e2 2d 8f 9f 72 |.b.5........-..r| -00000360 56 79 50 5f cd 73 00 f1 65 bf a4 3f 87 16 03 03 |VyP_.s..e..?....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 f1 a9 e3 69 c6 9b 08 |........ ...i...| +000002d0 76 5c 45 2f 7d 16 73 79 b2 c5 9f 01 05 13 74 56 |v\E/}.sy......tV| +000002e0 93 4a dd b2 db 97 61 f9 11 04 01 00 80 81 a1 58 |.J....a........X| +000002f0 99 41 95 ab 7b cc ac 46 e8 04 3e c9 2d 9c 66 63 |.A..{..F..>.-.fc| +00000300 0d 80 19 43 85 bc b5 cf d2 a4 db 9d 28 c2 f4 f7 |...C........(...| +00000310 fe a1 f3 8f 6b e3 b5 6e e2 c2 e2 ac b9 0f f8 8d |....k..n........| +00000320 29 d2 ba 46 dc 10 ae c2 f3 0f b0 8f 1c e6 22 54 |)..F.........."T| +00000330 84 9f 10 c9 a5 ae 53 43 15 61 eb 0c ad 49 78 47 |......SC.a...IxG| +00000340 69 f9 52 9e 58 23 dc df d7 92 0d f5 50 b2 43 44 |i.R.X#......P.CD| +00000350 fe 8b 8b b3 ed 69 e7 15 9c 10 20 51 67 bd b9 40 |.....i.... Qg..@| +00000360 0e 0a f9 65 bf e7 bf 5d 33 5c 71 3d 4c 16 03 03 |...e...]3\q=L...| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| 00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000040 00 00 00 00 00 93 4b 37 8d 57 43 52 77 56 d2 af |......K7.WCRwV..| -00000050 7c 56 d0 bf 1e 7b 29 55 3e b7 d0 1c 02 2e 0d de ||V...{)U>.......| -00000060 09 66 f2 98 21 57 ab d2 d2 4a 73 c1 c5 fe f1 b8 |.f..!W...Js.....| -00000070 95 d3 fc 70 ce |...p.| +00000040 00 00 00 00 00 8a cb 7f 37 ba e5 13 2b db f4 15 |........7...+...| +00000050 97 6e b5 08 7b 89 16 21 f8 45 1b ef df 17 e0 ad |.n..{..!.E......| +00000060 44 12 39 4a e6 fb 78 9d aa ab 8a 95 2a 02 1d 74 |D.9J..x.....*..t| +00000070 25 f1 3d 38 21 |%.=8!| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 b3 e1 81 3e 0a |..........@...>.| -00000010 f8 f3 c6 05 c1 09 f5 73 01 eb 18 1a 05 fa 2f 9b |.......s....../.| -00000020 b2 bc c7 44 23 38 ed b9 99 a0 56 7d 8b e4 a5 4b |...D#8....V}...K| -00000030 f1 89 45 bc 95 ea 06 a8 48 de 07 bf d5 cb 53 bc |..E.....H.....S.| -00000040 50 fa 25 fb d5 79 17 ec 4d be 3d |P.%..y..M.=| +00000000 14 03 03 00 01 01 16 03 03 00 40 1c 73 dd bb 45 |..........@.s..E| +00000010 89 89 e4 a9 05 db 10 5d 22 20 75 c7 b7 82 c5 64 |.......]" u....d| +00000020 2e 30 70 fc 0c a7 a8 c0 cb da ab 60 1e 68 12 bc |.0p........`.h..| +00000030 47 68 87 01 00 96 e1 f4 a1 a3 20 d1 05 31 7f 79 |Gh........ ..1.y| +00000040 28 36 f9 5c 24 a7 ba 68 b0 b6 e2 |(6.\$..h...| >>> 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 3e 90 61 a4 f1 53 ac 7b b2 9f 4e |.....>.a..S.{..N| -00000020 2c 16 5a 77 8b da 5d 68 5c 8b a8 6d 44 52 f3 ad |,.Zw..]h\..mDR..| -00000030 8e ba c8 89 2f 15 03 03 00 30 00 00 00 00 00 00 |..../....0......| -00000040 00 00 00 00 00 00 00 00 00 00 e5 01 5d ef 4c 0c |............].L.| -00000050 07 8f 21 99 60 83 ee 36 13 8e 25 15 32 85 a5 96 |..!.`..6..%.2...| -00000060 36 90 60 49 4f c7 54 99 dd 76 |6.`IO.T..v| +00000010 00 00 00 00 00 5d f7 4e 68 f6 93 58 4d 14 ae 10 |.....].Nh..XM...| +00000020 14 93 a4 01 58 59 b2 cf 18 da 91 13 5d be da 9e |....XY......]...| +00000030 12 a4 2c 02 f9 15 03 03 00 30 00 00 00 00 00 00 |..,......0......| +00000040 00 00 00 00 00 00 00 00 00 00 71 41 f1 68 4e 97 |..........qA.hN.| +00000050 b6 30 45 8b b9 89 4c 95 04 da 3e cb 4c ab 05 41 |.0E...L...>.L..A| +00000060 65 af 4e 60 91 34 8b 07 a3 10 |e.N`.4....| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 index 6b02249f3fc..480ff42295b 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 ab d3 05 5e d0 |....Y...U.....^.| -00000010 80 0b 87 e9 43 26 e2 c9 28 04 3f eb 68 05 54 3d |....C&..(.?.h.T=| -00000020 9b 28 d0 4e d4 d9 25 e5 b0 27 2b 20 89 27 da d5 |.(.N..%..'+ .'..| -00000030 3d 19 38 63 01 34 f6 43 1b a9 f7 09 12 7d 27 e1 |=.8c.4.C.....}'.| -00000040 f6 23 b8 39 24 8b 1e c7 a3 2f 07 16 c0 27 00 00 |.#.9$..../...'..| +00000000 16 03 03 00 59 02 00 00 55 03 03 6a 17 b0 7f 77 |....Y...U..j...w| +00000010 da 35 bb 45 c1 43 37 52 59 4d 8f 61 1f f8 77 dc |.5.E.C7RYM.a..w.| +00000020 fd 9d 55 5d a7 7f 58 4f dd 3d 42 20 cf e2 65 8f |..U]..XO.=B ..e.| +00000030 7a b8 d3 2c 99 cc 31 2f d7 fa b2 0b 34 2c 72 7e |z..,..1/....4,r~| +00000040 86 a1 c6 e7 b7 55 26 1f 9a 69 43 63 c0 27 00 00 |.....U&..iCc.'..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,42 +54,42 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 ec 71 cc fb 07 bd 0f |........ .q.....| -000002d0 6b e0 e1 27 7f 62 59 06 09 3c 09 bc b1 c9 09 93 |k..'.bY..<......| -000002e0 e9 b0 a4 5b f3 be 14 d1 3c 04 01 00 80 a9 c7 98 |...[....<.......| -000002f0 ea ac 6a 9b 49 7c 72 45 4d 5c c8 4c d6 56 64 1b |..j.I|rEM\.L.Vd.| -00000300 44 7f 13 4f 2a ed e9 6b c7 c0 a2 25 3b 7a 99 f4 |D..O*..k...%;z..| -00000310 93 84 35 78 72 21 ca f6 29 1b 60 d7 f6 bd 31 5b |..5xr!..).`...1[| -00000320 7a fb 57 20 30 cc e6 90 07 b2 0e 08 82 86 56 a7 |z.W 0.........V.| -00000330 55 00 fd f4 ce f4 b1 74 27 e9 0a 28 1c bc 56 47 |U......t'..(..VG| -00000340 f7 18 3e 9e 9c 45 2d 1d 82 a8 66 51 27 25 be ec |..>..E-...fQ'%..| -00000350 cd 9e 83 89 7e e0 e3 0f 3b 7b 32 f2 26 7b 30 c8 |....~...;{2.&{0.| -00000360 c1 e3 7b 4c f4 14 d5 51 ea b7 45 7a 59 16 03 03 |..{L...Q..EzY...| +000002c0 ac 0c 00 00 a8 03 00 1d 20 35 8c 3a f9 8a 04 e7 |........ 5.:....| +000002d0 2e dd 2c 82 05 62 da 91 3f 60 2b 0d a8 4d ec 50 |..,..b..?`+..M.P| +000002e0 d1 b1 e0 f6 34 38 e5 7c 11 04 01 00 80 97 25 9e |....48.|......%.| +000002f0 22 b3 40 b2 b9 ec 0f 0e 44 92 11 82 06 70 26 23 |".@.....D....p&#| +00000300 38 b5 fe de 08 32 cd 8e e5 d7 19 3a ba 40 76 74 |8....2.....:.@vt| +00000310 22 cf 19 dd cc 33 cf 34 a9 3a d4 82 e8 92 79 23 |"....3.4.:....y#| +00000320 c1 14 10 79 08 65 43 e9 02 93 32 c8 5f a4 68 ed |...y.eC...2._.h.| +00000330 24 b7 aa 4c 71 4e 01 63 74 2a f5 36 1a d0 15 95 |$..LqN.ct*.6....| +00000340 10 9c 46 87 75 16 55 88 b7 38 14 10 1c b8 34 84 |..F.u.U..8....4.| +00000350 4f 4a 99 0f 17 95 26 a4 31 e3 8f 71 5b 92 f3 27 |OJ....&.1..q[..'| +00000360 df d7 c4 6d 34 8d 14 e7 8e 62 ae 27 12 16 03 03 |...m4....b.'....| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| 00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........| -00000040 00 00 00 00 00 76 d8 c4 58 a1 94 11 ab 19 4c 7b |.....v..X.....L{| -00000050 7c 34 d1 b6 8b 7f a2 96 41 e6 e9 98 d8 55 62 2b ||4......A....Ub+| -00000060 56 54 2a 65 25 f0 fa 15 ac cb b7 cc 3b 59 8b 99 |VT*e%.......;Y..| -00000070 e9 be 9e fe 56 97 07 ae 39 38 a7 f4 f0 d0 e9 f5 |....V...98......| -00000080 33 de 20 a6 04 |3. ..| +00000040 00 00 00 00 00 6d a8 40 a4 2f 8d ea bb a0 fb f3 |.....m.@./......| +00000050 a7 38 78 1b 25 57 5c 8a c8 e6 e6 be e2 78 78 c1 |.8x.%W\......xx.| +00000060 dc ec ca 48 9a 85 56 6b da 40 bd 0b cc 0a aa 08 |...H..Vk.@......| +00000070 02 31 57 31 c2 57 ff ac 57 7e e5 08 3a 14 b0 11 |.1W1.W..W~..:...| +00000080 fb 46 83 db 37 |.F..7| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 50 8c 0f 2a be cd |..........P..*..| -00000010 30 f7 46 cf 58 5b 38 88 86 5e d1 33 b1 61 d6 95 |0.F.X[8..^.3.a..| -00000020 13 c7 e7 f2 fb bc 37 e5 a3 db ac a7 74 49 00 89 |......7.....tI..| -00000030 db 94 25 aa 00 b6 b2 34 0a dd 97 bf fa cf 33 6e |..%....4......3n| -00000040 6e f7 ab bf 70 a6 85 91 9b 4f f2 86 15 83 60 0d |n...p....O....`.| -00000050 79 9e 11 51 17 a6 6f 06 2f 98 bc |y..Q..o./..| +00000000 14 03 03 00 01 01 16 03 03 00 50 b7 d0 f9 1f 96 |..........P.....| +00000010 64 b8 99 14 da c9 ae d9 40 ff 8f 3f 69 9d bf 56 |d.......@..?i..V| +00000020 ac 9d 15 d7 84 82 bb e9 1e f3 15 1a b3 3a 96 58 |.............:.X| +00000030 9f a7 9e 7a fb 50 5f f2 9d 46 8d ed fc cb 3b 2c |...z.P_..F....;,| +00000040 6e fd 5a fc d5 8f 8b 11 f8 28 3d c7 e2 36 c4 1b |n.Z......(=..6..| +00000050 da ce ec b2 89 f1 80 a5 ec 7f a2 |...........| >>> Flow 5 (client to server) 00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| -00000010 00 00 00 00 00 c3 c9 23 7b bd 57 1a 29 5f ac f6 |.......#{.W.)_..| -00000020 8d bb 90 bb 48 8a 9a 75 65 3b 5b 52 c0 ee 0e 24 |....H..ue;[R...$| -00000030 43 f6 62 1f 1e 51 36 4e 3e a3 e4 96 d8 2b d8 a7 |C.b..Q6N>....+..| -00000040 d0 18 97 d7 1e 15 03 03 00 40 00 00 00 00 00 00 |.........@......| -00000050 00 00 00 00 00 00 00 00 00 00 c0 c8 9f 7d df b1 |.............}..| -00000060 78 72 b5 3d 0d 3e d9 88 38 c2 42 eb 2b 4d e0 b3 |xr.=.>..8.B.+M..| -00000070 d7 69 19 31 57 16 7c 0a bb 24 5b 9c 9b c2 4b b9 |.i.1W.|..$[...K.| -00000080 55 ef ad 2c c1 eb 9b 59 06 5a |U..,...Y.Z| +00000010 00 00 00 00 00 78 0e 09 23 37 5d ad e5 97 da 83 |.....x..#7].....| +00000020 93 90 d8 dc 96 5a 61 85 8c 8b e8 35 46 46 ac ac |.....Za....5FF..| +00000030 42 fa ee e1 88 41 bd 1c 9c 6a 0c 00 29 cc a4 56 |B....A...j..)..V| +00000040 40 27 8f 6c e3 15 03 03 00 40 00 00 00 00 00 00 |@'.l.....@......| +00000050 00 00 00 00 00 00 00 00 00 00 51 8d 6f 62 be c4 |..........Q.ob..| +00000060 aa d0 f1 83 04 67 7e c2 0a 8b 50 32 71 17 87 95 |.....g~...P2q...| +00000070 a6 31 f6 3d 3f a8 14 00 5d e0 5b c1 db b4 fa 79 |.1.=?...].[....y| +00000080 01 0f 63 0b fe 8c c9 e1 b4 6b |..c......k| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 index 64f999a05ad..0ddfbdc0d83 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 @@ -1,17 +1,17 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......| +00000000 16 03 01 00 6b 01 00 00 67 03 03 00 00 00 00 00 |....k...g.......| 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 02 cc a8 |................| -00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............| +00000030 01 00 00 3c 00 05 00 05 01 00 00 00 00 00 0a 00 |...<............| 00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................| -00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................| -00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............| +00000050 00 00 0d 00 12 00 10 04 01 04 03 05 01 05 03 06 |................| +00000060 01 06 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 |................| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 45 f5 61 06 a8 |....Y...U..E.a..| -00000010 4e ce c0 32 d6 af fb 12 5e c8 6c 06 ac c9 d7 e4 |N..2....^.l.....| -00000020 02 49 09 b9 42 ee ae fa e4 52 18 20 12 3a 53 7d |.I..B....R. .:S}| -00000030 11 cf 13 13 a3 f8 42 c3 98 bb bc a6 10 3e f4 13 |......B......>..| -00000040 a5 a2 fd ef aa b3 01 3c cb 8a 3a 2c cc a8 00 00 |.......<..:,....| +00000000 16 03 03 00 59 02 00 00 55 03 03 34 5a e3 34 22 |....Y...U..4Z.4"| +00000010 a6 72 28 26 73 2d 3c 9e f1 39 88 13 07 dd 75 7c |.r(&s-<..9....u|| +00000020 00 58 04 bc 18 28 d0 75 4d 80 96 20 46 c7 3c b7 |.X...(.uM.. F.<.| +00000030 05 16 0d ef 32 51 ab 46 47 95 4b 49 e8 cc 8b 47 |....2Q.FG.KI...G| +00000040 d2 41 e8 05 9a de 5a c3 05 7d d4 b2 cc a8 00 00 |.A....Z..}......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -51,31 +51,31 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 57 53 06 53 e5 14 06 |........ WS.S...| -000002d0 df 26 9d 3a 06 dc a9 d5 49 d3 3f 5f 7b c2 ab 77 |.&.:....I.?_{..w| -000002e0 fd a1 fe 28 dc 54 36 06 22 04 01 00 80 da 23 f5 |...(.T6.".....#.| -000002f0 19 de e8 d2 a9 79 b8 37 3d c0 8c ae f6 7c d5 d9 |.....y.7=....|..| -00000300 87 ab 6b 3f 76 7c 5f 94 be 11 55 a3 78 66 1e e3 |..k?v|_...U.xf..| -00000310 f3 11 3d 1a f7 02 26 a4 a6 cd 7c fe 87 0d 68 a1 |..=...&...|...h.| -00000320 50 e8 7e 94 41 bd 5b 74 d0 6d 3b 6c ef ee 88 2d |P.~.A.[t.m;l...-| -00000330 60 0a a9 53 cf 1f f4 03 a3 54 e5 91 36 50 62 54 |`..S.....T..6PbT| -00000340 5f e6 e5 36 63 58 ba 7b bb 3a 79 59 58 08 a8 f2 |_..6cX.{.:yYX...| -00000350 f5 1e 35 f8 f5 0f 7f 19 e7 7f 5f 56 e2 50 6d 8c |..5......._V.Pm.| -00000360 da 45 70 60 0d 58 32 94 e7 a0 f7 da 93 16 03 03 |.Ep`.X2.........| +000002c0 ac 0c 00 00 a8 03 00 1d 20 1a 1c c4 a1 b6 04 70 |........ ......p| +000002d0 b8 b9 cd 26 b1 c0 74 56 6c b5 5c ff e7 20 79 74 |...&..tVl.\.. yt| +000002e0 f7 84 d5 8d 62 57 fa 40 49 04 01 00 80 1b d8 2a |....bW.@I......*| +000002f0 60 af a6 8c 2d 7e 23 be b8 53 c8 8e 32 b2 29 49 |`...-~#..S..2.)I| +00000300 8c 54 c5 fc 7b 2e e4 b9 6c c3 26 21 84 89 2e cd |.T..{...l.&!....| +00000310 7c c1 e0 1e 16 dc 8f 76 1e c2 65 f0 c2 21 6e f7 ||......v..e..!n.| +00000320 cf 91 f9 d5 c5 bf 33 5e 4f bb 8a 85 86 dd 10 c0 |......3^O.......| +00000330 85 22 e6 c0 36 0b 67 48 10 0a 04 49 1d dd aa 97 |."..6.gH...I....| +00000340 11 4f 80 f0 66 cd 82 85 e1 fa 0c b6 3d e7 bd 16 |.O..f.......=...| +00000350 20 82 cd cc 44 bb 67 47 2a db 9f 22 1b 9e cc 13 | ...D.gG*.."....| +00000360 e2 de d1 1d 9f 16 0e 6f 01 5e de f4 72 16 03 03 |.......o.^..r...| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 9d 2f a6 b7 21 56 ad 38 a8 31 20 |.... ./..!V.8.1 | -00000040 0b 2e dc 3f 8a 34 64 de 81 0e d3 a5 b1 c1 fc 05 |...?.4d.........| -00000050 18 d9 3e 77 35 |..>w5| +00000030 16 03 03 00 20 3a 2e f4 52 80 92 77 cb e3 54 43 |.... :..R..w..TC| +00000040 cb d5 ba c4 62 e4 77 81 eb fe fc f1 88 c6 e6 46 |....b.w........F| +00000050 7f d9 23 38 e4 |..#8.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 a8 82 60 8a ef |.......... ..`..| -00000010 31 55 42 e9 1d 33 0e d8 a9 b1 43 85 1c 04 7b 20 |1UB..3....C...{ | -00000020 81 df 03 e9 fd c0 f7 32 b9 b3 31 |.......2..1| +00000000 14 03 03 00 01 01 16 03 03 00 20 21 4e a1 16 d0 |.......... !N...| +00000010 35 9f 19 c6 cc 64 64 f7 a0 25 13 3b 97 75 81 9f |5....dd..%.;.u..| +00000020 2f d3 30 d9 02 ad c7 72 8d 32 20 |/.0....r.2 | >>> Flow 5 (client to server) -00000000 17 03 03 00 16 ef 72 f7 1b 26 1a 47 99 f9 4c e7 |......r..&.G..L.| -00000010 be 8e ab c5 8e ea 8c c6 60 6c 10 15 03 03 00 12 |........`l......| -00000020 2c f4 39 e3 3a 74 a4 3c 72 63 77 e8 82 cf a9 e2 |,.9.:t.>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 ac bf 85 b8 5f |....Q...M......_| -00000010 56 44 a0 c5 3b 20 77 71 af de 34 bc 79 a0 a4 a7 |VD..; wq..4.y...| -00000020 fa 2e cf b5 ee c5 a7 a2 5e 11 48 20 05 89 5e a6 |........^.H ..^.| -00000030 cd ad 91 e4 be c3 c3 6c 6a 0e 1d ab 27 03 5e 0f |.......lj...'.^.| -00000040 05 9d ef b0 63 8d 2d b6 29 08 66 e3 00 05 00 00 |....c.-.).f.....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 90 26 c2 6e 52 |....Q...M...&.nR| +00000010 59 b2 e8 f1 c5 fc 4d 59 13 76 43 4e a4 ab 0b 33 |Y.....MY.vCN...3| +00000020 96 d0 4e 89 bd 1e bd 89 f6 2b d7 20 39 94 41 68 |..N......+. 9.Ah| +00000030 81 74 78 60 e1 5f f7 7d e3 9d 81 f1 62 bd 45 67 |.tx`._.}....b.Eg| +00000040 51 50 bd 84 76 70 52 c3 ce 32 90 51 00 05 00 00 |QP..vpR..2.Q....| 00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.| 00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......| 00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..| @@ -64,15 +64,15 @@ 00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..| 00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..| 00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....| -00000090 01 16 03 03 00 24 e1 ef 77 60 cf 7a 44 79 74 59 |.....$..w`.zDytY| -000000a0 ff 81 72 b9 b5 f5 97 af 60 59 78 f5 01 49 2d bb |..r.....`Yx..I-.| -000000b0 4a ec 98 1f f5 31 f4 00 a2 f3 |J....1....| +00000090 01 16 03 03 00 24 4b 7c 05 1b 5d ed 28 c0 ce db |.....$K|..].(...| +000000a0 c9 1d bb e8 a1 94 d7 30 ac aa 54 08 2a 82 a2 a0 |.......0..T.*...| +000000b0 52 e7 cb 32 0f c2 f8 ad f3 c9 |R..2......| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 52 fd a3 51 aa |..........$R..Q.| -00000010 ee 9d 4d be 8c 08 32 f6 f7 4a a5 26 26 6c b2 5a |..M...2..J.&&l.Z| -00000020 49 7f 31 7d 44 b1 83 67 19 4a e3 07 7d 59 34 |I.1}D..g.J..}Y4| +00000000 14 03 03 00 01 01 16 03 03 00 24 ad ef e3 a0 c4 |..........$.....| +00000010 2c a0 ca 82 a6 f0 eb 8f 73 f3 48 11 0f 1f cc 6f |,.......s.H....o| +00000020 6f 63 fa d8 9d 47 6b b2 ab 3e fe bc 0e 44 ce |oc...Gk..>...D.| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a 61 73 4d 86 b2 a1 36 b2 3e b0 1d |.....asM...6.>..| -00000010 6a b9 8a 8b 00 e0 3a d9 7e 23 c7 83 72 97 28 15 |j.....:.~#..r.(.| -00000020 03 03 00 16 4a 8a 04 00 0a b2 75 80 20 ad 76 2a |....J.....u. .v*| -00000030 88 16 56 e6 4a a5 c0 ea c7 0c |..V.J.....| +00000000 17 03 03 00 1a e7 90 92 8b a5 a6 4f 22 97 2f 23 |...........O"./#| +00000010 f1 3c 54 65 2c 14 7e fd 1d 8f c7 76 97 e8 f8 15 |.>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 16 d2 11 2e d6 |....Y...U.......| -00000010 62 0c 5e 5c 9b 1f d2 31 87 b3 43 3e cd 47 4f f1 |b.^\...1..C>.GO.| -00000020 0b a9 d1 4f f1 2a 42 5d 35 e0 ce 20 f2 f3 45 4b |...O.*B]5.. ..EK| -00000030 98 2f 80 06 49 9a c3 4f 3f 70 0d e5 9a 2a 2e ff |./..I..O?p...*..| -00000040 34 1b 0e 30 2c 85 52 e1 84 8c 3c dc cc a8 00 00 |4..0,.R...<.....| +00000000 16 03 03 00 59 02 00 00 55 03 03 f1 85 19 85 1e |....Y...U.......| +00000010 f5 97 e1 e6 08 15 6f a9 05 93 6f b9 41 ad 11 ae |......o...o.A...| +00000020 92 90 5e 00 97 46 42 af 2f b0 5d 20 b7 f3 e7 76 |..^..FB./.] ...v| +00000030 20 e4 c2 99 6e ba 87 79 21 5c 5c 62 d9 1f 08 88 | ...n..y!\\b....| +00000040 e1 1f 05 0c 31 9c d5 b3 65 19 26 4c cc a8 00 00 |....1...e.&L....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,178 +54,126 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 63 85 d4 43 2a d6 9f |........ c..C*..| -000002d0 2f 1f 0c 73 fe dc 96 1e 51 50 a5 0d 5e fd b0 5b |/..s....QP..^..[| -000002e0 a5 88 2a cd 1e bf c1 ec 4d 04 01 00 80 90 fc 48 |..*.....M......H| -000002f0 53 eb 1b bc ec 39 be ae 60 4d c9 d1 49 eb 97 cf |S....9..`M..I...| -00000300 94 53 75 30 84 35 ff 0c f6 ad 9f 24 98 70 2b d3 |.Su0.5.....$.p+.| -00000310 45 0a 7f 25 ca a3 eb 37 5a a5 97 f1 78 8b b6 02 |E..%...7Z...x...| -00000320 92 f9 12 9e 90 52 36 0e 40 15 76 de 37 02 c5 22 |.....R6.@.v.7.."| -00000330 44 8f a4 fc f9 ac 88 88 ad 0c 9b f6 0e d6 9f f3 |D...............| -00000340 68 cb f1 41 dd 2d c2 71 b6 43 36 12 d2 35 1c 9a |h..A.-.q.C6..5..| -00000350 a9 72 ea af a9 9e 77 19 16 86 be 3e ec 5f 5a 53 |.r....w....>._ZS| -00000360 f8 38 27 7f 08 2a ae 68 e0 17 31 df 9b 16 03 03 |.8'..*.h..1.....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 f8 4d 81 d8 29 29 e9 |........ .M..)).| +000002d0 2a 96 44 4b e3 d2 95 11 19 7a d5 26 ed 60 f2 d8 |*.DK.....z.&.`..| +000002e0 e7 7d 96 9e 06 9f 37 f8 3e 04 01 00 80 51 70 fb |.}....7.>....Qp.| +000002f0 66 2e 1f 40 97 95 47 34 e5 69 8b a7 f6 d2 d1 71 |f..@..G4.i.....q| +00000300 0a 4c 34 d8 4f 8a 59 fc a0 93 db 10 77 12 a9 52 |.L4.O.Y.....w..R| +00000310 b6 be 1b 48 2c 56 9a ad 89 57 58 30 90 03 bb 46 |...H,V...WX0...F| +00000320 df 8a 4b 81 9a 14 6a a0 c9 60 76 e5 c6 73 da 35 |..K...j..`v..s.5| +00000330 e5 98 81 31 6c c4 ff 41 0c b1 7c 6e fd 82 75 de |...1l..A..|n..u.| +00000340 d8 84 db 3e fa 80 bc a8 6a 77 6f c9 9b 78 1a 0a |...>....jwo..x..| +00000350 dc 7b f0 65 4d 0f 14 b2 78 e8 db fb ee ca 74 83 |.{.eM...x.....t.| +00000360 2c d5 78 1e 48 09 17 0a d8 08 de f9 9d 16 03 03 |,.x.H...........| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 b1 f2 9a ca 02 d3 ac 26 f5 32 03 |.... .......&.2.| -00000040 4c b6 de cb f2 a3 11 19 eb c3 e0 e9 3b 8e 99 7d |L...........;..}| -00000050 c2 f3 d0 6d 4d |...mM| +00000030 16 03 03 00 20 c9 e3 4a a0 72 57 a2 c6 8d e9 98 |.... ..J.rW.....| +00000040 28 8d 40 22 6e ed 46 50 0d 08 38 b4 b0 6e a6 0b |(.@"n.FP..8..n..| +00000050 16 57 3f 6a 96 |.W?j.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 c5 d4 b1 e2 0f |.......... .....| -00000010 37 ad d5 c1 1a 6c 7f da 5f 25 e3 bd 20 1d 6e 58 |7....l.._%.. .nX| -00000020 27 7a 07 55 76 11 76 72 1b 28 9e |'z.Uv.vr.(.| +00000000 14 03 03 00 01 01 16 03 03 00 20 28 1b b9 e9 46 |.......... (...F| +00000010 3d 61 64 fe 84 b5 ea ff 79 e3 b9 5f 7e 1d 9c e1 |=ad.....y.._~...| +00000020 84 0f 17 9b be 67 0e b7 71 b3 de |.....g..q..| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 3d 89 e4 a6 38 75 31 c2 08 3d 86 |.....=...8u1..=.| -00000010 45 ed 8d c4 49 c4 da 54 3b 8f e3 |E...I..T;..| +00000000 17 03 03 00 16 0d d9 98 93 d7 c2 0e 48 53 34 1c |............HS4.| +00000010 b6 58 70 58 af 24 7c 3e 43 55 8a |.XpX.$|>CU.| >>> Flow 6 (server to client) -00000000 16 03 03 00 14 aa 85 e4 64 46 2f 8e dc 89 3e ef |........dF/...>.| -00000010 6d 9e 1a af 53 3b a0 81 c2 |m...S;...| +00000000 16 03 03 00 14 96 19 2b 56 4c 10 ea 1a c4 6e e3 |.......+VL....n.| +00000010 95 31 61 ed 22 ce 87 b2 bb |.1a."....| >>> Flow 7 (client to server) -00000000 16 03 03 00 ad c3 12 d1 1a b2 88 da c1 0b 5a 32 |..............Z2| -00000010 cf 05 35 53 ce 5d d8 42 cd 99 7e e7 9f 62 b8 35 |..5S.].B..~..b.5| -00000020 9e f5 b5 a6 15 fd 82 26 9b 6a fe 3b 8e c0 43 27 |.......&.j.;..C'| -00000030 1c 56 37 d1 6f d9 2c a6 a8 e8 b4 50 64 80 ae 5c |.V7.o.,....Pd..\| -00000040 ed eb a6 58 58 52 cf 32 de 1d be 80 69 63 38 a6 |...XXR.2....ic8.| -00000050 12 4e 11 9b 50 aa 4b 10 f7 ad 6f 5b 08 c6 cc bd |.N..P.K...o[....| -00000060 94 42 64 90 c7 33 58 65 18 c5 a7 66 ce dd 83 8b |.Bd..3Xe...f....| -00000070 b0 15 8a 61 26 c7 eb 15 4b 6c 0b 15 45 33 2a 01 |...a&...Kl..E3*.| -00000080 ea 13 5a 20 52 16 15 a0 70 8f 86 dc 28 50 bb e4 |..Z R...p...(P..| -00000090 9d 01 f4 c9 7f 27 5a 54 3f 42 34 c9 5c 04 3f a3 |.....'ZT?B4.\.?.| -000000a0 6a 5c a1 3f 03 7c fc 57 94 9b 3e 76 65 bf 78 40 |j\.?.|.W..>ve.x@| -000000b0 b1 4f |.O| +00000000 16 03 03 00 b1 a7 01 a1 b3 16 21 88 5a 74 bd a0 |..........!.Zt..| +00000010 58 fa d2 fa ba e3 a2 21 ae b6 92 28 a4 90 e7 f7 |X......!...(....| +00000020 fc 1b 6e dd 12 19 18 30 5d 6e fe be b7 12 16 fc |..n....0]n......| +00000030 26 27 8d e0 8c 18 25 3e 97 fa 5b 3c 06 c0 ee 49 |&'....%>..[<...I| +00000040 6e 6f 29 28 ac 46 02 92 38 c3 e1 1b d8 cc 6e 23 |no)(.F..8.....n#| +00000050 a1 4e 67 58 3e 33 45 ed 85 da f1 e6 76 0d ab f5 |.NgX>3E.....v...| +00000060 25 a7 a1 ac 67 f5 b7 14 52 04 57 6b e7 7f ac 5e |%...g...R.Wk...^| +00000070 bb c4 3f 0b 3b 54 86 a0 9c 4f 9b b5 1e 9d f5 8a |..?.;T...O......| +00000080 0b 62 fd 89 84 16 ee 13 49 40 32 3d 90 d1 4a 11 |.b......I@2=..J.| +00000090 ea 13 84 b8 18 4c 50 9b 18 54 ab f1 b8 77 e7 b2 |.....LP..T...w..| +000000a0 8b 7a 85 34 47 0a 83 fb 86 f2 94 e6 4a 17 db a8 |.z.4G.......J...| +000000b0 31 61 8e e7 d8 f9 |1a....| >>> Flow 8 (server to client) -00000000 16 03 03 00 81 33 ef 78 c8 2d 94 4b e3 b8 ea eb |.....3.x.-.K....| -00000010 67 1e 6c 10 98 25 5f df ce 46 4c 13 77 ec d1 b1 |g.l..%_..FL.w...| -00000020 e9 e2 c9 b0 de 9c ce 40 d0 d9 6f a5 fb a6 69 1f |.......@..o...i.| -00000030 9f 53 68 6c ab f8 f0 10 4a c9 43 f0 ad 61 59 01 |.Shl....J.C..aY.| -00000040 b2 90 97 9e cf 62 64 a5 46 b2 27 2f 1e b8 33 24 |.....bd.F.'/..3$| -00000050 ed 7e 6b 5a dd 45 4d 00 61 a3 7e 22 5e bc 02 af |.~kZ.EM.a.~"^...| -00000060 5a a0 73 fb c5 1c 0f 11 f6 70 5f cc 9e 1c fa 3c |Z.s......p_....<| -00000070 13 0d 8b 03 4c 3b d5 5a 02 7b 95 64 ae cb 2f 50 |....L;.Z.{.d../P| -00000080 e7 e1 32 13 72 96 16 03 03 02 69 f0 60 6a b8 fb |..2.r.....i.`j..| -00000090 50 6e f9 f2 65 d0 73 90 f7 55 0d bc 3a 66 72 32 |Pn..e.s..U..:fr2| -000000a0 b7 32 ad 1d de 18 04 90 55 70 2d b8 c9 3f 4b 2f |.2......Up-..?K/| -000000b0 37 98 1c 4e c1 78 c1 ed 1f e2 bf 50 78 40 04 10 |7..N.x.....Px@..| -000000c0 b8 55 48 29 26 b0 a4 4d ea aa 45 65 b4 21 93 ed |.UH)&..M..Ee.!..| -000000d0 49 4c 1d d9 77 33 38 2e 14 92 b4 e3 06 ce fe 51 |IL..w38........Q| -000000e0 6a 19 1c aa e9 a6 7d fa 45 86 66 1a 6e bb 01 01 |j.....}.E.f.n...| -000000f0 82 86 89 86 81 ce 0a 93 1a b2 f1 90 71 7a 43 fa |............qzC.| -00000100 b1 03 24 75 a1 48 f8 ee a0 b4 c0 18 ff 81 95 2a |..$u.H.........*| -00000110 aa 74 87 39 da 23 ba ab 33 6b 63 ee df 2b f1 d1 |.t.9.#..3kc..+..| -00000120 1a 9a 4a 0d ef de 68 13 28 81 49 d5 c6 08 57 a9 |..J...h.(.I...W.| -00000130 d7 5e 56 a4 ec 81 42 de 28 39 51 7d 3a 66 cf a7 |.^V...B.(9Q}:f..| -00000140 f7 81 7a b2 a7 09 b3 24 a6 b0 a5 cc 96 24 30 b2 |..z....$.....$0.| -00000150 5b 94 1b ef 70 dd 7f bc 63 2f 7b bc 80 70 9e 9f |[...p...c/{..p..| -00000160 01 c9 20 ab 35 53 7c 3b d6 70 d9 1d 9a f6 e8 76 |.. .5S|;.p.....v| -00000170 f5 46 f8 b1 10 46 a9 eb da 7b 80 cc 74 18 f9 30 |.F...F...{..t..0| -00000180 56 1a cb 4e 60 2a b3 9f 35 fe a9 b8 b8 76 02 a7 |V..N`*..5....v..| -00000190 4e f9 43 c9 52 70 6a fd 9c 3e dd c4 3f 28 08 19 |N.C.Rpj..>..?(..| -000001a0 28 ed f9 44 e3 d1 b9 53 7e b7 cd 1b e9 11 c8 9f |(..D...S~.......| -000001b0 35 ed ab e3 5e 26 e8 49 7a 13 5c 20 9a b7 a0 95 |5...^&.Iz.\ ....| -000001c0 60 0f 54 68 5c a8 c9 1d 37 0b 9f f6 61 3b fe 4c |`.Th\...7...a;.L| -000001d0 dc 4f 11 98 0c 7a b7 32 0b 50 e2 cd a7 59 bf 05 |.O...z.2.P...Y..| -000001e0 a2 8a 51 33 23 ab 99 49 23 97 42 3b 0f 1c 39 b1 |..Q3#..I#.B;..9.| -000001f0 43 c4 01 aa f9 f8 54 d7 2c b4 ef 33 f3 05 13 d0 |C.....T.,..3....| -00000200 8d 81 06 23 d3 38 cb 3a 6b 37 f0 4d 1f be ed 0c |...#.8.:k7.M....| -00000210 b7 58 00 3a bd 74 02 a4 f4 b4 fc fd b8 fa 89 15 |.X.:.t..........| -00000220 01 46 49 52 47 f1 4c 94 ee de 00 a1 25 aa b4 9b |.FIRG.L.....%...| -00000230 f6 b4 23 a1 0d fd 00 5a de 45 38 ee 69 17 6f c3 |..#....Z.E8.i.o.| -00000240 0b ed c5 3b b1 7d b1 2c a4 8f ed 30 44 9a 0b 51 |...;.}.,...0D..Q| -00000250 34 12 cc 6a 09 e4 74 ec 11 94 4b ba ce 72 93 64 |4..j..t...K..r.d| -00000260 07 c8 ff 78 6e 1a bd 5e 26 15 a7 e8 72 90 71 a9 |...xn..^&...r.q.| -00000270 0a bb cf 25 40 1d 20 a7 d7 b3 46 4b 53 6c c2 50 |...%@. ...FKSl.P| -00000280 c7 7b 58 e1 3c df 6d db 28 71 15 f9 84 b7 ad b0 |.{X.<.m.(q......| -00000290 9f e9 7a 08 5d 85 7a dd bc c0 62 2e 6a d0 63 6a |..z.].z...b.j.cj| -000002a0 e2 46 6b 80 68 cf e5 a7 9e 60 42 8a 17 54 9c ec |.Fk.h....`B..T..| -000002b0 80 9b 81 80 7e 6f 33 8c d1 be 95 30 f2 a9 19 f8 |....~o3....0....| -000002c0 36 2c 8e 89 c2 5a b4 04 2e 12 05 21 3b 4f 42 26 |6,...Z.....!;OB&| -000002d0 d1 98 11 f4 17 c2 a3 06 54 37 31 8e ca 9b 07 62 |........T71....b| -000002e0 79 95 b8 fd 49 aa 60 5b 03 7d 60 50 b6 2f 3b 0a |y...I.`[.}`P./;.| -000002f0 5d c2 9f 92 16 03 03 00 bc ba f6 73 85 34 20 c4 |]..........s.4 .| -00000300 b3 a4 15 01 fe 37 b3 b4 57 a5 b5 26 0c 64 2b 3e |.....7..W..&.d+>| -00000310 07 d3 e4 59 a8 64 3f fd 15 24 24 70 61 77 9b 96 |...Y.d?..$$paw..| -00000320 c6 4b 79 2e a8 a7 c4 ac 5e cd 6e 8f 30 e5 3f f8 |.Ky.....^.n.0.?.| -00000330 08 22 cb de 5f 8c b8 dc 07 4b 79 ec 41 41 20 20 |.".._....Ky.AA | -00000340 02 f6 4e 98 a3 5e 38 e2 5a d9 4a 2d 2e 3b 29 13 |..N..^8.Z.J-.;).| -00000350 26 dc 4e eb a5 5e a3 b6 6f 16 75 b3 9e 63 4e 8e |&.N..^..o.u..cN.| -00000360 00 c1 46 30 fc 25 f9 05 86 ed 00 87 f2 6b 5c 18 |..F0.%.......k\.| -00000370 69 e5 5c 32 9e 15 d2 47 9e 0e d8 c1 7a 9d 45 7a |i.\2...G....z.Ez| -00000380 76 4a ef 8d b5 60 7d 4d fa 99 8f c5 58 18 ad a2 |vJ...`}M....X...| -00000390 93 c1 36 85 39 73 e1 7b 46 be 69 de 88 fa 68 8e |..6.9s.{F.i...h.| -000003a0 be d1 48 bc 7b 29 2a 21 ba 60 60 58 51 c2 03 66 |..H.{)*!.``XQ..f| -000003b0 51 9a 4e 70 06 16 03 03 00 3a c5 ed 8d 5d b9 c0 |Q.Np.....:...]..| -000003c0 a2 07 15 c3 ef 76 ff fb ca f6 b6 4b ab a5 7a 80 |.....v.....K..z.| -000003d0 a9 2e 43 d0 d2 f1 d9 96 61 ff 43 59 3d d1 82 57 |..C.....a.CY=..W| -000003e0 68 d7 c8 3a 5f 86 4a 2e 00 8f 3d 0e 73 49 c6 4a |h..:_.J...=.sI.J| -000003f0 81 4e ec e2 16 03 03 00 14 d5 5f c3 d2 9c 13 36 |.N........_....6| -00000400 cb 22 23 3d e4 03 5b b9 26 66 cf 79 7c |."#=..[.&f.y|| +00000000 16 03 03 00 81 8b 09 74 4a 5b 74 ef c4 91 26 84 |.......tJ[t...&.| +00000010 25 33 c2 f7 05 1c 13 cf 00 ba 54 dd 16 e9 f3 4d |%3........T....M| +00000020 80 f5 1f f9 9b 7e a8 a9 60 f1 d6 be f9 c1 75 b0 |.....~..`.....u.| +00000030 1b 98 c4 d2 f0 69 c5 d5 d9 07 dd 19 56 4f cd 6f |.....i......VO.o| +00000040 b0 df 58 a8 da 66 23 e6 8e 20 03 75 33 1a ee 61 |..X..f#.. .u3..a| +00000050 ab 31 f7 2e e0 ea f4 29 26 34 1d 8e 52 0d 1a 6f |.1.....)&4..R..o| +00000060 cc c7 bf 14 dc 1c 47 80 42 b7 d0 ac 26 f5 e1 8e |......G.B...&...| +00000070 08 d7 63 8a 3b c4 d3 e7 15 a1 46 e3 9b c1 4a 5a |..c.;.....F...JZ| +00000080 14 30 da 62 8f 3a 16 03 03 02 69 54 7c 6d 38 37 |.0.b.:....iT|m87| +00000090 01 fe 7c fe 75 30 f1 c0 e8 16 89 b7 d8 7e e0 70 |..|.u0.......~.p| +000000a0 90 4e c5 7d 37 1b 44 57 7b 91 50 cc aa 71 47 9d |.N.}7.DW{.P..qG.| +000000b0 64 67 42 2c b0 01 64 b1 05 6f b3 a9 07 61 f9 99 |dgB,..d..o...a..| +000000c0 f8 2c 59 08 12 80 c5 48 0c 88 67 05 74 da 91 e0 |.,Y....H..g.t...| +000000d0 6d 53 2a ac 02 14 cb f9 f5 c1 dd c2 29 29 e6 7d |mS*.........)).}| +000000e0 78 52 cb 19 74 80 6f 1b ab a9 4c b7 88 09 01 b8 |xR..t.o...L.....| +000000f0 66 a1 8c 1d 1a 06 08 05 7d 60 5d e6 a7 da 36 17 |f.......}`]...6.| +00000100 ef 5c 90 c3 77 d8 34 d4 99 e5 bd 1d 70 15 78 db |.\..w.4.....p.x.| +00000110 71 23 4d 4a 18 bd ac ab 36 86 79 05 70 1c 51 15 |q#MJ....6.y.p.Q.| +00000120 82 c9 a0 c2 cd 80 d0 41 a1 51 10 c5 96 44 1f 97 |.......A.Q...D..| +00000130 a7 20 0a 80 a4 7c fe 6d f3 b4 ae 19 17 17 d4 97 |. ...|.m........| +00000140 37 cf 69 34 8e ad 5a e6 66 fc f3 07 7d a7 5c 0d |7.i4..Z.f...}.\.| +00000150 c2 fd d6 3d 69 dc 41 6f b0 fd 3b db 3a 95 25 52 |...=i.Ao..;.:.%R| +00000160 a0 82 54 7c f3 4d d2 65 8b c6 55 3a 9c 89 19 f1 |..T|.M.e..U:....| +00000170 aa c0 49 7a bf 1c ec 7a 78 d2 11 c0 8f ab 53 2d |..Iz...zx.....S-| +00000180 68 69 9e 12 db ec 77 df 7d 7b 5f 75 76 df 76 1e |hi....w.}{_uv.v.| +00000190 b4 c3 32 3f c9 cb 58 bd c4 b0 45 61 2a dc 14 fb |..2?..X...Ea*...| +000001a0 3a 83 84 e0 ad a0 25 16 e7 1c 3c 4b f6 4e 6d a8 |:.....%...}a.>.b+..| +000001f0 0b 71 d8 1d ae 65 c0 f8 71 98 aa 08 af 10 09 6f |.q...e..q......o| +00000200 9d 79 9b 70 d5 48 5c 96 ac d0 2d ee 61 1f 8a 96 |.y.p.H\...-.a...| +00000210 5e 8b 04 06 80 20 f1 cc 61 93 9f ea c3 3a f0 ba |^.... ..a....:..| +00000220 ed 7c 80 25 4c ba e8 a6 97 62 04 cd 8b 58 00 d6 |.|.%L....b...X..| +00000230 e1 0d 0b f3 c0 73 b9 0d 57 e3 76 8d f8 a9 43 72 |.....s..W.v...Cr| +00000240 c0 37 d9 f5 16 02 0a 0c d1 44 2d e6 fe 57 3d 9f |.7.......D-..W=.| +00000250 64 ef a6 f6 9b 44 7a 16 de f7 64 94 6f 4c c4 57 |d....Dz...d.oL.W| +00000260 f8 ba dd 64 61 87 55 6e ac 96 1c 68 f4 68 b2 90 |...da.Un...h.h..| +00000270 ec 7a a5 f3 7c dd f0 30 af 27 9d c4 dc fe 05 c7 |.z..|..0.'......| +00000280 4b d3 44 63 5c bb e0 e0 eb 0d bc ef ea fa dd 17 |K.Dc\...........| +00000290 1f 27 a6 b7 79 6c 0c 64 25 91 4d a1 cf ae 5b 81 |.'..yl.d%.M...[.| +000002a0 2b d3 18 0b 82 3e 4a 4b 02 6c cb be c7 b7 a7 e0 |+....>JK.l......| +000002b0 2f a7 a0 32 f4 5d b2 5b 6e 9f b4 cd ee 58 e4 bd |/..2.].[n....X..| +000002c0 ac 44 4d 0d 37 31 8b d1 d5 01 83 0a 63 85 14 e3 |.DM.71......c...| +000002d0 55 93 1d 25 61 4b 43 b5 a4 e5 d3 50 e9 01 96 02 |U..%aKC....P....| +000002e0 10 aa 58 6a 9d e0 e4 80 c4 a9 20 c9 b5 0c 79 bb |..Xj...... ...y.| +000002f0 5c 5f 22 43 16 03 03 00 bc 56 b6 aa ae 4c 5f f5 |\_"C.....V...L_.| +00000300 4f 16 84 92 4b d3 be 30 7f ab 74 d2 5e eb 23 de |O...K..0..t.^.#.| +00000310 2f 5b 6e c4 1a b4 e6 39 33 f8 c9 0f a3 b0 d5 bb |/[n....93.......| +00000320 77 21 76 6d 6e 45 b9 75 d1 86 b8 be ad 31 85 db |w!vmnE.u.....1..| +00000330 90 39 92 74 3a fc e1 5c 71 b9 64 b5 ae d8 5b a5 |.9.t:..\q.d...[.| +00000340 ac ca b5 9c 3a ad 58 a3 b3 2d 80 52 47 8f 5c 9b |....:.X..-.RG.\.| +00000350 fd 09 a9 b0 b9 84 e5 01 03 69 ca b3 79 bc 61 da |.........i..y.a.| +00000360 f9 58 0a 0e 86 a3 aa 3a b9 e8 8d 87 a5 0b 62 fa |.X.....:......b.| +00000370 7f de 17 29 ed 75 38 49 4a f9 5f a3 cd 92 f7 bd |...).u8IJ._.....| +00000380 fd 5d d3 0e 2f 49 38 a1 ba b5 87 e2 65 e0 68 c1 |.]../I8.....e.h.| +00000390 c1 3d f2 57 06 25 9e b8 54 6e 9a 33 ee 3f 6a fc |.=.W.%..Tn.3.?j.| +000003a0 53 1c cc 1f ee 6a 0f 43 c5 68 08 02 4e d7 3e 5e |S....j.C.h..N.>^| +000003b0 a6 c9 aa da 0b 16 03 03 00 14 8b 31 f6 f0 2c bf |...........1..,.| +000003c0 d1 fa 59 12 4a 4d 9d 51 d2 79 ff 58 3a fa |..Y.JM.Q.y.X:.| >>> Flow 9 (client to server) -00000000 16 03 03 02 69 15 0b 29 0e 27 a9 4b 52 4d 0a 77 |....i..).'.KRM.w| -00000010 b8 3a 40 95 84 a7 7a 8d b1 6b 90 61 94 3a e4 06 |.:@...z..k.a.:..| -00000020 20 6f 88 40 8a 8c c2 4e dc 3a 01 39 c2 11 5a 9b | o.@...N.:.9..Z.| -00000030 28 92 bc 72 04 a3 60 c3 42 c0 b8 dd f3 41 40 be |(..r..`.B....A@.| -00000040 6d 51 5b b8 db 75 63 3d 4f 2a cf f5 04 3d 53 be |mQ[..uc=O*...=S.| -00000050 47 f1 ae be 0a 97 5d 2c df 55 5d dd 9a f6 0e 40 |G.....],.U]....@| -00000060 59 02 91 d8 55 c9 3b e6 84 9c 8d 40 af 29 77 59 |Y...U.;....@.)wY| -00000070 15 0c 83 dd ec c7 e2 16 85 d8 6e e7 4e c5 a5 b1 |..........n.N...| -00000080 8b 4b 46 3e 62 7c ff 27 1b 37 b7 5c 05 32 30 fb |.KF>b|.'.7.\.20.| -00000090 c1 cc 1d 13 1f 09 db 57 6a 70 2b 9f a7 25 9b 75 |.......Wjp+..%.u| -000000a0 d3 62 20 45 d1 2f 28 c0 d7 84 d6 2e b3 6d 4a c3 |.b E./(......mJ.| -000000b0 46 0d 92 32 87 65 dd b8 98 68 1a 52 0a df be b3 |F..2.e...h.R....| -000000c0 09 bc 63 bb a3 da f7 52 5a 81 53 9a e0 ff bb 06 |..c....RZ.S.....| -000000d0 7f 81 f8 ea 02 bb 3b 96 7b 0f 84 a5 4d 17 3a 2a |......;.{...M.:*| -000000e0 20 e9 21 70 b2 ab 8a 55 31 4b 1b 60 52 7f a8 39 | .!p...U1K.`R..9| -000000f0 5a 0f 0b 00 4e eb 01 0c a6 d8 f0 30 2b a3 6f 7b |Z...N......0+.o{| -00000100 99 82 90 9e 4c c8 03 1c 0e 85 55 bc 2d 42 28 66 |....L.....U.-B(f| -00000110 35 c3 1e 08 70 d0 45 05 5b 2e 00 fc 9a f1 44 0e |5...p.E.[.....D.| -00000120 cb 91 ce b8 0f 2a 9f 5a 18 a8 ca 38 ff 2a ab 11 |.....*.Z...8.*..| -00000130 57 a5 03 2f 3e 92 21 77 df dc 85 e7 fd d4 7e d0 |W../>.!w......~.| -00000140 d9 6e ef 99 66 5d a8 f5 9a d3 c3 0f 0c 98 cd fe |.n..f]..........| -00000150 5a 46 79 77 c9 28 fb 5e 3e c0 d5 b3 db 98 79 9d |ZFyw.(.^>.....y.| -00000160 d4 20 a5 ad 25 d8 3b 39 35 60 fd 21 e0 eb 86 be |. ..%.;95`.!....| -00000170 8f 65 72 a2 d3 91 4c 25 70 31 b1 02 29 17 da e0 |.er...L%p1..)...| -00000180 9f 7d 4e 5f 1a 7b 93 09 4c 84 5b 40 f8 3c 98 36 |.}N_.{..L.[@.<.6| -00000190 9b 14 43 db 43 11 0a e2 9a 8b 73 96 a3 7b 4d 67 |..C.C.....s..{Mg| -000001a0 d7 35 a6 85 40 6d 45 0e 9d 47 43 96 b8 64 d4 d7 |.5..@mE..GC..d..| -000001b0 d1 28 c8 32 7e ab d5 11 ad b4 a7 9c c9 ab c5 96 |.(.2~...........| -000001c0 72 69 1a db 42 06 8e 03 d0 70 f9 7a 75 56 53 49 |ri..B....p.zuVSI| -000001d0 29 e1 60 16 86 99 da 9e d6 c3 95 94 e3 e4 6c 9c |).`...........l.| -000001e0 4f d0 5d e7 a6 23 e1 49 a5 b8 3d 41 a4 e0 8c a2 |O.]..#.I..=A....| -000001f0 f8 35 40 4d 12 f1 0b 70 06 f5 b5 29 f8 5d 74 73 |.5@M...p...).]ts| -00000200 32 35 11 7f 50 a3 22 5b d6 db a5 a8 9f ca db 47 |25..P."[.......G| -00000210 b9 a8 c7 fc 16 40 ae 94 6e 6c 40 30 7a d6 9c 89 |.....@..nl@0z...| -00000220 d7 e9 1b 6b 26 72 1f d7 c9 bc ce 6f 84 03 3d 65 |...k&r.....o..=e| -00000230 34 f9 7b 32 54 e4 b4 72 8c e1 31 9e e5 13 50 2f |4.{2T..r..1...P/| -00000240 ea 16 27 15 cb ec 0f 1b 21 aa dd cb 25 74 b9 4d |..'.....!...%t.M| -00000250 36 c0 0d fe a4 99 2f 86 50 52 d0 83 e2 3f fa e7 |6...../.PR...?..| -00000260 2d 24 b6 7a ca 7f 69 3e 7d 0b 61 df 29 3b 16 03 |-$.z..i>}.a.);..| -00000270 03 00 35 8e 89 3d 7b 39 aa d2 21 01 6a 3d fe 4f |..5..={9..!.j=.O| -00000280 e2 d9 e6 6d 5d 1e d3 a5 1d 3f f8 8e fb 97 3d 06 |...m]....?....=.| -00000290 9b 68 67 45 15 3b a1 e8 e8 39 77 1a 41 77 2b c5 |.hgE.;...9w.Aw+.| -000002a0 8c fe bd 28 7a 85 eb 7a 16 03 03 00 98 f0 ed 3c |...(z..z.......<| -000002b0 37 3f 34 3b 35 e4 15 a8 f3 b4 b6 76 49 65 e8 26 |7?4;5......vIe.&| -000002c0 93 4b cc b1 31 7a 4c e7 7d 80 63 60 65 9a ff 11 |.K..1zL.}.c`e...| -000002d0 a8 c5 c4 4e c2 7a ca 95 cb 08 21 77 42 ce 70 1e |...N.z....!wB.p.| -000002e0 bf d9 b5 6d de dc 03 67 2e 11 b5 47 c1 c0 74 6b |...m...g...G..tk| -000002f0 b4 9d c4 de 8c d4 80 e4 99 92 31 68 09 85 00 34 |..........1h...4| -00000300 43 cc 06 09 bc a8 6e 83 a0 fa df 6e a0 04 e9 37 |C.....n....n...7| -00000310 b3 05 69 b9 f1 85 7f 48 27 73 d0 64 2c 33 48 1f |..i....H's.d,3H.| -00000320 f9 7c 0a 21 1f cb 0f 4c c2 28 b0 3b 8c 9b 23 21 |.|.!...L.(.;..#!| -00000330 f4 8c 69 b2 1d 55 35 20 b9 92 09 36 01 aa e1 e3 |..i..U5 ...6....| -00000340 ee b7 3d 83 7b 14 03 03 00 11 40 bb bb 2e 3d 48 |..=.{.....@...=H| -00000350 9f fa c6 0c d8 4f 45 cb 11 b3 a5 16 03 03 00 20 |.....OE........ | -00000360 39 b7 46 30 00 68 12 c5 f5 d7 a0 85 7f ce 49 70 |9.F0.h........Ip| -00000370 05 83 64 26 7a 0c 43 fb a9 4d bb 61 3a c3 8a 91 |..d&z.C..M.a:...| +00000000 16 03 03 00 35 24 68 32 63 8a 43 11 1f 91 a5 8b |....5$h2c.C.....| +00000010 4f 57 63 f6 de a8 23 c2 d2 68 33 d0 fc 9d 41 b1 |OWc...#..h3...A.| +00000020 5f 71 d8 e4 fb b6 71 e6 83 2f cc 15 53 e1 70 48 |_q....q../..S.pH| +00000030 34 92 68 ae 1f f4 88 b0 d0 59 14 03 03 00 11 e9 |4.h......Y......| +00000040 01 e9 1d fa c2 c3 2a 60 68 98 83 fa f5 7e 5f 2a |......*`h....~_*| +00000050 16 03 03 00 20 33 0c 00 8d 8a 60 06 dc 43 9d ae |.... 3....`..C..| +00000060 a5 a7 23 05 3a 55 53 e4 41 42 46 bb 35 ef a6 2c |..#.:US.ABF.5..,| +00000070 d4 d8 4d 85 d4 |..M..| >>> Flow 10 (server to client) -00000000 14 03 03 00 11 d1 d7 7e 3c 5f 01 cb f8 eb af d5 |.......~<_......| -00000010 ba 09 32 68 4b cf 16 03 03 00 20 02 f1 23 45 32 |..2hK..... ..#E2| -00000020 60 9b 49 db 2f 3a cb 5c e4 f3 64 b1 cb ca 09 b0 |`.I./:.\..d.....| -00000030 b3 34 a3 75 7d a5 a0 80 44 fd b7 17 03 03 00 19 |.4.u}...D.......| -00000040 d7 c3 c4 33 e6 f2 73 d2 2c 0b 7e 0e 40 d3 8b f6 |...3..s.,.~.@...| -00000050 47 57 13 88 be 4b 12 43 57 |GW...K.CW| +00000000 14 03 03 00 11 ce 28 cc ba 60 2b 9a 92 b1 a1 fc |......(..`+.....| +00000010 73 25 71 fd f5 59 16 03 03 00 20 5d 9c a5 c1 2f |s%q..Y.... ].../| +00000020 2a f3 af 84 9b 15 cd fa a1 6e ca a0 09 2b a4 b8 |*........n...+..| +00000030 e9 e2 b8 eb 17 84 d0 fb 20 7e fc 17 03 03 00 19 |........ ~......| +00000040 43 86 e9 94 82 d6 08 ac a3 90 97 05 b6 f0 54 28 |C.............T(| +00000050 3d d1 c9 f8 d9 19 5a d4 ed |=.....Z..| >>> Flow 11 (client to server) -00000000 15 03 03 00 12 3a 90 85 e8 ce 53 d1 2a 3b d6 9a |.....:....S.*;..| -00000010 f3 61 c1 72 81 c0 03 |.a.r...| +00000000 15 03 03 00 12 05 a9 95 98 5c 81 dc ae eb bc 17 |.........\......| +00000010 2e 08 b5 32 82 45 23 |...2.E#| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice index c2f4e4aca90..fb5ca90e034 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 30 5b 03 80 cf |....Y...U..0[...| -00000010 ad 5e 69 9b da 4a de 2f 07 f3 6c 42 d7 50 99 10 |.^i..J./..lB.P..| -00000020 80 15 dc dd d2 ef 3d 20 b9 eb bd 20 51 63 fd 9d |......= ... Qc..| -00000030 3d b7 3e ea 4e 18 45 90 40 50 f2 f3 2b b8 00 42 |=.>.N.E.@P..+..B| -00000040 bf 77 ae d1 ff 29 2d ca d8 c2 4e c7 cc a8 00 00 |.w...)-...N.....| +00000000 16 03 03 00 59 02 00 00 55 03 03 72 05 00 95 36 |....Y...U..r...6| +00000010 6c a5 d1 0f 06 bd 25 80 25 19 16 0d 70 56 8f c4 |l.....%.%...pV..| +00000020 b4 e9 17 be d2 06 09 b4 05 bc 2e 20 bc b9 5a 92 |........... ..Z.| +00000030 44 a5 91 7c 82 7e b6 c3 50 da cd f2 98 e1 26 14 |D..|.~..P.....&.| +00000040 d3 eb e2 98 c7 f6 6c 96 71 d3 7e b4 cc a8 00 00 |......l.q.~.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,323 +54,219 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 6b cd 37 6d a7 76 7a |........ k.7m.vz| -000002d0 04 0e 8c 93 db b0 62 67 14 65 26 5e 91 b3 8d 66 |......bg.e&^...f| -000002e0 20 40 31 c1 84 3c ef d8 67 04 01 00 80 ce 3a f2 | @1..<..g.....:.| -000002f0 16 01 b2 8a cd d6 1c b3 c4 46 a5 e8 1f 17 85 d9 |.........F......| -00000300 5b 97 fb dd 43 65 52 82 e3 49 99 e8 49 d9 09 13 |[...CeR..I..I...| -00000310 05 73 19 d0 d9 66 54 03 de 4b fa 43 2d f1 f8 98 |.s...fT..K.C-...| -00000320 79 21 3b fa a9 ea 29 78 fa 87 59 8e 9b 2f f2 99 |y!;...)x..Y../..| -00000330 14 85 21 9c 7e 59 5b 4b 2f e3 33 c4 7c 2c ac 35 |..!.~Y[K/.3.|,.5| -00000340 4f 68 c8 a3 0b f5 43 7e 72 9a e6 4f 9c 10 4d 4a |Oh....C~r..O..MJ| -00000350 d4 b5 84 62 61 4e f4 0f 3f a5 b5 23 89 d9 33 e2 |...baN..?..#..3.| -00000360 06 22 02 c5 fe db 27 fb 40 87 8c e7 6e 16 03 03 |."....'.@...n...| +000002c0 ac 0c 00 00 a8 03 00 1d 20 f0 1b 05 7a 25 88 37 |........ ...z%.7| +000002d0 65 0d 93 e7 44 ff b4 bd 8d 9a eb ca 4f 31 c6 42 |e...D.......O1.B| +000002e0 f8 83 aa 1e 33 6c c8 3f 2a 04 01 00 80 0c 5b 0c |....3l.?*.....[.| +000002f0 92 86 55 5a 05 c9 f0 df 0a 1f 57 46 24 53 a6 77 |..UZ......WF$S.w| +00000300 f9 6b b0 a0 2e a3 64 f0 21 f1 93 10 de 9c 6f fb |.k....d.!.....o.| +00000310 68 8c f0 d4 f6 b4 81 f6 60 8a 64 ee af f6 ee 3c |h.......`.d....<| +00000320 d8 45 fc 3a 70 1d 89 c2 11 94 4e 9a 5c ee 67 64 |.E.:p.....N.\.gd| +00000330 24 91 2c 97 09 ba 1f 76 2d ca e4 a1 52 e9 d6 8a |$.,....v-...R...| +00000340 e5 21 42 66 80 95 72 61 6e d7 09 eb db 30 fc b7 |.!Bf..ran....0..| +00000350 8e d6 3a 91 97 14 09 33 15 9a 5d 45 a9 53 0b 3d |..:....3..]E.S.=| +00000360 49 3b ba 95 8c ae 96 06 e1 e9 4c 2f 72 16 03 03 |I;........L/r...| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 5a b9 f7 81 81 7f 65 84 c9 87 40 |.... Z.....e...@| -00000040 a4 66 07 85 38 3b 85 8d ff c4 7e b7 f6 16 1d c1 |.f..8;....~.....| -00000050 36 4f 53 1a bb |6OS..| +00000030 16 03 03 00 20 f7 8a a0 59 29 4a b5 a1 1a d2 9c |.... ...Y)J.....| +00000040 d7 4f f7 eb 76 ed 9f d5 93 cb 30 dc dd a1 28 0a |.O..v.....0...(.| +00000050 82 3e fb 3b d0 |.>.;.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 ff b2 f4 3b af |.......... ...;.| -00000010 ba 44 66 0b f9 31 09 18 df 9d d0 04 82 38 11 dd |.Df..1.......8..| -00000020 a7 ee 83 ef 03 51 21 08 f9 c4 8a |.....Q!....| +00000000 14 03 03 00 01 01 16 03 03 00 20 01 ce 8d 74 22 |.......... ...t"| +00000010 4a 7e 22 fe ab b4 ed 5e 05 27 3f e9 35 97 f4 ef |J~"....^.'?.5...| +00000020 c5 df 0c 7f d7 6a 10 94 a0 72 dc |.....j...r.| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 b6 45 4e 35 df 21 f4 c7 24 ba e6 |......EN5.!..$..| -00000010 18 65 1c 75 ba 72 5d 5b 4a fd 78 |.e.u.r][J.x| +00000000 17 03 03 00 16 cc f5 66 f6 5e d6 b5 53 e6 d6 29 |.......f.^..S..)| +00000010 90 c6 dc b3 ad b5 43 ea 16 80 88 |......C....| >>> Flow 6 (server to client) -00000000 16 03 03 00 14 1a ec 37 ab 36 23 80 76 1c 0b d0 |.......7.6#.v...| -00000010 54 9a 8f 7e 7a c0 bd 09 9a |T..~z....| +00000000 16 03 03 00 14 0e 28 a6 a0 4a 78 90 fa d5 ed 0a |......(..Jx.....| +00000010 45 b8 21 75 18 de 93 16 12 |E.!u.....| >>> Flow 7 (client to server) -00000000 16 03 03 00 ad 7a d4 bf 4d bf 48 0a 0f 2c d1 38 |.....z..M.H..,.8| -00000010 9f 20 f7 c7 36 27 82 d9 5e f4 21 44 0e 75 46 ca |. ..6'..^.!D.uF.| -00000020 67 f8 87 6c 4f 1e c7 1e 5f 8d f2 88 58 1b 92 12 |g..lO..._...X...| -00000030 e0 f6 d5 5c d7 4b 21 b9 8c 93 a8 bc a4 e6 e5 cb |...\.K!.........| -00000040 d0 33 eb d5 10 ad 53 50 58 e0 94 f0 b8 52 20 8c |.3....SPX....R .| -00000050 c2 69 7a c3 43 73 3f 2e 4a 42 2c c1 8d c1 ff 1e |.iz.Cs?.JB,.....| -00000060 57 ba 7d 99 9c a2 10 99 19 d6 72 38 96 ba 2b ff |W.}.......r8..+.| -00000070 7b a8 42 c0 c0 c4 d4 50 20 39 39 b8 18 23 a1 d3 |{.B....P 99..#..| -00000080 38 d3 9d 41 81 c2 4b ba 4c 28 c0 14 22 71 df d9 |8..A..K.L(.."q..| -00000090 e1 57 fc 9c 4f 0e 28 9a 13 c6 a1 e2 de f0 81 3b |.W..O.(........;| -000000a0 5f c1 7b 61 f5 fc 74 93 f1 06 7d 9b 67 56 45 a4 |_.{a..t...}.gVE.| -000000b0 f8 83 |..| +00000000 16 03 03 00 b1 60 7a a2 91 30 f4 5b a4 5f 4c 38 |.....`z..0.[._L8| +00000010 5e 44 34 09 02 13 c3 1b 02 d3 64 e4 f3 c2 35 87 |^D4.......d...5.| +00000020 b2 4b 39 fd 89 10 12 42 97 b9 97 e5 67 82 0a 5c |.K9....B....g..\| +00000030 24 28 5a 0c be db d2 0b f7 ac b7 f4 9d c1 0f 0a |$(Z.............| +00000040 76 e4 6f 41 e2 31 e3 35 0b 39 71 a9 31 56 b0 41 |v.oA.1.5.9q.1V.A| +00000050 13 d6 0f 2c 10 e9 e7 bb 37 2a e9 b2 4d 8a f3 8a |...,....7*..M...| +00000060 5a ab 12 02 99 ba e4 45 b9 2d c6 be 45 35 37 6a |Z......E.-..E57j| +00000070 e5 24 be db 79 39 df 5e c8 a8 58 42 2d 40 00 96 |.$..y9.^..XB-@..| +00000080 89 8a 2e 45 32 61 3e 65 18 c1 8f bf 90 da 60 bd |...E2a>e......`.| +00000090 03 34 ad 93 ac aa 33 55 31 8c 41 fa d0 85 42 a8 |.4....3U1.A...B.| +000000a0 dd 69 2f fb e5 21 c6 64 39 42 8c af b6 1d 21 e2 |.i/..!.d9B....!.| +000000b0 47 ec 11 ed 4d 6d |G...Mm| >>> Flow 8 (server to client) -00000000 16 03 03 00 81 ec 0e 7c 60 5b ed 0f 29 e6 cd 3a |.......|`[..)..:| -00000010 ca ff f7 68 3e 22 30 cf 43 b2 29 71 ca 3a 06 db |...h>"0.C.)q.:..| -00000020 e0 df bc 87 51 62 df 37 37 7a 9d b4 2d 35 ab bb |....Qb.77z..-5..| -00000030 d2 ed d1 50 e7 61 a4 27 18 43 23 74 4b 1d 14 46 |...P.a.'.C#tK..F| -00000040 80 5c 10 99 10 47 b2 51 92 11 1f aa f1 5a c3 cf |.\...G.Q.....Z..| -00000050 f5 30 69 96 26 f6 0e 7c e9 e1 7c 4b d5 2f 46 1c |.0i.&..|..|K./F.| -00000060 7d 18 a5 20 f1 ff 40 9e c7 d5 d4 54 33 c4 99 9c |}.. ..@....T3...| -00000070 26 95 d9 ca 82 fc e7 27 37 fc 33 9f f8 c7 cb 0a |&......'7.3.....| -00000080 9d 4e bc 66 ca fc 16 03 03 02 69 ab be 55 39 99 |.N.f......i..U9.| -00000090 ac 66 a6 86 03 51 70 d8 fa 7d e7 89 09 fc eb b5 |.f...Qp..}......| -000000a0 25 f6 95 0c 40 3d b8 ea b6 78 41 db a4 f3 92 83 |%...@=...xA.....| -000000b0 00 c8 8d 1f 19 0c ec ec e5 60 07 d9 31 2d 3b 91 |.........`..1-;.| -000000c0 ba ad b3 c1 fb b5 57 52 73 37 43 89 22 e0 45 7c |......WRs7C.".E|| -000000d0 b0 da 1f 69 76 d3 af fc ba f0 98 ec d2 7f be f0 |...iv...........| -000000e0 a4 76 f0 d9 30 1b 78 22 bb 43 fd 45 64 07 e4 64 |.v..0.x".C.Ed..d| -000000f0 c5 74 2f ed ba 23 8d 3a 5a ff 7f 35 de 25 53 0d |.t/..#.:Z..5.%S.| -00000100 ac ae 5b da b1 7d 86 fe da c8 9e 79 58 6c 4c 9c |..[..}.....yXlL.| -00000110 6d f9 e9 1d 31 ff aa fb 8e 2e 98 f4 3a 67 33 9b |m...1.......:g3.| -00000120 a3 63 5e fc 74 f5 c5 28 76 30 e6 22 8a 85 79 56 |.c^.t..(v0."..yV| -00000130 4e cf 94 38 92 61 09 22 00 95 d4 16 b4 e0 80 05 |N..8.a."........| -00000140 28 35 30 6f 56 7d f8 b9 ed 49 72 b0 9f 47 9f 07 |(50oV}...Ir..G..| -00000150 7f 1d b9 3b 6d ce c9 09 72 2f 65 b0 88 b4 ec 24 |...;m...r/e....$| -00000160 29 8d 57 93 a7 51 85 32 26 4c 31 21 24 b1 ab 97 |).W..Q.2&L1!$...| -00000170 c6 3c 38 44 d4 8f d0 3b ea 62 39 48 90 ca c4 5c |.<8D...;.b9H...\| -00000180 9c 72 08 a4 3f d0 1e 3e 9f 23 02 0e 94 b4 14 cc |.r..?..>.#......| -00000190 96 bc 23 22 2f af c5 ed 81 da 49 ca 26 f4 55 6a |..#"/.....I.&.Uj| -000001a0 b3 24 3f 13 a5 f7 d6 82 70 04 37 63 dc 92 63 0f |.$?.....p.7c..c.| -000001b0 3d f7 4e 42 7c 5a 42 df 53 17 48 25 cb da 31 e1 |=.NB|ZB.S.H%..1.| -000001c0 67 a7 22 8c ca db 2d 33 49 86 62 b5 ba 38 53 4c |g."...-3I.b..8SL| -000001d0 12 f3 c3 f6 b6 01 53 b1 11 43 e1 e8 ba 3f 68 7a |......S..C...?hz| -000001e0 9c 10 09 82 d1 90 cd 9e 52 2e 29 15 0b 13 c3 e3 |........R.).....| -000001f0 34 ef 76 8a 0d f9 f6 17 76 57 c2 55 cb 7d 45 e0 |4.v.....vW.U.}E.| -00000200 d5 e6 53 93 75 57 c2 ab 26 5a 13 02 05 7a 60 2b |..S.uW..&Z...z`+| -00000210 b6 92 1a 88 0c 34 59 81 40 42 70 d5 4e 7b d3 14 |.....4Y.@Bp.N{..| -00000220 3c e6 70 81 90 ff 53 79 c5 f3 7c d9 02 6f 35 6b |<.p...Sy..|..o5k| -00000230 d4 81 ff 32 a2 71 28 a0 4b 22 75 9f 3b 50 c8 03 |...2.q(.K"u.;P..| -00000240 22 e7 4f 1f c5 c5 99 67 f3 2c 97 5e 43 89 84 39 |".O....g.,.^C..9| -00000250 04 c9 4c 1e e0 da 39 8f 78 8f 95 3a 64 74 d3 63 |..L...9.x..:dt.c| -00000260 13 d4 14 9d 98 6c bb 27 81 1e 12 88 8c d4 11 1c |.....l.'........| -00000270 4a 71 2f 10 dc 5b 9a 8e 70 e6 bf 0b a2 50 4c d1 |Jq/..[..p....PL.| -00000280 c4 29 b7 85 9e 0f 86 33 7c 38 e4 ae d4 53 5e 81 |.).....3|8...S^.| -00000290 95 cf 6c 1a 15 7d af 20 53 21 f4 84 5c 46 5f 10 |..l..}. S!..\F_.| -000002a0 1f 68 7d 9a 20 0d a8 1f 90 2f ae b8 c0 57 e0 4b |.h}. ..../...W.K| -000002b0 ad ec 9d ae 51 52 78 5d 3f bb de 54 54 d4 18 ff |....QRx]?..TT...| -000002c0 e6 b4 c9 52 f8 66 63 e3 bf 7a f3 5e c6 3f d9 27 |...R.fc..z.^.?.'| -000002d0 71 07 e7 69 6d cb 60 24 55 4e f9 34 e7 5f a3 37 |q..im.`$UN.4._.7| -000002e0 76 90 ec b5 eb ff 49 38 15 71 23 fd 77 30 80 c8 |v.....I8.q#.w0..| -000002f0 ca 0e 38 3c 16 03 03 00 bc 89 27 c8 13 dd 05 8b |..8<......'.....| -00000300 46 97 5f 19 76 db 29 8d b1 24 52 fe 7a 2e 2c 4d |F._.v.)..$R.z.,M| -00000310 e2 f9 59 89 48 82 f5 d7 87 af 99 4b 98 c5 7c 1d |..Y.H......K..|.| -00000320 1a e1 4d fd 0c 37 d0 d3 d8 e2 f8 0f 04 d5 15 21 |..M..7.........!| -00000330 60 09 47 0c d6 bf 09 bf 55 c1 ae 33 11 35 94 29 |`.G.....U..3.5.)| -00000340 80 96 3a 53 ae a8 29 c4 84 37 e2 80 f9 da 79 18 |..:S..)..7....y.| -00000350 77 50 26 32 bf f6 b2 6d 3a 73 25 e7 cd 34 6d ea |wP&2...m:s%..4m.| -00000360 a0 92 40 7e f8 eb d0 82 06 b3 a1 f5 1c 8e b2 ef |..@~............| -00000370 b2 4f 0c bb 04 1b c7 cf bc dd 42 19 00 3e 45 93 |.O........B..>E.| -00000380 e6 72 57 ed eb d9 1d b3 71 b7 fe 84 03 57 e4 9c |.rW.....q....W..| -00000390 71 78 35 39 63 b1 cf 36 b9 5a d6 95 13 ee 4d 2f |qx59c..6.Z....M/| -000003a0 22 ef ed 2e fc 69 7c 12 c2 0e 32 ed 05 17 42 5c |"....i|...2...B\| -000003b0 a7 62 ab 6b 46 16 03 03 00 3a b9 af 3d 25 e4 6a |.b.kF....:..=%.j| -000003c0 a9 b5 b4 00 79 21 aa 3c f3 56 50 bd 32 a4 a8 ab |....y!.<.VP.2...| -000003d0 8a 60 77 5d b7 3e 89 d3 60 a2 b8 5c a8 99 27 bb |.`w].>..`..\..'.| -000003e0 0e dd 93 af 3e 2b 66 8e 56 19 03 29 44 6a 63 a1 |....>+f.V..)Djc.| -000003f0 c7 17 f3 1e 16 03 03 00 14 1c bd e4 7b c3 88 d9 |............{...| -00000400 be ba c3 c3 fb b7 07 9d f1 58 3e b0 61 |.........X>.a| +00000000 16 03 03 00 81 1b 98 a8 9a 8f 4f c6 d0 1f b0 21 |..........O....!| +00000010 74 47 2a af 9f 6d a0 fb 4e 99 ed ad 05 99 5a 34 |tG*..m..N.....Z4| +00000020 ab 9c 4d c0 24 72 15 f4 6f ba 8f d2 43 33 d5 8b |..M.$r..o...C3..| +00000030 3a f6 10 cd d3 50 3e 8c b7 d6 03 b7 1c 28 d7 fb |:....P>......(..| +00000040 47 1c b9 a7 14 a4 6e 8e 06 65 d3 b8 8a 8c 73 ee |G.....n..e....s.| +00000050 36 63 24 bf 5a c8 0a 27 1f 93 a4 fc 50 c9 48 d0 |6c$.Z..'....P.H.| +00000060 43 27 63 6d c3 d9 ca bf 2c 03 c8 d1 e3 d1 94 43 |C'cm....,......C| +00000070 e0 12 87 b1 96 14 b4 7f ac 8a 85 50 5d f7 64 0e |...........P].d.| +00000080 05 cd 47 43 59 5e 16 03 03 02 69 90 f1 fe ba 32 |..GCY^....i....2| +00000090 b5 0d 2f 98 95 2f c1 95 9a 09 32 ab 9f a8 a8 bc |../../....2.....| +000000a0 2d f0 cf 7e 7f d0 f8 b9 0c e0 11 84 03 8e d3 27 |-..~...........'| +000000b0 c5 15 07 81 02 fa 64 7b eb 21 63 59 15 ba 9e 4e |......d{.!cY...N| +000000c0 6d 03 81 f4 d8 8b 4d f4 82 fd 62 1f 9f 28 64 80 |m.....M...b..(d.| +000000d0 5b af d3 fc fc 2e dd 6c b0 5c 28 5e 58 e7 01 07 |[......l.\(^X...| +000000e0 86 d1 40 35 f2 9c 2c 45 c0 2a 86 67 30 d4 d4 51 |..@5..,E.*.g0..Q| +000000f0 6c 18 31 bd 22 2e d0 6c ea d8 f4 9b 87 30 ea 09 |l.1."..l.....0..| +00000100 66 11 36 a3 ae f5 a7 91 a0 76 8e 77 c1 3d f7 3a |f.6......v.w.=.:| +00000110 88 29 b2 c4 2f 4e cd c6 d9 93 80 7f 9b 29 3a a4 |.)../N.......):.| +00000120 f5 63 77 7d 54 07 62 8c bc 23 c8 36 ea a8 e5 c4 |.cw}T.b..#.6....| +00000130 46 4b 59 dc 02 58 9d 21 00 47 39 29 60 9a 14 d8 |FKY..X.!.G9)`...| +00000140 ae 55 5c 03 fd 05 b7 66 30 de 81 87 9c 45 9f 52 |.U\....f0....E.R| +00000150 1e c5 2d d8 6a 7d d0 64 7b 0c 3a 47 b9 ff dd dd |..-.j}.d{.:G....| +00000160 60 a6 fa 69 f9 a0 43 a5 97 27 e8 fe 2d 99 94 01 |`..i..C..'..-...| +00000170 d7 52 c2 b2 ec 77 10 af ed 5e f6 82 d4 15 60 aa |.R...w...^....`.| +00000180 d3 cd 39 e5 a6 92 c9 f8 9e 63 e1 83 71 33 f2 dc |..9......c..q3..| +00000190 dd 7a eb de ac 91 46 06 ef 23 b2 6f 39 33 69 75 |.z....F..#.o93iu| +000001a0 43 d7 e5 e1 b0 5c 2f 0f 2d 39 d6 14 11 cd 6b a2 |C....\/.-9....k.| +000001b0 37 d2 32 0b b6 45 ad 2c b8 26 ef 43 3e 63 b0 1f |7.2..E.,.&.C>c..| +000001c0 a1 79 d2 c7 84 f9 7a 5f b2 c2 fd 4e 22 89 23 1d |.y....z_...N".#.| +000001d0 b7 4c 6c b5 b1 c1 19 a9 7c f7 23 bf 91 0e aa 8c |.Ll.....|.#.....| +000001e0 da 67 68 57 84 b9 68 5f 69 16 ad c7 32 86 98 81 |.ghW..h_i...2...| +000001f0 06 01 91 66 fd 5e e3 f5 63 4b e3 05 6d 41 f0 4e |...f.^..cK..mA.N| +00000200 f2 b1 70 26 de ed e5 83 87 d3 cf 5d 5c 7b d5 14 |..p&.......]\{..| +00000210 08 e9 e3 88 9a d0 9a e4 d6 40 44 1b 61 57 8f a3 |.........@D.aW..| +00000220 8a 52 5e 83 75 07 3d c2 16 00 3c a3 e9 61 cb 41 |.R^.u.=...<..a.A| +00000230 66 e7 54 7c e1 e5 7b 85 cb 0d f6 50 93 7d 85 c1 |f.T|..{....P.}..| +00000240 de 98 a8 8d 5a 0d 12 80 25 78 25 15 a3 0c 7a 7f |....Z...%x%...z.| +00000250 43 45 2e 0f e0 47 05 9f b2 2a 0d 9f 23 e3 0b 62 |CE...G...*..#..b| +00000260 33 91 d9 d8 7f f5 ac ed ef fd ea a5 f5 df 04 e8 |3...............| +00000270 6f 4a bd a2 bf aa fe 56 49 13 7a d3 58 2b ef ab |oJ.....VI.z.X+..| +00000280 ed f8 4b 6f 77 18 1e 37 59 2c 98 85 c4 59 f5 08 |..Kow..7Y,...Y..| +00000290 a6 03 f3 9b b0 79 24 cc 61 55 e3 b7 a7 f5 96 58 |.....y$.aU.....X| +000002a0 39 57 ec 40 33 a8 94 a2 c8 7f d4 5a f6 5e b0 be |9W.@3......Z.^..| +000002b0 89 b8 4d 45 73 ef 9f e9 cc d1 31 f8 46 97 82 be |..MEs.....1.F...| +000002c0 fa 44 de 62 36 47 6f 7b 5e 50 af b6 1b d2 0b 02 |.D.b6Go{^P......| +000002d0 17 df 6b c4 b5 ca 60 39 49 2e 86 d7 84 60 37 34 |..k...`9I....`74| +000002e0 65 43 0d f7 04 88 38 e4 5f 65 19 d0 62 8c 29 b6 |eC....8._e..b.).| +000002f0 2d d2 52 0f 16 03 03 00 bc 30 b3 f2 e1 bd 5e ec |-.R......0....^.| +00000300 c3 68 8a cc b4 4d e1 f1 76 e7 c1 47 0a c2 54 c1 |.h...M..v..G..T.| +00000310 9d d9 2d 72 1b 44 2d 3e 3d 22 5b 7d a1 c0 17 27 |..-r.D->="[}...'| +00000320 97 dd fe 9e a1 c5 5b ce 5f eb 9d 72 0e 14 ca b1 |......[._..r....| +00000330 61 f6 03 6e 84 d5 c4 53 91 ed 22 41 6e c9 84 91 |a..n...S.."An...| +00000340 59 a2 30 38 2a 29 b3 b8 9e 45 3a 1f 98 30 ce a4 |Y.08*)...E:..0..| +00000350 41 8a d9 ea e8 8d ee 43 cc 29 94 8c e5 86 cc 7b |A......C.).....{| +00000360 04 a7 31 1e 87 2b aa da 6c d0 4a a7 08 6e 31 2f |..1..+..l.J..n1/| +00000370 c3 95 06 3e 6d 9c 1b bb db 74 f5 a2 7e 6a 17 5f |...>m....t..~j._| +00000380 4c 2f f5 56 69 89 04 f7 17 41 85 ea 35 2f 59 db |L/.Vi....A..5/Y.| +00000390 d3 b9 f9 7a 6c 08 f8 f2 2d ba 04 ef 57 b5 d0 2f |...zl...-...W../| +000003a0 f3 3d 31 e6 c1 f8 26 9d 06 be 38 94 ba 8e ca 3f |.=1...&...8....?| +000003b0 4c 5b 70 c6 09 16 03 03 00 14 1e 86 bf c9 1e 7c |L[p............|| +000003c0 08 0c 5a fb e4 92 8c f9 78 85 34 e3 56 86 |..Z.....x.4.V.| >>> Flow 9 (client to server) -00000000 16 03 03 02 69 d3 b2 83 ca 08 61 36 6f fa 66 de |....i.....a6o.f.| -00000010 5c 42 5f 35 17 f4 4c b3 5e 17 94 07 c5 2a 89 90 |\B_5..L.^....*..| -00000020 b8 31 50 af 55 91 b1 28 bc 00 00 da 57 85 cc d5 |.1P.U..(....W...| -00000030 a5 a7 ec ba 52 d5 1f ab b5 4f a3 53 9c af 59 20 |....R....O.S..Y | -00000040 be 13 f6 c5 70 b0 cc f7 59 69 d1 db 80 7f 60 29 |....p...Yi....`)| -00000050 e1 e8 7a 1e 97 a6 e1 a2 11 70 4f b4 7b 53 7c 9a |..z......pO.{S|.| -00000060 dd fa 58 5d 12 a4 fb 3e 46 dd d3 4d ac e3 b6 73 |..X]...>F..M...s| -00000070 05 42 03 f3 37 79 a0 10 34 ef 01 6f c6 27 52 4b |.B..7y..4..o.'RK| -00000080 75 4c b2 86 1b d6 ca 13 b4 31 41 db 93 2f a3 35 |uL.......1A../.5| -00000090 e1 e9 bc 65 85 c8 1a e2 7b 6e 36 49 e8 ed 04 a9 |...e....{n6I....| -000000a0 cb a9 70 32 c0 4d e5 f5 94 d8 af 7d 41 b6 dc e5 |..p2.M.....}A...| -000000b0 fc ff db 9f 91 50 df c6 b2 4a 0c bb 86 4e 50 a5 |.....P...J...NP.| -000000c0 2a 3b 69 e2 3d fa 10 eb cc 48 21 9d 98 78 02 0b |*;i.=....H!..x..| -000000d0 e7 4d 83 63 9e e5 ad 2c 7b 46 d1 09 28 35 07 6c |.M.c...,{F..(5.l| -000000e0 12 c9 ae f0 4c 7c 00 aa 54 ba 7b e8 42 be e0 18 |....L|..T.{.B...| -000000f0 f4 df a0 9d eb 8f a2 3a d0 00 b6 e0 eb 90 65 38 |.......:......e8| -00000100 b2 cc 21 87 57 b7 50 07 41 e2 5a 9b c8 2b ae 64 |..!.W.P.A.Z..+.d| -00000110 55 6a d7 b5 0d 5d f0 ac da 0b f0 80 75 8d 6a 0a |Uj...]......u.j.| -00000120 5b c5 2a 20 f2 ab 75 76 a3 33 f1 43 24 06 45 75 |[.* ..uv.3.C$.Eu| -00000130 63 58 60 57 ca 7f d2 8f e8 a5 b8 e3 72 37 39 bd |cX`W........r79.| -00000140 9c dd 10 b0 f8 b5 e8 46 4a 39 ac 94 69 08 51 29 |.......FJ9..i.Q)| -00000150 27 2d 28 0f 15 8a 91 00 3b cc 99 77 ea 82 0d e1 |'-(.....;..w....| -00000160 66 ed 34 da 6e 88 47 e5 f4 1b 28 28 cd 38 9f e5 |f.4.n.G...((.8..| -00000170 1c 26 67 3d 83 d0 b1 88 a3 08 9c 2e 08 a5 b7 af |.&g=............| -00000180 15 28 d5 1e aa c9 58 17 48 85 f7 13 17 6f 55 c3 |.(....X.H....oU.| -00000190 dc 9d 2e 7e 67 45 7a cb 80 a7 e5 77 86 96 36 4d |...~gEz....w..6M| -000001a0 f7 df 27 7d f4 5d 53 9b be e6 b2 b9 44 b9 86 e9 |..'}.]S.....D...| -000001b0 8f 33 26 4e 20 97 e4 34 66 58 6d d5 28 be e8 84 |.3&N ..4fXm.(...| -000001c0 de 2f 19 f2 46 52 80 84 e9 ef 0e 6c 55 5c 43 8c |./..FR.....lU\C.| -000001d0 51 19 8b 22 30 b7 b3 eb 9f ed 35 a1 fe 09 aa 6a |Q.."0.....5....j| -000001e0 f8 b6 37 7e 20 4c e5 76 ae 10 4c dd 67 7c 07 e2 |..7~ L.v..L.g|..| -000001f0 0c dc 78 77 a1 8e c1 d1 aa fa d3 36 8b 9c 74 ed |..xw.......6..t.| -00000200 e2 fe 84 98 40 95 f2 1a a6 fd 77 cf 47 d3 c3 d6 |....@.....w.G...| -00000210 bc 38 45 a9 94 63 13 52 2d 7b 3f 3d 06 1e 0a 31 |.8E..c.R-{?=...1| -00000220 cb 98 1d 18 fa a7 86 21 65 c7 58 dd 78 13 2d 4d |.......!e.X.x.-M| -00000230 76 57 9d 65 15 a3 2d be 7f c9 58 78 b7 89 3c d6 |vW.e..-...Xx..<.| -00000240 dc 7e 5b c5 1b 93 78 04 7b ca ef 61 77 6c 27 6b |.~[...x.{..awl'k| -00000250 a5 30 67 43 64 a7 30 f0 dd 5c 63 92 76 9a e3 a2 |.0gCd.0..\c.v...| -00000260 31 12 49 8e c4 7e 80 ce 1e ce 94 66 2f 6f 16 03 |1.I..~.....f/o..| -00000270 03 00 35 39 86 a0 5a 88 07 66 5f 43 59 ed fb b5 |..59..Z..f_CY...| -00000280 0c 0b ee ff 76 62 28 ea 62 7e 53 72 3d d9 26 9f |....vb(.b~Sr=.&.| -00000290 06 64 99 83 a5 3c 59 45 84 4d 79 86 1d b4 21 14 |.d...2Cd...R..V..| -000002e0 4e d2 1a b8 f6 ae 64 d2 c0 05 9b 18 84 71 a7 ad |N.....d......q..| -000002f0 ea 49 f6 b5 ae 91 ad 66 6f cb fa 56 de 1e 40 22 |.I.....fo..V..@"| -00000300 7f d3 44 c4 a7 bf b1 7b 61 e3 09 1f fe 3b 4b 7b |..D....{a....;K{| -00000310 5a 3f ae 4e c4 5c a8 ac a4 c2 fc 0e 1f 12 4f 9b |Z?.N.\........O.| -00000320 f9 e0 a2 89 ab a0 bb e8 f9 97 5a 7c 8d e8 58 87 |..........Z|..X.| -00000330 3f 4c 1c f3 ff 6e b9 a0 e6 f7 e4 c2 43 cc af 9e |?L...n......C...| -00000340 06 3a 1c ee ef 14 03 03 00 11 8b 6d c3 12 83 c4 |.:.........m....| -00000350 2f e7 67 81 db 18 9a 33 e6 fa 82 16 03 03 00 20 |/.g....3....... | -00000360 ef c9 6f 3f b7 9d 9d 2d a0 05 b6 fd 74 8e ff de |..o?...-....t...| -00000370 cc 4b ca 4c 5b 4d 61 30 76 b5 f3 7a d1 46 d6 6a |.K.L[Ma0v..z.F.j| +00000000 16 03 03 00 35 a7 bb 37 bb b1 b0 8e 12 72 8b a8 |....5..7.....r..| +00000010 c5 d4 cc 44 1c 4b 87 1f bc cb 39 35 60 fb 06 de |...D.K....95`...| +00000020 44 ac 0a c5 13 cb 15 1b ce 6b d8 45 28 d6 80 1b |D........k.E(...| +00000030 06 1f 32 4c 26 81 77 08 9c 23 14 03 03 00 11 c0 |..2L&.w..#......| +00000040 1b 3b 4d e8 9d ba d9 2c 50 10 03 b9 0c 57 83 60 |.;M....,P....W.`| +00000050 16 03 03 00 20 e0 d7 07 fe 04 89 25 3c b6 c0 8a |.... ......%<...| +00000060 33 14 6c 3e f4 48 5c 17 33 f8 f0 11 3a cb d8 17 |3.l>.H\.3...:...| +00000070 cd 42 be 22 68 |.B."h| >>> Flow 10 (server to client) -00000000 14 03 03 00 11 2e d9 0e 1b 6b 4b 9a 60 96 e9 38 |.........kK.`..8| -00000010 35 a3 72 3d c4 5b 16 03 03 00 20 62 1f 2b 02 e8 |5.r=.[.... b.+..| -00000020 22 0a 89 a2 f6 60 8a da f2 09 52 5a 92 12 a8 f6 |"....`....RZ....| -00000030 c3 ee 25 17 6b 91 25 3e 2b 75 ba 17 03 03 00 19 |..%.k.%>+u......| -00000040 b9 4e 6b c3 74 30 39 f9 3f a2 aa af 80 49 6b 8a |.Nk.t09.?....Ik.| -00000050 f2 a1 9b f5 c7 34 f7 1b 2f 16 03 03 00 14 2d 25 |.....4../.....-%| -00000060 74 c2 c7 80 a8 5f 65 ff 65 b0 c2 50 c8 bc fe 8c |t...._e.e..P....| -00000070 d4 9e |..| +00000000 14 03 03 00 11 05 69 30 af cd 8e 28 8b 04 3c de |......i0...(..<.| +00000010 39 2c cc 79 60 dc 16 03 03 00 20 64 e4 49 e1 a5 |9,.y`..... d.I..| +00000020 59 be ed d9 04 59 24 01 16 65 aa b9 22 7d 91 5f |Y....Y$..e.."}._| +00000030 e5 e4 db a7 67 a0 10 51 7e 3b 77 17 03 03 00 19 |....g..Q~;w.....| +00000040 70 cc 7d 13 21 aa ac d3 fb a7 ee cc f6 db 51 4b |p.}.!.........QK| +00000050 2d 2a e2 66 f4 ba 29 aa e1 16 03 03 00 14 e2 ba |-*.f..).........| +00000060 56 31 77 97 4a 4a a5 f0 05 28 d5 9f b7 3e 38 50 |V1w.JJ...(...>8P| +00000070 1f 1b |..| >>> Flow 11 (client to server) -00000000 16 03 03 00 ad d0 25 9a 38 60 d3 94 8e b8 23 45 |......%.8`....#E| -00000010 44 67 95 20 79 1a 27 5f cf bb dc 72 8c 95 2a 02 |Dg. y.'_...r..*.| -00000020 1d d9 80 c6 61 12 c2 5c ae d5 62 a9 aa b0 4a d0 |....a..\..b...J.| -00000030 13 ad 6d ae df c9 63 e2 6b 27 bb ca 88 c3 dc 8b |..m...c.k'......| -00000040 e9 bc 0b fb 32 d6 0f 99 b6 d1 03 7e c9 8d 72 ee |....2......~..r.| -00000050 09 7b 82 f1 79 11 a7 23 43 8b 77 b8 a9 bd 9e 67 |.{..y..#C.w....g| -00000060 43 03 79 88 34 ab c2 6b d1 2a cf c7 c9 b6 14 ee |C.y.4..k.*......| -00000070 ee 32 01 10 fb 85 dc 5a 04 cf 9a ea 8d 8c fc f8 |.2.....Z........| -00000080 b3 b2 49 c0 93 37 93 09 24 1c 26 97 43 5f dd 09 |..I..7..$.&.C_..| -00000090 7a 0d c0 6c bd 17 df 78 37 3d 23 6b 9d 27 d2 f7 |z..l...x7=#k.'..| -000000a0 1c 2e 82 5c ba 95 1c 0f b3 40 af 9f 2f 5e 42 40 |...\.....@../^B@| -000000b0 cc b9 |..| +00000000 16 03 03 00 b1 86 78 3d 4f eb 03 b0 00 ca a5 94 |......x=O.......| +00000010 9d 70 04 ff 30 82 59 9c ea 95 44 02 f0 14 fa 3c |.p..0.Y...D....<| +00000020 aa af fa e8 17 3c ac 69 91 3d b6 23 85 85 7a be |.....<.i.=.#..z.| +00000030 11 9e 17 4e 32 79 de 3e 04 54 71 d0 ae 94 03 97 |...N2y.>.Tq.....| +00000040 d1 90 50 1f d5 8d d3 ff aa ce 0a fb 81 bd e9 11 |..P.............| +00000050 3f c2 c5 68 f9 e6 71 00 4f d9 ef cb c9 fd 0e 0d |?..h..q.O.......| +00000060 23 ce 04 f3 19 86 cb 4c a0 71 52 8e c2 90 a1 5b |#......L.qR....[| +00000070 e2 1e f4 e7 24 4c 9a b0 0c fc eb 70 d0 94 44 4e |....$L.....p..DN| +00000080 fc 5d 2e 16 2d 0f ff 61 20 3a 4d 19 cd 1c 22 d7 |.]..-..a :M...".| +00000090 d0 23 ff a9 a1 bf 79 7c 91 ba d8 15 47 9a a3 88 |.#....y|....G...| +000000a0 cb 06 f9 5d bd 8b c1 cb f6 16 ee 5d af 9c 7a 54 |...].......]..zT| +000000b0 0c af 31 ee 4a d0 |..1.J.| >>> Flow 12 (server to client) -00000000 16 03 03 00 81 39 20 22 4a e1 4e 21 2e 78 35 50 |.....9 "J.N!.x5P| -00000010 8a d4 c4 c6 a9 20 74 8e 10 4b fd 31 4c ba c4 7f |..... t..K.1L...| -00000020 14 91 ab 4b 7a b2 7a 86 56 cc 61 ed 12 63 4a d5 |...Kz.z.V.a..cJ.| -00000030 b5 c9 48 6e ae 10 71 fc 30 f5 e5 36 8b e2 7d 9d |..Hn..q.0..6..}.| -00000040 93 e2 34 cd 8e a0 72 c4 19 9b 62 eb 9b c4 5e c3 |..4...r...b...^.| -00000050 df 22 d4 16 4d 88 b1 d5 e5 74 ac 9d 38 40 7d 1f |."..M....t..8@}.| -00000060 40 bd 86 e5 fc 19 88 bb 67 cf 3f 22 0f 39 1f 8f |@.......g.?".9..| -00000070 40 5c ee 29 48 00 c1 bf 6a f1 85 51 03 c0 e8 7a |@\.)H...j..Q...z| -00000080 2e f4 2a f9 b6 fb 16 03 03 02 69 59 b1 5a b9 98 |..*.......iY.Z..| -00000090 86 77 af 76 a7 4c 69 0d 83 79 3c 9a b9 3c dd 49 |.w.v.Li..y<..<.I| -000000a0 f2 0f ef d2 38 ac 31 b0 9b 5d 57 ed a7 ca f9 79 |....8.1..]W....y| -000000b0 7c ef 58 f7 ca 7e 0c 60 1c 53 09 c5 06 dd b8 31 ||.X..~.`.S.....1| -000000c0 09 88 af 50 9f c2 2a 2c 24 89 9e 57 ae c8 e6 49 |...P..*,$..W...I| -000000d0 f4 6f 46 e9 dd 38 f1 52 e9 06 50 38 69 b3 e1 69 |.oF..8.R..P8i..i| -000000e0 f5 33 28 54 39 43 05 b9 04 04 c2 d9 3d 34 da 48 |.3(T9C......=4.H| -000000f0 99 7e 8a b2 59 d1 d3 20 da 34 c8 ab 91 f7 66 69 |.~..Y.. .4....fi| -00000100 3a 4f fc 6d ee e6 ef f5 c0 b0 08 bf 59 c0 f8 e5 |:O.m........Y...| -00000110 dc c6 dc c6 49 a7 d5 3c 22 0f e3 9f 39 0b 2a 09 |....I..<"...9.*.| -00000120 7a 56 f8 90 33 05 06 09 21 6f 6a 53 0d 89 63 2a |zV..3...!ojS..c*| -00000130 76 28 19 33 73 e5 a0 2a fa d2 82 bf 4c 43 84 f9 |v(.3s..*....LC..| -00000140 e1 bb 7f 31 62 04 c5 26 ed 16 40 f5 6a 04 e0 c5 |...1b..&..@.j...| -00000150 4e fe bd e3 4c 57 e2 61 41 2f 9a 95 7f 8a e1 34 |N...LW.aA/.....4| -00000160 64 f4 fc ce 13 e5 0c 68 c1 e5 29 df e7 b1 56 0b |d......h..)...V.| -00000170 42 6b fc d6 5d 63 0b 3c 0c ca ce 38 11 50 f2 64 |Bk..]c.<...8.P.d| -00000180 1a 6e 16 da 3e 69 cf 82 ba a0 03 0f 9d 72 ed 10 |.n..>i.......r..| -00000190 78 b2 54 c0 be 9c 16 fa 15 4b 88 db dd 85 dd 08 |x.T......K......| -000001a0 bd f4 50 a0 50 01 77 7a cf 20 c1 3e 50 55 5f bd |..P.P.wz. .>PU_.| -000001b0 4a ba b4 d5 6d 51 38 b2 6d 4f fc b5 af b9 92 ff |J...mQ8.mO......| -000001c0 c4 44 f1 0e db 4d 71 09 15 b3 c3 37 47 57 03 35 |.D...Mq....7GW.5| -000001d0 95 de da 33 31 8c 60 bc 8a 97 2d f8 27 9b 4e dc |...31.`...-.'.N.| -000001e0 2a 6d aa 3e 4d eb 8f 97 b8 fa d4 ef f6 27 d9 da |*m.>M........'..| -000001f0 a6 fe 38 91 4b 96 ff 75 4b 71 52 9f 37 e4 d9 85 |..8.K..uKqR.7...| -00000200 a8 d8 ac 21 e9 b2 c0 4f c0 c0 e3 3a 9f ab e0 93 |...!...O...:....| -00000210 dc 03 18 30 92 55 33 67 58 f3 47 f3 0a 95 bc 33 |...0.U3gX.G....3| -00000220 70 73 e1 5b 9d 63 cf f7 c7 9b da 9e 5d 2e 7a 66 |ps.[.c......].zf| -00000230 03 b1 b8 5c fa b9 f4 fb 4e 0b 38 9a 97 f0 c9 e5 |...\....N.8.....| -00000240 ce 18 33 ea 66 1c 59 cd 41 3e af 71 7c bf 00 a0 |..3.f.Y.A>.q|...| -00000250 d9 ee 20 d7 80 a9 5d 55 b8 f8 92 7b 7e 4f bc 66 |.. ...]U...{~O.f| -00000260 92 98 6a c6 15 5b e3 1d 59 14 d9 d0 5a 30 c0 4d |..j..[..Y...Z0.M| -00000270 37 f5 d9 40 a4 f9 f4 ad b6 cf 55 98 03 1e e7 13 |7..@......U.....| -00000280 5a 23 49 69 36 fa ae 9d c2 cb 90 16 cc 36 f4 41 |Z#Ii6........6.A| -00000290 3a c7 56 9f 05 23 be 1d 3f 8f 90 41 09 6b 88 9a |:.V..#..?..A.k..| -000002a0 70 91 76 e1 6d f0 5c 86 de 77 a4 83 c7 d5 3c c4 |p.v.m.\..w....<.| -000002b0 67 ff b1 a2 e2 f5 61 4f 3b 4d 38 5d c9 c2 8c 97 |g.....aO;M8]....| -000002c0 e2 a7 c0 72 3b 5e 4c d9 0f 18 a8 b9 77 8d 31 8f |...r;^L.....w.1.| -000002d0 d9 73 ac 33 a6 7a b5 bd 5e 58 b4 51 22 be d8 d4 |.s.3.z..^X.Q"...| -000002e0 f5 e1 bc 37 80 d3 cf 3b 58 be 3e ce 33 83 1c 46 |...7...;X.>.3..F| -000002f0 8b f3 f3 56 16 03 03 00 bc 30 f0 e1 0b eb 80 fe |...V.....0......| -00000300 5f fb 94 c9 5a 04 08 82 0f 0b b5 9b f7 f6 f6 d3 |_...Z...........| -00000310 7e 68 e7 e5 2e cf a0 56 e6 b7 70 0a 63 5e 53 42 |~h.....V..p.c^SB| -00000320 7f 27 ec 82 a0 5d e3 e8 77 27 40 3c 6d 47 ce dd |.'...]..w'@.3..Y..V| -000003a0 95 3a 8b dc 1f 24 6c 08 07 c0 f1 20 6d 96 43 71 |.:...$l.... m.Cq| -000003b0 bf c6 92 81 e3 16 03 03 00 3a 91 c1 13 a0 26 c9 |.........:....&.| -000003c0 12 6a 09 23 5b 8b e8 da 10 cc 4d 00 ed 9e a6 09 |.j.#[.....M.....| -000003d0 d8 d4 c0 b7 f0 cd 5f 7a 6e 4d 31 21 f6 6a 22 e7 |......_znM1!.j".| -000003e0 6e 25 11 94 4a f2 b1 f1 b2 c9 30 4b e4 cd f3 f5 |n%..J.....0K....| -000003f0 ce 86 e7 5d 16 03 03 00 14 20 c5 91 f0 6e 21 b8 |...]..... ...n!.| -00000400 e8 a1 bb cf 62 ed 4b 5a fa 19 40 ea 54 |....b.KZ..@.T| +00000000 16 03 03 00 81 d3 34 51 a2 7a 93 5e f9 ef 8f f7 |......4Q.z.^....| +00000010 a3 be aa 40 2c 53 e4 5d 62 2e 19 4a bf f3 dc ce |...@,S.]b..J....| +00000020 da e8 49 8e 4d 0c 68 72 3f 79 74 59 e2 8d 0c 78 |..I.M.hr?ytY...x| +00000030 b7 13 05 0f 4f df 4f 01 71 40 38 f3 79 b2 33 51 |....O.O.q@8.y.3Q| +00000040 f5 25 73 11 9a 30 b9 3c 5f d2 8b 32 71 6f 0d ef |.%s..0.<_..2qo..| +00000050 6a 42 da f6 c5 1d a4 90 ad e4 08 60 39 55 19 97 |jB.........`9U..| +00000060 a6 2c 5e 2c e3 96 ba 0c 54 50 bc b9 0f 3c 53 bd |.,^,....TP...| +00000090 92 4c 49 8e 40 86 28 53 c2 aa 43 2f 49 00 fa ee |.LI.@.(S..C/I...| +000000a0 48 0d 01 ec 94 e0 37 1a 05 97 6e ec a4 71 1e aa |H.....7...n..q..| +000000b0 50 5a 49 e9 cc 21 b0 d6 ab 38 4a 30 a7 84 ec 7d |PZI..!...8J0...}| +000000c0 38 34 91 63 3f 1a 59 eb 22 91 9b 23 23 b1 3f 7d |84.c?.Y."..##.?}| +000000d0 0c 70 23 71 0d 50 09 80 21 56 fe f2 c8 14 3d 19 |.p#q.P..!V....=.| +000000e0 91 04 a8 10 b8 2b b0 cb ff b7 6f 53 62 86 61 22 |.....+....oSb.a"| +000000f0 4e 6d 67 12 d3 18 ac 90 ab 62 42 0f cb 08 47 73 |Nmg......bB...Gs| +00000100 42 97 01 37 67 13 99 49 d6 f1 7f 0d 8a 83 6b 01 |B..7g..I......k.| +00000110 00 76 d9 3a bd 0c 7a 64 c7 49 9e 06 d6 6c 04 48 |.v.:..zd.I...l.H| +00000120 07 cc 96 03 f1 fe 38 76 b2 c3 97 ae 37 57 25 5e |......8v....7W%^| +00000130 54 18 07 b5 e2 6a ca fe 07 01 d7 9c a6 5c 95 df |T....j.......\..| +00000140 02 66 88 53 51 23 ba f2 0f b2 66 b2 df 14 61 28 |.f.SQ#....f...a(| +00000150 50 cd 7a 56 47 79 33 6e 75 0d b6 0d 66 69 eb c6 |P.zVGy3nu...fi..| +00000160 07 31 97 10 46 ec a7 59 b6 02 0b ab 40 d3 ce 88 |.1..F..Y....@...| +00000170 62 aa ab ce 1b 73 9a 62 d7 8c 7c ca 40 a0 bb 1d |b....s.b..|.@...| +00000180 ff f4 85 54 fe ae 83 61 10 ec 38 64 ab 60 36 e1 |...T...a..8d.`6.| +00000190 88 92 ba 74 e0 68 30 0b 61 7b da eb 3b d3 6b ed |...t.h0.a{..;.k.| +000001a0 fc eb 3f 98 dd 30 f1 28 bd e0 07 6b 77 53 29 02 |..?..0.(...kwS).| +000001b0 d7 18 69 2b ac 0b 4c 38 3b 35 e0 15 91 c4 34 42 |..i+..L8;5....4B| +000001c0 74 67 c0 2a 2b df 2f 70 13 7c 99 ba f6 cc e4 f4 |tg.*+./p.|......| +000001d0 bd 3c 7f cd 08 b4 3c 05 da bf c7 01 61 93 21 d6 |.<....<.....a.!.| +000001e0 1b ca b0 35 d1 89 f3 08 67 85 93 c9 da 6f cf a4 |...5....g....o..| +000001f0 ad 1e a8 70 71 4a ac 56 73 25 8f 9c 25 13 5f 2c |...pqJ.Vs%..%._,| +00000200 20 bc f2 56 af a0 03 38 43 9c 83 79 33 ea 81 8c | ..V...8C..y3...| +00000210 d8 5d c0 50 d4 44 cd df 55 e7 4e fc f6 67 55 92 |.].P.D..U.N..gU.| +00000220 39 a2 ec 25 3e 1f 7e 14 28 3b d8 84 f5 83 66 c4 |9..%>.~.(;....f.| +00000230 e1 d7 c3 63 51 d7 4e e4 72 1a da 76 ce 91 6b 56 |...cQ.N.r..v..kV| +00000240 0a 68 42 63 7e 57 31 98 cc d0 e0 3c 7c 7e 81 be |.hBc~W1....<|~..| +00000250 be 37 8d cd e7 da df 91 55 8c 71 e3 67 ec bf 6e |.7......U.q.g..n| +00000260 4c 5a a6 b6 2b 2c 31 0b da 19 66 26 f1 92 c2 7e |LZ..+,1...f&...~| +00000270 fd 12 50 6f 04 ee 83 85 bb d0 f1 77 12 10 c9 e7 |..Po.......w....| +00000280 4a 2f 17 96 55 0f 7e 1e fd 6d 18 13 74 a8 54 38 |J/..U.~..m..t.T8| +00000290 a5 ef bb 70 c9 71 07 09 c5 a3 26 f9 73 1f d0 e8 |...p.q....&.s...| +000002a0 a2 23 a1 46 46 1b f6 b1 e7 ac 22 22 ee df b9 5b |.#.FF.....""...[| +000002b0 38 02 c6 59 33 e5 12 0b 9f 49 e2 d7 de 77 30 ac |8..Y3....I...w0.| +000002c0 1e a0 ee 20 9f 1b 1d e0 8c fd d4 02 09 7b 1b d6 |... .........{..| +000002d0 c7 41 de 67 90 71 5f 06 ea ac 18 e7 5f 11 67 c3 |.A.g.q_....._.g.| +000002e0 d6 5d c1 37 0a 67 5b f7 93 93 eb 29 70 e3 cb 7f |.].7.g[....)p...| +000002f0 2c c9 bb 6b 16 03 03 00 bc ab 60 8e 1d 2e e1 42 |,..k......`....B| +00000300 81 91 89 69 78 5d 99 9c e7 1b d1 ac 36 39 c5 32 |...ix]......69.2| +00000310 58 4e 4c 48 b9 15 eb 21 b6 24 df 8e b2 16 f0 95 |XNLH...!.$......| +00000320 cd 57 8e 14 3b 5b a2 f9 7a 10 0d fa 57 52 70 f9 |.W..;[..z...WRp.| +00000330 b8 a9 b0 fd 22 0a 51 ef dd ba 3c fb 68 00 05 45 |....".Q...<.h..E| +00000340 d6 c3 1f 56 91 b4 06 80 a4 28 84 a5 bb 11 72 af |...V.....(....r.| +00000350 b7 f6 14 58 76 b7 76 ad 1b e6 65 57 af f7 46 a2 |...Xv.v...eW..F.| +00000360 bc 60 12 6d 30 d3 cf 26 62 9d 9f 19 b0 28 96 d2 |.`.m0..&b....(..| +00000370 e2 43 de 64 90 49 1d 29 2c bb 59 4c c7 d1 9b be |.C.d.I.),.YL....| +00000380 c3 e9 ae 8e 74 36 1b 03 00 43 65 56 30 3b e6 8b |....t6...CeV0;..| +00000390 4c d9 98 a2 f7 2b 06 77 4b 9c 53 c4 7f 24 88 75 |L....+.wK.S..$.u| +000003a0 30 91 66 fa ba 9c 7f 84 ab c1 51 21 1c d3 2e 93 |0.f.......Q!....| +000003b0 f9 4d db 6e 08 16 03 03 00 14 ed f9 cc ef c4 2b |.M.n...........+| +000003c0 fd 97 fe 35 ad 33 01 46 9b 52 d7 e9 49 c2 |...5.3.F.R..I.| >>> Flow 13 (client to server) -00000000 16 03 03 02 69 1a b5 80 9c c6 42 be a6 d9 d1 c8 |....i.....B.....| -00000010 0b 2c f7 f8 2a 1a 02 f6 db 48 8b 5c 45 fc 28 41 |.,..*....H.\E.(A| -00000020 a4 db 35 fb a7 a9 72 07 19 86 9e e9 dc 53 48 fb |..5...r......SH.| -00000030 97 94 f3 a0 0d 8d 46 69 cf eb d9 ea de 21 a3 f4 |......Fi.....!..| -00000040 b9 94 4f 8f 09 c3 de 66 fa 20 83 34 fc 50 ae c6 |..O....f. .4.P..| -00000050 13 f6 7c c5 80 45 17 51 af a9 da bd 24 dd f6 15 |..|..E.Q....$...| -00000060 8e c4 b4 e6 10 54 85 23 9d fe 72 b1 4c 2f ab ec |.....T.#..r.L/..| -00000070 78 9a 06 60 03 96 f7 d0 af dd 94 26 c9 67 1d e5 |x..`.......&.g..| -00000080 9f 87 22 c4 11 82 f1 4c f5 68 a7 fd d8 f3 dc ac |.."....L.h......| -00000090 35 90 6b c2 97 1c 78 54 d9 b2 3c d8 9d 13 66 42 |5.k...xT..<...fB| -000000a0 6e 3b 1b 8f 32 4e 8f b5 a0 60 6e e4 35 fd d5 b4 |n;..2N...`n.5...| -000000b0 f8 fb a6 a9 c7 b7 31 39 8e 90 0c 42 bc 1a 4f 67 |......19...B..Og| -000000c0 fa b3 10 a8 45 01 88 8a dd 41 43 c6 6c 41 9d 28 |....E....AC.lA.(| -000000d0 bd 4c 43 85 4c 3b 7c 03 c4 55 70 f1 49 a0 d6 52 |.LC.L;|..Up.I..R| -000000e0 5c 49 3e 2b d7 e8 a9 75 5e 92 bf f3 4c 1c c3 7e |\I>+...u^...L..~| -000000f0 69 ca 52 25 07 bb 54 e0 58 2d 28 ba 50 30 81 e8 |i.R%..T.X-(.P0..| -00000100 93 0d 9d 78 3d c0 f1 c3 34 72 29 f1 da 60 de 84 |...x=...4r)..`..| -00000110 aa fc d3 0f 2b 1e 1a 9c 7c af 6f 6a 4c cc 88 36 |....+...|.ojL..6| -00000120 03 03 34 79 f9 89 6d 41 bb 19 61 6a 60 75 d7 0f |..4y..mA..aj`u..| -00000130 dc 22 7a e4 36 91 32 2b 99 24 36 19 4b 4c c4 ae |."z.6.2+.$6.KL..| -00000140 4f 98 6d f0 97 ce bc b4 ee 97 30 97 0b 54 8c 14 |O.m.......0..T..| -00000150 8f d5 9d 44 ae 0a a6 07 9f 39 f6 66 80 cb fa 27 |...D.....9.f...'| -00000160 bb 2f 26 bb c3 1a a4 9b a0 d3 e8 75 13 49 da 0a |./&........u.I..| -00000170 8f cc e8 15 77 f8 05 c2 17 a0 ff e7 2a 59 bc c8 |....w.......*Y..| -00000180 67 b5 7e b8 78 1e 32 81 22 3e 57 28 ee 51 96 b7 |g.~.x.2.">W(.Q..| -00000190 0e dc 3f d1 00 16 a5 eb 01 cb c3 e3 5b 01 ad a9 |..?.........[...| -000001a0 d5 1b ac 9b e2 0d 9a 6f 7a 2f f1 7d 05 57 6d 2d |.......oz/.}.Wm-| -000001b0 9d 35 68 88 e7 c5 e0 fb 9d 87 a7 ef 71 d8 47 b8 |.5h.........q.G.| -000001c0 19 8e 87 d8 b1 36 0f 52 ab 98 8b 97 43 53 86 be |.....6.R....CS..| -000001d0 9d 86 2a cd 7c b0 46 c4 48 89 5b 6c 1e 93 9e a2 |..*.|.F.H.[l....| -000001e0 15 af 60 8f 84 75 99 97 53 11 23 f9 0d ba 78 12 |..`..u..S.#...x.| -000001f0 9b a9 04 91 d0 3a b3 4d 7b 67 a0 fa 78 5c 19 d6 |.....:.M{g..x\..| -00000200 88 d2 21 f6 8d e4 91 d1 76 95 67 9d 4e 3b a1 d2 |..!.....v.g.N;..| -00000210 61 c3 d2 a6 53 fd 82 93 20 7e f6 07 a0 49 3a ea |a...S... ~...I:.| -00000220 bc 73 03 0b f2 df 51 ac 35 d8 e4 35 9d 13 56 b5 |.s....Q.5..5..V.| -00000230 be fc 7c 36 8b 37 a0 71 57 62 bd 89 38 18 90 1e |..|6.7.qWb..8...| -00000240 7a 1f b3 8f 73 55 32 94 5a 3a 31 91 b3 95 bd 61 |z...sU2.Z:1....a| -00000250 ea 93 9d f0 38 33 fb 5b 28 3d a7 29 a4 91 de 85 |....83.[(=.)....| -00000260 9c 16 63 10 81 c6 e0 11 92 3d 53 db 69 95 16 03 |..c......=S.i...| -00000270 03 00 35 f7 3a b7 d1 20 aa f7 ed b1 c7 46 52 cb |..5.:.. .....FR.| -00000280 6e dd e2 f4 ae 83 20 cd 6c 59 b5 26 f9 81 7e 6c |n..... .lY.&..~l| -00000290 ed e9 0b 2a f1 3a dc f8 d6 ed e5 6d 89 14 3d 79 |...*.:.....m..=y| -000002a0 e7 c8 af 89 30 eb 98 3d 16 03 03 00 98 a0 59 2f |....0..=......Y/| -000002b0 cd d9 f6 63 e3 53 47 77 e5 c4 fc 2e 12 d7 24 8a |...c.SGw......$.| -000002c0 4c c7 d8 c9 77 4f bc 3c af 93 6f 57 3d 6f 5d 1c |L...wO.<..oW=o].| -000002d0 6a 5a 2c 42 1c e0 92 d5 5e 34 c8 a5 9e 11 21 16 |jZ,B....^4....!.| -000002e0 01 1a 08 af 4e f6 a1 e3 19 a6 81 41 3d 7a f3 d1 |....N......A=z..| -000002f0 e0 9e 55 90 42 4b d9 5c 46 b7 eb c8 fb 83 1c 97 |..U.BK.\F.......| -00000300 9e d9 74 bb 7f 2f 4d 61 89 46 db 32 da 1a 76 95 |..t../Ma.F.2..v.| -00000310 88 f8 ca 62 14 88 dc 97 b8 58 82 74 16 78 be c5 |...b.....X.t.x..| -00000320 f9 78 a4 88 c1 d4 6b 36 6e 54 60 a5 21 30 47 07 |.x....k6nT`.!0G.| -00000330 e8 2d 22 ce a5 17 fb 43 10 9d 74 c9 64 a3 db ac |.-"....C..t.d...| -00000340 d9 24 7a a7 5d 14 03 03 00 11 68 20 87 e9 9b 91 |.$z.].....h ....| -00000350 81 67 2b 31 c4 47 e8 9b 2e 7c c4 16 03 03 00 20 |.g+1.G...|..... | -00000360 ef 6f 3d 0f 23 fa 77 8c a9 46 d9 0d b0 d9 f8 16 |.o=.#.w..F......| -00000370 62 e2 07 21 ec b6 a7 78 ce a6 ea b3 68 c1 c7 af |b..!...x....h...| +00000000 16 03 03 00 35 77 aa f6 e5 92 a0 83 9f b7 0e e3 |....5w..........| +00000010 d2 ae 3e 72 3d 67 59 0a 67 04 10 3c 44 9c 6f 8e |..>r=gY.g..>> Flow 14 (server to client) -00000000 14 03 03 00 11 bb 45 96 9e 08 cb e4 24 c2 e3 71 |......E.....$..q| -00000010 40 d1 ef a1 5e 2f 16 03 03 00 20 1b 3f 69 fb ae |@...^/.... .?i..| -00000020 cd 98 15 59 16 14 cf a5 16 af 36 6d 6d 3a 49 06 |...Y......6mm:I.| -00000030 a6 f9 cf 53 ea 9a b7 3b 48 d2 e3 17 03 03 00 19 |...S...;H.......| -00000040 72 2c 82 a0 8c 6c 8b c3 78 e4 41 1b ff ba 92 6d |r,...l..x.A....m| -00000050 3c 4d 9c c3 95 e3 27 b9 82 |>> Flow 15 (client to server) -00000000 15 03 03 00 12 3d f9 72 53 84 b5 a4 ec 27 39 cc |.....=.rS....'9.| -00000010 72 29 c0 e6 37 7b 0f |r)..7{.| +00000000 15 03 03 00 12 45 0b 80 2d f1 c6 08 39 3c 70 07 |.....E..-...9>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 75 f6 1b 17 2f |....Y...U..u.../| -00000010 e0 d4 19 06 0d 93 90 51 46 d9 c3 a0 cd 45 6c 85 |.......QF....El.| -00000020 94 87 01 21 3e 92 62 1d e7 d1 39 20 07 26 a1 5b |...!>.b...9 .&.[| -00000030 d2 4a 61 40 ba 58 c0 23 0c 3f c3 08 5d 28 04 94 |.Ja@.X.#.?..](..| -00000040 a9 34 37 28 64 75 6f 9c ae fa 1f 24 cc a8 00 00 |.47(duo....$....| +00000000 16 03 03 00 59 02 00 00 55 03 03 15 c2 a7 b9 2f |....Y...U....../| +00000010 c7 f0 d8 ce 09 47 ff 49 c2 09 ea b1 59 ab ab cf |.....G.I....Y...| +00000020 d8 97 31 dd e6 5a 84 6e 39 af 23 20 7d 9c ed cb |..1..Z.n9.# }...| +00000030 b4 fc 4f 6b ec 07 75 b2 c4 ca 44 63 12 f5 35 95 |..Ok..u...Dc..5.| +00000040 93 c8 6e d0 59 7e 58 cb 00 05 ae d7 cc a8 00 00 |..n.Y~X.........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,181 +54,129 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 84 74 e5 bc 24 39 39 |........ .t..$99| -000002d0 e0 6e 35 fb 34 87 76 0d 78 89 35 5c 85 e7 92 da |.n5.4.v.x.5\....| -000002e0 e1 39 f4 b2 e7 ec d5 cd 58 04 01 00 80 cf 3a 57 |.9......X.....:W| -000002f0 6a 8b b7 72 d8 a2 6b 47 87 77 8b 7a bf 63 6c e8 |j..r..kG.w.z.cl.| -00000300 d4 20 6a 6a 9c 62 b6 ef 4b 9f a7 89 8c a6 fd 02 |. jj.b..K.......| -00000310 92 2f 8d 07 44 09 f6 d9 03 99 39 49 1d 8d 1b 7f |./..D.....9I....| -00000320 eb eb 4b a6 fb 9f 83 3b 3d d3 61 3e e4 d3 22 24 |..K....;=.a>.."$| -00000330 c1 44 76 e8 75 c7 aa 31 96 e3 50 bb 76 3e 87 02 |.Dv.u..1..P.v>..| -00000340 b9 1d 82 dd 55 ee 05 b9 b5 1e 65 90 2c 50 c9 87 |....U.....e.,P..| -00000350 49 dd 35 c8 84 67 6e 52 3a 3b ec 3c 63 f4 0f 95 |I.5..gnR:;.>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 3e a2 12 3b a4 83 4a c2 0e 93 d5 |.... >..;..J....| -00000040 98 d5 2e 11 9e 60 60 23 78 5a 63 49 f1 7a ee c4 |.....``#xZcI.z..| -00000050 47 00 6c 4e fb |G.lN.| +00000030 16 03 03 00 20 1d 93 0e bd 9d 79 c8 be 62 9e c3 |.... .....y..b..| +00000040 5b 6d 1e e7 3a d1 35 32 1b 20 3b 66 70 71 95 f4 |[m..:.52. ;fpq..| +00000050 88 58 6d b8 f1 |.Xm..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 6d 78 5b 5f 1b |.......... mx[_.| -00000010 2c 05 ba 92 46 e2 f0 04 48 fa a1 da be 93 ed fd |,...F...H.......| -00000020 f5 f8 b8 dd 00 60 09 a6 36 3c c4 |.....`..6<.| +00000000 14 03 03 00 01 01 16 03 03 00 20 76 95 22 fc b0 |.......... v."..| +00000010 06 76 53 a8 f5 41 60 39 2b 22 ce 5e d9 d1 1b 6a |.vS..A`9+".^...j| +00000020 36 cc a2 3a 59 a0 a1 51 48 db d3 |6..:Y..QH..| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 a4 db 13 bc c1 6e 06 9e 6d 1a c9 |..........n..m..| -00000010 85 a7 e9 28 b8 27 74 19 8f 1a bc |...(.'t....| +00000000 17 03 03 00 16 67 62 ca a7 ec ee 51 18 ad 90 65 |.....gb....Q...e| +00000010 fc 87 10 13 5c 2d 66 6f e2 5b d6 |....\-fo.[.| >>> Flow 6 (server to client) -00000000 16 03 03 00 14 fa a3 77 3c 76 11 5d be 12 4f 6a |.......w>> Flow 7 (client to server) -00000000 16 03 03 00 ad 59 80 a4 91 95 56 2a 01 ee 04 84 |.....Y....V*....| -00000010 f9 d2 dd a5 2c a6 46 a8 69 a3 c7 47 7e eb 54 da |....,.F.i..G~.T.| -00000020 ec cc 9d aa e1 0a b1 7c e9 cf 9f c9 c8 12 62 35 |.......|......b5| -00000030 d2 4a eb 28 0d 9b aa a4 d5 79 66 f7 72 4c 26 10 |.J.(.....yf.rL&.| -00000040 b6 71 db 4a 68 8b 47 f9 47 e3 6d a6 4e 99 d5 0b |.q.Jh.G.G.m.N...| -00000050 27 b2 2c 23 9b 58 60 8a 37 a1 8e 26 09 26 2a 46 |'.,#.X`.7..&.&*F| -00000060 e6 24 7f 9b cb 6b d1 9d b1 c0 48 c9 50 8b ab 06 |.$...k....H.P...| -00000070 05 57 ef 1a e0 bd ce db ca 3d e1 59 df 24 4c 02 |.W.......=.Y.$L.| -00000080 bf 1b 9e 48 52 42 6c dd 8f fa 82 68 56 52 a6 be |...HRBl....hVR..| -00000090 d0 93 cb 43 74 e1 2f 86 cc e1 4c fa ba fc 1d f0 |...Ct./...L.....| -000000a0 d5 20 3a 79 b3 b8 b7 24 b5 cf 4c dd a5 d0 4d 18 |. :y...$..L...M.| -000000b0 15 55 |.U| +00000000 16 03 03 00 b1 92 1a 73 ea 30 62 10 b9 c7 83 ec |.......s.0b.....| +00000010 55 24 17 f7 ba a1 3a 13 5f cb 8b ff 64 79 5e 5b |U$....:._...dy^[| +00000020 6c 34 7b c8 0b 38 92 b6 14 7f fd 35 be ba 72 2d |l4{..8.....5..r-| +00000030 bd 78 e3 f6 bc 61 ba 65 83 a6 6a 5e cd 1f 34 ab |.x...a.e..j^..4.| +00000040 5d 84 58 03 06 a0 4d 32 a0 a9 42 92 8f d4 27 3d |].X...M2..B...'=| +00000050 e8 a5 75 9b b7 06 c2 3b 4f 8e 83 10 be 12 4f ea |..u....;O.....O.| +00000060 d1 e7 37 9c 29 dc a9 0f aa f6 a1 0c 1c 3b 19 67 |..7.)........;.g| +00000070 b1 7c 41 9a fd b8 dd 86 92 49 4f 7e 23 75 df 82 |.|A......IO~#u..| +00000080 d0 ca 43 94 61 a8 d4 1f 3f 15 69 b0 6c bf f7 15 |..C.a...?.i.l...| +00000090 1c 8d dc 61 11 73 3c 5e b0 bd 23 a9 3d fb ed 1d |...a.s<^..#.=...| +000000a0 d5 3d 6d de b7 29 fe 85 0d af 85 6c 8a 32 90 09 |.=m..).....l.2..| +000000b0 87 c2 a2 4f f9 9b |...O..| >>> Flow 8 (server to client) -00000000 16 03 03 00 81 10 b8 d9 9a 82 21 14 86 6d ef e4 |..........!..m..| -00000010 b6 bc 10 84 80 a6 72 7b dc 24 ba e1 e5 d2 bb d2 |......r{.$......| -00000020 9f 09 d3 d7 37 20 ec 7d bd 13 e0 bd 40 44 8a 6e |....7 .}....@D.n| -00000030 7f f6 d5 42 03 4b 00 b5 87 99 ac 6d 11 03 38 46 |...B.K.....m..8F| -00000040 33 71 c4 10 ce da 36 d6 c1 41 9f 96 8e eb 4b 99 |3q....6..A....K.| -00000050 24 07 8c 6b 88 2c f1 dd 31 35 ba 43 0f 60 bf b0 |$..k.,..15.C.`..| -00000060 74 77 a9 d4 a7 65 f6 68 e2 70 4a 7e fe db ab 13 |tw...e.h.pJ~....| -00000070 7f 51 c3 0f b4 93 42 12 d6 29 5d 44 5c df 17 6e |.Q....B..)]D\..n| -00000080 73 1d b8 95 fc 8b 16 03 03 02 69 64 5d 4f b4 3a |s.........id]O.:| -00000090 23 98 07 51 63 18 09 07 9a 8c dd 8e 51 a8 ca 23 |#..Qc.......Q..#| -000000a0 37 21 f4 d5 e0 8f 03 1c 6f 6d c4 60 dd 99 8f 4b |7!......om.`...K| -000000b0 4c 11 f7 78 f8 aa f6 29 87 cf 4d ba 89 87 2a c9 |L..x...)..M...*.| -000000c0 48 66 48 d3 a6 19 8a 84 f6 db 17 b4 59 5b e4 8e |HfH.........Y[..| -000000d0 8e ef fc 32 10 aa 0d 57 47 68 82 07 72 95 03 f6 |...2...WGh..r...| -000000e0 e5 c1 c3 01 00 f9 85 4f 0f 85 37 73 f7 c5 af a2 |.......O..7s....| -000000f0 37 96 ba 06 49 6a 2d a2 23 39 2e 9b f1 fc 01 de |7...Ij-.#9......| -00000100 53 75 ee 34 ae 27 ea 49 6a d8 d0 cd 9b e8 60 b7 |Su.4.'.Ij.....`.| -00000110 f6 b1 8e 26 ec 6c 36 87 d6 70 49 07 e0 96 2a bd |...&.l6..pI...*.| -00000120 45 a3 b1 f5 dc b0 a3 4f dc d8 c3 fd 4f fb 98 13 |E......O....O...| -00000130 67 55 99 39 b5 16 19 72 9d f1 5a cf 6e 53 d9 03 |gU.9...r..Z.nS..| -00000140 05 f5 81 07 a1 38 a1 e5 4c 76 51 1a ae f6 4b f6 |.....8..LvQ...K.| -00000150 b2 a7 84 1e 2a 31 b0 b8 9f 41 e8 e5 32 18 44 4c |....*1...A..2.DL| -00000160 0b fb e3 d9 4c dd 45 c5 c4 c4 57 bf f7 5a dc f6 |....L.E...W..Z..| -00000170 73 98 d4 ea 2f c0 cb 35 97 c1 45 94 37 87 d3 8c |s.../..5..E.7...| -00000180 65 3f ee a8 67 a6 00 80 92 02 76 e8 0a 04 ce 7a |e?..g.....v....z| -00000190 79 4f cd 70 1a 31 5a 03 83 01 de 1f 4a 46 39 4e |yO.p.1Z.....JF9N| -000001a0 d0 80 6e 67 d7 e6 fc ba 74 4b 57 d2 3c 19 7b 03 |..ng....tKW.<.{.| -000001b0 ab 9a e2 f7 db 58 c2 b7 58 96 55 88 e6 e2 e2 f8 |.....X..X.U.....| -000001c0 ab e9 b0 12 ef ff e6 53 7b 4e 01 2f 65 0d 05 f0 |.......S{N./e...| -000001d0 95 9f 46 d2 ae e7 33 5c 37 56 ab 67 95 87 81 59 |..F...3\7V.g...Y| -000001e0 f2 35 76 78 ed 13 63 a3 58 52 af 46 e6 aa c3 99 |.5vx..c.XR.F....| -000001f0 37 9d 10 25 cc 7f 7e 63 e1 96 6d 7a 8e ac 9e 00 |7..%..~c..mz....| -00000200 d1 0e 7a 48 b6 82 77 6a a0 17 d1 77 70 f8 40 4a |..zH..wj...wp.@J| -00000210 c4 90 da b0 3f 25 68 f5 9f dd 5e ec 95 02 19 53 |....?%h...^....S| -00000220 08 6a 13 11 88 9e 2b 25 b8 28 cd 58 36 d7 d3 95 |.j....+%.(.X6...| -00000230 f5 91 63 92 ff 3b d2 4f 75 ae 47 6c 64 8a a4 76 |..c..;.Ou.Gld..v| -00000240 48 96 a7 35 d6 35 22 96 4d 4f ee 45 fb 88 52 68 |H..5.5".MO.E..Rh| -00000250 4e 38 93 e8 08 6a e6 f3 00 a7 f7 b0 0b 68 41 ab |N8...j.......hA.| -00000260 9b 3a 92 2b fd b2 71 14 77 91 48 e7 70 62 b5 b0 |.:.+..q.w.H.pb..| -00000270 45 90 35 d2 b3 22 f5 70 6c 62 7f 55 6b 56 42 f8 |E.5..".plb.UkVB.| -00000280 6c 87 a7 60 45 37 f0 41 41 ec 73 f5 f1 d9 d2 84 |l..`E7.AA.s.....| -00000290 bd 88 bc 9b 43 ec 8b b3 c4 3a 59 2c 30 61 30 98 |....C....:Y,0a0.| -000002a0 78 d3 e7 85 dd 7e 80 b8 fb b3 bf 7e 11 79 e8 20 |x....~.....~.y. | -000002b0 aa b8 81 94 10 5c f8 ba 70 4c 1e 7c 35 8f 48 30 |.....\..pL.|5.H0| -000002c0 17 38 d6 1c 91 ed 00 2c f7 af 29 d3 cb 9b ab 6b |.8.....,..)....k| -000002d0 b3 fa 6e 1a 9b a8 cf 08 8e 03 a5 f7 76 17 74 3a |..n.........v.t:| -000002e0 9e 36 ae 19 fd 2c 44 14 f3 2b 1d 01 db e1 96 22 |.6...,D..+....."| -000002f0 25 14 5b d8 16 03 03 00 bc bb 8c bb cf f9 d7 76 |%.[............v| -00000300 7a a7 d6 e0 29 cb 45 21 8d 57 0b 81 0c e0 96 05 |z...).E!.W......| -00000310 c7 96 67 43 0f 41 11 e9 c2 07 2d 62 17 b4 64 01 |..gC.A....-b..d.| -00000320 c5 75 79 dc 9c 36 3f ea 42 ea 09 a7 bc 0f 6b b1 |.uy..6?.B.....k.| -00000330 b4 4d ae 38 0a ca 51 d0 97 46 b6 55 12 7c 24 28 |.M.8..Q..F.U.|$(| -00000340 77 16 64 42 53 70 c4 52 ed e5 aa 20 3a 00 7e d0 |w.dBSp.R... :.~.| -00000350 9e 99 e4 56 5f ef 30 56 00 8b e7 31 6d 66 6d dc |...V_.0V...1mfm.| -00000360 58 8a b0 60 6f 16 a7 b0 14 a5 9d 3d 38 94 6e 16 |X..`o......=8.n.| -00000370 a3 22 76 e9 59 d8 90 cd 32 83 bb 8c c5 23 cb c2 |."v.Y...2....#..| -00000380 c5 03 02 de 13 97 ac 4e 99 9f 4d 6d aa ed 72 b7 |.......N..Mm..r.| -00000390 76 db 8b c9 31 17 b9 1c 4a fa 87 2c 6b dc 07 82 |v...1...J..,k...| -000003a0 a2 39 e0 09 32 a2 8e 1c 6e 68 e1 14 ba ab 3a d4 |.9..2...nh....:.| -000003b0 1e 4f f4 39 c7 16 03 03 00 3a cf b2 61 5f 7e ef |.O.9.....:..a_~.| -000003c0 04 51 64 f6 3d b3 54 44 bd 8a d0 87 48 64 76 a6 |.Qd.=.TD....Hdv.| -000003d0 0d bc 7f b7 99 d4 67 8b cd e3 c4 5d df c5 c8 fc |......g....]....| -000003e0 be d1 c4 03 6d 61 2d 10 58 b1 7a 7c 9e 1c 6b 16 |....ma-.X.z|..k.| -000003f0 ff 31 a8 87 16 03 03 00 14 85 99 57 4b a1 19 33 |.1.........WK..3| -00000400 bd 9a 86 ed be 5d 24 f0 02 9d ca 1e 26 |.....]$.....&| +00000000 16 03 03 00 81 69 80 3b d5 74 82 55 ad c5 6d 92 |.....i.;.t.U..m.| +00000010 5c d6 02 a0 5a e5 c7 a9 64 94 20 5f b4 03 7d 25 |\...Z...d. _..}%| +00000020 aa 6b de 09 09 cb 92 a1 73 fa 58 bc 02 a2 01 d4 |.k......s.X.....| +00000030 e6 c6 56 42 4e 8e c5 09 de 2d e1 6a 96 9e 1a b4 |..VBN....-.j....| +00000040 1f 73 44 f2 20 07 3d 99 5f 8e 6e 76 ba 6f 8f d5 |.sD. .=._.nv.o..| +00000050 a1 f9 78 22 9d 84 b3 b1 9c 91 88 3c a7 0f d4 64 |..x".......<...d| +00000060 6d 6e 16 54 b4 1c 38 07 3c 56 b7 67 b5 ab d7 79 |mn.T..8......| +00000230 7b 65 85 82 ba 23 3d 78 22 17 d0 03 02 a0 04 1d |{e...#=x".......| +00000240 e5 b0 be d7 4d a4 6e 40 83 b2 ae ee b9 c3 18 ce |....M.n@........| +00000250 45 7d d8 2e 6d d1 92 7d 60 bd 44 dd 29 11 cd 7d |E}..m..}`.D.)..}| +00000260 13 2f a2 97 b1 ca 6a 76 e0 88 fd 6a b4 cc f3 f1 |./....jv...j....| +00000270 63 4b 4a 74 cb c6 49 ba 82 2b 29 22 0e a0 23 78 |cKJt..I..+)"..#x| +00000280 ad 25 59 85 a8 b2 6e d3 34 1f 31 ff 94 ac 3b 42 |.%Y...n.4.1...;B| +00000290 84 97 17 8a 21 1d 3f 7c e5 ac 17 50 d9 77 a9 54 |....!.?|...P.w.T| +000002a0 2f bd 19 3b b9 de 90 64 8a 02 46 bf 7e 02 ac 60 |/..;...d..F.~..`| +000002b0 55 0c 6f c3 58 04 3a a7 fd e9 26 26 41 a1 8f 43 |U.o.X.:...&&A..C| +000002c0 7a 9e dd a6 1a 7f cf 1d 0c 40 11 59 4f 36 bc e1 |z........@.YO6..| +000002d0 63 20 0b ef 3c e7 de 25 e2 e0 d2 4d 42 62 84 97 |c ..<..%...MBb..| +000002e0 23 64 b2 b5 22 e4 8f f5 b2 1f 9e 99 00 e5 27 f6 |#d..".........'.| +000002f0 02 b9 b3 d0 16 03 03 00 bc 9c 9e 74 fe d3 9f c5 |...........t....| +00000300 50 2a 35 af 0d 27 96 94 a0 0a b4 79 f5 ca 9e 30 |P*5..'.....y...0| +00000310 8c 03 87 75 9c ac 63 a4 96 a5 d8 05 ef cd d5 1a |...u..c.........| +00000320 13 24 81 a7 84 aa 69 a2 e4 a4 13 85 25 c0 ca c8 |.$....i.....%...| +00000330 ec 8f 27 68 77 12 78 bc 98 b2 4e 8b b4 ae c8 47 |..'hw.x...N....G| +00000340 53 b8 7f d6 cf f0 9a 1e 65 33 b0 77 11 9e f4 72 |S.......e3.w...r| +00000350 57 f5 c4 55 06 07 1f a7 3e 3e 31 ce 52 97 58 0c |W..U....>>1.R.X.| +00000360 23 6e 3c 4c b6 a7 f5 c5 ec 3a fa 96 a4 f6 ee 0d |#n>> Flow 9 (client to server) -00000000 16 03 03 02 69 8c c7 01 da 38 a5 36 3d 2c 21 1c |....i....8.6=,!.| -00000010 64 1b b8 e7 c2 cd 17 06 b6 51 0e e6 d9 d9 18 c5 |d........Q......| -00000020 a9 c9 ac 5d 2d 23 f8 15 92 b2 e1 62 6e d7 8d 58 |...]-#.....bn..X| -00000030 5b d9 b8 26 e5 ec 0f 61 15 3e 12 70 89 0d 3f 4e |[..&...a.>.p..?N| -00000040 e3 2e 18 42 7c c7 59 7b e1 48 d9 a8 cf b1 cd 38 |...B|.Y{.H.....8| -00000050 17 90 97 89 2e 4f 4b df 58 b0 9f 4e 95 d2 e9 70 |.....OK.X..N...p| -00000060 6d 0b 82 af b7 05 be 11 26 d8 f9 89 e6 d6 44 f5 |m.......&.....D.| -00000070 db 7c 8c 91 61 78 dc 68 98 9b 10 17 5b 85 42 93 |.|..ax.h....[.B.| -00000080 31 a2 16 97 72 c5 f2 d0 81 76 a6 9b b7 9c 14 ab |1...r....v......| -00000090 a7 bf 19 f7 34 e3 8f 3f a5 aa 23 c8 49 07 1b 6f |....4..?..#.I..o| -000000a0 e5 5d 65 66 a1 dc d2 e7 bb c2 4b 9e a7 9a dc d6 |.]ef......K.....| -000000b0 72 42 d3 71 d3 51 a4 3a 82 f7 cd 2a 15 34 da 6d |rB.q.Q.:...*.4.m| -000000c0 44 3a a9 7d 6e 4c ce a5 ba 6b 5b 3b 88 8c e1 29 |D:.}nL...k[;...)| -000000d0 ee a8 17 1b 02 36 8f 68 c9 9e e6 f1 bf e3 e3 e0 |.....6.h........| -000000e0 cd 6d 7f ff c2 4d 3f 88 c7 9b 75 20 e5 cd fa fa |.m...M?...u ....| -000000f0 a0 d7 10 6a c1 00 73 f9 df bd 22 60 8c 82 71 e6 |...j..s..."`..q.| -00000100 56 aa 90 bf c7 a8 82 51 e7 23 42 ec 99 f5 b9 aa |V......Q.#B.....| -00000110 3c cc c6 32 11 29 1f a6 ae 89 03 04 e8 de 9f f4 |<..2.)..........| -00000120 bd 87 ae af 91 ee a2 f3 e2 6d 7b 87 ad 67 16 2d |.........m{..g.-| -00000130 ad 92 34 38 52 ed 7c 38 92 45 16 26 9f 65 d2 67 |..48R.|8.E.&.e.g| -00000140 3e 33 a1 bd b2 f6 d3 c8 76 96 52 11 0d 8d ac a6 |>3......v.R.....| -00000150 27 10 6a 43 63 5f 82 41 e7 fe 91 24 68 70 bd 2c |'.jCc_.A...$hp.,| -00000160 35 fd 0e 49 ec 3a dd f3 c0 af 5c f4 61 9a 2a 00 |5..I.:....\.a.*.| -00000170 59 b5 28 24 f0 cf d3 25 bc 77 65 74 04 ee 4b 5e |Y.($...%.wet..K^| -00000180 2b 9f 1d 27 e2 dd 1a ed ab e5 ff d6 1a 55 d7 4d |+..'.........U.M| -00000190 5c da 14 96 21 43 f6 c3 2d 78 e5 75 60 69 26 ce |\...!C..-x.u`i&.| -000001a0 7a 66 5e 42 91 0e ef 41 c2 c4 e6 15 8a 9a 17 a1 |zf^B...A........| -000001b0 d9 23 2c cc c7 81 00 71 b0 52 ec 4e ea eb f9 75 |.#,....q.R.N...u| -000001c0 2e 87 16 b4 ba 25 8c 09 f1 23 f9 ee ea db 0e b5 |.....%...#......| -000001d0 d0 dd 47 9b b6 06 a3 f3 5e 0d 34 5a ba 76 cd 0a |..G.....^.4Z.v..| -000001e0 b1 9f 8a 99 aa d3 02 2e b6 04 7b c5 d3 2f dc d7 |..........{../..| -000001f0 68 af 6b 88 90 0a 94 a4 29 65 0b ba b3 da f2 cd |h.k.....)e......| -00000200 51 93 4f ea b4 f8 54 c7 28 e3 2d 63 d0 62 54 d9 |Q.O...T.(.-c.bT.| -00000210 27 a0 85 57 7b a2 f2 f5 a5 25 83 1b e2 36 15 06 |'..W{....%...6..| -00000220 41 ae e1 f9 ca a5 c6 59 2d da 4a ed 10 7b 80 01 |A......Y-.J..{..| -00000230 06 39 f2 a8 4b 22 37 4d aa 84 79 85 71 29 1b 4e |.9..K"7M..y.q).N| -00000240 c3 79 af 13 f5 4e 3c 6d fa 8c d7 55 13 2b 48 3d |.y...N..0....| -000002f0 96 89 a7 0f 7c fb 96 18 84 86 e7 bd e2 35 31 0c |....|........51.| -00000300 7a 51 d7 94 6b 61 62 7a 6a d8 56 62 e6 cf bf 60 |zQ..kabzj.Vb...`| -00000310 df 7a c5 ce d3 87 ea 2f 5a ad 90 d4 39 f7 47 8e |.z...../Z...9.G.| -00000320 8b d3 6b 8e e0 3f 2f 59 71 e4 e6 bf 3f 4a 29 a8 |..k..?/Yq...?J).| -00000330 60 df 1b 5c 2d 21 ab 0a a5 9f 5a a2 a3 d6 08 3c |`..\-!....Z....<| -00000340 4a 4b f9 d6 a0 14 03 03 00 11 44 a4 62 7e c1 4a |JK........D.b~.J| -00000350 4e 56 dd 08 65 b2 ab 12 cd fa 8d 16 03 03 00 20 |NV..e.......... | -00000360 b4 52 5a e8 33 b6 23 b1 b4 e6 59 da b0 84 52 94 |.RZ.3.#...Y...R.| -00000370 70 de dc 02 f6 41 e3 27 7c 27 56 6a 7c 92 e3 48 |p....A.'|'Vj|..H| +00000000 16 03 03 00 35 01 62 fd 6b 2e 24 0f 01 03 98 44 |....5.b.k.$....D| +00000010 7a 1a 51 4c 09 f0 da 53 b7 cf 31 06 94 9d 09 bd |z.QL...S..1.....| +00000020 d2 ec 3a 20 47 1e 28 e6 d6 66 4d bb dd 2f 9d 4b |..: G.(..fM../.K| +00000030 ff e5 4e ed 84 1d 9b 0c 40 a4 14 03 03 00 11 58 |..N.....@......X| +00000040 2f a4 8e f0 38 bb f8 44 b2 e9 61 68 63 ba 8e 63 |/...8..D..ahc..c| +00000050 16 03 03 00 20 f3 0f ac 3d e2 65 c4 0e c8 b7 22 |.... ...=.e...."| +00000060 2f c9 08 d3 b1 75 e1 f8 91 ea 98 c3 9b c8 9b 21 |/....u.........!| +00000070 cb cd 35 b3 ce |..5..| >>> Flow 10 (server to client) -00000000 14 03 03 00 11 c7 92 b3 aa a0 91 21 4f 42 96 0c |...........!OB..| -00000010 3a 92 c3 53 55 d1 16 03 03 00 20 4b da e5 1c 08 |:..SU..... K....| -00000020 ce a7 33 f1 a6 c7 47 52 19 68 b4 f5 1d 66 a7 38 |..3...GR.h...f.8| -00000030 97 45 43 9f ca b5 db 2c 14 fc f4 17 03 03 00 19 |.EC....,........| -00000040 28 f4 bb bf c1 5a 2d 1e b8 fc c7 fc 55 16 e9 cc |(....Z-.....U...| -00000050 43 a3 63 58 7e 2c 60 77 23 16 03 03 00 14 2c e6 |C.cX~,`w#.....,.| -00000060 25 0a b7 26 7b 13 55 62 f1 fe 6e fe 0e 57 53 57 |%..&{.Ub..n..WSW| -00000070 19 1b |..| +00000000 14 03 03 00 11 c0 ed 05 6a 71 44 98 9a d6 b8 ae |........jqD.....| +00000010 ab 10 43 a9 27 91 16 03 03 00 20 93 fe ed 5f 3e |..C.'..... ..._>| +00000020 61 9f 10 95 c9 f6 82 c5 68 14 3d 9e 3e c3 9d e9 |a.......h.=.>...| +00000030 f2 2d a1 a5 ff ec b9 31 ae 78 e8 17 03 03 00 19 |.-.....1.x......| +00000040 27 c4 6c 54 03 88 b2 36 38 79 1f 1d 68 c2 ca fd |'.lT...68y..h...| +00000050 bf 47 67 44 e1 13 3b f2 fb 16 03 03 00 14 9d 9d |.GgD..;.........| +00000060 67 bf 0e 28 3c 56 a3 7b 49 cb 56 b5 5d 3e 39 45 |g..(9E| +00000070 c8 c5 |..| >>> Flow 11 (client to server) -00000000 15 03 03 00 12 dd 2b 00 09 fd 8c 7d 21 3d 7c 06 |......+....}!=|.| -00000010 93 ca c9 21 b2 3e 20 15 03 03 00 12 90 32 4b 3b |...!.> ......2K;| -00000020 33 4d fd 69 55 81 aa 42 16 ae 47 b9 4c 06 |3M.iU..B..G.L.| +00000000 15 03 03 00 12 00 dc 08 22 b1 d3 cc d2 f7 6b 03 |........".....k.| +00000010 92 e9 4d 62 8d 5d f6 15 03 03 00 12 ce e8 8d 1b |..Mb.]..........| +00000020 78 a3 63 10 bc 77 e8 88 1f 91 9c a5 b5 f2 |x.c..w........| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected index cb964324fd2..71d98417ce4 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 91 a6 bc 02 ab |....Y...U.......| -00000010 19 62 2c de 45 57 ba 71 c0 b0 4d 78 5e f4 c2 b9 |.b,.EW.q..Mx^...| -00000020 81 ba 8b d6 b1 9b c8 fb 0c 7c 40 20 dc 66 80 5b |.........|@ .f.[| -00000030 20 3c 60 65 7f 9e 0c 67 a8 f3 22 c9 c5 48 80 fa | <`e...g.."..H..| -00000040 02 a1 1a 48 6d 1c 46 07 db 6c 8e 85 cc a8 00 00 |...Hm.F..l......| +00000000 16 03 03 00 59 02 00 00 55 03 03 db bb 55 42 4d |....Y...U....UBM| +00000010 7e 2c 47 97 1c 97 97 e4 35 a1 a9 f4 d6 1a 2f 97 |~,G.....5...../.| +00000020 96 f7 d6 3b 7e 81 7c 96 f4 42 f8 20 b1 92 02 f0 |...;~.|..B. ....| +00000030 91 56 81 2c 4e ba e0 02 26 c7 f6 d9 0a ef e9 40 |.V.,N...&......@| +00000040 54 10 60 a4 d3 e1 b5 cf d3 ad 59 c7 cc a8 00 00 |T.`.......Y.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -54,36 +54,36 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 f5 fd 54 ea 3e bb 70 |........ ..T.>.p| -000002d0 fb 8e fb e4 8a 25 1f 9d 3d 9a fb fb 9d ff d1 52 |.....%..=......R| -000002e0 81 9d b0 ea a1 e6 b0 87 2f 04 01 00 80 77 54 16 |......../....wT.| -000002f0 98 5d 22 c4 7f 9b 2a 44 dd e4 0d 78 c2 60 6a ad |.]"...*D...x.`j.| -00000300 91 9d d9 ed 93 0b 4e b4 c6 26 f1 94 6d e0 cc f4 |......N..&..m...| -00000310 8d fa 9c ec 70 f5 5b ac 80 d7 5e 4f 49 04 bc 24 |....p.[...^OI..$| -00000320 8e 0a 7d 44 e1 7e 47 1e a8 68 d1 fe 6f 41 0d 4a |..}D.~G..h..oA.J| -00000330 e5 5b f6 f6 a3 af 76 21 56 1a 25 d2 03 3c f4 dd |.[....v!V.%..<..| -00000340 0c 13 ce 56 8a 61 6f 5b 8c a1 04 43 82 87 64 20 |...V.ao[...C..d | -00000350 4a 3b ec 90 d7 59 aa ca 08 3a 39 57 f1 56 57 6a |J;...Y...:9W.VWj| -00000360 18 c9 14 7f e3 8d 83 0f e2 0b 4d 24 01 16 03 03 |..........M$....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 7c 4a f0 08 30 5f 04 |........ |J..0_.| +000002d0 46 3d 38 6c 55 57 44 82 a5 98 a1 fd 60 26 ce 03 |F=8lUWD.....`&..| +000002e0 cd 93 14 0a 0b 69 02 bf 03 04 01 00 80 c6 a5 05 |.....i..........| +000002f0 fa 60 d4 cb 47 ad 03 16 04 bf a7 43 7c 84 54 b3 |.`..G......C|.T.| +00000300 29 dc 73 29 d2 43 29 90 3b 1f ff dd da 8b 56 06 |).s).C).;.....V.| +00000310 08 9d fd 1f f6 42 7a 3e f9 ab 76 87 0b 42 e3 d8 |.....Bz>..v..B..| +00000320 29 32 55 50 d0 1a 1e 00 8e c9 83 cc 08 bc e5 39 |)2UP...........9| +00000330 9c 58 79 ab 27 5a 55 21 99 fb 2b ee 3a 3a a2 27 |.Xy.'ZU!..+.::.'| +00000340 d6 64 a7 d9 c9 c6 46 dc 03 0a 30 b4 1b 8a 61 36 |.d....F...0...a6| +00000350 b8 22 46 6a ea cc ee 30 e5 58 8e 7e 09 b2 0d 6a |."Fj...0.X.~...j| +00000360 b5 84 54 ea ab ed d5 29 1e 7e 67 17 48 16 03 03 |..T....).~g.H...| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 6b ce 5c 2f df 85 e7 5e fa 51 48 |.... k.\/...^.QH| -00000040 f9 31 a5 02 64 c7 1e b1 2e f2 6b 86 30 43 23 91 |.1..d.....k.0C#.| -00000050 76 6b 40 74 2b |vk@t+| +00000030 16 03 03 00 20 c8 0e 66 f9 0a 9c 23 fb ed 6a 04 |.... ..f...#..j.| +00000040 83 b3 72 c4 5f 7b 2f 9f 03 c9 32 d5 60 30 6d 07 |..r._{/...2.`0m.| +00000050 e7 d3 fc ed 83 |.....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 e7 1e 88 10 2d |.......... ....-| -00000010 dc 35 6d 2b 4a 91 39 5d 5c 46 ed 2e 45 6f 41 38 |.5m+J.9]\F..EoA8| -00000020 66 0f 15 58 f8 af d8 a6 6c 99 61 |f..X....l.a| +00000000 14 03 03 00 01 01 16 03 03 00 20 2e 07 51 3c b8 |.......... ..Q<.| +00000010 97 34 f5 21 da 22 b1 e9 e6 98 61 83 22 06 45 c2 |.4.!."....a.".E.| +00000020 db 60 08 27 bc 64 30 3e 1c 77 70 |.`.'.d0>.wp| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 ab 2a df 2f 3c 07 6a 24 98 55 0b |......*./<.j$.U.| -00000010 67 20 2d 92 cd 9a 44 74 da fd 6a |g -...Dt..j| +00000000 17 03 03 00 16 89 dc 04 82 f8 16 f2 0d 91 53 80 |..............S.| +00000010 7a a7 7b 43 66 f4 95 b3 c2 db ec |z.{Cf......| >>> Flow 6 (server to client) -00000000 16 03 03 00 14 d6 fb e7 9a 76 2a 6f e1 e9 33 1a |.........v*o..3.| -00000010 77 07 fd 7f 98 af 1e 04 43 |w.......C| +00000000 16 03 03 00 14 c7 99 03 a6 e5 88 0c f4 31 22 67 |.............1"g| +00000010 ee 08 ff ff df d8 5d 63 ad |......]c.| >>> Flow 7 (client to server) -00000000 15 03 03 00 12 7e e3 20 96 03 31 8c 6a 31 f8 62 |.....~. ..1.j1.b| -00000010 02 a7 a4 ce 77 83 c1 15 03 03 00 12 b9 91 75 45 |....w.........uE| -00000020 a5 4a f9 c6 6d b2 5c c3 0a 1a 26 63 00 04 |.J..m.\...&c..| +00000000 15 03 03 00 12 ea 8d 5d 03 03 80 85 91 ca cf 7e |.......].......~| +00000010 10 53 60 44 f6 86 3d 15 03 03 00 12 96 b9 d3 2b |.S`D..=........+| +00000020 c9 d0 bd 38 c3 4d 32 10 4c e9 c4 9a b3 01 |...8.M2.L.....| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT index a0f6a090af2..e081554833b 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT @@ -1,20 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| 00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| -00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| -00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| -00000090 01 00 00 12 00 00 |......| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 01 c6 02 00 01 c2 03 03 08 db 5c c4 da |.............\..| -00000010 fe 2c a2 21 0d c4 9e c4 14 b9 e3 15 d7 c5 2c 84 |.,.!..........,.| -00000020 f2 b8 0e 32 67 9e 72 08 9c 17 6b 20 86 09 60 52 |...2g.r...k ..`R| -00000030 9d 53 ba c8 8a c3 1a 11 c0 e5 c6 a0 59 49 ed cb |.S..........YI..| -00000040 e0 6f 0a 56 e9 4f bf 02 2f 23 10 b8 cc a8 00 01 |.o.V.O../#......| +00000000 16 03 03 01 c6 02 00 01 c2 03 03 7c 81 f9 b1 c8 |...........|....| +00000010 a6 92 26 e6 ef 52 6b 33 51 64 e1 e8 77 73 c2 c6 |..&..Rk3Qd..ws..| +00000020 9a 7c 38 c8 df 43 8e da 8c ea 21 20 6b ea 4c 41 |.|8..C....! k.LA| +00000030 1e 3d d0 b9 e9 d8 e9 0b 12 e1 a2 82 b7 69 0a d7 |.=...........i..| +00000040 42 57 8e 24 62 77 3d e0 af 5b 97 2c cc a8 00 01 |BW.$bw=..[.,....| 00000050 7a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 12 |z...............| 00000060 01 69 01 67 00 75 00 a4 b9 09 90 b4 18 58 14 87 |.i.g.u.......X..| 00000070 bb 13 a2 cc 67 70 0a 3c 35 98 04 f9 1b df b8 e3 |....gp.<5.......| @@ -77,31 +77,31 @@ 00000400 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F| 00000410 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.| 00000420 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........| -00000430 00 a8 03 00 1d 20 27 94 d8 62 00 f3 3f 21 e6 e1 |..... '..b..?!..| -00000440 0f 1f 2d 9b 37 4d cf 72 34 48 72 2e 85 46 dd b6 |..-.7M.r4Hr..F..| -00000450 32 23 64 b3 4b 63 04 01 00 80 82 34 e5 7f 70 51 |2#d.Kc.....4..pQ| -00000460 42 3b ab 51 61 73 1f 2c 64 04 1d 66 96 ff f9 95 |B;.Qas.,d..f....| -00000470 86 09 a8 75 11 16 34 05 17 fb 96 9c fb 78 40 4c |...u..4......x@L| -00000480 10 5b ee 0d 31 a0 77 32 a8 0f 19 ef a4 30 cd 08 |.[..1.w2.....0..| -00000490 cb f5 ec 36 fa 24 0a ca 0b d8 16 02 d1 34 86 a7 |...6.$.......4..| -000004a0 f8 e3 cb e6 62 1c cd 40 d6 4f 0c 2f 5b 66 12 6f |....b..@.O./[f.o| -000004b0 8a 2f c4 ef ac 46 86 44 90 e0 65 38 94 4d 5e df |./...F.D..e8.M^.| -000004c0 51 a3 40 6e 64 b6 00 6b 88 97 7b 43 78 d9 df 70 |Q.@nd..k..{Cx..p| -000004d0 fe 66 66 56 82 14 ed ab 08 cd 16 03 03 00 04 0e |.ffV............| +00000430 00 a8 03 00 1d 20 46 5e b3 7c 5b 77 d3 2d ff 1a |..... F^.|[w.-..| +00000440 60 d8 56 9b c8 f0 fa 09 ec 33 89 08 8f 9e 54 86 |`.V......3....T.| +00000450 7e 5d 72 e5 3d 37 04 01 00 80 6e e6 45 b9 1d b5 |~]r.=7....n.E...| +00000460 03 a5 d6 ec 37 ca 35 a1 b0 e9 3f b5 b8 2f 65 d2 |....7.5...?../e.| +00000470 f6 8e 28 e8 23 76 23 f7 26 b6 96 64 89 bb ab 88 |..(.#v#.&..d....| +00000480 4b c5 9a b0 f5 df f2 44 19 15 25 67 5e 66 8c f7 |K......D..%g^f..| +00000490 3d 9a 6a 2a c7 1d 85 d3 7c 2e 5e 9c 9d ca 87 c3 |=.j*....|.^.....| +000004a0 ee 12 ec bd ba 19 fd bc 86 0e d7 8e d2 6a 90 f6 |.............j..| +000004b0 bf bb 15 ab 2e 6b 6a 4d 6f 59 dd c9 ca 40 f5 60 |.....kjMoY...@.`| +000004c0 b0 ab 47 2a 6e ee 1b 20 d8 ca c4 8c 8b f3 51 65 |..G*n.. ......Qe| +000004d0 18 25 41 d3 1f 4e 6b fe ef 10 16 03 03 00 04 0e |.%A..Nk.........| 000004e0 00 00 00 |...| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 20 7a 58 e1 33 d4 ce ca 57 ef ea b9 |.... zX.3...W...| -00000040 9d f2 4d ec ce 86 4b e9 c2 b5 64 dd 0f 32 f0 66 |..M...K...d..2.f| -00000050 65 42 74 d8 59 |eBt.Y| +00000030 16 03 03 00 20 5f a3 77 a5 b0 8f 47 73 4c a9 1d |.... _.w...GsL..| +00000040 84 17 76 fe a5 17 6e c8 cd a4 dc 47 e5 76 23 2f |..v...n....G.v#/| +00000050 18 8b 59 41 12 |..YA.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 20 27 df 9b 14 a1 |.......... '....| -00000010 cd a5 83 5b 6b 30 60 a3 ae 8d 64 56 fe 8e 87 a2 |...[k0`...dV....| -00000020 ff 1b 54 72 c8 7c b2 85 9d 8a de |..Tr.|.....| +00000000 14 03 03 00 01 01 16 03 03 00 20 3e 65 a2 34 77 |.......... >e.4w| +00000010 84 52 61 db 52 89 e8 f0 27 f3 ab 70 17 38 1f 37 |.Ra.R...'..p.8.7| +00000020 17 ad d8 56 23 32 2d 2d e2 b3 d0 |...V#2--...| >>> Flow 5 (client to server) -00000000 17 03 03 00 16 c7 bf a9 7a 72 07 27 88 9a ec 1b |........zr.'....| -00000010 d3 44 f2 20 88 e4 c2 8b 61 86 5c 15 03 03 00 12 |.D. ....a.\.....| -00000020 35 ab f5 f6 92 f9 db 23 bf f1 8e e8 65 62 cf 48 |5......#....eb.H| -00000030 91 9d |..| +00000000 17 03 03 00 16 92 d2 88 0c 8a ac 62 fe fd d5 d4 |...........b....| +00000010 fd 98 b2 60 02 97 a2 80 d7 5f f9 15 03 03 00 12 |...`....._......| +00000020 e9 3d 30 95 1b f8 fd 05 3b ba ac af f9 66 f7 ac |.=0.....;....f..| +00000030 e5 ec |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM index 90541fd16e0..7a265ea2fb8 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM @@ -1,19 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 8b 01 00 00 87 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 8f 01 00 00 8b 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| 00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| 00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| -00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 32 00 05 |.............2..| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 36 00 05 |.............6..| 00000060 00 05 01 00 00 00 00 00 0a 00 04 00 02 00 1d 00 |................| -00000070 0b 00 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 |................| -00000080 01 05 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 |................| +00000070 0b 00 02 01 00 00 0d 00 12 00 10 04 01 04 03 05 |................| +00000080 01 05 03 06 01 06 03 02 01 02 03 ff 01 00 01 00 |................| +00000090 00 12 00 00 |....| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 07 42 b0 44 05 |....Y...U...B.D.| -00000010 b1 6d 3c f0 60 fe 6a f2 1f 8f 1d 88 de 4b 6a 1b |.m<.`.j......Kj.| -00000020 4f 72 60 4d 42 a5 f7 77 eb 86 c2 20 99 35 47 07 |Or`MB..w... .5G.| -00000030 64 60 32 52 2e 1d 54 d5 b7 e2 26 85 72 c1 ec 8d |d`2R..T...&.r...| -00000040 fb 59 86 91 46 7d ad 16 bd b7 38 94 c0 2f 00 00 |.Y..F}....8../..| +00000000 16 03 03 00 59 02 00 00 55 03 03 ff 52 25 9b 48 |....Y...U...R%.H| +00000010 77 0c cd cf 49 c4 b4 5e 02 32 d4 56 99 d0 ce ad |w...I..^.2.V....| +00000020 d4 9d 8b e9 ae 4c 50 26 4b 65 c3 20 99 54 f7 5d |.....LP&Ke. .T.]| +00000030 68 da 00 e0 88 d8 0c ed b1 8f 60 d1 70 16 c4 c6 |h.........`.p...| +00000040 84 69 55 23 43 27 22 b7 94 2a 79 4c c0 2f 00 00 |.iU#C'"..*yL./..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| 00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| @@ -53,33 +54,33 @@ 00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| 000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| 000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| -000002c0 ac 0c 00 00 a8 03 00 1d 20 cc f6 2e 98 6c e0 8b |........ ....l..| -000002d0 15 17 63 6f 97 5e 37 6a a7 3c 4b f2 d4 91 e0 87 |..co.^7j.$| -00000340 04 f0 b9 ab 81 b8 4e 39 88 8f b7 46 2c 60 b8 5c |......N9...F,`.\| -00000350 6f 4d d4 5d 7a 04 f7 1d 82 98 a2 b1 f9 7e f0 1f |oM.]z........~..| -00000360 cf a5 e5 28 25 d4 3d b0 32 ea eb 21 c6 16 03 03 |...(%.=.2..!....| +000002c0 ac 0c 00 00 a8 03 00 1d 20 7e 24 e6 eb 12 22 e0 |........ ~$...".| +000002d0 7b 1e ad 2d 1e a8 3a ea ff 9e 87 bf 38 21 6e 51 |{..-..:.....8!nQ| +000002e0 a8 42 0b 13 a2 3f 01 b9 7d 04 01 00 80 be e8 7e |.B...?..}......~| +000002f0 db 65 e8 0c 5e 31 4c 72 b4 fb 42 ca f0 e2 e2 32 |.e..^1Lr..B....2| +00000300 26 46 f5 62 e5 09 71 8c 82 60 d3 e1 3b 1d d4 3d |&F.b..q..`..;..=| +00000310 6f 9d 5e 22 e7 22 41 44 1b b1 77 18 dc 5a 82 18 |o.^"."AD..w..Z..| +00000320 f3 ae 31 a2 46 32 86 cb 6e f7 37 b3 a4 7e 5c 62 |..1.F2..n.7..~\b| +00000330 11 8d 78 aa 78 6b 6f 78 da 75 26 bf 9b fc 5a 4b |..x.xkox.u&...ZK| +00000340 18 d7 28 84 9d 66 70 69 2f f5 24 c5 90 ef 33 14 |..(..fpi/.$...3.| +00000350 2e c8 14 3f 46 5c 61 c1 a5 2e ee 81 b5 4e 32 01 |...?F\a......N2.| +00000360 85 8b 3a 30 de 0d e7 23 07 be 36 9a 66 16 03 03 |..:0...#..6.f...| 00000370 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| 00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| 00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| -00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 75 70 c8 |....(........up.| -00000040 c5 ef ae 60 b5 8d ba 98 1a 7d 8d c3 e4 32 fc 33 |...`.....}...2.3| -00000050 5e 15 cc e2 d7 5d d5 76 52 1a fe ac 1e |^....].vR....| +00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 71 e9 b4 |....(........q..| +00000040 8b 8a 93 23 22 6a 61 09 5f e6 5b 05 53 f6 7e b0 |...#"ja._.[.S.~.| +00000050 18 53 da 44 b4 04 4d a4 d6 8e fe 8e d8 |.S.D..M......| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 7f 2b fe 0d 9f |..........(.+...| -00000010 93 07 fd ee 48 76 09 fb 8d 4c dd 7b b5 b5 26 36 |....Hv...L.{..&6| -00000020 3e 05 e1 1b a7 dc 0b 4a c0 69 a8 22 33 0b 17 fc |>......J.i."3...| -00000030 6f ab b8 |o..| +00000000 14 03 03 00 01 01 16 03 03 00 28 b0 0e df 0e b0 |..........(.....| +00000010 b0 3b 09 c7 9e 23 21 34 35 3a 15 94 64 8e 54 c9 |.;...#!45:..d.T.| +00000020 5c c7 e3 3f b6 8f ca 10 4e d9 60 60 b7 b4 f9 13 |\..?....N.``....| +00000030 5d c4 53 |].S| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 49 61 5c |.............Ia\| -00000010 db f2 e5 63 23 3a f1 dd 12 3e 61 ed d9 4b 5f b5 |...c#:...>a..K_.| -00000020 d3 f7 38 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..8.............| -00000030 af 09 a7 f1 e1 d9 1f 54 d1 35 19 16 b7 23 ce 4e |.......T.5...#.N| -00000040 3a b1 |:.| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 6b a1 83 |.............k..| +00000010 cc af 9b e1 88 55 43 c2 7d 05 b7 2d 7d 33 d9 b6 |.....UC.}..-}3..| +00000020 a3 9b 85 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 e2 8b 82 76 99 3d 8b b7 7d 69 76 d5 cd 6c aa 7c |...v.=..}iv..l.|| +00000040 64 82 |d.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN index 3e90ebd90f8..f2e7eb7b13b 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 bf 01 00 00 bb 03 03 18 c9 32 10 f3 |.............2..| -00000010 be ff a8 60 c5 2a 03 cb 25 8a b3 54 8d 70 27 90 |...`.*..%..T.p'.| -00000020 74 1e 15 3e 61 48 9b be f0 77 1f 00 00 38 c0 2c |t..>aH...w...8.,| +00000000 16 03 01 00 bf 01 00 00 bb 03 03 dc d0 a1 64 e2 |..............d.| +00000010 38 c3 1c 2b 8c fc d4 e9 25 b7 20 01 fb 72 37 8f |8..+....%. ..r7.| +00000020 1b da 7b ec 74 f3 20 c4 78 eb 15 00 00 38 c0 2c |..{.t. .x....8.,| 00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..| 00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....| 00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<| @@ -58,37 +58,37 @@ 000002a0 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 |.;..............| 000002b0 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb |. /.}.G.bC.(.._.| 000002c0 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb |).0.........._X.| -000002d0 3b 74 05 01 00 80 2e c1 51 a1 e8 92 a6 bb ad 1e |;t......Q.......| -000002e0 4d f1 22 c5 e7 10 e6 31 1d 78 61 8a 22 a3 93 84 |M."....1.xa."...| -000002f0 58 d6 5a c6 94 d0 da 6c 6a 35 d1 31 ea 1b 7e 55 |X.Z....lj5.1..~U| -00000300 d6 35 a3 b7 42 e4 04 f8 31 15 15 88 5f 91 a8 7e |.5..B...1..._..~| -00000310 3e 73 52 8f 32 50 2e ad 95 44 83 b6 88 d6 18 99 |>sR.2P...D......| -00000320 cf 86 57 97 c0 b2 a0 91 ee a7 ac f8 38 4b 1c 8e |..W.........8K..| -00000330 a4 58 59 4a f6 fc 88 a4 02 ed c8 04 1a 8b 7b 9e |.XYJ..........{.| -00000340 83 91 72 ca 1e 1c e0 76 58 73 89 3a 7d 12 c5 ef |..r....vXs.:}...| -00000350 f8 f7 45 dc ca c4 16 03 03 00 04 0e 00 00 00 |..E............| +000002d0 3b 74 06 01 00 80 54 89 2f 46 ff 41 c2 56 47 33 |;t....T./F.A.VG3| +000002e0 fa d6 91 64 47 df 46 89 75 73 6d 84 c6 8a 54 f8 |...dG.F.usm...T.| +000002f0 80 34 55 00 34 8d 64 ab 72 94 6e e9 e6 18 a1 e9 |.4U.4.d.r.n.....| +00000300 15 00 f5 2a 84 9f 22 95 c5 a3 17 91 b3 36 3a 9c |...*.."......6:.| +00000310 b9 65 54 bd 03 29 69 1a 5b 44 bd 1f c1 16 5a 7d |.eT..)i.[D....Z}| +00000320 53 35 8c c3 28 5f 3c ac 71 d2 bc c7 86 82 08 e7 |S5..(_<.q.......| +00000330 72 22 1f 98 68 5d a7 0e 8b 2c 6c 80 b9 36 79 4a |r"..h]...,l..6yJ| +00000340 f2 64 c1 14 8b b2 61 a8 c2 ca 83 44 e9 5a f8 fb |.d....a....D.Z..| +00000350 6d 67 b4 d6 7e fa 16 03 03 00 04 0e 00 00 00 |mg..~..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 be 4e 0d d5 31 aa |....%...! .N..1.| -00000010 27 13 df 73 d3 8d 17 8c b3 5f 44 61 7b 01 b6 99 |'..s....._Da{...| -00000020 7b ba b3 5d bf d4 be 3c 87 26 14 03 03 00 01 01 |{..]...<.&......| -00000030 16 03 03 00 28 9c 86 e0 30 d4 a5 ec 0c 9e a6 08 |....(...0.......| -00000040 ce 8a 7a ff ef be 52 0c 56 86 62 de 49 09 a1 18 |..z...R.V.b.I...| -00000050 aa 62 e5 e3 d3 2e 4a 24 c9 ef 44 c9 67 |.b....J$..D.g| +00000000 16 03 03 00 25 10 00 00 21 20 61 b6 16 25 fb ca |....%...! a..%..| +00000010 39 11 1b 39 91 0f ad a0 1b 53 cb 23 3a 8b 4c bf |9..9.....S.#:.L.| +00000020 c3 95 b7 fa 74 2c 44 55 d3 3b 14 03 03 00 01 01 |....t,DU.;......| +00000030 16 03 03 00 28 2a f0 0e a4 54 25 0c 3f 46 9e d4 |....(*...T%.?F..| +00000040 32 63 db 36 71 11 9d 63 57 d5 5d e6 70 86 01 f8 |2c.6q..cW.].p...| +00000050 2f 8e 79 65 b7 39 4f 31 a9 f5 a5 70 9a |/.ye.9O1...p.| >>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| -00000030 6f ec 80 83 61 da 3d a1 df 0d 11 25 4b 66 55 09 |o...a.=....%KfU.| -00000040 af 7a c1 82 b9 ea 2f 9f 5c f4 0a 62 15 62 c2 32 |.z..../.\..b.b.2| -00000050 c6 37 51 5b bb 19 14 f8 73 f8 fb 82 00 ef 19 21 |.7Q[....s......!| -00000060 e2 52 7d ab 0a 33 94 df 78 54 ba 6c 5e 94 eb 16 |.R}..3..xT.l^...| -00000070 ad 85 01 ca d5 98 8f 8e b7 04 7e 9a 3c 35 c0 e5 |..........~.<5..| -00000080 8f cf 27 6d b4 12 c2 14 03 03 00 01 01 16 03 03 |..'m............| -00000090 00 28 00 00 00 00 00 00 00 00 75 da b5 10 2e 7c |.(........u....|| -000000a0 39 ec 3d 98 12 fb 5d 15 81 79 f3 c7 b1 e4 e0 54 |9.=...]..y.....T| -000000b0 ed 27 6e bc c3 81 a0 74 7e 38 17 03 03 00 25 00 |.'n....t~8....%.| -000000c0 00 00 00 00 00 00 01 bf 81 cc 93 49 4f b2 59 8b |...........IO.Y.| -000000d0 53 4a 61 96 04 00 4b ac 34 d5 bd 5a 94 44 18 5b |SJa...K.4..Z.D.[| -000000e0 7d 81 dc 05 15 03 03 00 1a 00 00 00 00 00 00 00 |}...............| -000000f0 02 bd 32 d5 cf 4d 13 61 6a 77 8b 3e 51 b3 13 84 |..2..M.ajw.>Q...| -00000100 e6 1a 23 |..#| +00000030 6f ec 80 83 61 19 68 1a 40 8c 4c 8f 85 a2 2e fa |o...a.h.@.L.....| +00000040 3f b5 7c 5f 46 d1 fa 20 23 89 e7 e6 d6 82 6f 78 |?.|_F.. #.....ox| +00000050 5b 28 32 89 60 4a e7 22 51 9a 13 f5 0e 82 9c 1e |[(2.`J."Q.......| +00000060 29 e1 2a 91 62 33 94 51 e1 bf b8 99 2a 20 e6 87 |).*.b3.Q....* ..| +00000070 c4 1f 65 fe 7e 6e 0e 33 7f 77 f9 33 0c 9d 05 df |..e.~n.3.w.3....| +00000080 e5 7d 2c db cc 48 f6 14 03 03 00 01 01 16 03 03 |.},..H..........| +00000090 00 28 00 00 00 00 00 00 00 00 91 05 0e 09 9f b6 |.(..............| +000000a0 e1 48 98 28 ae 68 0a 89 9f a7 47 1b 67 d5 8c 0a |.H.(.h....G.g...| +000000b0 3c 4f da 1e 4f 3f 13 80 cd a5 17 03 03 00 25 00 |>> Flow 1 (client to server) -00000000 16 03 01 00 bf 01 00 00 bb 03 03 82 57 14 fc ab |............W...| -00000010 56 21 ff 72 39 72 3f fe f1 9b 0f 22 00 ff ef 44 |V!.r9r?...."...D| -00000020 da db e0 83 d2 c0 a7 1c fb f0 6c 00 00 38 c0 2c |..........l..8.,| +00000000 16 03 01 00 bf 01 00 00 bb 03 03 12 5f 10 32 01 |............_.2.| +00000010 84 0f 82 05 7e ca 97 58 65 65 d5 ad d3 94 e4 88 |....~..Xee......| +00000020 e9 15 91 0a 2c 99 55 ca ae 18 aa 00 00 38 c0 2c |....,.U......8.,| 00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..| 00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....| 00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<| @@ -57,38 +57,38 @@ 00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 |.\!.;...........| 000002a0 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.| 000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........| -000002c0 5f 58 cb 3b 74 05 01 00 80 bf 6d 57 f5 0c 78 c4 |_X.;t.....mW..x.| -000002d0 77 48 0e 60 67 7a 3a 1b 3e 9e d2 88 a4 89 07 ef |wH.`gz:.>.......| -000002e0 d1 45 1a 66 7e 8c ec cb da 71 ea ec ba ed 81 9e |.E.f~....q......| -000002f0 21 4d 2e ba d4 8f c2 0a 67 ea 3a a1 d1 67 09 66 |!M......g.:..g.f| -00000300 dc a8 ad 16 a2 23 2a db 4f 31 65 b1 54 13 73 d1 |.....#*.O1e.T.s.| -00000310 f6 7b 75 d9 f1 07 19 b8 67 21 87 d2 3b cf a5 6c |.{u.....g!..;..l| -00000320 61 8e af ed 60 7f f2 56 9f 0d 0f 19 88 98 30 3a |a...`..V......0:| -00000330 61 8c 21 e7 8b 5d ab 6f cf 93 73 33 63 cd 50 bb |a.!..].o..s3c.P.| -00000340 dd 0e ab 4f 6a fb a3 f9 68 16 03 03 00 04 0e 00 |...Oj...h.......| +000002c0 5f 58 cb 3b 74 06 01 00 80 50 95 28 ab df d3 74 |_X.;t....P.(...t| +000002d0 7a 9b 7a d8 d2 31 34 87 75 29 a9 d0 fd 3c e4 be |z.z..14.u)...<..| +000002e0 59 e6 60 52 39 9f 8e 9d e3 1c 1d 75 47 b0 86 57 |Y.`R9......uG..W| +000002f0 3f e1 a8 a5 72 21 1a 22 49 61 71 83 20 76 8c b6 |?...r!."Iaq. v..| +00000300 e4 c4 99 de 4e 9c f6 22 df 8d 92 1e a9 c7 0e 83 |....N.."........| +00000310 d2 93 a9 2d 9b 74 f8 1b 1b 2f 1e 71 b6 7c d0 99 |...-.t.../.q.|..| +00000320 a3 d2 95 45 87 36 28 be 0a 26 53 89 77 6b b6 e4 |...E.6(..&S.wk..| +00000330 f9 3a 82 7c 67 81 08 22 cf 3a 94 83 68 29 f3 a5 |.:.|g..".:..h)..| +00000340 67 b4 95 77 0f fb 06 da 5f 16 03 03 00 04 0e 00 |g..w...._.......| 00000350 00 00 |..| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 05 0c 3b 8b 22 36 |....%...! ..;."6| -00000010 61 79 58 28 b0 82 65 44 39 67 93 c5 2c 3b d1 40 |ayX(..eD9g..,;.@| -00000020 88 af 9f 38 c1 fa e0 81 a0 19 14 03 03 00 01 01 |...8............| -00000030 16 03 03 00 28 87 2e d2 c2 ce 65 6d e8 d9 da a0 |....(.....em....| -00000040 9d dc f5 51 b0 84 88 8d c6 a3 0a 5d 08 10 ca c6 |...Q.......]....| -00000050 e3 83 0c 0a cb 6d ec 09 b8 9f a5 45 99 |.....m.....E.| +00000000 16 03 03 00 25 10 00 00 21 20 a4 d7 31 f0 60 aa |....%...! ..1.`.| +00000010 97 48 1f a8 fb 3c 78 77 5f 90 b3 f7 f2 0c 5e ed |.H....w.r....e......| +00000030 16 03 03 00 28 6d 3e 7f a1 0e 5b ea 24 ee ec 77 |....(m>...[.$..w| +00000040 3c 03 eb cb 5c ad b4 21 b2 c1 9c 5e 4f 36 88 01 |<...\..!...^O6..| +00000050 b6 0c 7c 92 70 70 63 4f d4 e1 98 45 e4 |..|.ppcO...E.| >>> Flow 4 (server to client) 00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| 00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| -00000030 6f ec 80 83 61 34 53 e2 a4 e2 ff 73 4f 1b 15 8f |o...a4S....sO...| -00000040 3b 43 47 ac 20 c6 2d 5e 52 7a 61 6f af 40 c3 5a |;CG. .-^Rzao.@.Z| -00000050 cb 3f 7d 10 a9 90 ca cf 8d c4 c4 d4 a3 b8 1d 62 |.?}............b| -00000060 7d a9 68 32 01 33 94 65 8b 67 73 aa 51 d4 08 1d |}.h2.3.e.gs.Q...| -00000070 ce 76 6b ef 3d e6 ce d3 42 fe 24 cf f3 82 5b 17 |.vk.=...B.$...[.| -00000080 5c 03 e9 50 94 8e 8b 14 03 03 00 01 01 16 03 03 |\..P............| -00000090 00 28 00 00 00 00 00 00 00 00 c2 7c e6 69 c9 ec |.(.........|.i..| -000000a0 b5 55 57 34 8e 86 38 e6 28 85 b0 c8 2e c8 0f a6 |.UW4..8.(.......| -000000b0 a9 07 f4 91 47 46 dd fe c8 57 17 03 03 00 25 00 |....GF...W....%.| -000000c0 00 00 00 00 00 00 01 39 9a a2 da d8 3d 7f 25 0e |.......9....=.%.| -000000d0 83 a8 cd 57 d8 a4 7e 9f e1 e2 fe 3f 5a ed b9 99 |...W..~....?Z...| -000000e0 b6 4d 97 3a 15 03 03 00 1a 00 00 00 00 00 00 00 |.M.:............| -000000f0 02 d5 2a aa 1e 7a 60 b8 79 56 c6 56 75 11 b7 4c |..*..z`.yV.Vu..L| -00000100 83 19 9c |...| +00000030 6f ec 80 83 61 34 3a 86 15 18 26 50 d0 12 69 5a |o...a4:...&P..iZ| +00000040 8e 67 6a ce 99 67 0a 90 09 d5 ad 29 62 08 9b 29 |.gj..g.....)b..)| +00000050 6c 12 bb d4 74 3c fb 5b dc e5 89 f0 98 93 03 e9 |l...t<.[........| +00000060 2a ea 31 74 0a 33 94 96 49 53 80 c9 3e 9b 53 32 |*.1t.3..IS..>.S2| +00000070 4a 15 31 0e fa 90 bd da af 07 d1 a8 fa 15 e8 df |J.1.............| +00000080 3d f1 d1 7a 21 8c 7a 14 03 03 00 01 01 16 03 03 |=..z!.z.........| +00000090 00 28 00 00 00 00 00 00 00 00 70 0c c0 3b 84 68 |.(........p..;.h| +000000a0 4d e5 7d 54 18 ba 77 3d 8c 20 03 3e 50 69 45 0d |M.}T..w=. .>PiE.| +000000b0 64 a2 0f 1e 4e bf 86 0b 9c 05 17 03 03 00 25 00 |d...N.........%.| +000000c0 00 00 00 00 00 00 01 43 a9 fa 0f e3 5a 86 46 2a |.......C....Z.F*| +000000d0 56 3a 6c d5 88 b7 40 a0 d5 59 45 45 ac 06 5d b0 |V:l...@..YEE..].| +000000e0 d7 c9 ed 00 15 03 03 00 1a 00 00 00 00 00 00 00 |................| +000000f0 02 ce de ef aa b4 47 77 4c f6 e9 fb 67 e8 fb 7f |......GwL...g...| +00000100 c6 05 20 |.. | diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA index e2864070a4a..3a84905c1c5 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 a7 01 00 00 a3 03 03 27 01 f3 21 98 |...........'..!.| -00000010 ff 55 7f 78 32 44 b7 9d 88 6b 82 43 26 52 00 74 |.U.x2D...k.C&R.t| -00000020 fb 05 ca be 23 1f d0 18 1f 74 c2 00 00 38 c0 2c |....#....t...8.,| +00000000 16 03 01 00 a7 01 00 00 a3 03 03 7e 8a c0 04 93 |...........~....| +00000010 7a be 32 5c b3 38 83 b1 ec d0 31 8d a1 61 f3 2b |z.2\.8....1..a.+| +00000020 b2 6a 0d 08 71 41 fb 20 c2 46 0c 00 00 38 c0 2c |.j..qA. .F...8.,| 00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..| 00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....| 00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<| @@ -47,39 +47,39 @@ 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 b7 0c 00 |{j.9....*.......| -00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(| +00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b6 0c 00 |{j.9....*.......| +00000250 00 b2 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(| 00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........| -00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.| -00000280 4f 30 aa d0 4d e5 61 db ba fc 95 15 52 ef 2a 41 |O0..M.a.....R.*A| -00000290 b4 d6 59 ac 39 61 b6 38 08 1e 87 b3 ca 9b 49 d3 |..Y.9a.8......I.| -000002a0 95 5a c5 29 84 cd 10 73 4a cc 09 df 1a b0 54 6d |.Z.)...sJ.....Tm| -000002b0 b8 61 28 80 2e ec cf 95 9d 6f c3 d9 ed 80 53 63 |.a(......o....Sc| -000002c0 d9 02 42 00 af 71 2f 91 80 ff a1 79 82 c7 d9 79 |..B..q/....y...y| -000002d0 fa 12 a9 88 7b 93 47 be 6a dc 80 42 17 9d 85 7a |....{.G.j..B...z| -000002e0 b8 1b fe 85 7f 5c 10 9c 9e 0e e1 71 a7 b0 12 02 |.....\.....q....| -000002f0 e2 a4 79 c4 8d d8 02 09 01 9c 6f 7a 27 7c 1f f4 |..y.......oz'|..| -00000300 38 46 59 46 94 16 03 03 00 04 0e 00 00 00 |8FYF..........| +00000270 99 5f 58 cb 3b 74 06 03 00 8a 30 81 87 02 42 01 |._X.;t....0...B.| +00000280 ed a6 35 6b 28 3f cc 4a 66 c1 21 a0 ba e3 a2 c2 |..5k(?.Jf.!.....| +00000290 3b 45 41 87 9b c4 5d 01 b7 8b 01 89 b4 b1 16 99 |;EA...].........| +000002a0 72 e2 94 6d 24 f2 9f be 6a 8b 9b b5 c7 9c cb 65 |r..m$...j......e| +000002b0 38 ab 29 de 38 e5 64 4c 0b 75 67 c9 9d 5b dc 37 |8.).8.dL.ug..[.7| +000002c0 86 02 41 33 ac b4 ff f3 db f7 2c c9 0b 43 8a 62 |..A3......,..C.b| +000002d0 df 9d b9 c5 50 0b 8c f1 da 40 b1 ba a8 41 99 66 |....P....@...A.f| +000002e0 1b e8 a0 20 0b 4f 0d 1e 55 12 c5 a2 a3 89 88 a0 |... .O..U.......| +000002f0 9f 91 b9 73 9b b1 19 95 d6 53 3a b3 d7 5d 73 5c |...s.....S:..]s\| +00000300 c4 d6 6a 1a 16 03 03 00 04 0e 00 00 00 |..j..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 8c 80 e4 c7 bd d7 |....%...! ......| -00000010 ea ea 42 f7 53 24 50 28 6a e9 f3 ff 4f 4a 28 22 |..B.S$P(j...OJ("| -00000020 a2 95 09 fc f0 d9 3e fc cc 6e 14 03 03 00 01 01 |......>..n......| -00000030 16 03 03 00 40 79 56 60 f5 45 e7 48 9e 97 1d 49 |....@yV`.E.H...I| -00000040 de 59 dd b0 f0 0a d2 cc 10 f0 98 3c c2 d5 67 d6 |.Y.........<..g.| -00000050 2c 18 2b 21 ae a3 2f ea 2d 0b ff fd e6 c2 73 25 |,.+!../.-.....s%| -00000060 1c 01 3e 94 3a cc 1d 58 6b fb 7f 85 e4 50 ec 10 |..>.:..Xk....P..| -00000070 b9 d7 71 cb be |..q..| +00000000 16 03 03 00 25 10 00 00 21 20 5e 83 48 ba 4f 66 |....%...! ^.H.Of| +00000010 74 7d 8a c6 53 d2 a9 cf 68 f1 50 f4 2a 06 74 ef |t}..S...h.P.*.t.| +00000020 07 57 b0 f9 3e 1a 49 98 52 44 14 03 03 00 01 01 |.W..>.I.RD......| +00000030 16 03 03 00 40 1a b1 de ad 95 eb 28 ed 07 ce fe |....@......(....| +00000040 8b 8a fc 9a 24 a8 c3 d4 2f 27 20 52 9d 47 ac 45 |....$.../' R.G.E| +00000050 cc 66 c0 a4 03 cb 49 3c 93 05 3c 3e 64 91 d6 5c |.f....I<..<>d..\| +00000060 f9 73 1b 18 54 0b 67 c7 97 53 c8 7d 72 18 ab 47 |.s..T.g..S.}r..G| +00000070 98 32 54 4c ff |.2TL.| >>> 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 83 5c 5c e3 c0 |............\\..| -00000020 20 56 8c 92 4b 75 f0 30 bd 67 74 52 f1 af 9c 14 | V..Ku.0.gtR....| -00000030 29 1e e4 b2 5b c0 2c e6 48 6f 94 42 7b 21 92 96 |)...[.,.Ho.B{!..| -00000040 0a 83 ce 1c 91 36 95 8c 14 38 57 17 03 03 00 40 |.....6...8W....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 21 f3 63 c9 0a |...........!.c..| +00000020 7e 39 23 21 2d 2b 4b 72 47 65 30 b4 43 21 d1 d7 |~9#!-+KrGe0.C!..| +00000030 4f fa 00 65 a1 95 fd 62 2c d3 4d 7d 30 d7 fd eb |O..e...b,.M}0...| +00000040 64 08 41 d6 70 ab cf 9d 75 c5 e1 17 03 03 00 40 |d.A.p...u......@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 73 a4 40 cf ad 86 cc 05 9e 47 5f 83 50 ae 68 d5 |s.@......G_.P.h.| -00000070 d1 6a a9 8c ba 74 fe c0 cc 4a 1a e3 b0 14 0d 31 |.j...t...J.....1| -00000080 9f 06 54 e3 95 3a 89 6d 34 54 0c e4 b4 34 38 21 |..T..:.m4T...48!| +00000060 50 e5 5e 3a c1 2a 71 0a ba eb 40 74 f1 70 0d 0a |P.^:.*q...@t.p..| +00000070 e1 86 22 fd 13 de e8 8f a0 d3 22 a8 62 76 ca fa |..".......".bv..| +00000080 5f 63 95 ba bb e2 f3 b3 ef 5b d8 bf 56 0b 60 53 |_c.......[..V.`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 e6 dd b2 11 ab a7 34 61 00 d4 09 |...........4a...| -000000b0 bc ea c1 5f c4 e2 52 60 63 96 f0 fd 44 4e f9 0e |..._..R`c...DN..| -000000c0 af 32 99 e4 12 |.2...| +000000a0 00 00 00 00 00 4d 2c 41 d8 4c 63 71 bd bc 83 5a |.....M,A.Lcq...Z| +000000b0 1b 2b b7 20 5b 14 51 d4 5b 38 4b fc 61 58 97 34 |.+. [.Q.[8K.aX.4| +000000c0 1a cf 08 f1 16 |.....| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA index 1f9fbc1abb8..154521da998 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 a7 01 00 00 a3 03 03 1d 39 c9 33 73 |............9.3s| -00000010 c2 b9 71 d8 66 23 63 a7 5c 9e 50 b6 3e a5 f9 bb |..q.f#c.\.P.>...| -00000020 34 1b 71 e1 09 4f ae d5 53 8a e8 00 00 38 c0 2c |4.q..O..S....8.,| +00000000 16 03 01 00 a7 01 00 00 a3 03 03 df fc 06 29 d8 |..............).| +00000010 a1 69 bd 2c d2 21 97 39 e8 4f 81 94 fa b9 58 6d |.i.,.!.9.O....Xm| +00000020 aa 15 ae f7 bc 03 7a fa e3 33 bf 00 00 38 c0 2c |......z..3...8.,| 00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..| 00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....| 00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<| @@ -55,35 +55,35 @@ 00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............| 000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)| 000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;| -000002c0 74 05 01 00 80 06 d4 bd e4 7b 10 77 89 d7 d4 d6 |t........{.w....| -000002d0 4e f6 3e 46 49 db ee 5c 4e bc ee fe cb 8b a6 9b |N.>FI..\N.......| -000002e0 5c f6 99 fb 31 96 60 a8 23 09 f6 31 65 53 f0 6e |\...1.`.#..1eS.n| -000002f0 07 5c 32 f9 59 5d 8b c0 b4 74 c8 01 85 8a b7 19 |.\2.Y]...t......| -00000300 ab 19 08 68 6a e8 2f 81 bd 04 9b 38 ab d9 27 66 |...hj./....8..'f| -00000310 d7 a5 3f 75 9c 4f 81 5b 9e 69 10 20 2b f2 1d a2 |..?u.O.[.i. +...| -00000320 8f fc 7f ba ee 5b 76 8b 19 3f 46 60 01 25 99 72 |.....[v..?F`.%.r| -00000330 78 24 02 8e 28 d5 24 f1 2e 6b 70 53 75 ec e2 8d |x$..(.$..kpSu...| -00000340 76 ab e0 8e e8 16 03 03 00 04 0e 00 00 00 |v.............| +000002c0 74 06 01 00 80 a3 e7 63 ff 8a 7e 1c cb 9b ab 8a |t......c..~.....| +000002d0 7e f3 d1 fe c0 34 23 10 5e 0c e3 60 0d c5 cc 11 |~....4#.^..`....| +000002e0 49 37 37 b6 ad b1 9a 29 b7 e4 1f 90 29 bf b3 bd |I77....)....)...| +000002f0 31 ed e6 20 4d 4c 2a a1 64 d8 cb 44 5e b1 5d b5 |1.. ML*.d..D^.].| +00000300 a5 d5 67 de 29 e4 89 29 a9 51 bd b9 1f 01 de 72 |..g.)..).Q.....r| +00000310 8b c1 b2 d0 fd 96 ec 94 29 4d 2e ee da 08 58 81 |........)M....X.| +00000320 3b db 53 26 26 0e cb 57 37 f4 d0 fe 19 3e 41 a0 |;.S&&..W7....>A.| +00000330 d5 0e a8 7a bf 29 56 a9 d4 84 da 33 bb bf f9 ba |...z.)V....3....| +00000340 54 7b d0 4a 95 16 03 03 00 04 0e 00 00 00 |T{.J..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 21 75 22 84 bc b7 |....%...! !u"...| -00000010 82 b3 03 d2 42 ff b6 ce 76 26 88 bf 8f 72 fc dd |....B...v&...r..| -00000020 63 9b f1 4c 22 6d 12 cc d3 57 14 03 03 00 01 01 |c..L"m...W......| -00000030 16 03 03 00 40 20 2b 26 bd 60 1b 27 a1 32 cb ab |....@ +&.`.'.2..| -00000040 30 83 9c 47 59 7d f5 bb d9 45 8a d9 3e 29 86 4d |0..GY}...E..>).M| -00000050 54 86 48 38 25 d9 b9 af 36 7c 7a f0 ae f6 b6 4e |T.H8%...6|z....N| -00000060 a1 76 93 91 26 f3 c9 49 b5 6d 49 cf 22 97 bf c7 |.v..&..I.mI."...| -00000070 db 44 c8 7a e3 |.D.z.| +00000000 16 03 03 00 25 10 00 00 21 20 36 84 23 91 d3 76 |....%...! 6.#..v| +00000010 b3 ea 4a a6 39 f6 c9 1a 99 2c 69 c0 70 2d b2 72 |..J.9....,i.p-.r| +00000020 72 be b3 24 4b d3 72 a1 eb 76 14 03 03 00 01 01 |r..$K.r..v......| +00000030 16 03 03 00 40 e9 a5 32 9d 72 3d 9d 38 f3 0b fa |....@..2.r=.8...| +00000040 38 95 0f de 7d 99 42 b2 5b 1c f0 fe e4 66 2b 5a |8...}.B.[....f+Z| +00000050 98 1c e5 0e bf d9 37 d4 4c 72 29 a3 eb 8a f5 0e |......7.Lr).....| +00000060 44 ee 1e 21 c7 8c 10 23 dc 41 6d ac ee 72 5b d5 |D..!...#.Am..r[.| +00000070 4b 3f 66 f3 d1 |K?f..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 43 7c 61 f2 30 |...........C|a.0| -00000020 c6 4a c2 76 da 7d 84 c6 ed 5d ee 2e 9c 33 e4 3b |.J.v.}...]...3.;| -00000030 e3 a1 ea ee 44 02 4b f7 90 f6 0c 8b 45 d7 26 2e |....D.K.....E.&.| -00000040 4a 37 43 1d 93 44 79 e6 5d c5 8c 17 03 03 00 40 |J7C..Dy.]......@| +00000010 00 00 00 00 00 00 00 00 00 00 00 f8 fb 0a 12 f2 |................| +00000020 ee 27 b0 88 5d c9 02 c0 16 3c b8 a5 54 86 4b cb |.'..]....<..T.K.| +00000030 01 ef d1 6e 31 a8 88 86 e3 9f 71 f5 fb 2a a9 12 |...n1.....q..*..| +00000040 72 76 98 30 1e 59 49 64 b1 6b e5 17 03 03 00 40 |rv.0.YId.k.....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 b2 e4 62 17 e2 d4 d8 73 2b ea 77 39 78 51 1a 86 |..b....s+.w9xQ..| -00000070 64 54 1f 36 9a cc a1 c0 d2 6d df b7 8a 2e 68 b0 |dT.6.....m....h.| -00000080 79 9a 9f a1 15 b1 78 fa db 2e 5a 43 0d fe 45 71 |y.....x...ZC..Eq| +00000060 da fe c6 34 b0 e7 8d 34 78 11 b1 94 43 da 85 21 |...4...4x...C..!| +00000070 28 9a f3 f8 f0 7f 14 9a 59 be 4e c4 a0 81 17 1b |(.......Y.N.....| +00000080 08 cd 6d 47 57 73 f1 10 e4 df 25 1b 8b 9d 87 98 |..mGWs....%.....| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 04 8c d0 bf 15 9f b4 55 22 b8 8e |............U"..| -000000b0 a5 a7 df ed bd b2 ab 88 71 38 bd b2 5d b4 5e 8e |........q8..].^.| -000000c0 54 fc e4 63 5a |T..cZ| +000000a0 00 00 00 00 00 41 b6 ed ca 43 0d 83 67 da 4b 0e |.....A...C..g.K.| +000000b0 5a f4 a8 90 85 7f d6 d7 76 03 62 2e 49 7e 4a 62 |Z.......v.b.I~Jb| +000000c0 32 03 a8 7c a0 |2..|.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven index 7a950db0ac9..8c6a7ed98c2 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5d 01 00 00 59 03 03 8e 50 ff 02 c4 |....]...Y...P...| -00000010 3b 5e dd ee 59 d1 3a e1 db f1 30 f4 bb a7 8a 8c |;^..Y.:...0.....| -00000020 b2 d2 1a fd f8 a4 c9 e4 5f 41 e1 00 00 04 00 2f |........_A...../| +00000000 16 03 01 00 5d 01 00 00 59 03 03 ba cf e7 3a 42 |....]...Y.....:B| +00000010 aa f9 cd ca b8 b7 46 a0 4a 87 2c f8 76 14 d6 d0 |......F.J.,.v...| +00000020 f8 66 ad ed 80 57 b0 9f bf f5 32 00 00 04 00 2f |.f...W....2..../| 00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................| @@ -48,9 +48,9 @@ 00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......| 00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..| 00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.| -00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@| -000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................| -000002b0 16 03 03 00 04 0e 00 00 00 |.........| +00000290 3b e9 fa e7 16 03 03 00 1b 0d 00 00 17 02 01 40 |;..............@| +000002a0 00 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 |................| +000002b0 02 03 00 00 16 03 03 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| @@ -85,40 +85,36 @@ 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 2b 80 6e 49 b8 ec |..........+.nI..| -00000220 12 7a 7c f3 2a d3 7e 16 a0 39 e5 77 61 7a 56 15 |.z|.*.~..9.wazV.| -00000230 97 c6 64 63 13 cf 09 d0 1b f5 b6 78 1d cb 86 4f |..dc.......x...O| -00000240 14 84 c9 e6 5d 3c 6b 61 5e 46 83 7e ef 1d 74 d4 |....].i[X.Z..,.\.| +00000250 65 2e 9a 9d 9e d4 3f 01 6b 47 e3 c8 ec e2 90 23 |e.....?.kG.....#| +00000260 b9 9f a7 1f bf 7a c4 b3 68 e5 8a ee f5 4e 7b 49 |.....z..h....N{I| +00000270 f3 3c b7 86 89 76 60 14 d5 a4 8e b1 5e 3f 5c 89 |.<...v`.....^?\.| +00000280 a5 f8 69 7e 12 88 9d 30 7a 07 c2 ff 8f bb d0 94 |..i~...0z.......| +00000290 1b 3c c4 fe 73 e6 25 99 77 d3 16 03 03 00 93 0f |.<..s.%.w.......| +000002a0 00 00 8f 04 03 00 8b 30 81 88 02 42 01 21 35 66 |.......0...B.!5f| +000002b0 57 df 29 1a e5 10 1d e0 e0 00 ee 2a 0b 20 22 8b |W.)........*. ".| +000002c0 1d 70 4f 39 cb 96 30 b1 f0 8d 12 ba c8 15 67 05 |.pO9..0.......g.| +000002d0 45 d2 fe 0a 4e 25 ce f4 8d 14 7b b8 6c 92 8b 99 |E...N%....{.l...| +000002e0 9b 56 0a 78 ad 45 d6 09 88 ae c7 e6 2d 13 02 42 |.V.x.E......-..B| +000002f0 01 5e 7e c9 ae 56 9e b6 de 38 fc a9 a6 e7 b9 35 |.^~..V...8.....5| +00000300 9b 47 cd f7 82 1a 56 1c cc d4 3a 15 79 d9 44 c4 |.G....V...:.y.D.| +00000310 96 1a 10 69 31 ad c7 96 6b 3f f7 81 b6 04 4c bd |...i1...k?....L.| +00000320 ee e2 a1 15 8a 83 bc a0 42 b9 0f aa 6a 14 d1 fd |........B...j...| +00000330 9d 95 14 03 03 00 01 01 16 03 03 00 40 46 6b 0c |............@Fk.| +00000340 5d 7e 32 26 ef 7c a5 88 f0 ec 50 92 de 5f 87 7c |]~2&.|....P.._.|| +00000350 b4 80 19 80 f4 89 19 f5 28 8f 21 09 fc 19 43 81 |........(.!...C.| +00000360 92 94 37 f5 9b 6e 07 b1 35 29 ed 9a 87 a5 e9 ce |..7..n..5)......| +00000370 c3 e3 83 42 dd 2e 5a 0b 8e 22 bf 32 4e |...B..Z..".2N| >>> 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 93 a2 18 a9 e2 |................| -00000020 51 be f7 bd c0 05 64 51 0a 17 9d 58 11 d1 a6 b9 |Q.....dQ...X....| -00000030 6d 1e 42 16 e4 bc bf 09 f2 b9 29 20 74 8a cd 8a |m.B.......) t...| -00000040 b6 31 04 64 fb 5b 1f 83 c3 19 78 17 03 03 00 40 |.1.d.[....x....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 13 c4 d2 3f b0 |..............?.| +00000020 84 08 32 74 de cc e0 97 90 8a c6 cc 94 87 ac 48 |..2t...........H| +00000030 65 f7 20 04 18 42 68 46 8e c0 19 b6 9d 2a 84 58 |e. ..BhF.....*.X| +00000040 85 20 b3 ed 75 94 71 4e 5b 0a de 17 03 03 00 40 |. ..u.qN[......@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 ee c4 d0 5d 69 37 2b fc dc 9c f1 77 df 44 6f da |...]i7+....w.Do.| -00000070 4e 22 05 05 3a 6c 32 a8 6c c2 fb ce ca a7 1b 54 |N"..:l2.l......T| -00000080 2a 25 ae cf 77 e4 47 21 33 b6 29 54 62 00 dd 30 |*%..w.G!3.)Tb..0| -00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 cf e1 fd e3 5f d3 19 cd 05 70 79 |........._....py| -000000b0 be 16 a5 26 18 f1 92 bc 73 bd 6f 4d 33 3d 6f 8a |...&....s.oM3=o.| -000000c0 13 51 7c 57 c7 |.Q|W.| +00000060 c2 6e c5 13 4d 35 ab b1 de e2 1b a6 6f 0e 40 64 |.n..M5......o.@d| +00000070 cc 67 bf 0d b1 e4 fe 48 c4 01 35 6a 94 50 17 7a |.g.....H..5j.P.z| +00000080 b3 6b f6 6b 2a 24 c9 b9 7b b0 42 0e 71 4d c2 da |.k.k*$..{.B.qM..| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven index c81acc8992f..aa4cfe1261c 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5d 01 00 00 59 03 03 f3 3a db 98 ff |....]...Y...:...| -00000010 29 a2 30 75 53 87 b3 5f 00 b5 9f 77 4d 88 38 ea |).0uS.._...wM.8.| -00000020 e9 87 f4 a4 e4 da dd 73 00 47 d1 00 00 04 00 2f |.......s.G...../| +00000000 16 03 01 00 5d 01 00 00 59 03 03 ed f9 4a 41 31 |....]...Y....JA1| +00000010 20 6a df af 85 92 37 a1 38 81 ed 3c 1a 7e d2 31 | j....7.8..<.~.1| +00000020 80 5b 68 87 b6 72 43 8e c0 f0 dd 00 00 04 00 2f |.[h..rC......../| 00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................| @@ -48,9 +48,9 @@ 00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......| 00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..| 00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.| -00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@| -000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................| -000002b0 16 03 03 00 04 0e 00 00 00 |.........| +00000290 3b e9 fa e7 16 03 03 00 1b 0d 00 00 17 02 01 40 |;..............@| +000002a0 00 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 |................| +000002b0 02 03 00 00 16 03 03 00 04 0e 00 00 00 |.............| >>> Flow 3 (client to server) 00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0| 00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.| @@ -84,40 +84,40 @@ 000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......| 000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{| 000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....| -00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 47 31 82 |.5...........G1.| -00000210 ae c1 d2 74 3f a4 74 5a 57 16 ae e2 d0 46 72 53 |...t?.tZW....FrS| -00000220 e1 5e 6a e8 e4 d5 8c 84 2b d9 82 c1 4a da 9e 1d |.^j.....+...J...| -00000230 a0 da 60 08 0d 35 0c 55 6d 6a 68 04 09 ee 94 39 |..`..5.Umjh....9| -00000240 c7 a3 49 7f 2c ee 6a cf 09 01 bd 08 d3 59 0a bd |..I.,.j......Y..| -00000250 7f 6c d3 26 eb be 7b fd 9b 17 fd e2 6e 82 d1 c7 |.l.&..{.....n...| -00000260 dd c3 64 8c 87 f0 41 f2 71 75 f1 0a 01 26 5b 97 |..d...A.qu...&[.| -00000270 94 ba ac 50 df 19 32 39 80 ae 14 ea 4a d2 e5 9f |...P..29....J...| -00000280 5d 07 9f 2d 89 ac 83 33 40 aa 8e cc 2c 16 03 03 |]..-...3@...,...| -00000290 00 88 0f 00 00 84 04 01 00 80 7d 37 8b 6f be e9 |..........}7.o..| -000002a0 e7 fa 4c 28 cf 16 0d 28 40 e9 f2 9a 11 22 fc 8a |..L(...(@...."..| -000002b0 2c 52 f7 36 af 1a cf d7 8a f8 17 19 9f ed 9d 1d |,R.6............| -000002c0 43 f9 e2 fb 0f dd ca d6 1d 4c 03 4e 25 8d 5c 4c |C........L.N%.\L| -000002d0 95 98 02 db cf ea 44 2a ad 36 74 e3 08 07 e3 9a |......D*.6t.....| -000002e0 50 6c dc 46 a1 f5 84 9b 65 7f 48 94 b5 de cc a9 |Pl.F....e.H.....| -000002f0 cf ee 0e 31 f2 f8 6f 8f 19 4b 29 14 b4 32 1d 21 |...1..o..K)..2.!| -00000300 02 d2 da 64 68 e8 a1 72 cc ee 64 48 d8 74 e5 64 |...dh..r..dH.t.d| -00000310 90 b3 50 cc 3e 25 0e b1 88 53 14 03 03 00 01 01 |..P.>%...S......| -00000320 16 03 03 00 40 6a 61 6b 3e ea 63 2c b8 26 95 e2 |....@jak>.c,.&..| -00000330 5f 83 e3 c3 cd c3 b7 a8 0b 76 81 8a 5b 46 ff 41 |_........v..[F.A| -00000340 c2 02 eb 21 85 31 b9 ba 2e 30 e7 6e 8d 1c 49 15 |...!.1...0.n..I.| -00000350 af a0 a7 67 62 b7 42 8c fa a8 04 8c 23 7a 3d 39 |...gb.B.....#z=9| -00000360 74 18 70 2b 99 |t.p+.| +00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 90 96 a6 |.5..............| +00000210 45 0a 8d 6a 38 86 3a f0 0a cb d6 bb db 9b 27 a6 |E..j8.:.......'.| +00000220 17 ca 02 6d 67 3c 56 80 74 9b 06 6e 62 58 55 43 |...mg>> 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 a6 5b 7c b0 91 |............[|..| -00000020 53 f6 d5 e4 34 71 4f 64 2a 03 9d 75 62 d9 8d a8 |S...4qOd*..ub...| -00000030 39 7b e1 d8 31 80 26 db 14 f3 3a 52 66 7d 12 31 |9{..1.&...:Rf}.1| -00000040 29 14 7f a1 39 b6 1c e0 c9 55 6e 17 03 03 00 40 |)...9....Un....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 52 d1 34 99 c9 |...........R.4..| +00000020 60 18 c3 99 36 2d c5 c2 14 ae f4 e5 10 e1 6f af |`...6-........o.| +00000030 70 3b c3 d6 d1 81 ee da fe 6e a5 96 81 53 cf 9a |p;.......n...S..| +00000040 cc c2 ac 98 95 0c 75 81 ac 55 6b 17 03 03 00 40 |......u..Uk....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 5e 00 64 9b 25 cd 74 94 b7 65 6e 83 8e 5b 68 e8 |^.d.%.t..en..[h.| -00000070 59 4c f0 31 8b f2 0c 59 2a ff 11 8e 43 d4 73 fd |YL.1...Y*...C.s.| -00000080 b3 2a 76 59 25 52 32 76 bd 2e 1d 4d 0a 53 d7 c2 |.*vY%R2v...M.S..| +00000060 46 ff 8d a9 0d 65 e1 82 48 4c 31 ec 60 24 61 52 |F....e..HL1.`$aR| +00000070 33 41 b1 7b 6a a8 96 b3 59 eb c9 2c f8 f2 4d 15 |3A.{j...Y..,..M.| +00000080 83 3e 99 c4 08 89 24 e3 de 4a bf 54 f4 eb a3 2a |.>....$..J.T...*| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 23 96 6e 7d 41 bb 51 4f 40 52 07 |.....#.n}A.QO@R.| -000000b0 90 cc 6c bd c0 bb 99 d4 8a 91 7b 8a f3 24 ef 71 |..l.......{..$.q| -000000c0 20 d4 98 b0 14 | ....| +000000a0 00 00 00 00 00 dc f3 c7 14 24 b7 a8 fa f4 78 6f |.........$....xo| +000000b0 7a 0c bd ad 14 d5 83 f7 97 30 58 0a a8 b5 76 88 |z........0X...v.| +000000c0 60 00 3d 4c 1a |`.=L.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven index 091de9081eb..924ef9df7e5 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5d 01 00 00 59 03 03 41 24 db 27 37 |....]...Y..A$.'7| -00000010 2e 1e a8 61 b7 7f 08 f1 83 84 fb d5 a2 96 e0 53 |...a...........S| -00000020 1a 2b cd 8e 50 38 7b a5 64 d8 92 00 00 04 00 2f |.+..P8{.d....../| +00000000 16 03 01 00 5d 01 00 00 59 03 03 ee 51 24 51 2c |....]...Y...Q$Q,| +00000010 0b 9f 26 d2 7c e0 8b 8a 9b a8 d3 a9 a7 59 05 a3 |..&.|........Y..| +00000020 67 92 fc 3f cb e8 cd ba 62 b7 19 00 00 04 00 2f |g..?....b....../| 00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| 00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................| @@ -48,36 +48,36 @@ 00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......| 00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..| 00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.| -00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@| -000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................| -000002b0 16 03 03 00 04 0e 00 00 00 |.........| +00000290 3b e9 fa e7 16 03 03 00 1b 0d 00 00 17 02 01 40 |;..............@| +000002a0 00 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 |................| +000002b0 02 03 00 00 16 03 03 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 61 2e 6b ad 77 48 8d 2f 0e |.......a.k.wH./.| -00000020 e6 27 64 fd 95 22 72 68 80 8e 2b 0e b2 0f cc be |.'d.."rh..+.....| -00000030 19 31 93 1d d3 0a fb 00 da 50 26 66 17 59 6b e9 |.1.......P&f.Yk.| -00000040 7e 16 4e 24 ba 68 0a 0c 69 2f 03 74 34 50 12 85 |~.N$.h..i/.t4P..| -00000050 4a f0 6c 52 d4 dd 13 18 c7 a4 9d ea f0 c6 94 d9 |J.lR............| -00000060 ae fe 19 6c 83 dd ed 38 e3 d2 21 18 e6 76 11 e7 |...l...8..!..v..| -00000070 62 13 8b 56 65 e0 f6 61 d9 db 7c 7b 5b 57 13 3d |b..Ve..a..|{[W.=| -00000080 58 64 67 8d 9f 3f 6a a0 70 c5 c6 d0 db eb 17 3f |Xdg..?j.p......?| -00000090 6c 58 d7 c3 ba ec 4c 14 03 03 00 01 01 16 03 03 |lX....L.........| -000000a0 00 40 6e 24 1b a4 b3 e7 d4 c2 7e cb bd 82 2d 4c |.@n$......~...-L| -000000b0 a8 f1 5e 81 c8 61 a6 2c 6a e3 6d 30 7f fa c7 f3 |..^..a.,j.m0....| -000000c0 f6 b1 b1 4f 0b 23 9a fd 66 81 48 97 4b 0f 88 07 |...O.#..f.H.K...| -000000d0 37 7b 97 b0 62 6c 2a e1 47 65 e9 f9 cd c1 79 99 |7{..bl*.Ge....y.| -000000e0 6d 84 |m.| +00000010 86 10 00 00 82 00 80 0b e8 d9 4f fa 7d 63 8c 89 |..........O.}c..| +00000020 b7 c8 73 76 9b fa 7f b6 c3 57 f2 54 75 90 90 ec |..sv.....W.Tu...| +00000030 9e 8d 08 ae 3f dc 6e fa df 2a 32 2b 35 e9 03 f7 |....?.n..*2+5...| +00000040 c5 d1 7c f5 20 1f 77 0a 24 b8 4e 7e 11 fe b0 87 |..|. .w.$.N~....| +00000050 db f6 ff 92 1a fc 6a 8d 48 7e ac bc 95 99 4a f8 |......j.H~....J.| +00000060 1b cc 07 42 48 0c 25 d2 47 82 59 14 76 84 d3 e9 |...BH.%.G.Y.v...| +00000070 d6 0a 5a b1 0a c6 31 3e 80 e2 29 c8 a6 31 dd 64 |..Z...1>..)..1.d| +00000080 96 7a f5 ee d9 0f 03 b5 93 05 b8 a2 04 66 ff fc |.z...........f..| +00000090 f5 2f e7 6c b9 2d 98 14 03 03 00 01 01 16 03 03 |./.l.-..........| +000000a0 00 40 f2 d2 da 46 89 c4 17 25 b8 33 d6 38 46 5c |.@...F...%.3.8F\| +000000b0 80 a0 eb cf fd 5a 27 f3 0b 16 e1 29 bd b8 46 28 |.....Z'....)..F(| +000000c0 11 d3 cc 12 12 96 9b b8 31 52 50 73 81 57 aa 29 |........1RPs.W.)| +000000d0 5c 66 da 39 2d f8 cb 15 e0 01 86 b5 0b d5 1f 56 |\f.9-..........V| +000000e0 23 a0 |#.| >>> 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 40 c6 62 4e 26 |...........@.bN&| -00000020 e7 32 09 ba d6 3b 71 79 8e 75 ee fb af 09 db c5 |.2...;qy.u......| -00000030 a5 8b cd 1f 90 f3 65 86 4a b4 b1 9a e8 1e 80 f6 |......e.J.......| -00000040 ad db bd c2 9f ec 98 42 0b 37 30 17 03 03 00 40 |.......B.70....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 65 58 5e 2f 25 |...........eX^/%| +00000020 67 71 87 7d a9 75 73 80 6b 03 76 63 a8 1f 80 06 |gq.}.us.k.vc....| +00000030 0f 78 b0 75 20 9e ab 36 59 d7 f9 88 22 c1 d1 be |.x.u ..6Y..."...| +00000040 c9 d2 c1 13 20 6a 75 07 95 00 ca 17 03 03 00 40 |.... ju........@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 a9 74 3c 13 87 f4 cf 77 be 07 c2 a1 e0 47 4e 52 |.t<....w.....GNR| -00000070 c2 86 da 08 c2 93 21 80 4c 19 51 cc 0d 76 49 75 |......!.L.Q..vIu| -00000080 0b 48 3d e0 e2 01 93 4b f1 73 91 17 aa 00 b5 71 |.H=....K.s.....q| +00000060 25 31 9c 1d 48 d9 c3 e4 59 3a 3a e2 85 3a 78 27 |%1..H...Y::..:x'| +00000070 85 69 63 8e 3c 32 b2 03 65 3f 7a 7f 3b fe b1 83 |.ic.<2..e?z.;...| +00000080 f6 64 a1 3e 83 55 7b 39 2a 01 86 de 79 a3 55 b1 |.d.>.U{9*...y.U.| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 1f 2f 2d d7 39 06 c4 59 49 80 66 |....../-.9..YI.f| -000000b0 6c 35 2e a7 45 ee 0a 05 4b 1e 7f 78 5d cd 24 2c |l5..E...K..x].$,| -000000c0 0a 3e 55 1c 7d |.>U.}| +000000a0 00 00 00 00 00 40 26 48 75 e5 e0 83 c0 1a 66 5a |.....@&Hu.....fZ| +000000b0 5f b2 11 a6 b7 a3 4d f2 ca 49 6a f2 48 a1 ee 99 |_.....M..Ij.H...| +000000c0 ff 0d c1 f7 4f |....O| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES index b412980e2af..8aa11abc62a 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 73 01 00 00 6f 03 03 f0 4f 82 cc 2a |....s...o...O..*| -00000010 27 0b 7f 2e e4 af 6d ba 4e fe 61 99 fc 0a 44 ee |'.....m.N.a...D.| -00000020 c0 4e 7b 3a 7c f0 6d 12 b7 7d 9e 00 00 04 c0 0a |.N{:|.m..}......| +00000000 16 03 01 00 73 01 00 00 6f 03 03 8b 7a 0c fa 8b |....s...o...z...| +00000010 92 b9 b6 d6 b8 93 50 29 07 2e 8e 70 9b a1 55 65 |......P)...p..Ue| +00000020 ba 05 9d 74 2e 7e a6 2a 10 e1 3c 00 00 04 c0 0a |...t.~.*..<.....| 00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........| 00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... | 00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| @@ -47,36 +47,36 @@ 00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b7 0c 00 |{j.9....*.......| 00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(| 00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........| -00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.| -00000280 2d d4 82 80 01 6b e6 8c 6a 2a b3 09 1b 0d 86 e6 |-....k..j*......| -00000290 62 92 85 46 d9 e3 b2 e9 f1 5e 77 c2 27 fd 2b 68 |b..F.....^w.'.+h| -000002a0 6a e1 3d e2 42 d2 86 96 42 b1 3b 50 7b e2 2c 34 |j.=.B...B.;P{.,4| -000002b0 d3 e7 f6 14 89 48 eb 5c 9a 98 98 ab f3 db 85 06 |.....H.\........| -000002c0 cb 02 42 00 df 42 94 63 a5 ff 43 a5 20 5d 83 09 |..B..B.c..C. ]..| -000002d0 88 7d 10 ff ec 32 33 28 1d 43 b2 d2 bf 39 0c 63 |.}...23(.C...9.c| -000002e0 9a c0 f8 0e 9f 71 a7 9a 5d 27 1a 5c f2 36 80 b3 |.....q..]'.\.6..| -000002f0 71 0f d3 c0 fd 0d 5d 02 90 c4 9d 90 db 74 ad f6 |q.....]......t..| -00000300 22 8f 6b 9d 55 16 03 03 00 04 0e 00 00 00 |".k.U.........| +00000270 99 5f 58 cb 3b 74 06 03 00 8b 30 81 88 02 42 00 |._X.;t....0...B.| +00000280 cb 8e af 48 f8 79 66 5b 9a 52 8d 67 ec 13 02 a5 |...H.yf[.R.g....| +00000290 ab 77 9e 15 17 c2 4e ff 7a b4 5b 53 1a 16 22 3f |.w....N.z.[S.."?| +000002a0 b8 83 40 99 64 67 b3 54 19 29 6b 2d a8 3c 63 44 |..@.dg.T.)k-.>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 af 52 73 d4 46 4d |....%...! .Rs.FM| -00000010 bc 0e dd 56 1f 7f 72 ce 6c 99 b9 64 53 7d 53 8d |...V..r.l..dS}S.| -00000020 0c a4 75 8c 83 3b 4b 76 2d 4f 14 03 03 00 01 01 |..u..;Kv-O......| -00000030 16 03 03 00 40 a0 ef 9f 54 a8 ab 7c 5b 4a a1 b2 |....@...T..|[J..| -00000040 5d 5b 6a d7 a7 32 35 46 58 d0 ba 38 6f 94 6e 9a |][j..25FX..8o.n.| -00000050 41 16 82 ed 4d 39 c4 ff 06 bf 2c 67 47 70 56 4e |A...M9....,gGpVN| -00000060 c5 ac 7f a0 5d d9 89 82 7a d9 36 07 55 b3 20 f4 |....]...z.6.U. .| -00000070 b2 73 cf c3 7d |.s..}| +00000000 16 03 03 00 25 10 00 00 21 20 d2 c0 5b 2a f2 05 |....%...! ..[*..| +00000010 4d 57 b0 d0 8b 51 b0 7f 1f 71 8b d9 55 76 46 c9 |MW...Q...q..UvF.| +00000020 a8 40 44 2c a1 51 74 50 4a 22 14 03 03 00 01 01 |.@D,.QtPJ"......| +00000030 16 03 03 00 40 79 6d 1b bc e7 5b 5c 7b 99 62 2b |....@ym...[\{.b+| +00000040 4a 1a b2 0f 76 72 67 d1 ec 25 04 5f fb 25 f4 9c |J...vrg..%._.%..| +00000050 9c 47 bb b9 85 28 59 0c 0c 15 3f 86 a5 16 c8 ef |.G...(Y...?.....| +00000060 a4 e6 8e c0 96 37 47 5a c8 cd f2 90 41 9b 94 dc |.....7GZ....A...| +00000070 ec fe e2 df d4 |.....| >>> 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 73 5f db 9e 08 |...........s_...| -00000020 10 38 3b c0 95 6b dd fc 16 b2 d1 db 63 13 ca d5 |.8;..k......c...| -00000030 b5 be 5a 1d 74 b5 75 f3 a2 63 59 be a7 d0 ab 0d |..Z.t.u..cY.....| -00000040 d3 43 83 8a 1d 59 ed fd ea f0 b9 17 03 03 00 40 |.C...Y.........@| +00000010 00 00 00 00 00 00 00 00 00 00 00 8a 19 1e 82 d0 |................| +00000020 46 f4 79 8d 9b fd 55 25 a9 6b d8 30 b3 41 f8 df |F.y...U%.k.0.A..| +00000030 a5 f8 9d 4c fe cc e1 1c 62 70 cf 60 12 cb 14 3e |...L....bp.`...>| +00000040 86 e9 d1 bb 46 60 7d b5 74 5f f5 17 03 03 00 40 |....F`}.t_.....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 cf 20 4f 4f bf c4 00 05 1e ca 7f 6f 69 77 e9 52 |. OO.......oiw.R| -00000070 14 61 02 6d f1 c0 ad 7c 1a 34 cf b2 7a 58 4a 70 |.a.m...|.4..zXJp| -00000080 11 36 5f e9 21 62 cb eb 8f e7 11 04 bf 66 03 69 |.6_.!b.......f.i| +00000060 97 1c 70 9d cf 17 89 8c c7 ad 84 38 6e f5 c6 d1 |..p........8n...| +00000070 c8 6e b2 a2 69 27 9a 59 fb bc af c0 15 47 40 b9 |.n..i'.Y.....G@.| +00000080 e1 35 9b 37 50 9f 05 53 60 f8 f9 91 40 67 36 a8 |.5.7P..S`...@g6.| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 f5 35 92 09 6c 45 c0 27 95 98 a9 |......5..lE.'...| -000000b0 86 56 53 1f a8 01 d5 0b 79 0e 91 15 3b 9a 07 21 |.VS.....y...;..!| -000000c0 cb ce f0 2b 6a |...+j| +000000a0 00 00 00 00 00 0f 90 a8 00 9e 0e 51 29 b5 96 da |...........Q)...| +000000b0 b1 0d 81 7b 71 ff c9 de f8 aa c4 bd e1 7d 0d 35 |...{q........}.5| +000000c0 b1 ed ae 20 3c |... <| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM index 4e52915ac5f..4c1cbc9ede4 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 73 01 00 00 6f 03 03 4e 1a d7 67 e4 |....s...o..N..g.| -00000010 d1 11 85 bc 62 59 da 8f ea d0 a0 2b 9b d3 47 aa |....bY.....+..G.| -00000020 d0 39 6f 3f 42 dc 7c 16 bb 25 ef 00 00 04 c0 2f |.9o?B.|..%...../| +00000000 16 03 01 00 73 01 00 00 6f 03 03 38 2b d9 54 15 |....s...o..8+.T.| +00000010 60 c3 a7 88 e6 c3 73 8f b0 76 4f d0 10 72 2c d6 |`.....s..vO..r,.| +00000020 55 fc c2 f0 ab 0f 62 43 f1 86 f8 00 00 04 c0 2f |U.....bC......./| 00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........| 00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... | 00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| @@ -52,28 +52,28 @@ 00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............| 000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)| 000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;| -000002c0 74 05 01 00 80 b2 49 30 60 b7 0c 48 cb 9f 1c 75 |t.....I0`..H...u| -000002d0 a6 b0 b0 7b 5e e6 f9 bc 5a 49 d4 51 e2 76 4c 01 |...{^...ZI.Q.vL.| -000002e0 55 bd 37 cf 86 75 4f 33 9b fd 3c fc bb da 81 a9 |U.7..uO3..<.....| -000002f0 26 7b 82 31 c5 51 0f d4 e8 fa a3 16 45 19 c8 40 |&{.1.Q......E..@| -00000300 23 fa 32 bc 05 36 fb a7 a2 d9 6f e7 bc b8 27 0b |#.2..6....o...'.| -00000310 2a 9e 7b 95 fd b4 c0 2e f0 73 fe fb a2 ea 20 a2 |*.{......s.... .| -00000320 73 73 96 c8 bc 82 58 09 84 fc f4 09 2a c8 68 cb |ss....X.....*.h.| -00000330 66 b0 de 2c 78 7a d4 ec 06 f1 1c 52 03 5a 69 24 |f..,xz.....R.Zi$| -00000340 c4 e6 bb 68 f4 16 03 03 00 04 0e 00 00 00 |...h..........| +000002c0 74 06 01 00 80 65 4e 5d 69 d6 97 39 e8 dc 13 58 |t....eN]i..9...X| +000002d0 c1 2a cf 72 12 42 34 8c 4a c1 b5 94 44 0c f2 97 |.*.r.B4.J...D...| +000002e0 46 ba 59 20 1c f2 9d 23 d7 2e 9f 7c 52 ac 08 fe |F.Y ...#...|R...| +000002f0 02 23 e3 ee ec 21 1f bd 08 8a 50 48 aa 21 b7 ed |.#...!....PH.!..| +00000300 be 30 be ac ff 8f e8 71 c9 bc d8 b8 56 63 8a fc |.0.....q....Vc..| +00000310 52 0e 3d e1 4e ce cc 53 d4 f8 36 70 1f 4e 16 61 |R.=.N..S..6p.N.a| +00000320 14 4d dd fe 17 08 f5 09 53 9b c6 24 7d de af dc |.M......S..$}...| +00000330 1b 84 23 c2 72 9c 25 73 1a 4f 42 27 b5 95 b1 06 |..#.r.%s.OB'....| +00000340 dd 36 de 0c 76 16 03 03 00 04 0e 00 00 00 |.6..v.........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 41 d4 8d 53 2e 47 |....%...! A..S.G| -00000010 b8 35 ba 86 3c 41 07 2e c1 a0 9d c2 e9 11 d8 20 |.5..>> 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 ec 99 e0 9a 83 28 94 e6 72 4f be 28 24 |........(..rO.($| -00000020 64 bd 9d 86 79 cc ab 05 15 39 06 6e da 0c b8 4e |d...y....9.n...N| -00000030 6c a9 f3 17 03 03 00 25 00 00 00 00 00 00 00 01 |l......%........| -00000040 9a d7 b0 54 dd 3c ae 8e 3f 1f 41 68 a5 01 a0 da |...T.<..?.Ah....| -00000050 e8 8e 90 55 1a 11 f0 70 8d a3 af a4 29 15 03 03 |...U...p....)...| -00000060 00 1a 00 00 00 00 00 00 00 02 a8 96 cb 16 d7 b1 |................| -00000070 41 7e bc 0e 01 8f cc 47 40 e5 c7 2a |A~.....G@..*| +00000010 00 00 00 fb 80 e0 2e 22 3e 45 98 c2 64 a1 0d 0a |.......">E..d...| +00000020 0c 55 40 6e 1b a9 de 29 e3 c8 1a b3 36 ba 5d 88 |.U@n...)....6.].| +00000030 c0 c9 d6 17 03 03 00 25 00 00 00 00 00 00 00 01 |.......%........| +00000040 ef 6a 01 41 ec 78 94 2d d5 c3 48 b8 5e 57 93 34 |.j.A.x.-..H.^W.4| +00000050 82 03 33 ae 03 22 69 9b 32 8f 71 73 6c 15 03 03 |..3.."i.2.qsl...| +00000060 00 1a 00 00 00 00 00 00 00 02 31 37 35 60 f8 01 |..........175`..| +00000070 5d 1f ab be 0d 79 ac c8 34 f0 14 f9 |]....y..4...| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 index 36be9da0d08..f80f166a47f 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 73 01 00 00 6f 03 03 b7 d2 dc fe 53 |....s...o......S| -00000010 d6 13 08 19 be 30 22 17 db a7 06 9b 62 82 14 38 |.....0".....b..8| -00000020 2e 68 70 08 02 7d 22 64 13 75 f5 00 00 04 c0 30 |.hp..}"d.u.....0| +00000000 16 03 01 00 73 01 00 00 6f 03 03 7c 43 b4 7c 36 |....s...o..|C.|6| +00000010 56 e5 d4 47 83 a7 ae 17 cb 5e 7d 5f b7 ef 41 dd |V..G.....^}_..A.| +00000020 63 d3 e6 a0 62 f7 af 91 25 75 15 00 00 04 c0 30 |c...b...%u.....0| 00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........| 00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... | 00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| @@ -52,28 +52,28 @@ 00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............| 000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)| 000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;| -000002c0 74 05 01 00 80 b8 c4 6a be 2a dd 47 03 7b 84 72 |t......j.*.G.{.r| -000002d0 0b a4 c0 a7 2e b5 a4 be c7 6a 2a 8b d0 23 6f b5 |.........j*..#o.| -000002e0 bc 0e ba 3c f5 9d a3 90 b0 af 80 11 bd 22 b5 7b |...<.........".{| -000002f0 3c 53 f8 54 d0 b4 b0 53 28 75 0d 15 58 88 c2 90 |R.....m.| +000002d0 8f de 69 34 58 71 9e 36 46 35 7e 73 ad f0 ee 30 |..i4Xq.6F5~s...0| +000002e0 0c 95 dc cc 28 ce 9b ee e6 44 3d ab ab 60 13 7c |....(....D=..`.|| +000002f0 3d 37 2d d0 36 95 04 74 df 5a a5 ef 9b 68 7c 58 |=7-.6..t.Z...h|X| +00000300 b4 22 e9 5d 15 aa 18 cc fc 8d 35 f4 ad aa dc 0d |.".]......5.....| +00000310 86 b6 e5 ac e3 8f ea c7 63 c6 a5 1e 2a 7e e2 9b |........c...*~..| +00000320 05 33 81 04 d4 87 ad 15 2d 7f 91 fd ca 85 a8 cb |.3......-.......| +00000330 66 56 e3 7a 4a 90 8c dc 7d 8f d0 af 6e 5e 88 7b |fV.zJ...}...n^.{| +00000340 34 2e 2f a0 2e 16 03 03 00 04 0e 00 00 00 |4./...........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 20 df 4a b8 02 4f |....%...! .J..O| -00000010 31 db 22 90 59 57 20 23 e1 72 8d 28 60 b3 f2 77 |1.".YW #.r.(`..w| -00000020 db 3a ce 64 5a a5 63 94 be 09 14 03 03 00 01 01 |.:.dZ.c.........| -00000030 16 03 03 00 28 de 72 f3 c3 b2 aa b4 9b b7 fe 35 |....(.r........5| -00000040 3b 25 af 74 47 d3 49 39 07 d9 70 37 30 d0 b7 47 |;%.tG.I9..p70..G| -00000050 bf ad 97 08 44 59 a7 3c 12 f2 4a 2d 7c |....DY.<..J-|| +00000000 16 03 03 00 25 10 00 00 21 20 a5 ce 37 03 eb 08 |....%...! ..7...| +00000010 67 8e 6b f8 37 b6 f8 cd c6 62 59 c1 8f 46 22 0d |g.k.7....bY..F".| +00000020 d8 e1 85 2e 26 dc 40 d3 f0 60 14 03 03 00 01 01 |....&.@..`......| +00000030 16 03 03 00 28 7d cf e0 cb 63 b3 22 fb b2 94 82 |....(}...c."....| +00000040 a7 1e 8d 71 15 a8 ba 14 b6 4b 67 37 f9 78 c4 33 |...q.....Kg7.x.3| +00000050 1b 7d 6c 8b 56 8f 85 d1 3e d3 9c 9f 95 |.}l.V...>....| >>> 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 16 18 e1 e8 d4 c0 d1 19 3a 50 10 85 fc |...........:P...| -00000020 fc 3e 27 54 e4 57 b6 e7 c4 25 d5 4e 10 ad 0f ff |.>'T.W...%.N....| -00000030 ad 45 8c 17 03 03 00 25 00 00 00 00 00 00 00 01 |.E.....%........| -00000040 50 b8 af 5f a2 3e 0f f7 f0 81 1f 32 69 39 2f f2 |P.._.>.....2i9/.| -00000050 47 28 80 fb d0 46 d4 b7 a2 ba e3 71 ea 15 03 03 |G(...F.....q....| -00000060 00 1a 00 00 00 00 00 00 00 02 c4 64 7a 81 b3 3a |...........dz..:| -00000070 2c 71 35 ec f7 0c 52 36 20 2c eb fe |,q5...R6 ,..| +00000010 00 00 00 3e cd 20 97 7b b3 2c 24 f2 cc ac 70 a4 |...>. .{.,$...p.| +00000020 4f f5 db 05 51 52 a8 ff 6e 01 98 c3 ec c7 2c 97 |O...QR..n.....,.| +00000030 6f f9 2c 17 03 03 00 25 00 00 00 00 00 00 00 01 |o.,....%........| +00000040 67 b8 c3 d5 7e 02 18 6f b8 db 10 5c 28 29 3d f6 |g...~..o...\()=.| +00000050 d0 69 a1 4f e8 a4 ce 22 81 65 10 7e d1 15 03 03 |.i.O...".e.~....| +00000060 00 1a 00 00 00 00 00 00 00 02 b0 df 28 f8 b8 f2 |............(...| +00000070 32 43 c3 d0 01 55 8f 47 c1 52 8d e3 |2C...U.G.R..| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM index 89587e9b8dc..17136d41130 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 73 01 00 00 6f 03 03 33 6d f4 4a 4b |....s...o..3m.JK| -00000010 48 35 ef 62 e9 bd 66 90 7e 73 62 bf 93 51 3d 90 |H5.b..f.~sb..Q=.| -00000020 9e f1 17 ae bd 24 28 54 44 50 8e 00 00 04 c0 2f |.....$(TDP...../| +00000000 16 03 01 00 73 01 00 00 6f 03 03 c3 5c 1e ad 54 |....s...o...\..T| +00000010 5b 03 af 49 42 dd cc 76 83 21 fe b4 4f 15 84 81 |[..IB..v.!..O...| +00000020 e5 07 5c 7d 58 3d 37 5a 3a ae f8 00 00 04 c0 2f |..\}X=7Z:....../| 00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........| 00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... | 00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| @@ -52,28 +52,28 @@ 00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............| 000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)| 000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;| -000002c0 74 05 01 00 80 61 aa 96 74 97 9f 2a 81 df 73 4d |t....a..t..*..sM| -000002d0 58 fb 8b 34 d9 51 02 1d 30 45 98 11 fa 20 cc 48 |X..4.Q..0E... .H| -000002e0 18 8d 92 4a bc bf 34 c2 52 cc 7b 7d 93 32 f9 98 |...J..4.R.{}.2..| -000002f0 eb d0 6d 58 4c 24 71 f1 78 cc ee 4d f8 26 26 d3 |..mXL$q.x..M.&&.| -00000300 b0 1c 46 67 ff 75 fc b5 b3 75 31 f3 9d d6 51 07 |..Fg.u...u1...Q.| -00000310 7a c1 2f 52 3f 88 23 f2 90 74 d0 77 6d 2b c7 31 |z./R?.#..t.wm+.1| -00000320 3d 81 a8 b9 84 a6 8f 96 25 91 e8 31 3b e9 20 b8 |=.......%..1;. .| -00000330 c4 11 68 da 58 0a ee 79 de fe 32 29 d6 24 b0 56 |..h.X..y..2).$.V| -00000340 ab e8 b5 57 fc 16 03 03 00 04 0e 00 00 00 |...W..........| +000002c0 74 06 01 00 80 d1 1b d9 90 1c 69 ef 70 d8 76 10 |t.........i.p.v.| +000002d0 fe ea ce c5 42 ea e7 da 1a 45 83 11 75 51 e9 a4 |....B....E..uQ..| +000002e0 fe 4c c6 b2 76 62 35 83 ae 45 08 80 07 76 0c d2 |.L..vb5..E...v..| +000002f0 b6 a7 7d b4 ca 5d a0 70 88 2c ad 03 44 30 14 d7 |..}..].p.,..D0..| +00000300 0b 9e 19 77 5f 2f 95 83 8a 5e 07 3e 7f 22 ca 86 |...w_/...^.>."..| +00000310 b9 ae 0d eb b8 0e ce ec 5d 1f 72 95 cf a5 3f 2c |........].r...?,| +00000320 82 2f 17 f7 63 07 cd 01 d1 50 31 49 e4 d1 2c 75 |./..c....P1I..,u| +00000330 1a 18 b9 76 51 33 f4 ff 74 37 cc bd 18 f9 3a 09 |...vQ3..t7....:.| +00000340 25 38 56 a4 7b 16 03 03 00 04 0e 00 00 00 |%8V.{.........| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 eb 0e 38 40 3f 32 |....%...! ..8@?2| -00000010 a4 95 fb c4 de e5 82 9a 4b 46 37 de 29 e5 6b e6 |........KF7.).k.| -00000020 44 bf f0 af 0c 62 19 bd 5c 0e 14 03 03 00 01 01 |D....b..\.......| -00000030 16 03 03 00 28 67 ad 91 f6 8d 8a 39 f7 f2 a6 42 |....(g.....9...B| -00000040 f2 8c 2f 1d b3 1d dd f1 88 65 7e 66 d2 d9 70 09 |../......e~f..p.| -00000050 4e 12 90 0d 0b d5 a5 a6 20 bc 32 63 05 |N....... .2c.| +00000000 16 03 03 00 25 10 00 00 21 20 71 94 86 30 e3 73 |....%...! q..0.s| +00000010 65 46 cb e3 ea 30 0b 32 77 f5 52 28 6f 98 a2 ed |eF...0.2w.R(o...| +00000020 52 6e 14 eb 5f 89 33 98 13 4a 14 03 03 00 01 01 |Rn.._.3..J......| +00000030 16 03 03 00 28 31 f7 9a 7d 84 21 17 7f c4 6e 9e |....(1..}.!...n.| +00000040 78 59 64 d1 d0 e7 74 fb 77 1b 7a b9 d5 e0 a6 c6 |xYd...t.w.z.....| +00000050 ec a4 9f 64 38 dd 24 8c d8 13 71 69 4f |...d8.$...qiO| >>> 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 56 b1 b8 16 9a 27 c6 ee d4 7f b7 68 83 |...V....'.....h.| -00000020 43 3b 04 92 ec cc c7 db 82 f8 7d 04 64 1d 55 cf |C;........}.d.U.| -00000030 02 69 ac 17 03 03 00 25 00 00 00 00 00 00 00 01 |.i.....%........| -00000040 d6 69 51 5d 3b 00 93 c2 a6 19 97 7d bf a9 d9 96 |.iQ];......}....| -00000050 43 1d ae 32 c3 52 1a f0 18 ba 10 4c e0 15 03 03 |C..2.R.....L....| -00000060 00 1a 00 00 00 00 00 00 00 02 1e 8a 5e 37 c0 b1 |............^7..| -00000070 0d 1e c9 6a 90 23 d6 4c 5c 47 5b bf |...j.#.L\G[.| +00000010 00 00 00 65 fc d6 aa c0 c7 6d 5e 94 bb cb 7c 19 |...e.....m^...|.| +00000020 f4 4f 4b 0e d5 b1 66 cc fb 7b d0 bb bc d3 de 55 |.OK...f..{.....U| +00000030 79 d5 57 17 03 03 00 25 00 00 00 00 00 00 00 01 |y.W....%........| +00000040 bf d0 4a cb ab f0 86 9a ec 92 19 5e 51 6e 63 4e |..J........^QncN| +00000050 00 c6 1f e8 af 15 ec e7 29 45 f5 54 dd 15 03 03 |........)E.T....| +00000060 00 1a 00 00 00 00 00 00 00 02 7e 20 a1 70 fa b9 |..........~ .p..| +00000070 6f b3 3b b0 65 b5 96 15 b0 f6 db 8a |o.;.e.......| diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go index 86812f0c974..97934ccbf4b 100644 --- a/libgo/go/crypto/tls/tls_test.go +++ b/libgo/go/crypto/tls/tls_test.go @@ -566,6 +566,58 @@ func TestConnCloseWrite(t *testing.T) { } } +func TestWarningAlertFlood(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + + server := func() error { + sconn, err := ln.Accept() + if err != nil { + return fmt.Errorf("accept: %v", err) + } + defer sconn.Close() + + serverConfig := testConfig.Clone() + srv := Server(sconn, serverConfig) + if err := srv.Handshake(); err != nil { + return fmt.Errorf("handshake: %v", err) + } + defer srv.Close() + + _, err = ioutil.ReadAll(srv) + if err == nil { + return errors.New("unexpected lack of error from server") + } + const expected = "too many warn" + if str := err.Error(); !strings.Contains(str, expected) { + return fmt.Errorf("expected error containing %q, but saw: %s", expected, str) + } + + return nil + } + + errChan := make(chan error, 1) + go func() { errChan <- server() }() + + clientConfig := testConfig.Clone() + conn, err := Dial("tcp", ln.Addr().String(), clientConfig) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + if err := conn.Handshake(); err != nil { + t.Fatal(err) + } + + for i := 0; i < maxWarnAlertCount+1; i++ { + conn.sendAlert(alertNoRenegotiation) + } + + if err := <-errChan; err != nil { + t.Fatal(err) + } +} + func TestCloneFuncFields(t *testing.T) { const expectedCount = 5 called := 0 diff --git a/libgo/go/crypto/x509/name_constraints_test.go b/libgo/go/crypto/x509/name_constraints_test.go new file mode 100644 index 00000000000..10cc3483576 --- /dev/null +++ b/libgo/go/crypto/x509/name_constraints_test.go @@ -0,0 +1,2002 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "fmt" + "io/ioutil" + "math/big" + "net" + "net/url" + "os" + "os/exec" + "strconv" + "strings" + "sync" + "testing" + "time" +) + +const ( + // testNameConstraintsAgainstOpenSSL can be set to true to run tests + // against the system OpenSSL. This is disabled by default because Go + // cannot depend on having OpenSSL installed at testing time. + testNameConstraintsAgainstOpenSSL = false + + // debugOpenSSLFailure can be set to true, when + // testNameConstraintsAgainstOpenSSL is also true, to cause + // intermediate files to be preserved for debugging. + debugOpenSSLFailure = false +) + +type nameConstraintsTest struct { + roots []constraintsSpec + intermediates [][]constraintsSpec + leaf leafSpec + expectedError string + noOpenSSL bool +} + +type constraintsSpec struct { + ok []string + bad []string + ekus []string +} + +type leafSpec struct { + sans []string + ekus []string +} + +var nameConstraintsTests = []nameConstraintsTest{ + // #0: dummy test for the certificate generation process itself. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #1: dummy test for the certificate generation process itself: single + // level of intermediate. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #2: dummy test for the certificate generation process itself: two + // levels of intermediates. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #3: matching DNS constraint in root + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #4: matching DNS constraint in intermediate. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #5: .example.com only matches subdomains. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + expectedError: "\"example.com\" is not permitted", + }, + + // #6: .example.com matches subdomains. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.example.com"}, + }, + }, + + // #7: .example.com matches multiple levels of subdomains + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.bar.example.com"}, + }, + }, + + // #8: specifying a permitted list of names does not exclude other name + // types + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:10.1.1.1"}, + }, + }, + + // #9: specifying a permitted list of names does not exclude other name + // types + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:10.0.0.0/8"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #10: intermediates can try to permit other names, which isn't + // forbidden if the leaf doesn't mention them. I.e. name constraints + // apply to names, not constraints themselves. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com", "dns:foo.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #11: intermediates cannot add permitted names that the root doesn't + // grant them. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:example.com", "dns:foo.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.com"}, + }, + expectedError: "\"foo.com\" is not permitted", + }, + + // #12: intermediates can further limit their scope if they wish. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.bar.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.bar.example.com"}, + }, + }, + + // #13: intermediates can further limit their scope and that limitation + // is effective + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.bar.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.notbar.example.com"}, + }, + expectedError: "\"foo.notbar.example.com\" is not permitted", + }, + + // #14: roots can exclude subtrees and that doesn't affect other names. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.com"}, + }, + }, + + // #15: roots exclusions are effective. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.example.com"}, + }, + expectedError: "\"foo.example.com\" is excluded", + }, + + // #16: intermediates can also exclude names and that doesn't affect + // other names. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.com"}, + }, + }, + + // #17: intermediate exclusions are effective. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.example.com"}, + }, + expectedError: "\"foo.example.com\" is excluded", + }, + + // #18: having an exclusion doesn't prohibit other types of names. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.com", "ip:10.1.1.1"}, + }, + }, + + // #19: IP-based exclusions are permitted and don't affect unrelated IP + // addresses. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:10.0.0.0/8"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:192.168.1.1"}, + }, + }, + + // #20: IP-based exclusions are effective + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:10.0.0.0/8"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:10.0.0.1"}, + }, + expectedError: "\"10.0.0.1\" is excluded", + }, + + // #21: intermediates can further constrain IP ranges. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:0.0.0.0/1"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:11.0.0.0/8"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:11.0.0.1"}, + }, + expectedError: "\"11.0.0.1\" is excluded", + }, + + // #22: when multiple intermediates are present, chain building can + // avoid intermediates with incompatible constraints. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.foo.com"}, + }, + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.example.com"}, + }, + noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. + }, + + // #23: (same as the previous test, but in the other order in ensure + // that we don't pass it by luck.) + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:.example.com"}, + }, + constraintsSpec{ + ok: []string{"dns:.foo.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:foo.example.com"}, + }, + noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. + }, + + // #24: when multiple roots are valid, chain building can avoid roots + // with incompatible constraints. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. + }, + + // #25: (same as the previous test, but in the other order in ensure + // that we don't pass it by luck.) + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. + }, + + // #26: chain building can find a valid path even with multiple levels + // of alternative intermediates and alternative roots. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + }, + []constraintsSpec{ + constraintsSpec{}, + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:bar.com"}, + }, + noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. + }, + + // #27: chain building doesn't get stuck when there is no valid path. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + constraintsSpec{ + ok: []string{"dns:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + }, + []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:bar.com"}, + }, + constraintsSpec{ + ok: []string{"dns:foo.com"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:bar.com"}, + }, + expectedError: "\"bar.com\" is not permitted", + }, + + // #28: unknown name types don't cause a problem without constraints. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"unknown:"}, + }, + }, + + // #29: unknown name types are allowed even in constrained chains. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:foo.com", "dns:.foo.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"unknown:"}, + }, + }, + + // #30: without SANs, a certificate is rejected in a constrained chain. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:foo.com", "dns:.foo.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{}, + }, + expectedError: "leaf doesn't have a SAN extension", + noOpenSSL: true, // OpenSSL doesn't require SANs in this case. + }, + + // #31: IPv6 addresses work in constraints: roots can permit them as + // expected. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:abcd:1234::"}, + }, + }, + + // #32: IPv6 addresses work in constraints: root restrictions are + // effective. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:1234:abcd::"}, + }, + expectedError: "\"2000:1234:abcd::\" is not permitted", + }, + + // #33: An IPv6 permitted subtree doesn't affect DNS names. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:abcd::", "dns:foo.com"}, + }, + }, + + // #34: IPv6 exclusions don't affect unrelated addresses. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:1234::"}, + }, + }, + + // #35: IPv6 exclusions are effective. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:abcd::"}, + }, + expectedError: "\"2000:abcd::\" is excluded", + }, + + // #36: IPv6 constraints do not permit IPv4 addresses. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:2000:abcd::/32"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:10.0.0.1"}, + }, + expectedError: "\"10.0.0.1\" is not permitted", + }, + + // #37: IPv4 constraints do not permit IPv6 addresses. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:10.0.0.0/8"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:2000:abcd::"}, + }, + expectedError: "\"2000:abcd::\" is not permitted", + }, + + // #38: an exclusion of an unknown type doesn't affect other names. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"unknown:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #39: a permitted subtree of an unknown type doesn't affect other + // name types. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"unknown:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #40: exact email constraints work + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:foo@example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + }, + + // #41: exact email constraints are effective + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:foo@example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:bar@example.com"}, + }, + expectedError: "\"bar@example.com\" is not permitted", + }, + + // #42: email canonicalisation works. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:foo@example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:\"\\f\\o\\o\"@example.com"}, + }, + noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching + }, + + // #43: limiting email addresses to a host works. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + }, + + // #44: a leading dot matches hosts one level deep + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@sub.example.com"}, + }, + }, + + // #45: a leading dot does not match the host itself + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + expectedError: "\"foo@example.com\" is not permitted", + }, + + // #46: a leading dot also matches two (or more) levels deep. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:.example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@sub.sub.example.com"}, + }, + }, + + // #47: the local part of an email is case-sensitive + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:foo@example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:Foo@example.com"}, + }, + expectedError: "\"Foo@example.com\" is not permitted", + }, + + // #48: the domain part of an email is not case-sensitive + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:foo@EXAMPLE.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + }, + + // #49: the domain part of a DNS constraint is also not case-sensitive. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:EXAMPLE.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #50: URI constraints only cover the host part of the URI + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{ + "uri:http://example.com/bar", + "uri:http://example.com:8080/", + "uri:https://example.com/wibble#bar", + }, + }, + }, + + // #51: URIs with IPs are rejected + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://1.2.3.4/"}, + }, + expectedError: "URI with IP", + }, + + // #52: URIs with IPs and ports are rejected + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://1.2.3.4:43/"}, + }, + expectedError: "URI with IP", + }, + + // #53: URIs with IPv6 addresses are also rejected + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://[2006:abcd::1]/"}, + }, + expectedError: "URI with IP", + }, + + // #54: URIs with IPv6 addresses with ports are also rejected + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://[2006:abcd::1]:16/"}, + }, + expectedError: "URI with IP", + }, + + // #55: URI constraints are effective + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://bar.com/"}, + }, + expectedError: "\"http://bar.com/\" is not permitted", + }, + + // #56: URI constraints are effective + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"uri:foo.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://foo.com/"}, + }, + expectedError: "\"http://foo.com/\" is excluded", + }, + + // #57: URI constraints can allow subdomains + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:.foo.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://www.foo.com/"}, + }, + }, + + // #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4 + // version of that address. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"ip:::ffff:1.2.3.4/128"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:1.2.3.4"}, + }, + }, + + // #59: a URI constraint isn't matched by a URN. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:urn:example"}, + }, + expectedError: "URI with empty host", + }, + + // #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses + // too, even though IPv4 is mapped into the IPv6 range. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"ip:1.2.3.0/24"}, + bad: []string{"ip:::0/0"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"ip:1.2.3.4"}, + }, + }, + + // #61: omitting extended key usage in a CA certificate implies that + // any usage is ok. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth", "other"}, + }, + }, + + // #62: The “any” EKU also means that any usage is ok. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"any"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth", "other"}, + }, + }, + + // #63: A specified key usage in an intermediate forbids other usages + // in the leaf. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"email"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth"}, + }, + expectedError: "EKU not permitted", + }, + + // #64: A specified key usage in an intermediate forbids other usages + // in the leaf, even if we don't recognise them. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"email"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"other"}, + }, + expectedError: "EKU not permitted", + }, + + // #65: trying to add extra permitted key usages in an intermediate + // (after a limitation in the root) is acceptable so long as the leaf + // certificate doesn't use them. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ekus: []string{"serverAuth"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"serverAuth", "email"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth"}, + }, + }, + + // #66: EKUs in roots are ignored. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ekus: []string{"serverAuth"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"serverAuth", "email"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth", "email"}, + }, + }, + + // #67: in order to support COMODO chains, SGC key usages permit + // serverAuth and clientAuth. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"netscapeSGC"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth", "clientAuth"}, + }, + }, + + // #68: in order to support COMODO chains, SGC key usages permit + // serverAuth and clientAuth. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{ + ekus: []string{"msSGC"}, + }, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth", "clientAuth"}, + }, + }, + + // #69: an empty DNS constraint should allow anything. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"dns:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + }, + + // #70: an empty DNS constraint should also reject everything. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"dns:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + }, + expectedError: "\"example.com\" is excluded", + }, + + // #71: an empty email constraint should allow anything + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"email:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + }, + + // #72: an empty email constraint should also reject everything. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"email:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:foo@example.com"}, + }, + expectedError: "\"foo@example.com\" is excluded", + }, + + // #73: an empty URI constraint should allow anything + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + ok: []string{"uri:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:https://example.com/test"}, + }, + }, + + // #74: an empty URI constraint should also reject everything. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"uri:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:https://example.com/test"}, + }, + expectedError: "\"https://example.com/test\" is excluded", + }, +} + +func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { + var serialBytes [16]byte + rand.Read(serialBytes[:]) + + template := &Certificate{ + SerialNumber: new(big.Int).SetBytes(serialBytes[:]), + Subject: pkix.Name{ + CommonName: name, + }, + NotBefore: time.Unix(1000, 0), + NotAfter: time.Unix(2000, 0), + KeyUsage: KeyUsageCertSign, + BasicConstraintsValid: true, + IsCA: true, + } + + if err := addConstraintsToTemplate(constraints, template); err != nil { + return nil, err + } + + if parent == nil { + parent = template + } + derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) + if err != nil { + return nil, err + } + + caCert, err := ParseCertificate(derBytes) + if err != nil { + return nil, err + } + + return caCert, nil +} + +func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { + var serialBytes [16]byte + rand.Read(serialBytes[:]) + + template := &Certificate{ + SerialNumber: new(big.Int).SetBytes(serialBytes[:]), + Subject: pkix.Name{ + // Don't set a CommonName because OpenSSL (at least) will try to + // match it against name constraints. + OrganizationalUnit: []string{"Leaf"}, + }, + NotBefore: time.Unix(1000, 0), + NotAfter: time.Unix(2000, 0), + KeyUsage: KeyUsageDigitalSignature, + BasicConstraintsValid: true, + IsCA: false, + } + + for _, name := range leaf.sans { + switch { + case strings.HasPrefix(name, "dns:"): + template.DNSNames = append(template.DNSNames, name[4:]) + + case strings.HasPrefix(name, "ip:"): + ip := net.ParseIP(name[3:]) + if ip == nil { + return nil, fmt.Errorf("cannot parse IP %q", name[3:]) + } + template.IPAddresses = append(template.IPAddresses, ip) + + case strings.HasPrefix(name, "email:"): + template.EmailAddresses = append(template.EmailAddresses, name[6:]) + + case strings.HasPrefix(name, "uri:"): + uri, err := url.Parse(name[4:]) + if err != nil { + return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err) + } + template.URIs = append(template.URIs, uri) + + case strings.HasPrefix(name, "unknown:"): + // This is a special case for testing unknown + // name types. A custom SAN extension is + // injected into the certificate. + if len(leaf.sans) != 1 { + panic("when using unknown name types, it must be the sole name") + } + + template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{ + Id: []int{2, 5, 29, 17}, + Value: []byte{ + 0x30, // SEQUENCE + 3, // three bytes + 9, // undefined GeneralName type 9 + 1, + 1, + }, + }) + + default: + return nil, fmt.Errorf("unknown name type %q", name) + } + } + + var err error + if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil { + return nil, err + } + + if parent == nil { + parent = template + } + + derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) + if err != nil { + return nil, err + } + + return ParseCertificate(derBytes) +} + +func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension { + appendConstraint := func(contents []byte, tag uint8) []byte { + contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */) + contents = append(contents, byte(4+len(constraint)) /* length */) + contents = append(contents, 0x30 /* SEQUENCE */) + contents = append(contents, byte(2+len(constraint)) /* length */) + contents = append(contents, byte(typeNum) /* GeneralName type */) + contents = append(contents, byte(len(constraint))) + return append(contents, constraint...) + } + + var contents []byte + if !isExcluded { + contents = appendConstraint(contents, 0 /* tag 0 for permitted */) + } else { + contents = appendConstraint(contents, 1 /* tag 1 for excluded */) + } + + var value []byte + value = append(value, 0x30 /* SEQUENCE */) + value = append(value, byte(len(contents))) + value = append(value, contents...) + + return pkix.Extension{ + Id: []int{2, 5, 29, 30}, + Value: value, + } +} + +func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error { + parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) { + for _, constraint := range constraints { + switch { + case strings.HasPrefix(constraint, "dns:"): + dnsNames = append(dnsNames, constraint[4:]) + + case strings.HasPrefix(constraint, "ip:"): + _, ipNet, err := net.ParseCIDR(constraint[3:]) + if err != nil { + return nil, nil, nil, nil, err + } + ips = append(ips, ipNet) + + case strings.HasPrefix(constraint, "email:"): + emailAddrs = append(emailAddrs, constraint[6:]) + + case strings.HasPrefix(constraint, "uri:"): + uriDomains = append(uriDomains, constraint[4:]) + + default: + return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint) + } + } + + return dnsNames, ips, emailAddrs, uriDomains, err + } + + handleSpecialConstraint := func(constraint string, isExcluded bool) bool { + switch { + case constraint == "unknown:": + template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded)) + + default: + return false + } + + return true + } + + if len(constraints.ok) == 1 && len(constraints.bad) == 0 { + if handleSpecialConstraint(constraints.ok[0], false) { + return nil + } + } + + if len(constraints.bad) == 1 && len(constraints.ok) == 0 { + if handleSpecialConstraint(constraints.bad[0], true) { + return nil + } + } + + var err error + template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok) + if err != nil { + return err + } + + template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad) + if err != nil { + return err + } + + if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil { + return err + } + + return nil +} + +func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) { + for _, s := range ekuStrs { + switch s { + case "serverAuth": + ekus = append(ekus, ExtKeyUsageServerAuth) + case "clientAuth": + ekus = append(ekus, ExtKeyUsageClientAuth) + case "email": + ekus = append(ekus, ExtKeyUsageEmailProtection) + case "netscapeSGC": + ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto) + case "msSGC": + ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto) + case "any": + ekus = append(ekus, ExtKeyUsageAny) + case "other": + unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3}) + default: + return nil, nil, fmt.Errorf("unknown EKU %q", s) + } + } + + return +} + +func TestConstraintCases(t *testing.T) { + privateKeys := sync.Pool{ + New: func() interface{} { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + return priv + }, + } + + for i, test := range nameConstraintsTests { + rootPool := NewCertPool() + rootKey := privateKeys.Get().(*ecdsa.PrivateKey) + rootName := "Root " + strconv.Itoa(i) + + // keys keeps track of all the private keys used in a given + // test and puts them back in the privateKeys pool at the end. + keys := []*ecdsa.PrivateKey{rootKey} + + // At each level (root, intermediate(s), leaf), parent points to + // an example parent certificate and parentKey the key for the + // parent level. Since all certificates at a given level have + // the same name and public key, any parent certificate is + // sufficient to get the correct issuer name and authority + // key ID. + var parent *Certificate + parentKey := rootKey + + for _, root := range test.roots { + rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey) + if err != nil { + t.Fatalf("#%d: failed to create root: %s", i, err) + } + + parent = rootCert + rootPool.AddCert(rootCert) + } + + intermediatePool := NewCertPool() + + for level, intermediates := range test.intermediates { + levelKey := privateKeys.Get().(*ecdsa.PrivateKey) + keys = append(keys, levelKey) + levelName := "Intermediate level " + strconv.Itoa(level) + var last *Certificate + + for _, intermediate := range intermediates { + caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey) + if err != nil { + t.Fatalf("#%d: failed to create %q: %s", i, levelName, err) + } + + last = caCert + intermediatePool.AddCert(caCert) + } + + parent = last + parentKey = levelKey + } + + leafKey := privateKeys.Get().(*ecdsa.PrivateKey) + keys = append(keys, leafKey) + + leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey) + if err != nil { + t.Fatalf("#%d: cannot create leaf: %s", i, err) + } + + if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL { + output, err := testChainAgainstOpenSSL(leafCert, intermediatePool, rootPool) + if err == nil && len(test.expectedError) > 0 { + t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i) + if debugOpenSSLFailure { + return + } + } + + if err != nil { + if _, ok := err.(*exec.ExitError); !ok { + t.Errorf("#%d: OpenSSL failed to run: %s", i, err) + } else if len(test.expectedError) == 0 { + t.Errorf("#%d: OpenSSL unexpectedly failed: %q", i, output) + if debugOpenSSLFailure { + return + } + } + } + } + + verifyOpts := VerifyOptions{ + Roots: rootPool, + Intermediates: intermediatePool, + CurrentTime: time.Unix(1500, 0), + } + _, err = leafCert.Verify(verifyOpts) + + logInfo := true + if len(test.expectedError) == 0 { + if err != nil { + t.Errorf("#%d: unexpected failure: %s", i, err) + } else { + logInfo = false + } + } else { + if err == nil { + t.Errorf("#%d: unexpected success", i) + } else if !strings.Contains(err.Error(), test.expectedError) { + t.Errorf("#%d: expected error containing %q, but got: %s", i, test.expectedError, err) + } else { + logInfo = false + } + } + + if logInfo { + certAsPEM := func(cert *Certificate) string { + var buf bytes.Buffer + pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) + return string(buf.Bytes()) + } + t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0])) + t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert)) + } + + for _, key := range keys { + privateKeys.Put(key) + } + keys = keys[:0] + } +} + +func writePEMsToTempFile(certs []*Certificate) *os.File { + file, err := ioutil.TempFile("", "name_constraints_test") + if err != nil { + panic("cannot create tempfile") + } + + pemBlock := &pem.Block{Type: "CERTIFICATE"} + for _, cert := range certs { + pemBlock.Bytes = cert.Raw + pem.Encode(file, pemBlock) + } + + return file +} + +func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool) (string, error) { + args := []string{"verify", "-no_check_time"} + + rootsFile := writePEMsToTempFile(roots.certs) + if debugOpenSSLFailure { + println("roots file:", rootsFile.Name()) + } else { + defer os.Remove(rootsFile.Name()) + } + args = append(args, "-CAfile", rootsFile.Name()) + + if len(intermediates.certs) > 0 { + intermediatesFile := writePEMsToTempFile(intermediates.certs) + if debugOpenSSLFailure { + println("intermediates file:", intermediatesFile.Name()) + } else { + defer os.Remove(intermediatesFile.Name()) + } + args = append(args, "-untrusted", intermediatesFile.Name()) + } + + leafFile := writePEMsToTempFile([]*Certificate{leaf}) + if debugOpenSSLFailure { + println("leaf file:", leafFile.Name()) + } else { + defer os.Remove(leafFile.Name()) + } + args = append(args, leafFile.Name()) + + var output bytes.Buffer + cmd := exec.Command("openssl", args...) + cmd.Stdout = &output + cmd.Stderr = &output + + err := cmd.Run() + return string(output.Bytes()), err +} + +var rfc2821Tests = []struct { + in string + localPart, domain string +}{ + {"foo@example.com", "foo", "example.com"}, + {"@example.com", "", ""}, + {"\"@example.com", "", ""}, + {"\"\"@example.com", "", "example.com"}, + {"\"a\"@example.com", "a", "example.com"}, + {"\"\\a\"@example.com", "a", "example.com"}, + {"a\"@example.com", "", ""}, + {"foo..bar@example.com", "", ""}, + {".foo.bar@example.com", "", ""}, + {"foo.bar.@example.com", "", ""}, + {"|{}?'@example.com", "|{}?'", "example.com"}, + + // Examples from RFC 3696 + {"Abc\\@def@example.com", "Abc@def", "example.com"}, + {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"}, + {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"}, + {"\"Abc@def\"@example.com", "Abc@def", "example.com"}, + {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"}, + {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"}, + {"$A12345@example.com", "$A12345", "example.com"}, + {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"}, + {"_somename@example.com", "_somename", "example.com"}, +} + +func TestRFC2821Parsing(t *testing.T) { + for i, test := range rfc2821Tests { + mailbox, ok := parseRFC2821Mailbox(test.in) + expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0 + + if ok && expectedFailure { + t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain) + continue + } + + if !ok && !expectedFailure { + t.Errorf("#%d: unexpected failure for %q", i, test.in) + continue + } + + if !ok { + continue + } + + if mailbox.local != test.localPart || mailbox.domain != test.domain { + t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain) + } + } +} + +func TestBadNamesInConstraints(t *testing.T) { + constraintParseError := func(err error) bool { + str := err.Error() + return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint") + } + + encodingError := func(err error) bool { + return strings.Contains(err.Error(), "cannot be encoded as an IA5String") + } + + // Bad names in constraints should not parse. + badNames := []struct { + name string + matcher func(error) bool + }{ + {"dns:foo.com.", constraintParseError}, + {"email:abc@foo.com.", constraintParseError}, + {"email:foo.com.", constraintParseError}, + {"uri:example.com.", constraintParseError}, + {"uri:1.2.3.4", constraintParseError}, + {"uri:ffff::1", constraintParseError}, + {"dns:not–hyphen.com", encodingError}, + {"email:foo@not–hyphen.com", encodingError}, + {"uri:not–hyphen.com", encodingError}, + } + + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + + for _, test := range badNames { + _, err := makeConstraintsCACert(constraintsSpec{ + ok: []string{test.name}, + }, "TestAbsoluteNamesInConstraints", priv, nil, priv) + + if err == nil { + t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name) + continue + } else { + if !test.matcher(err) { + t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err) + } + } + } +} + +func TestBadNamesInSANs(t *testing.T) { + // Bad names in SANs should not parse. + badNames := []string{ + "dns:foo.com.", + "email:abc@foo.com.", + "email:foo.com.", + "uri:https://example.com./dsf", + } + + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + + for _, badName := range badNames { + _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv) + + if err == nil { + t.Errorf("bad name %q unexpectedly accepted in SAN", badName) + continue + } + + if err != nil { + if str := err.Error(); !strings.Contains(str, "cannot parse ") { + t.Errorf("bad name %q triggered unrecognised error: %s", badName, str) + } + } + } +} diff --git a/libgo/go/crypto/x509/pkcs1.go b/libgo/go/crypto/x509/pkcs1.go index 73bc7623a5a..82502cfe581 100644 --- a/libgo/go/crypto/x509/pkcs1.go +++ b/libgo/go/crypto/x509/pkcs1.go @@ -119,3 +119,36 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { b, _ := asn1.Marshal(priv) return b } + +// ParsePKCS1PublicKey parses a PKCS#1 public key in ASN.1 DER form. +func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) { + var pub pkcs1PublicKey + rest, err := asn1.Unmarshal(der, &pub) + if err != nil { + return nil, err + } + if len(rest) > 0 { + return nil, asn1.SyntaxError{Msg: "trailing data"} + } + + if pub.N.Sign() <= 0 || pub.E <= 0 { + return nil, errors.New("x509: public key contains zero or negative value") + } + if pub.E > 1<<31-1 { + return nil, errors.New("x509: public key contains large public exponent") + } + + return &rsa.PublicKey{ + E: pub.E, + N: pub.N, + }, nil +} + +// MarshalPKCS1PublicKey converts an RSA public key to PKCS#1, ASN.1 DER form. +func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte { + derBytes, _ := asn1.Marshal(pkcs1PublicKey{ + N: key.N, + E: key.E, + }) + return derBytes +} diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go index b304a3f63c9..eb051b6e114 100644 --- a/libgo/go/crypto/x509/pkcs8.go +++ b/libgo/go/crypto/x509/pkcs8.go @@ -5,6 +5,8 @@ package x509 import ( + "crypto/ecdsa" + "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" "errors" @@ -52,3 +54,48 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } } + +// MarshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form. +// The following key types are supported: *rsa.PrivateKey, *ecdsa.PublicKey. +// Unsupported key types result in an error. +// +// See RFC 5208. +func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { + var privKey pkcs8 + + switch k := key.(type) { + case *rsa.PrivateKey: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyRSA, + Parameters: asn1.NullRawValue, + } + privKey.PrivateKey = MarshalPKCS1PrivateKey(k) + + case *ecdsa.PrivateKey: + oid, ok := oidFromNamedCurve(k.Curve) + if !ok { + return nil, errors.New("x509: unknown curve while marshalling to PKCS#8") + } + + oidBytes, err := asn1.Marshal(oid) + if err != nil { + return nil, errors.New("x509: failed to marshal curve OID: " + err.Error()) + } + + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyECDSA, + Parameters: asn1.RawValue{ + FullBytes: oidBytes, + }, + } + + if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil { + return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error()) + } + + default: + return nil, fmt.Errorf("x509: unknown key type while marshalling PKCS#8: %T", key) + } + + return asn1.Marshal(privKey) +} diff --git a/libgo/go/crypto/x509/pkcs8_test.go b/libgo/go/crypto/x509/pkcs8_test.go index 4114efd0e0d..c8f11e64d12 100644 --- a/libgo/go/crypto/x509/pkcs8_test.go +++ b/libgo/go/crypto/x509/pkcs8_test.go @@ -5,24 +5,105 @@ package x509 import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rsa" "encoding/hex" + "reflect" "testing" ) +// Generated using: +// openssl genrsa 1024 | openssl pkcs8 -topk8 -nocrypt var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` +// Generated using: +// openssl ecparam -genkey -name secp224r1 | openssl pkcs8 -topk8 -nocrypt +var pkcs8P224PrivateKeyHex = `3078020100301006072a8648ce3d020106052b810400210461305f020101041cca3d72b3e88fed2684576dad9b80a9180363a5424986900e3abcab3fa13c033a0004f8f2a6372872a4e61263ed893afb919576a4cacfecd6c081a2cbc76873cf4ba8530703c6042b3a00e2205087e87d2435d2e339e25702fae1` + +// Generated using: +// openssl ecparam -genkey -name secp256r1 | openssl pkcs8 -topk8 -nocrypt +var pkcs8P256PrivateKeyHex = `308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420dad6b2f49ca774c36d8ae9517e935226f667c929498f0343d2424d0b9b591b43a14403420004b9c9b90095476afe7b860d8bd43568cab7bcb2eed7b8bf2fa0ce1762dd20b04193f859d2d782b1e4cbfd48492f1f533113a6804903f292258513837f07fda735` + +// Generated using: +// openssl ecparam -genkey -name secp384r1 | openssl pkcs8 -topk8 -nocrypt +var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104309bf832f6aaaeacb78ce47ffb15e6fd0fd48683ae79df6eca39bfb8e33829ac94aa29d08911568684c2264a08a4ceb679a164036200049070ad4ed993c7770d700e9f6dc2baa83f63dd165b5507f98e8ff29b5d2e78ccbe05c8ddc955dbf0f7497e8222cfa49314fe4e269459f8e880147f70d785e530f2939e4bf9f838325bb1a80ad4cf59272ae0e5efe9a9dc33d874492596304bd3` + // Generated using: // openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt -var pkcs8ECPrivateKeyHex = `3081ed020100301006072a8648ce3d020106052b810400230481d53081d20201010441850d81618c5da1aec74c2eed608ba816038506975e6427237c2def150c96a3b13efbfa1f89f1be15cdf4d0ac26422e680e65a0ddd4ad3541ad76165fbf54d6e34ba18189038186000400da97bcedba1eb6d30aeb93c9f9a1454598fa47278df27d6f60ea73eb672d8dc528a9b67885b5b5dcef93c9824f7449ab512ee6a27e76142f56b94b474cfd697e810046c8ca70419365245c1d7d44d0db82c334073835d002232714548abbae6e5700f5ef315ee08b929d8581383dcf2d1c98c2f8a9fccbf79c9579f7b2fd8a90115ac2` +// +// Note that OpenSSL will truncate the private key if it can (i.e. it emits it +// like an integer, even though it's an OCTET STRING field). Thus if you +// regenerate this you may, randomly, find that it's a byte shorter than +// expected and the Go test will fail to recreate it exactly. +var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea` func TestPKCS8(t *testing.T) { - derBytes, _ := hex.DecodeString(pkcs8RSAPrivateKeyHex) - if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { - t.Errorf("failed to decode PKCS8 with RSA private key: %s", err) + tests := []struct { + name string + keyHex string + keyType reflect.Type + curve elliptic.Curve + }{ + { + name: "RSA private key", + keyHex: pkcs8RSAPrivateKeyHex, + keyType: reflect.TypeOf(&rsa.PrivateKey{}), + }, + { + name: "P-224 private key", + keyHex: pkcs8P224PrivateKeyHex, + keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), + curve: elliptic.P224(), + }, + { + name: "P-256 private key", + keyHex: pkcs8P256PrivateKeyHex, + keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), + curve: elliptic.P256(), + }, + { + name: "P-384 private key", + keyHex: pkcs8P384PrivateKeyHex, + keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), + curve: elliptic.P384(), + }, + { + name: "P-521 private key", + keyHex: pkcs8P521PrivateKeyHex, + keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), + curve: elliptic.P521(), + }, } - derBytes, _ = hex.DecodeString(pkcs8ECPrivateKeyHex) - if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { - t.Errorf("failed to decode PKCS8 with EC private key: %s", err) + for _, test := range tests { + derBytes, err := hex.DecodeString(test.keyHex) + if err != nil { + t.Errorf("%s: failed to decode hex: %s", test.name, err) + continue + } + privKey, err := ParsePKCS8PrivateKey(derBytes) + if err != nil { + t.Errorf("%s: failed to decode PKCS#8: %s", test.name, err) + continue + } + if reflect.TypeOf(privKey) != test.keyType { + t.Errorf("%s: decoded PKCS#8 returned unexpected key type: %T", test.name, privKey) + continue + } + if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC && ecKey.Curve != test.curve { + t.Errorf("%s: decoded PKCS#8 returned unexpected curve %#v", test.name, ecKey.Curve) + continue + } + reserialised, err := MarshalPKCS8PrivateKey(privKey) + if err != nil { + t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err) + continue + } + if !bytes.Equal(derBytes, reserialised) { + t.Errorf("%s: marshalled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes) + continue + } } } diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go index 39fd78df596..7b32220b74e 100644 --- a/libgo/go/crypto/x509/pkix/pkix.go +++ b/libgo/go/crypto/x509/pkix/pkix.go @@ -8,6 +8,8 @@ package pkix import ( "encoding/asn1" + "encoding/hex" + "fmt" "math/big" "time" ) @@ -21,6 +23,75 @@ type AlgorithmIdentifier struct { type RDNSequence []RelativeDistinguishedNameSET +var attributeTypeNames = map[string]string{ + "2.5.4.6": "C", + "2.5.4.10": "O", + "2.5.4.11": "OU", + "2.5.4.3": "CN", + "2.5.4.5": "SERIALNUMBER", + "2.5.4.7": "L", + "2.5.4.8": "ST", + "2.5.4.9": "STREET", + "2.5.4.17": "POSTALCODE", +} + +// String returns a string representation of the sequence r, +// roughly following the RFC 2253 Distinguished Names syntax. +func (r RDNSequence) String() string { + s := "" + for i := 0; i < len(r); i++ { + rdn := r[len(r)-1-i] + if i > 0 { + s += "," + } + for j, tv := range rdn { + if j > 0 { + s += "+" + } + + oidString := tv.Type.String() + typeName, ok := attributeTypeNames[oidString] + if !ok { + derBytes, err := asn1.Marshal(tv.Value) + if err == nil { + s += oidString + "=#" + hex.EncodeToString(derBytes) + continue // No value escaping necessary. + } + + typeName = oidString + } + + valueString := fmt.Sprint(tv.Value) + escaped := make([]rune, 0, len(valueString)) + + for k, c := range valueString { + escape := false + + switch c { + case ',', '+', '"', '\\', '<', '>', ';': + escape = true + + case ' ': + escape = k == 0 || k == len(valueString)-1 + + case '#': + escape = k == 0 + } + + if escape { + escaped = append(escaped, '\\', c) + } else { + escaped = append(escaped, c) + } + } + + s += typeName + "=" + string(escaped) + } + } + + return s +} + type RelativeDistinguishedNameSET []AttributeTypeAndValue // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in @@ -150,6 +221,12 @@ func (n Name) ToRDNSequence() (ret RDNSequence) { return ret } +// String returns the string form of n, roughly following +// the RFC 2253 Distinguished Names syntax. +func (n Name) String() string { + return n.ToRDNSequence().String() +} + // oidInAttributeTypeAndValue returns whether a type with the given OID exists // in atv. func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool { @@ -170,9 +247,9 @@ type CertificateList struct { SignatureValue asn1.BitString } -// HasExpired reports whether now is past the expiry time of certList. +// HasExpired reports whether certList should have been updated by now. func (certList *CertificateList) HasExpired(now time.Time) bool { - return now.After(certList.TBSCertList.NextUpdate) + return !now.Before(certList.TBSCertList.NextUpdate) } // TBSCertificateList represents the ASN.1 structure of the same name. See RFC diff --git a/libgo/go/crypto/x509/root_cgo_darwin.go b/libgo/go/crypto/x509/root_cgo_darwin.go index 8e805335904..5f0e5e1888a 100644 --- a/libgo/go/crypto/x509/root_cgo_darwin.go +++ b/libgo/go/crypto/x509/root_cgo_darwin.go @@ -207,8 +207,8 @@ import ( func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() - var data C.CFDataRef = nil - var untrustedData C.CFDataRef = nil + var data C.CFDataRef = 0 + var untrustedData C.CFDataRef = 0 err := C.FetchPEMRoots(&data, &untrustedData) if err == -1 { // TODO: better error message @@ -218,7 +218,7 @@ func loadSystemRoots() (*CertPool, error) { defer C.CFRelease(C.CFTypeRef(data)) buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) roots.AppendCertsFromPEM(buf) - if untrustedData == nil { + if untrustedData == 0 { return roots, nil } defer C.CFRelease(C.CFTypeRef(untrustedData)) diff --git a/libgo/go/crypto/x509/root_windows.go b/libgo/go/crypto/x509/root_windows.go index a936fec7d84..92cc71692d8 100644 --- a/libgo/go/crypto/x509/root_windows.go +++ b/libgo/go/crypto/x509/root_windows.go @@ -87,7 +87,7 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e status := chainCtx.TrustStatus.ErrorStatus switch status { case syscall.CERT_TRUST_IS_NOT_TIME_VALID: - return CertificateInvalidError{c, Expired} + return CertificateInvalidError{c, Expired, ""} default: return UnknownAuthorityError{c, nil, nil} } @@ -125,7 +125,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex if status.Error != 0 { switch status.Error { case syscall.CERT_E_EXPIRED: - return CertificateInvalidError{c, Expired} + return CertificateInvalidError{c, Expired, ""} case syscall.CERT_E_CN_NO_MATCH: return HostnameError{c, opts.DNSName} case syscall.CERT_E_UNTRUSTEDROOT: diff --git a/libgo/go/crypto/x509/sec1.go b/libgo/go/crypto/x509/sec1.go index 33f376c072c..3008d0df773 100644 --- a/libgo/go/crypto/x509/sec1.go +++ b/libgo/go/crypto/x509/sec1.go @@ -40,6 +40,12 @@ func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { return nil, errors.New("x509: unknown elliptic curve") } + return marshalECPrivateKeyWithOID(key, oid) +} + +// marshalECPrivateKey marshals an EC private key into ASN.1, DER format and +// sets the curve ID to the given OID, or omits it if OID is nil. +func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) { privateKeyBytes := key.D.Bytes() paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) diff --git a/libgo/go/crypto/x509/sec1_test.go b/libgo/go/crypto/x509/sec1_test.go index 55b76d6c381..573c937cafd 100644 --- a/libgo/go/crypto/x509/sec1_test.go +++ b/libgo/go/crypto/x509/sec1_test.go @@ -18,7 +18,7 @@ var ecKeyTests = []struct { // openssl ecparam -genkey -name secp384r1 -outform PEM {"3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50", true}, // This key was generated by GnuTLS and has illegal zero-padding of the - // private key. See https://github.com/golang/go/issues/13699. + // private key. See https://golang.org/issues/13699. {"3078020101042100f9f43a04b9bdc3ab01f53be6df80e7a7bc3eaf7b87fc24e630a4a0aa97633645a00a06082a8648ce3d030107a1440342000441a51bc318461b4c39a45048a16d4fc2a935b1ea7fe86e8c1fa219d6f2438f7c7fd62957d3442efb94b6a23eb0ea66dda663dc42f379cda6630b21b7888a5d3d", false}, // This was generated using an old version of OpenSSL and is missing a // leading zero byte in the private key that should be present. diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 2b4f39d62ea..7a6bd454f20 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -9,6 +9,8 @@ import ( "errors" "fmt" "net" + "net/url" + "reflect" "runtime" "strings" "time" @@ -25,8 +27,8 @@ const ( // given in the VerifyOptions. Expired // CANotAuthorizedForThisName results when an intermediate or root - // certificate has a name constraint which doesn't include the name - // being checked. + // certificate has a name constraint which doesn't permit a DNS or + // other name (including IP address) in the leaf certificate. CANotAuthorizedForThisName // TooManyIntermediates results when a path length constraint is // violated. @@ -37,6 +39,24 @@ const ( // NameMismatch results when the subject name of a parent certificate // does not match the issuer name in the child. NameMismatch + // NameConstraintsWithoutSANs results when a leaf certificate doesn't + // contain a Subject Alternative Name extension, but a CA certificate + // contains name constraints. + NameConstraintsWithoutSANs + // UnconstrainedName results when a CA certificate contains permitted + // name constraints, but leaf certificate contains a name of an + // unsupported or unconstrained type. + UnconstrainedName + // TooManyConstraints results when the number of comparision operations + // needed to check a certificate exceeds the limit set by + // VerifyOptions.MaxConstraintComparisions. This limit exists to + // prevent pathological certificates can consuming excessive amounts of + // CPU time to verify. + TooManyConstraints + // CANotAuthorizedForExtKeyUsage results when an intermediate or root + // certificate does not permit an extended key usage that is claimed by + // the leaf certificate. + CANotAuthorizedForExtKeyUsage ) // CertificateInvalidError results when an odd error occurs. Users of this @@ -44,6 +64,7 @@ const ( type CertificateInvalidError struct { Cert *Certificate Reason InvalidReason + Detail string } func (e CertificateInvalidError) Error() string { @@ -53,13 +74,19 @@ func (e CertificateInvalidError) Error() string { case Expired: return "x509: certificate has expired or is not yet valid" case CANotAuthorizedForThisName: - return "x509: a root or intermediate certificate is not authorized to sign in this domain" + return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail + case CANotAuthorizedForExtKeyUsage: + return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail case TooManyIntermediates: return "x509: too many intermediates for path length constraint" case IncompatibleUsage: - return "x509: certificate specifies an incompatible key usage" + return "x509: certificate specifies an incompatible key usage: " + e.Detail case NameMismatch: return "x509: issuer name does not match subject from issuing certificate" + case NameConstraintsWithoutSANs: + return "x509: issuer has name constraints but leaf doesn't have a SAN extension" + case UnconstrainedName: + return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail } return "x509: unknown error" } @@ -156,6 +183,12 @@ type VerifyOptions struct { // constraint down the chain which mirrors Windows CryptoAPI behavior, // but not the spec. To accept any key usage, include ExtKeyUsageAny. KeyUsages []ExtKeyUsage + // MaxConstraintComparisions is the maximum number of comparisons to + // perform when checking a given certificate's name constraints. If + // zero, a sensible default is used. This limit prevents pathalogical + // certificates from consuming excessive amounts of CPU time when + // validating. + MaxConstraintComparisions int } const ( @@ -164,37 +197,398 @@ const ( rootCertificate ) -func matchNameConstraint(domain, constraint string) bool { +// rfc2821Mailbox represents a “mailbox” (which is an email address to most +// people) by breaking it into the “local” (i.e. before the '@') and “domain” +// parts. +type rfc2821Mailbox struct { + local, domain string +} + +// parseRFC2821Mailbox parses an email address into local and domain parts, +// based on the ABNF for a “Mailbox” from RFC 2821. According to +// https://tools.ietf.org/html/rfc5280#section-4.2.1.6 that's correct for an +// rfc822Name from a certificate: “The format of an rfc822Name is a "Mailbox" +// as defined in https://tools.ietf.org/html/rfc2821#section-4.1.2”. +func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { + if len(in) == 0 { + return mailbox, false + } + + localPartBytes := make([]byte, 0, len(in)/2) + + if in[0] == '"' { + // Quoted-string = DQUOTE *qcontent DQUOTE + // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 + // qcontent = qtext / quoted-pair + // qtext = non-whitespace-control / + // %d33 / %d35-91 / %d93-126 + // quoted-pair = ("\" text) / obs-qp + // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text + // + // (Names beginning with “obs-” are the obsolete syntax from + // https://tools.ietf.org/html/rfc2822#section-4. Since it has + // been 16 years, we no longer accept that.) + in = in[1:] + QuotedString: + for { + if len(in) == 0 { + return mailbox, false + } + c := in[0] + in = in[1:] + + switch { + case c == '"': + break QuotedString + + case c == '\\': + // quoted-pair + if len(in) == 0 { + return mailbox, false + } + if in[0] == 11 || + in[0] == 12 || + (1 <= in[0] && in[0] <= 9) || + (14 <= in[0] && in[0] <= 127) { + localPartBytes = append(localPartBytes, in[0]) + in = in[1:] + } else { + return mailbox, false + } + + case c == 11 || + c == 12 || + // Space (char 32) is not allowed based on the + // BNF, but RFC 3696 gives an example that + // assumes that it is. Several “verified” + // errata continue to argue about this point. + // We choose to accept it. + c == 32 || + c == 33 || + c == 127 || + (1 <= c && c <= 8) || + (14 <= c && c <= 31) || + (35 <= c && c <= 91) || + (93 <= c && c <= 126): + // qtext + localPartBytes = append(localPartBytes, c) + + default: + return mailbox, false + } + } + } else { + // Atom ("." Atom)* + NextChar: + for len(in) > 0 { + // atext from https://tools.ietf.org/html/rfc2822#section-3.2.4 + c := in[0] + + switch { + case c == '\\': + // Examples given in RFC 3696 suggest that + // escaped characters can appear outside of a + // quoted string. Several “verified” errata + // continue to argue the point. We choose to + // accept it. + in = in[1:] + if len(in) == 0 { + return mailbox, false + } + fallthrough + + case ('0' <= c && c <= '9') || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + c == '!' || c == '#' || c == '$' || c == '%' || + c == '&' || c == '\'' || c == '*' || c == '+' || + c == '-' || c == '/' || c == '=' || c == '?' || + c == '^' || c == '_' || c == '`' || c == '{' || + c == '|' || c == '}' || c == '~' || c == '.': + localPartBytes = append(localPartBytes, in[0]) + in = in[1:] + + default: + break NextChar + } + } + + if len(localPartBytes) == 0 { + return mailbox, false + } + + // https://tools.ietf.org/html/rfc3696#section-3 + // “period (".") may also appear, but may not be used to start + // or end the local part, nor may two or more consecutive + // periods appear.” + twoDots := []byte{'.', '.'} + if localPartBytes[0] == '.' || + localPartBytes[len(localPartBytes)-1] == '.' || + bytes.Contains(localPartBytes, twoDots) { + return mailbox, false + } + } + + if len(in) == 0 || in[0] != '@' { + return mailbox, false + } + in = in[1:] + + // The RFC species a format for domains, but that's known to be + // violated in practice so we accept that anything after an '@' is the + // domain part. + if _, ok := domainToReverseLabels(in); !ok { + return mailbox, false + } + + mailbox.local = string(localPartBytes) + mailbox.domain = in + return mailbox, true +} + +// domainToReverseLabels converts a textual domain name like foo.example.com to +// the list of labels in reverse order, e.g. ["com", "example", "foo"]. +func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { + for len(domain) > 0 { + if i := strings.LastIndexByte(domain, '.'); i == -1 { + reverseLabels = append(reverseLabels, domain) + domain = "" + } else { + reverseLabels = append(reverseLabels, domain[i+1:len(domain)]) + domain = domain[:i] + } + } + + if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { + // An empty label at the end indicates an absolute value. + return nil, false + } + + for _, label := range reverseLabels { + if len(label) == 0 { + // Empty labels are otherwise invalid. + return nil, false + } + + for _, c := range label { + if c < 33 || c > 126 { + // Invalid character. + return nil, false + } + } + } + + return reverseLabels, true +} + +func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { + // If the constraint contains an @, then it specifies an exact mailbox + // name. + if strings.Contains(constraint, "@") { + constraintMailbox, ok := parseRFC2821Mailbox(constraint) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint) + } + return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil + } + + // Otherwise the constraint is like a DNS constraint of the domain part + // of the mailbox. + return matchDomainConstraint(mailbox.domain, constraint) +} + +func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { + // https://tools.ietf.org/html/rfc5280#section-4.2.1.10 + // “a uniformResourceIdentifier that does not include an authority + // component with a host name specified as a fully qualified domain + // name (e.g., if the URI either does not include an authority + // component or includes an authority component in which the host name + // is specified as an IP address), then the application MUST reject the + // certificate.” + + host := uri.Host + if len(host) == 0 { + return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String()) + } + + if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") { + var err error + host, _, err = net.SplitHostPort(uri.Host) + if err != nil { + return false, err + } + } + + if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || + net.ParseIP(host) != nil { + return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) + } + + return matchDomainConstraint(host, constraint) +} + +func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { + if len(ip) != len(constraint.IP) { + return false, nil + } + + for i := range ip { + if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask { + return false, nil + } + } + + return true, nil +} + +func matchDomainConstraint(domain, constraint string) (bool, error) { // The meaning of zero length constraints is not specified, but this // code follows NSS and accepts them as matching everything. if len(constraint) == 0 { - return true + return true, nil } - if len(domain) < len(constraint) { - return false + domainLabels, ok := domainToReverseLabels(domain) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) } - prefixLen := len(domain) - len(constraint) - if !strings.EqualFold(domain[prefixLen:], constraint) { - return false + // RFC 5280 says that a leading period in a domain name means that at + // least one label must be prepended, but only for URI and email + // constraints, not DNS constraints. The code also supports that + // behaviour for DNS constraints. + + mustHaveSubdomains := false + if constraint[0] == '.' { + mustHaveSubdomains = true + constraint = constraint[1:] + } + + constraintLabels, ok := domainToReverseLabels(constraint) + if !ok { + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) + } + + if len(domainLabels) < len(constraintLabels) || + (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) { + return false, nil + } + + for i, constraintLabel := range constraintLabels { + if !strings.EqualFold(constraintLabel, domainLabels[i]) { + return false, nil + } + } + + return true, nil +} + +// checkNameConstraints checks that c permits a child certificate to claim the +// given name, of type nameType. The argument parsedName contains the parsed +// form of name, suitable for passing to the match function. The total number +// of comparisons is tracked in the given count and should not exceed the given +// limit. +func (c *Certificate) checkNameConstraints(count *int, + maxConstraintComparisons int, + nameType string, + name string, + parsedName interface{}, + match func(parsedName, constraint interface{}) (match bool, err error), + permitted, excluded interface{}) error { + + excludedValue := reflect.ValueOf(excluded) + + *count += excludedValue.Len() + if *count > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + for i := 0; i < excludedValue.Len(); i++ { + constraint := excludedValue.Index(i).Interface() + match, err := match(parsedName, constraint) + if err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } + + if match { + return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)} + } + } + + permittedValue := reflect.ValueOf(permitted) + + *count += permittedValue.Len() + if *count > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + ok := true + for i := 0; i < permittedValue.Len(); i++ { + constraint := permittedValue.Index(i).Interface() + + var err error + if ok, err = match(parsedName, constraint); err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } + + if ok { + break + } + } + + if !ok { + return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)} + } + + return nil +} + +// ekuPermittedBy returns true iff the given extended key usage is permitted by +// the given EKU from a certificate. Normally, this would be a simple +// comparison plus a special case for the “any” EKU. But, in order to support +// existing certificates, some exceptions are made. +func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool { + if certEKU == ExtKeyUsageAny || eku == certEKU { + return true } - if prefixLen == 0 { + // Some exceptions are made to support existing certificates. Firstly, + // the ServerAuth and SGC EKUs are treated as a group. + mapServerAuthEKUs := func(eku ExtKeyUsage) ExtKeyUsage { + if eku == ExtKeyUsageNetscapeServerGatedCrypto || eku == ExtKeyUsageMicrosoftServerGatedCrypto { + return ExtKeyUsageServerAuth + } + return eku + } + + eku = mapServerAuthEKUs(eku) + certEKU = mapServerAuthEKUs(certEKU) + + if eku == certEKU || + // ServerAuth in a CA permits ClientAuth in the leaf. + (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) || + // Any CA may issue an OCSP responder certificate. + eku == ExtKeyUsageOCSPSigning || + // Code-signing CAs can use Microsoft's commercial and + // kernel-mode EKUs. + ((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) { return true } - isSubdomain := domain[prefixLen-1] == '.' - constraintHasLeadingDot := constraint[0] == '.' - return isSubdomain != constraintHasLeadingDot + return false } -// isValid performs validity checks on the c. +// isValid performs validity checks on c given that it is a candidate to append +// to the chain in currentChain. func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { + if len(c.UnhandledCriticalExtensions) > 0 { + return UnhandledCriticalExtension{} + } + if len(currentChain) > 0 { child := currentChain[len(currentChain)-1] if !bytes.Equal(child.RawIssuer, c.RawSubject) { - return CertificateInvalidError{c, NameMismatch} + return CertificateInvalidError{c, NameMismatch, ""} } } @@ -203,26 +597,148 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V now = time.Now() } if now.Before(c.NotBefore) || now.After(c.NotAfter) { - return CertificateInvalidError{c, Expired} + return CertificateInvalidError{c, Expired, ""} } - if len(c.PermittedDNSDomains) > 0 { - ok := false - for _, constraint := range c.PermittedDNSDomains { - ok = matchNameConstraint(opts.DNSName, constraint) - if ok { - break - } + maxConstraintComparisons := opts.MaxConstraintComparisions + if maxConstraintComparisons == 0 { + maxConstraintComparisons = 250000 + } + comparisonCount := 0 + + var leaf *Certificate + if certType == intermediateCertificate || certType == rootCertificate { + if len(currentChain) == 0 { + return errors.New("x509: internal error: empty chain when appending CA cert") } + leaf = currentChain[0] + } + if (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() { + sanExtension, ok := leaf.getSANExtension() if !ok { - return CertificateInvalidError{c, CANotAuthorizedForThisName} + // This is the deprecated, legacy case of depending on + // the CN as a hostname. Chains modern enough to be + // using name constraints should not be depending on + // CNs. + return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""} + } + + err := forEachSAN(sanExtension, func(tag int, data []byte) error { + switch tag { + case nameTypeEmail: + name := string(data) + mailbox, ok := parseRFC2821Mailbox(name) + if !ok { + // This certificate should not have parsed. + return errors.New("x509: internal error: rfc822Name SAN failed to parse") + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, + func(parsedName, constraint interface{}) (bool, error) { + return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) + }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { + return err + } + + case nameTypeDNS: + name := string(data) + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, + func(parsedName, constraint interface{}) (bool, error) { + return matchDomainConstraint(parsedName.(string), constraint.(string)) + }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { + return err + } + + case nameTypeURI: + name := string(data) + uri, err := url.Parse(name) + if err != nil { + return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, + func(parsedName, constraint interface{}) (bool, error) { + return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) + }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { + return err + } + + case nameTypeIP: + ip := net.IP(data) + if l := len(ip); l != net.IPv4len && l != net.IPv6len { + return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, + func(parsedName, constraint interface{}) (bool, error) { + return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) + }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { + return err + } + + default: + // Unknown SAN types are ignored. + } + + return nil + }) + + if err != nil { + return err } } - for _, constraint := range c.ExcludedDNSDomains { - if matchNameConstraint(opts.DNSName, constraint) { - return CertificateInvalidError{c, CANotAuthorizedForThisName} + checkEKUs := certType == intermediateCertificate + + // If no extended key usages are specified, then all are acceptable. + if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) { + checkEKUs = false + } + + // If the “any” key usage is permitted, then no more checks are needed. + if checkEKUs { + for _, caEKU := range c.ExtKeyUsage { + comparisonCount++ + if caEKU == ExtKeyUsageAny { + checkEKUs = false + break + } + } + } + + if checkEKUs { + NextEKU: + for _, eku := range leaf.ExtKeyUsage { + if comparisonCount > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + for _, caEKU := range c.ExtKeyUsage { + comparisonCount++ + if ekuPermittedBy(eku, caEKU) { + continue NextEKU + } + } + + oid, _ := oidFromExtKeyUsage(eku) + return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", oid)} + } + + NextUnknownEKU: + for _, eku := range leaf.UnknownExtKeyUsage { + if comparisonCount > maxConstraintComparisons { + return CertificateInvalidError{c, TooManyConstraints, ""} + } + + for _, caEKU := range c.UnknownExtKeyUsage { + comparisonCount++ + if caEKU.Equal(eku) { + continue NextUnknownEKU + } + } + + return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", eku)} } } @@ -244,13 +760,13 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V // encryption key could only be used for Diffie-Hellman key agreement. if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { - return CertificateInvalidError{c, NotAuthorizedToSign} + return CertificateInvalidError{c, NotAuthorizedToSign, ""} } if c.BasicConstraintsValid && c.MaxPathLen >= 0 { numIntermediates := len(currentChain) - 1 if numIntermediates > c.MaxPathLen { - return CertificateInvalidError{c, TooManyIntermediates} + return CertificateInvalidError{c, TooManyIntermediates, ""} } } @@ -285,10 +801,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e return c.systemVerify(&opts) } - if len(c.UnhandledCriticalExtensions) > 0 { - return nil, UnhandledCriticalExtension{} - } - if opts.Roots == nil { opts.Roots = systemRootsPool() if opts.Roots == nil { @@ -308,39 +820,46 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e } } - var candidateChains [][]*Certificate - if opts.Roots.contains(c) { - candidateChains = append(candidateChains, []*Certificate{c}) - } else { - if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil { - return nil, err - } + requestedKeyUsages := make([]ExtKeyUsage, len(opts.KeyUsages)) + copy(requestedKeyUsages, opts.KeyUsages) + if len(requestedKeyUsages) == 0 { + requestedKeyUsages = append(requestedKeyUsages, ExtKeyUsageServerAuth) } - keyUsages := opts.KeyUsages - if len(keyUsages) == 0 { - keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} - } + // If no key usages are specified, then any are acceptable. + checkEKU := len(c.ExtKeyUsage) > 0 - // If any key usage is acceptable then we're done. - for _, usage := range keyUsages { - if usage == ExtKeyUsageAny { - chains = candidateChains - return + for _, eku := range requestedKeyUsages { + if eku == ExtKeyUsageAny { + checkEKU = false + break } } - for _, candidate := range candidateChains { - if checkChainForKeyUsage(candidate, keyUsages) { - chains = append(chains, candidate) + if checkEKU { + NextUsage: + for _, eku := range requestedKeyUsages { + for _, leafEKU := range c.ExtKeyUsage { + if ekuPermittedBy(eku, leafEKU) { + continue NextUsage + } + } + + oid, _ := oidFromExtKeyUsage(eku) + return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)} } } - if len(chains) == 0 { - err = CertificateInvalidError{c, IncompatibleUsage} + var candidateChains [][]*Certificate + if opts.Roots.contains(c) { + candidateChains = append(candidateChains, []*Certificate{c}) + } else { + if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil { + return nil, err + } } - return + return candidateChains, nil } func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { @@ -501,65 +1020,3 @@ func (c *Certificate) VerifyHostname(h string) error { return HostnameError{c, h} } - -func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { - usages := make([]ExtKeyUsage, len(keyUsages)) - copy(usages, keyUsages) - - if len(chain) == 0 { - return false - } - - usagesRemaining := len(usages) - - // We walk down the list and cross out any usages that aren't supported - // 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 { - // The certificate doesn't have any extended key usage specified. - continue - } - - for _, usage := range cert.ExtKeyUsage { - if usage == ExtKeyUsageAny { - // The certificate is explicitly good for any usage. - continue NextCert - } - } - - const invalidUsage ExtKeyUsage = -1 - - NextRequestedUsage: - for i, requestedUsage := range usages { - if requestedUsage == invalidUsage { - continue - } - - for _, usage := range cert.ExtKeyUsage { - if requestedUsage == usage { - continue NextRequestedUsage - } else if requestedUsage == ExtKeyUsageServerAuth && - (usage == ExtKeyUsageNetscapeServerGatedCrypto || - usage == ExtKeyUsageMicrosoftServerGatedCrypto) { - // In order to support COMODO - // certificate chains, we have to - // accept Netscape or Microsoft SGC - // usages as equal to ServerAuth. - continue NextRequestedUsage - } - } - - usages[i] = invalidUsage - usagesRemaining-- - if usagesRemaining == 0 { - return false - } - } - } - - return true -} diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 335c477d0da..bd3df479078 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -296,6 +296,30 @@ var verifyTests = []verifyTest{ errorCallback: expectNameConstraintsError, }, + { + // Test that unknown critical extensions in a leaf cause a + // verify error. + leaf: criticalExtLeafWithExt, + dnsName: "example.com", + intermediates: []string{criticalExtIntermediate}, + roots: []string{criticalExtRoot}, + currentTime: 1486684488, + systemSkip: true, + + errorCallback: expectUnhandledCriticalExtension, + }, + { + // Test that unknown critical extensions in an intermediate + // cause a verify error. + leaf: criticalExtLeaf, + dnsName: "example.com", + intermediates: []string{criticalExtIntermediateWithExt}, + roots: []string{criticalExtRoot}, + currentTime: 1486684488, + systemSkip: true, + + errorCallback: expectUnhandledCriticalExtension, + }, } func expectHostnameError(t *testing.T, i int, err error) (ok bool) { @@ -379,6 +403,14 @@ func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) { return true } +func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) { + if _, ok := err.(UnhandledCriticalExtension); !ok { + t.Errorf("#%d: error was not an UnhandledCriticalExtension: %s", i, err) + return false + } + return true +} + func certificateFromPEM(pemBytes string) (*Certificate, error) { block, _ := pem.Decode([]byte(pemBytes)) if block == nil { @@ -1519,22 +1551,37 @@ func TestUnknownAuthorityError(t *testing.T) { var nameConstraintTests = []struct { constraint, domain string + expectError bool shouldMatch bool }{ - {"", "anything.com", true}, - {"example.com", "example.com", true}, - {"example.com", "ExAmPle.coM", true}, - {"example.com", "exampl1.com", false}, - {"example.com", "www.ExAmPle.coM", true}, - {"example.com", "notexample.com", false}, - {".example.com", "example.com", false}, - {".example.com", "www.example.com", true}, - {".example.com", "www..example.com", false}, + {"", "anything.com", false, true}, + {"example.com", "example.com", false, true}, + {"example.com.", "example.com", true, false}, + {"example.com", "example.com.", true, false}, + {"example.com", "ExAmPle.coM", false, true}, + {"example.com", "exampl1.com", false, false}, + {"example.com", "www.ExAmPle.coM", false, true}, + {"example.com", "sub.www.ExAmPle.coM", false, true}, + {"example.com", "notexample.com", false, false}, + {".example.com", "example.com", false, false}, + {".example.com", "www.example.com", false, true}, + {".example.com", "www..example.com", true, false}, } func TestNameConstraints(t *testing.T) { for i, test := range nameConstraintTests { - result := matchNameConstraint(test.domain, test.constraint) + result, err := matchDomainConstraint(test.domain, test.constraint) + + if err != nil && !test.expectError { + t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err) + continue + } + + if err == nil && test.expectError { + t.Errorf("unexpected success for test #%d: domain=%s, constraint=%s", i, test.domain, test.constraint) + continue + } + if result != test.shouldMatch { t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result) } @@ -1596,3 +1643,67 @@ w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi 4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs 8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA== -----END CERTIFICATE-----` + +const criticalExtRoot = `-----BEGIN CERTIFICATE----- +MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT +A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw +MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib +gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC +BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB +/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av +uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY +FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo= +-----END CERTIFICATE-----` + +const criticalExtIntermediate = `-----BEGIN CERTIFICATE----- +MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT +A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw +MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n +rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P +AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB +Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA +EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE +cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y +xXbdbm27KQ== +-----END CERTIFICATE-----` + +const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE----- +MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT +A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1 +MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No +6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw +gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD +AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud +IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID +SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E +I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg== +-----END CERTIFICATE-----` + +const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE----- +MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD +T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw +MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD +cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH +mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP +oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr +BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv +UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED +BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG +c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx +-----END CERTIFICATE-----` + +const criticalExtLeaf = `-----BEGIN CERTIFICATE----- +MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT +A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z +aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD +T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h +GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE +FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ +UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG +CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA +2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc= +-----END CERTIFICATE-----` diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index fdc7c5307bd..4c9182d9021 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -27,8 +27,14 @@ import ( "io" "math/big" "net" + "net/url" "strconv" + "strings" "time" + "unicode/utf8" + + "golang_org/x/crypto/cryptobyte" + cryptobyte_asn1 "golang_org/x/crypto/cryptobyte/asn1" ) // pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo @@ -194,27 +200,11 @@ func (algo SignatureAlgorithm) isRSAPSS() bool { } } -var algoName = [...]string{ - MD2WithRSA: "MD2-RSA", - MD5WithRSA: "MD5-RSA", - SHA1WithRSA: "SHA1-RSA", - SHA256WithRSA: "SHA256-RSA", - SHA384WithRSA: "SHA384-RSA", - SHA512WithRSA: "SHA512-RSA", - SHA256WithRSAPSS: "SHA256-RSAPSS", - SHA384WithRSAPSS: "SHA384-RSAPSS", - SHA512WithRSAPSS: "SHA512-RSAPSS", - DSAWithSHA1: "DSA-SHA1", - DSAWithSHA256: "DSA-SHA256", - ECDSAWithSHA1: "ECDSA-SHA1", - ECDSAWithSHA256: "ECDSA-SHA256", - ECDSAWithSHA384: "ECDSA-SHA384", - ECDSAWithSHA512: "ECDSA-SHA512", -} - func (algo SignatureAlgorithm) String() string { - if 0 < algo && int(algo) < len(algoName) { - return algoName[algo] + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.name + } } return strconv.Itoa(int(algo)) } @@ -228,6 +218,19 @@ const ( ECDSA ) +var publicKeyAlgoName = [...]string{ + RSA: "RSA", + DSA: "DSA", + ECDSA: "ECDSA", +} + +func (algo PublicKeyAlgorithm) String() string { + if 0 < algo && int(algo) < len(publicKeyAlgoName) { + return publicKeyAlgoName[algo] + } + return strconv.Itoa(int(algo)) +} + // OIDs for signature algorithms // // pkcs-1 OBJECT IDENTIFIER ::= { @@ -307,26 +310,27 @@ var ( var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm + name string 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}, - {SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, - {SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, - {SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, - {SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, - {SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA256}, - {SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA384}, - {SHA512WithRSAPSS, oidSignatureRSAPSS, 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}, + {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, + {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5}, + {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, + {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, + {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, + {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, + {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, + {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256}, + {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384}, + {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512}, + {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, + {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, + {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, + {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, + {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, + {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, } // pssParameters reflects the parameters in an AlgorithmIdentifier that @@ -549,18 +553,20 @@ const ( // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } var ( - oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} - oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} - oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} - oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} - oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} - oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} - oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} - oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} - oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} - oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} - oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} - oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} + oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} + oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} + oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} + oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} + oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} + oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} + oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} + oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} + oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} + oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} + oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} + oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} + oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} + oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} ) // ExtKeyUsage represents an extended set of actions that are valid for a given key. @@ -580,6 +586,8 @@ const ( ExtKeyUsageOCSPSigning ExtKeyUsageMicrosoftServerGatedCrypto ExtKeyUsageNetscapeServerGatedCrypto + ExtKeyUsageMicrosoftCommercialCodeSigning + ExtKeyUsageMicrosoftKernelCodeSigning ) // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. @@ -599,6 +607,8 @@ var extKeyUsageOIDs = []struct { {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, + {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, + {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, } func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { @@ -700,11 +710,18 @@ type Certificate struct { DNSNames []string EmailAddresses []string IPAddresses []net.IP + URIs []*url.URL // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. PermittedDNSDomains []string ExcludedDNSDomains []string + PermittedIPRanges []*net.IPNet + ExcludedIPRanges []*net.IPNet + PermittedEmailAddresses []string + ExcludedEmailAddresses []string + PermittedURIDomains []string + ExcludedURIDomains []string // CRL Distribution Points CRLDistributionPoints []string @@ -823,24 +840,48 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature return checkSignature(algo, signed, signature, c.PublicKey) } +func (c *Certificate) hasNameConstraints() bool { + for _, e := range c.Extensions { + if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 30 { + return true + } + } + + return false +} + +func (c *Certificate) getSANExtension() ([]byte, bool) { + for _, e := range c.Extensions { + if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 17 { + return e.Value, true + } + } + + return nil, false +} + +func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error { + return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey) +} + // CheckSignature verifies that signature is a valid signature over signed from // a crypto.PublicKey. func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) { var hashType crypto.Hash + var pubKeyAlgo PublicKeyAlgorithm - switch algo { - case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1: - hashType = crypto.SHA1 - case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256: - hashType = crypto.SHA256 - case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384: - hashType = crypto.SHA384 - case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512: - hashType = crypto.SHA512 - case MD2WithRSA, MD5WithRSA: - return InsecureAlgorithmError(algo) - default: + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + hashType = details.hash + pubKeyAlgo = details.pubKeyAlgo + } + } + + switch hashType { + case crypto.Hash(0): return ErrUnsupportedAlgorithm + case crypto.MD5: + return InsecureAlgorithmError(algo) } if !hashType.Available() { @@ -853,12 +894,18 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey switch pub := publicKey.(type) { case *rsa.PublicKey: + if pubKeyAlgo != RSA { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } if algo.isRSAPSS() { return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } else { return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) } case *dsa.PublicKey: + if pubKeyAlgo != DSA { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } dsaSig := new(dsaSignature) if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil { return err @@ -873,6 +920,9 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey } return case *ecdsa.PublicKey: + if pubKeyAlgo != ECDSA { + return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) + } ecdsaSig := new(ecdsaSignature) if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { return err @@ -913,15 +963,12 @@ type policyInformation struct { // policyQualifiers omitted } -// RFC 5280, 4.2.1.10 -type nameConstraints struct { - Permitted []generalSubtree `asn1:"optional,tag:0"` - Excluded []generalSubtree `asn1:"optional,tag:1"` -} - -type generalSubtree struct { - Name string `asn1:"tag:2,optional,ia5"` -} +const ( + nameTypeEmail = 1 + nameTypeDNS = 2 + nameTypeURI = 6 + nameTypeIP = 7 +) // RFC 5280, 4.2.2.1 type authorityInfoAccess struct { @@ -1031,7 +1078,7 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ } } -func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) { +func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error { // RFC 5280, 4.2.1.6 // SubjectAltName ::= GeneralNames @@ -1049,16 +1096,14 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue - var rest []byte - if rest, err = asn1.Unmarshal(value, &seq); err != nil { - return + rest, err := asn1.Unmarshal(extension, &seq) + if err != nil { + return err } else if len(rest) != 0 { - err = errors.New("x509: trailing data after X.509 extension") - return + return errors.New("x509: trailing data after X.509 extension") } if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { - err = asn1.StructuralError{Msg: "bad SAN sequence"} - return + return asn1.StructuralError{Msg: "bad SAN sequence"} } rest = seq.Bytes @@ -1066,27 +1111,243 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { - return + return err + } + + if err := callback(v.Tag, v.Bytes); err != nil { + return err } - 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) { + } + + return nil +} + +func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { + err = forEachSAN(value, func(tag int, data []byte) error { + switch tag { + case nameTypeEmail: + mailbox := string(data) + if _, ok := parseRFC2821Mailbox(mailbox); !ok { + return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) + } + emailAddresses = append(emailAddresses, mailbox) + case nameTypeDNS: + domain := string(data) + if _, ok := domainToReverseLabels(domain); !ok { + return fmt.Errorf("x509: cannot parse dnsName %q", string(data)) + } + dnsNames = append(dnsNames, domain) + case nameTypeURI: + uri, err := url.Parse(string(data)) + if err != nil { + return fmt.Errorf("x509: cannot parse URI %q: %s", string(data), err) + } + if len(uri.Host) > 0 { + if _, ok := domainToReverseLabels(uri.Host); !ok { + return fmt.Errorf("x509: cannot parse URI %q: invalid domain", string(data)) + } + } + uris = append(uris, uri) + case nameTypeIP: + switch len(data) { case net.IPv4len, net.IPv6len: - ipAddresses = append(ipAddresses, v.Bytes) + ipAddresses = append(ipAddresses, data) default: - err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes))) - return + return errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(data))) } } - } + + return nil + }) return } +// isValidIPMask returns true iff mask consists of zero or more 1 bits, followed by zero bits. +func isValidIPMask(mask []byte) bool { + seenZero := false + + for _, b := range mask { + if seenZero { + if b != 0 { + return false + } + + continue + } + + switch b { + case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: + seenZero = true + case 0xff: + default: + return false + } + } + + return true +} + +func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { + // RFC 5280, 4.2.1.10 + + // NameConstraints ::= SEQUENCE { + // permittedSubtrees [0] GeneralSubtrees OPTIONAL, + // excludedSubtrees [1] GeneralSubtrees OPTIONAL } + // + // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + // + // GeneralSubtree ::= SEQUENCE { + // base GeneralName, + // minimum [0] BaseDistance DEFAULT 0, + // maximum [1] BaseDistance OPTIONAL } + // + // BaseDistance ::= INTEGER (0..MAX) + + outer := cryptobyte.String(e.Value) + var toplevel, permitted, excluded cryptobyte.String + var havePermitted, haveExcluded bool + if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || + !outer.Empty() || + !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || + !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || + !toplevel.Empty() { + return false, errors.New("x509: invalid NameConstraints extension") + } + + if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { + // https://tools.ietf.org/html/rfc5280#section-4.2.1.10: + // “either the permittedSubtrees field + // or the excludedSubtrees MUST be + // present” + return false, errors.New("x509: empty name constraints extension") + } + + getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { + for !subtrees.Empty() { + var seq, value cryptobyte.String + var tag cryptobyte_asn1.Tag + if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || + !seq.ReadAnyASN1(&value, &tag) { + return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") + } + + var ( + dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() + emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() + ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() + uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() + ) + + switch tag { + case dnsTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain + // itself, but that's not valid in a + // normal domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) + } + dnsNames = append(dnsNames, domain) + + case ipTag: + l := len(value) + var ip, mask []byte + + switch l { + case 8: + ip = value[:4] + mask = value[4:] + + case 32: + ip = value[:16] + mask = value[16:] + + default: + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) + } + + if !isValidIPMask(mask) { + return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) + } + + ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) + + case emailTag: + constraint := string(value) + if err := isIA5String(constraint); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + // If the constraint contains an @ then + // it specifies an exact mailbox name. + if strings.Contains(constraint, "@") { + if _, ok := parseRFC2821Mailbox(constraint); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } else { + // Otherwise it's a domain name. + domain := constraint + if len(domain) > 0 && domain[0] == '.' { + domain = domain[1:] + } + if _, ok := domainToReverseLabels(domain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) + } + } + emails = append(emails, constraint) + + case uriTag: + domain := string(value) + if err := isIA5String(domain); err != nil { + return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) + } + + if net.ParseIP(domain) != nil { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) + } + + trimmedDomain := domain + if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { + // constraints can have a leading + // period to exclude the domain itself, + // but that's not valid in a normal + // domain name. + trimmedDomain = trimmedDomain[1:] + } + if _, ok := domainToReverseLabels(trimmedDomain); !ok { + return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) + } + uriDomains = append(uriDomains, domain) + + default: + unhandled = true + } + } + + return dnsNames, ips, emails, uriDomains, nil + } + + if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { + return false, err + } + if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { + return false, err + } + out.PermittedDNSDomainsCritical = e.Critical + + return unhandled, nil +} + func parseCertificate(in *certificate) (*Certificate, error) { out := new(Certificate) out.Raw = in.Raw @@ -1166,61 +1427,22 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.MaxPathLenZero = out.MaxPathLen == 0 // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) case 17: - out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value) + out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) if err != nil { return nil, err } - if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 { + if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { // If we didn't parse anything then we do the critical check, below. unhandled = true } case 30: - // RFC 5280, 4.2.1.10 - - // NameConstraints ::= SEQUENCE { - // permittedSubtrees [0] GeneralSubtrees OPTIONAL, - // excludedSubtrees [1] GeneralSubtrees OPTIONAL } - // - // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree - // - // GeneralSubtree ::= SEQUENCE { - // base GeneralName, - // minimum [0] BaseDistance DEFAULT 0, - // maximum [1] BaseDistance OPTIONAL } - // - // BaseDistance ::= INTEGER (0..MAX) - - var constraints nameConstraints - if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil { + unhandled, err = parseNameConstraintsExtension(out, e) + if err != nil { return nil, err - } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after X.509 NameConstraints") - } - - getDNSNames := func(subtrees []generalSubtree, isCritical bool) (dnsNames []string, err error) { - for _, subtree := range subtrees { - if len(subtree.Name) == 0 { - if isCritical { - return nil, UnhandledCriticalExtension{} - } - continue - } - dnsNames = append(dnsNames, subtree.Name) - } - - return dnsNames, nil } - if out.PermittedDNSDomains, err = getDNSNames(constraints.Permitted, e.Critical); err != nil { - return out, err - } - if out.ExcludedDNSDomains, err = getDNSNames(constraints.Excluded, e.Critical); err != nil { - return out, err - } - out.PermittedDNSDomainsCritical = e.Critical - case 31: // RFC 5280, 4.2.1.13 @@ -1454,13 +1676,13 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo // 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) { +func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) { var rawValues []asn1.RawValue for _, name := range dnsNames { - rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}) + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)}) } for _, email := range emailAddresses { - rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)}) + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)}) } for _, rawIP := range ipAddresses { // If possible, we always want to encode IPv4 addresses in 4 bytes. @@ -1468,12 +1690,25 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBy if ip == nil { ip = rawIP } - rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip}) + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip}) + } + for _, uri := range uris { + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())}) } return asn1.Marshal(rawValues) } -func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.Extension, err error) { +func isIA5String(s string) error { + for _, r := range s { + if r >= utf8.RuneSelf { + return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) + } + } + + return nil +} + +func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 @@ -1579,10 +1814,14 @@ func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.E n++ } - if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) && + if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { ret[n].Id = oidExtensionSubjectAltName - ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses) + // https://tools.ietf.org/html/rfc5280#section-4.2.1.6 + // “If the subject field contains an empty sequence ... then + // subjectAltName extension ... is marked as critical” + ret[n].Critical = subjectIsEmpty + ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) if err != nil { return } @@ -1603,25 +1842,100 @@ func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.E n++ } - if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0) && + if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 || + len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 || + len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 || + len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) && !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { ret[n].Id = oidExtensionNameConstraints ret[n].Critical = template.PermittedDNSDomainsCritical - var out nameConstraints + ipAndMask := func(ipNet *net.IPNet) []byte { + maskedIP := ipNet.IP.Mask(ipNet.Mask) + ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask)) + ipAndMask = append(ipAndMask, maskedIP...) + ipAndMask = append(ipAndMask, ipNet.Mask...) + return ipAndMask + } + + serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) { + var b cryptobyte.Builder + + for _, name := range dns { + if err = isIA5String(name); err != nil { + return nil, err + } + + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(name)) + }) + }) + } + + for _, ipNet := range ips { + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes(ipAndMask(ipNet)) + }) + }) + } + + for _, email := range emails { + if err = isIA5String(email); err != nil { + return nil, err + } + + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(email)) + }) + }) + } + + for _, uriDomain := range uriDomains { + if err = isIA5String(uriDomain); err != nil { + return nil, err + } - out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains)) - for i, permitted := range template.PermittedDNSDomains { - out.Permitted[i] = generalSubtree{Name: permitted} + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddBytes([]byte(uriDomain)) + }) + }) + } + + return b.Bytes() } - out.Excluded = make([]generalSubtree, len(template.ExcludedDNSDomains)) - for i, excluded := range template.ExcludedDNSDomains { - out.Excluded[i] = generalSubtree{Name: excluded} + + permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains) + if err != nil { + return nil, err } - ret[n].Value, err = asn1.Marshal(out) + excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains) if err != nil { - return + return nil, err + } + + var b cryptobyte.Builder + b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { + if len(permitted) > 0 { + b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { + b.AddBytes(permitted) + }) + } + + if len(excluded) > 0 { + b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { + b.AddBytes(excluded) + }) + } + }) + + ret[n].Value, err = b.Bytes() + if err != nil { + return nil, err } n++ } @@ -1732,7 +2046,11 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori return } -// CreateCertificate creates a new certificate based on a template. +// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is +// just an empty SEQUENCE. +var emptyASN1Subject = []byte{0x30, 0} + +// CreateCertificate creates a new X.509v3 certificate based on a template. // The following members of template are used: AuthorityKeyId, // BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, // IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore, @@ -1786,7 +2104,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv authorityKeyId = parent.SubjectKeyId } - extensions, err := buildExtensions(template, authorityKeyId) + extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId) if err != nil { return } @@ -1968,6 +2286,7 @@ type CertificateRequest struct { DNSNames []string EmailAddresses []string IPAddresses []net.IP + URIs []*url.URL } // These structures reflect the ASN.1 structure of X.509 certificate @@ -2059,7 +2378,7 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) // CreateCertificateRequest creates a new certificate request based on a // template. The following members of template are used: Attributes, DNSNames, -// EmailAddresses, ExtraExtensions, IPAddresses, SignatureAlgorithm, and +// EmailAddresses, ExtraExtensions, IPAddresses, URIs, SignatureAlgorithm, and // Subject. The private key is the private key of the signer. // // The returned slice is the certificate request in DER encoding. @@ -2088,9 +2407,9 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv var extensions []pkix.Extension - if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) && + if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { - sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses) + sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) if err != nil { return nil, err } @@ -2265,7 +2584,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error for _, extension := range out.Extensions { if extension.Id.Equal(oidExtensionSubjectAltName) { - out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(extension.Value) + out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value) if err != nil { return nil, err } diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index 2d1acf93bf5..502f5d21d38 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -22,6 +22,7 @@ import ( "internal/testenv" "math/big" "net" + "net/url" "os/exec" "reflect" "runtime" @@ -178,6 +179,125 @@ func TestMarshalRSAPrivateKey(t *testing.T) { } } +func TestMarshalRSAPublicKey(t *testing.T) { + pub := &rsa.PublicKey{ + N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"), + E: 3, + } + derBytes := MarshalPKCS1PublicKey(pub) + pub2, err := ParsePKCS1PublicKey(derBytes) + if err != nil { + t.Errorf("ParsePKCS1PublicKey: %s", err) + } + if pub.N.Cmp(pub2.N) != 0 || pub.E != pub2.E { + t.Errorf("ParsePKCS1PublicKey = %+v, want %+v", pub, pub2) + } + + // It's never been documented that asn1.Marshal/Unmarshal on rsa.PublicKey works, + // but it does, and we know of code that depends on it. + // Lock that in, even though we'd prefer that people use MarshalPKCS1PublicKey and ParsePKCS1PublicKey. + derBytes2, err := asn1.Marshal(*pub) + if err != nil { + t.Errorf("Marshal(rsa.PublicKey): %v", err) + } else if !bytes.Equal(derBytes, derBytes2) { + t.Errorf("Marshal(rsa.PublicKey) = %x, want %x", derBytes2, derBytes) + } + pub3 := new(rsa.PublicKey) + rest, err := asn1.Unmarshal(derBytes, pub3) + if err != nil { + t.Errorf("Unmarshal(rsa.PublicKey): %v", err) + } + if len(rest) != 0 || pub.N.Cmp(pub3.N) != 0 || pub.E != pub3.E { + t.Errorf("Unmarshal(rsa.PublicKey) = %+v, %q want %+v, %q", pub, rest, pub2, []byte(nil)) + } + + publicKeys := []struct { + derBytes []byte + expectedErrSubstr string + }{ + { + derBytes: []byte{ + 0x30, 6, // SEQUENCE, 6 bytes + 0x02, 1, // INTEGER, 1 byte + 17, + 0x02, 1, // INTEGER, 1 byte + 3, // 3 + }, + }, { + derBytes: []byte{ + 0x30, 6, // SEQUENCE + 0x02, 1, // INTEGER, 1 byte + 0xff, // -1 + 0x02, 1, // INTEGER, 1 byte + 3, + }, + expectedErrSubstr: "zero or negative", + }, { + derBytes: []byte{ + 0x30, 6, // SEQUENCE + 0x02, 1, // INTEGER, 1 byte + 17, + 0x02, 1, // INTEGER, 1 byte + 0xff, // -1 + }, + expectedErrSubstr: "zero or negative", + }, { + derBytes: []byte{ + 0x30, 6, // SEQUENCE + 0x02, 1, // INTEGER, 1 byte + 17, + 0x02, 1, // INTEGER, 1 byte + 3, + 1, + }, + expectedErrSubstr: "trailing data", + }, { + derBytes: []byte{ + 0x30, 9, // SEQUENCE + 0x02, 1, // INTEGER, 1 byte + 17, + 0x02, 4, // INTEGER, 4 bytes + 0x7f, 0xff, 0xff, 0xff, + }, + }, { + derBytes: []byte{ + 0x30, 10, // SEQUENCE + 0x02, 1, // INTEGER, 1 byte + 17, + 0x02, 5, // INTEGER, 5 bytes + 0x00, 0x80, 0x00, 0x00, 0x00, + }, + // On 64-bit systems, encoding/asn1 will accept the + // public exponent, but ParsePKCS1PublicKey will return + // an error. On 32-bit systems, encoding/asn1 will + // return the error. The common substring of both error + // is the word “large”. + expectedErrSubstr: "large", + }, + } + + for i, test := range publicKeys { + shouldFail := len(test.expectedErrSubstr) > 0 + pub, err := ParsePKCS1PublicKey(test.derBytes) + if shouldFail { + if err == nil { + t.Errorf("#%d: unexpected success, got %#v", i, pub) + } else if !strings.Contains(err.Error(), test.expectedErrSubstr) { + t.Errorf("#%d: expected error containing %q, got %s", i, test.expectedErrSubstr, err) + } + } else { + if err != nil { + t.Errorf("#%d: unexpected failure: %s", i, err) + continue + } + reserialized := MarshalPKCS1PublicKey(pub) + if !bytes.Equal(reserialized, test.derBytes) { + t.Errorf("#%d: failed to reserialize: got %x, expected %x", i, reserialized, test.derBytes) + } + } + } +} + type matchHostnamesTest struct { pattern, host string ok bool @@ -288,6 +408,27 @@ func TestCertificateParse(t *testing.T) { } } +func TestMismatchedSignatureAlgorithm(t *testing.T) { + der, _ := pem.Decode([]byte(rsaPSSSelfSignedPEM)) + if der == nil { + t.Fatal("Failed to find PEM block") + } + + cert, err := ParseCertificate(der.Bytes) + if err != nil { + t.Fatal(err) + } + + if err = cert.CheckSignature(ECDSAWithSHA256, nil, nil); err == nil { + t.Fatal("CheckSignature unexpectedly return no error") + } + + const expectedSubstring = " but have public key of type " + if !strings.Contains(err.Error(), expectedSubstring) { + t.Errorf("Expected error containing %q, but got %q", expectedSubstring, err) + } +} + var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886" + "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465" + "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465" + @@ -331,6 +472,22 @@ var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be13 "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a" + "36dcd585d6ace53f546f961e05af" +func parseCIDR(s string) *net.IPNet { + _, net, err := net.ParseCIDR(s) + if err != nil { + panic(err) + } + return net +} + +func parseURI(s string) *url.URL { + uri, err := url.Parse(s) + if err != nil { + panic(err) + } + return uri +} + func TestCreateSelfSignedCertificate(t *testing.T) { random := rand.Reader @@ -402,10 +559,17 @@ func TestCreateSelfSignedCertificate(t *testing.T) { 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")}, - - PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, - PermittedDNSDomains: []string{".example.com", "example.com"}, - ExcludedDNSDomains: []string{"bar.example.com"}, + URIs: []*url.URL{parseURI("https://foo.com/wibble#foo")}, + + PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, + PermittedDNSDomains: []string{".example.com", "example.com"}, + ExcludedDNSDomains: []string{"bar.example.com"}, + PermittedIPRanges: []*net.IPNet{parseCIDR("192.168.1.1/16"), parseCIDR("1.2.3.4/8")}, + ExcludedIPRanges: []*net.IPNet{parseCIDR("2001:db8::/48")}, + PermittedEmailAddresses: []string{"foo@example.com"}, + ExcludedEmailAddresses: []string{".example.com", "example.com"}, + PermittedURIDomains: []string{".bar.com", "bar.com"}, + ExcludedURIDomains: []string{".bar2.com", "bar2.com"}, CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"}, @@ -447,6 +611,30 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: failed to parse name constraint exclusions: %#v", test.name, cert.ExcludedDNSDomains) } + if len(cert.PermittedIPRanges) != 2 || cert.PermittedIPRanges[0].String() != "192.168.0.0/16" || cert.PermittedIPRanges[1].String() != "1.0.0.0/8" { + t.Errorf("%s: failed to parse IP constraints: %#v", test.name, cert.PermittedIPRanges) + } + + if len(cert.ExcludedIPRanges) != 1 || cert.ExcludedIPRanges[0].String() != "2001:db8::/48" { + t.Errorf("%s: failed to parse IP constraint exclusions: %#v", test.name, cert.ExcludedIPRanges) + } + + if len(cert.PermittedEmailAddresses) != 1 || cert.PermittedEmailAddresses[0] != "foo@example.com" { + t.Errorf("%s: failed to parse permitted email addreses: %#v", test.name, cert.PermittedEmailAddresses) + } + + if len(cert.ExcludedEmailAddresses) != 2 || cert.ExcludedEmailAddresses[0] != ".example.com" || cert.ExcludedEmailAddresses[1] != "example.com" { + t.Errorf("%s: failed to parse excluded email addreses: %#v", test.name, cert.ExcludedEmailAddresses) + } + + if len(cert.PermittedURIDomains) != 2 || cert.PermittedURIDomains[0] != ".bar.com" || cert.PermittedURIDomains[1] != "bar.com" { + t.Errorf("%s: failed to parse permitted URIs: %#v", test.name, cert.PermittedURIDomains) + } + + if len(cert.ExcludedURIDomains) != 2 || cert.ExcludedURIDomains[0] != ".bar2.com" || cert.ExcludedURIDomains[1] != "bar2.com" { + t.Errorf("%s: failed to parse excluded URIs: %#v", test.name, cert.ExcludedURIDomains) + } + if cert.Subject.CommonName != commonName { t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName) } @@ -455,6 +643,14 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: ExtraNames didn't override Country", test.name) } + for _, ext := range cert.Extensions { + if ext.Id.Equal(oidExtensionSubjectAltName) { + if ext.Critical { + t.Fatal("SAN extension is marked critical") + } + } + } + found := false for _, atv := range cert.Subject.Names { if atv.Type.Equal([]int{2, 5, 4, 42}) { @@ -498,6 +694,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: SAN emails differ from template. Got %v, want %v", test.name, cert.EmailAddresses, template.EmailAddresses) } + if len(cert.URIs) != 1 || cert.URIs[0].String() != "https://foo.com/wibble#foo" { + t.Errorf("%s: URIs differ from template. Got %v, want %v", test.name, cert.URIs, template.URIs) + } + if !reflect.DeepEqual(cert.IPAddresses, template.IPAddresses) { t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses) } @@ -523,74 +723,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) { } } -func TestUnknownCriticalExtension(t *testing.T) { - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatalf("Failed to generate ECDSA key: %s", err) - } - - oids := []asn1.ObjectIdentifier{ - // This OID is in the PKIX arc, but unknown. - {2, 5, 29, 999999}, - // This is a nonsense, unassigned OID. - {1, 2, 3, 4}, - } - - for _, oid := range oids { - template := Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: "foo", - }, - NotBefore: time.Unix(1000, 0), - NotAfter: time.Now().AddDate(1, 0, 0), - - BasicConstraintsValid: true, - IsCA: true, - - KeyUsage: KeyUsageCertSign, - ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, - - ExtraExtensions: []pkix.Extension{ - { - Id: oid, - Critical: true, - Value: nil, - }, - }, - } - - derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - t.Fatalf("failed to create certificate: %s", err) - } - - cert, err := ParseCertificate(derBytes) - if err != nil { - t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err) - } - - roots := NewCertPool() - roots.AddCert(cert) - - // Setting Roots ensures that Verify won't delegate to the OS - // library and thus the correct error should always be - // returned. - _, err = cert.Verify(VerifyOptions{Roots: roots}) - if err == nil { - t.Fatal("Certificate with unknown critical extension was verified without error") - } - if _, ok := err.(UnhandledCriticalExtension); !ok { - t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err) - } - - cert.UnhandledCriticalExtensions = nil - if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil { - t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err) - } - } -} - // Self-signed certificate using ECDSA with SHA1 & secp256r1 var ecdsaSHA1CertPem = ` -----BEGIN CERTIFICATE----- @@ -1059,7 +1191,7 @@ func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *Certificate } func TestCertificateRequestOverrides(t *testing.T) { - sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil) + sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -1116,7 +1248,7 @@ func TestCertificateRequestOverrides(t *testing.T) { t.Errorf("bad attributes: %#v\n", csr.Attributes) } - sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil) + sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -1491,3 +1623,271 @@ func TestSystemCertPool(t *testing.T) { t.Fatal(err) } } + +const emptyNameConstraintsPEM = ` +-----BEGIN CERTIFICATE----- +MIIC1jCCAb6gAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UEAxMdRW1w +dHkgbmFtZSBjb25zdHJhaW50cyBpc3N1ZXIwHhcNMTMwMjAxMDAwMDAwWhcNMjAw +NTMwMTA0ODM4WjAhMR8wHQYDVQQDExZFbXB0eSBuYW1lIGNvbnN0cmFpbnRzMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwriElUIt3LCqmJObs+yDoWPD +F5IqgWk6moIobYjPfextZiYU6I3EfvAwoNxPDkN2WowcocUZMJbEeEq5ebBksFnx +f12gBxlIViIYwZAzu7aFvhDMyPKQI3C8CG0ZSC9ABZ1E3umdA3CEueNOmP/TChNq +Cl23+BG1Qb/PJkpAO+GfpWSVhTcV53Mf/cKvFHcjGNrxzdSoq9fyW7a6gfcGEQY0 +LVkmwFWUfJ0wT8kaeLr0E0tozkIfo01KNWNzv6NcYP80QOBRDlApWu9ODmEVJHPD +blx4jzTQ3JLa+4DvBNOjVUOp+mgRmjiW0rLdrxwOxIqIOwNjweMCp/hgxX/hTQID +AQABoxEwDzANBgNVHR4EBjAEoAChADANBgkqhkiG9w0BAQsFAAOCAQEAWG+/zUMH +QhP8uNCtgSHyim/vh7wminwAvWgMKxlkLBFns6nZeQqsOV1lABY7U0Zuoqa1Z5nb +6L+iJa4ElREJOi/erLc9uLwBdDCAR0hUTKD7a6i4ooS39DTle87cUnj0MW1CUa6H +v5SsvpYW+1XleYJk/axQOOTcy4Es53dvnZsjXH0EA/QHnn7UV+JmlE3rtVxcYp6M +LYPmRhTioROA/drghicRkiu9hxdPyxkYS16M5g3Zj30jdm+k/6C6PeNtN9YmOOga +nCOSyFYfGhqOANYzpmuV+oIedAsPpIbfIzN8njYUs1zio+1IoI4o8ddM9sCbtPU8 +o+WoY6IsCKXV/g== +-----END CERTIFICATE-----` + +func TestEmptyNameConstraints(t *testing.T) { + block, _ := pem.Decode([]byte(emptyNameConstraintsPEM)) + _, err := ParseCertificate(block.Bytes) + if err == nil { + t.Fatal("unexpected success") + } + + const expected = "empty name constraints" + if str := err.Error(); !strings.Contains(str, expected) { + t.Errorf("expected %q in error but got %q", expected, str) + } +} + +func TestPKIXNameString(t *testing.T) { + pem, err := hex.DecodeString(certBytes) + if err != nil { + t.Fatal(err) + } + certs, err := ParseCertificates(pem) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + dn pkix.Name + want string + }{ + {pkix.Name{ + CommonName: "Steve Kille", + Organization: []string{"Isode Limited"}, + OrganizationalUnit: []string{"RFCs"}, + Locality: []string{"Richmond"}, + Province: []string{"Surrey"}, + StreetAddress: []string{"The Square"}, + PostalCode: []string{"TW9 1DT"}, + SerialNumber: "RFC 2253", + Country: []string{"GB"}, + }, "SERIALNUMBER=RFC 2253,CN=Steve Kille,OU=RFCs,O=Isode Limited,POSTALCODE=TW9 1DT,STREET=The Square,L=Richmond,ST=Surrey,C=GB"}, + {certs[0].Subject, + "CN=mail.google.com,O=Google Inc,L=Mountain View,ST=California,C=US"}, + {pkix.Name{ + Organization: []string{"#Google, Inc. \n-> 'Alphabet\" "}, + Country: []string{"US"}, + }, "O=\\#Google\\, Inc. \n-\\> 'Alphabet\\\"\\ ,C=US"}, + {pkix.Name{ + CommonName: "foo.com", + Organization: []string{"Gopher Industries"}, + ExtraNames: []pkix.AttributeTypeAndValue{ + {Type: asn1.ObjectIdentifier([]int{2, 5, 4, 3}), Value: "bar.com"}}, + }, "CN=bar.com,O=Gopher Industries"}, + {pkix.Name{ + Locality: []string{"Gophertown"}, + ExtraNames: []pkix.AttributeTypeAndValue{ + {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}}, + }, "1.2.3.4.5=#130a676f6c616e672e6f7267,L=Gophertown"}, + } + + for i, test := range tests { + if got := test.dn.String(); got != test.want { + t.Errorf("#%d: String() = \n%s\n, want \n%s", i, got, test.want) + } + } +} + +func TestRDNSequenceString(t *testing.T) { + // Test some extra cases that get lost in pkix.Name conversions such as + // multi-valued attributes. + + var ( + oidCountry = []int{2, 5, 4, 6} + oidOrganization = []int{2, 5, 4, 10} + oidOrganizationalUnit = []int{2, 5, 4, 11} + oidCommonName = []int{2, 5, 4, 3} + ) + + tests := []struct { + seq pkix.RDNSequence + want string + }{ + { + seq: pkix.RDNSequence{ + pkix.RelativeDistinguishedNameSET{ + pkix.AttributeTypeAndValue{Type: oidCountry, Value: "US"}, + }, + pkix.RelativeDistinguishedNameSET{ + pkix.AttributeTypeAndValue{Type: oidOrganization, Value: "Widget Inc."}, + }, + pkix.RelativeDistinguishedNameSET{ + pkix.AttributeTypeAndValue{Type: oidOrganizationalUnit, Value: "Sales"}, + pkix.AttributeTypeAndValue{Type: oidCommonName, Value: "J. Smith"}, + }, + }, + want: "OU=Sales+CN=J. Smith,O=Widget Inc.,C=US", + }, + } + + for i, test := range tests { + if got := test.seq.String(); got != test.want { + t.Errorf("#%d: String() = \n%s\n, want \n%s", i, got, test.want) + } + } +} + +const criticalNameConstraintWithUnknownTypePEM = ` +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UEAxMdRW1w +dHkgbmFtZSBjb25zdHJhaW50cyBpc3N1ZXIwHhcNMTMwMjAxMDAwMDAwWhcNMjAw +NTMwMTA0ODM4WjAhMR8wHQYDVQQDExZFbXB0eSBuYW1lIGNvbnN0cmFpbnRzMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwriElUIt3LCqmJObs+yDoWPD +F5IqgWk6moIobYjPfextZiYU6I3EfvAwoNxPDkN2WowcocUZMJbEeEq5ebBksFnx +f12gBxlIViIYwZAzu7aFvhDMyPKQI3C8CG0ZSC9ABZ1E3umdA3CEueNOmP/TChNq +Cl23+BG1Qb/PJkpAO+GfpWSVhTcV53Mf/cKvFHcjGNrxzdSoq9fyW7a6gfcGEQY0 +LVkmwFWUfJ0wT8kaeLr0E0tozkIfo01KNWNzv6NcYP80QOBRDlApWu9ODmEVJHPD +blx4jzTQ3JLa+4DvBNOjVUOp+mgRmjiW0rLdrxwOxIqIOwNjweMCp/hgxX/hTQID +AQABozgwNjA0BgNVHR4BAf8EKjAooCQwIokgIACrzQAAAAAAAAAAAAAAAP////8A +AAAAAAAAAAAAAAChADANBgkqhkiG9w0BAQsFAAOCAQEAWG+/zUMHQhP8uNCtgSHy +im/vh7wminwAvWgMKxlkLBFns6nZeQqsOV1lABY7U0Zuoqa1Z5nb6L+iJa4ElREJ +Oi/erLc9uLwBdDCAR0hUTKD7a6i4ooS39DTle87cUnj0MW1CUa6Hv5SsvpYW+1Xl +eYJk/axQOOTcy4Es53dvnZsjXH0EA/QHnn7UV+JmlE3rtVxcYp6MLYPmRhTioROA +/drghicRkiu9hxdPyxkYS16M5g3Zj30jdm+k/6C6PeNtN9YmOOganCOSyFYfGhqO +ANYzpmuV+oIedAsPpIbfIzN8njYUs1zio+1IoI4o8ddM9sCbtPU8o+WoY6IsCKXV +/g== +-----END CERTIFICATE-----` + +func TestCriticalNameConstraintWithUnknownType(t *testing.T) { + block, _ := pem.Decode([]byte(criticalNameConstraintWithUnknownTypePEM)) + cert, err := ParseCertificate(block.Bytes) + if err != nil { + t.Fatalf("unexpected parsing failure: %s", err) + } + + if l := len(cert.UnhandledCriticalExtensions); l != 1 { + t.Fatalf("expected one unhandled critical extension, but found %d", l) + } +} + +const badIPMaskPEM = ` +-----BEGIN CERTIFICATE----- +MIICzzCCAbegAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQmFk +IElQIG1hc2sgaXNzdWVyMB4XDTEzMDIwMTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow +FjEUMBIGA1UEAxMLQmFkIElQIG1hc2swggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCuISVQi3csKqYk5uz7IOhY8MXkiqBaTqagihtiM997G1mJhTojcR+ +8DCg3E8OQ3ZajByhxRkwlsR4Srl5sGSwWfF/XaAHGUhWIhjBkDO7toW+EMzI8pAj +cLwIbRlIL0AFnUTe6Z0DcIS5406Y/9MKE2oKXbf4EbVBv88mSkA74Z+lZJWFNxXn +cx/9wq8UdyMY2vHN1Kir1/JbtrqB9wYRBjQtWSbAVZR8nTBPyRp4uvQTS2jOQh+j +TUo1Y3O/o1xg/zRA4FEOUCla704OYRUkc8NuXHiPNNDcktr7gO8E06NVQ6n6aBGa +OJbSst2vHA7Eiog7A2PB4wKn+GDFf+FNAgMBAAGjIDAeMBwGA1UdHgEB/wQSMBCg +DDAKhwgBAgME//8BAKEAMA0GCSqGSIb3DQEBCwUAA4IBAQBYb7/NQwdCE/y40K2B +IfKKb++HvCaKfAC9aAwrGWQsEWezqdl5Cqw5XWUAFjtTRm6iprVnmdvov6IlrgSV +EQk6L96stz24vAF0MIBHSFRMoPtrqLiihLf0NOV7ztxSePQxbUJRroe/lKy+lhb7 +VeV5gmT9rFA45NzLgSznd2+dmyNcfQQD9AeeftRX4maUTeu1XFxinowtg+ZGFOKh +E4D92uCGJxGSK72HF0/LGRhLXozmDdmPfSN2b6T/oLo942031iY46BqcI5LIVh8a +Go4A1jOma5X6gh50Cw+kht8jM3yeNhSzXOKj7Uigjijx10z2wJu09Tyj5ahjoiwI +pdX+ +-----END CERTIFICATE-----` + +func TestBadIPMask(t *testing.T) { + block, _ := pem.Decode([]byte(badIPMaskPEM)) + _, err := ParseCertificate(block.Bytes) + if err == nil { + t.Fatalf("unexpected success") + } + + const expected = "contained invalid mask" + if !strings.Contains(err.Error(), expected) { + t.Fatalf("expected %q in error but got: %s", expected, err) + } +} + +const additionalGeneralSubtreePEM = ` +-----BEGIN CERTIFICATE----- +MIIG4TCCBMmgAwIBAgIRALss+4rLw2Ia7tFFhxE8g5cwDQYJKoZIhvcNAQELBQAw +bjELMAkGA1UEBhMCTkwxIDAeBgNVBAoMF01pbmlzdGVyaWUgdmFuIERlZmVuc2ll +MT0wOwYDVQQDDDRNaW5pc3RlcmllIHZhbiBEZWZlbnNpZSBDZXJ0aWZpY2F0aWUg +QXV0b3JpdGVpdCAtIEcyMB4XDTEzMDMwNjEyMDM0OVoXDTEzMTEzMDEyMDM1MFow +bDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUNlcnRpUGF0aCBMTEMxIjAgBgNVBAsT +GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxITAfBgNVBAMTGENlcnRpUGF0aCBC +cmlkZ2UgQ0EgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLW +4kXiRqvwBhJfN9uz12FA+P2D34MPxOt7TGXljm2plJ2CLzvaH8/ymsMdSWdJBS1M +8FmwvNL1w3A6ZuzksJjPikAu8kY3dcp3mrkk9eCPORDAwGtfsXwZysLiuEaDWpbD +dHOaHnI6qWU0N6OI+hNX58EjDpIGC1WQdho1tHOTPc5Hf5/hOpM/29v/wr7kySjs +Z+7nsvkm5rNhuJNzPsLsgzVaJ5/BVyOplZy24FKM8Y43MjR4osZm+a2e0zniqw6/ +rvcjcGYabYaznZfQG1GXoyf2Vea+CCgpgUhlVafgkwEs8izl8rIpvBzXiFAgFQuG +Ituoy92PJbDs430fA/cCAwEAAaOCAnowggJ2MEUGCCsGAQUFBwEBBDkwNzA1Bggr +BgEFBQcwAoYpaHR0cDovL2NlcnRzLmNhLm1pbmRlZi5ubC9taW5kZWYtY2EtMi5w +N2MwHwYDVR0jBBgwFoAUzln9WSPz2M64Rl2HYf2/KD8StmQwDwYDVR0TAQH/BAUw +AwEB/zCB6QYDVR0gBIHhMIHeMEgGCmCEEAGHawECBQEwOjA4BggrBgEFBQcCARYs +aHR0cDovL2Nwcy5kcC5jYS5taW5kZWYubmwvbWluZGVmLWNhLWRwLWNwcy8wSAYK +YIQQAYdrAQIFAjA6MDgGCCsGAQUFBwIBFixodHRwOi8vY3BzLmRwLmNhLm1pbmRl +Zi5ubC9taW5kZWYtY2EtZHAtY3BzLzBIBgpghBABh2sBAgUDMDowOAYIKwYBBQUH +AgEWLGh0dHA6Ly9jcHMuZHAuY2EubWluZGVmLm5sL21pbmRlZi1jYS1kcC1jcHMv +MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmxzLmNhLm1pbmRlZi5ubC9taW5k +ZWYtY2EtMi5jcmwwDgYDVR0PAQH/BAQDAgEGMEYGA1UdHgEB/wQ8MDqhODA2pDEw +LzELMAkGA1UEBhMCTkwxIDAeBgNVBAoTF01pbmlzdGVyaWUgdmFuIERlZmVuc2ll +gQFjMF0GA1UdIQRWMFQwGgYKYIQQAYdrAQIFAQYMKwYBBAGBu1MBAQECMBoGCmCE +EAGHawECBQIGDCsGAQQBgbtTAQEBAjAaBgpghBABh2sBAgUDBgwrBgEEAYG7UwEB +AQIwHQYDVR0OBBYEFNDCjBM3M3ZKkag84ei3/aKc0d0UMA0GCSqGSIb3DQEBCwUA +A4ICAQAQXFn9jF90/DNFf15JhoGtta/0dNInb14PMu3PAjcdrXYCDPpQZOArTUng +5YT1WuzfmjnXiTsziT3my0r9Mxvz/btKK/lnVOMW4c2q/8sIsIPnnW5ZaRGrsANB +dNDZkzMYmeG2Pfgvd0AQSOrpE/TVgWfu/+MMRWwX9y6VbooBR7BLv7zMuVH0WqLn +6OMFth7fqsThlfMSzkE/RDSaU6n3wXAWT1SIqBITtccRjSUQUFm/q3xrb2cwcZA6 +8vdS4hzNd+ttS905ay31Ks4/1Wrm1bH5RhEfRSH0VSXnc0b+z+RyBbmiwtVZqzxE +u3UQg/rAmtLDclLFEzjp8YDTIRYSLwstDbEXO/0ArdGrQm79HQ8i/3ZbP2357myW +i15qd6gMJIgGHS4b8Hc7R1K8LQ9Gm1aLKBEWVNGZlPK/cpXThpVmoEyslN2DHCrc +fbMbjNZpXlTMa+/b9z7Fa4X8dY8u/ELzZuJXJv5Rmqtg29eopFFYDCl0Nkh1XAjo +QejEoHHUvYV8TThHZr6Z6Ib8CECgTehU4QvepkgDXNoNrKRZBG0JhLjkwxh2whZq +nvWBfALC2VuNOM6C0rDY+HmhMlVt0XeqnybD9MuQALMit7Z00Cw2CIjNsBI9xBqD +xKK9CjUb7gzRUWSpB9jGHsvpEMHOzIFhufvH2Bz1XJw+Cl7khw== +-----END CERTIFICATE-----` + +func TestAdditionFieldsInGeneralSubtree(t *testing.T) { + // Very rarely, certificates can include additional fields in the + // GeneralSubtree structure. This tests that such certificates can be + // parsed. + block, _ := pem.Decode([]byte(additionalGeneralSubtreePEM)) + if _, err := ParseCertificate(block.Bytes); err != nil { + t.Fatalf("failed to parse certificate: %s", err) + } +} + +func TestEmptySubject(t *testing.T) { + template := Certificate{ + SerialNumber: big.NewInt(1), + DNSNames: []string{"example.com"}, + } + + derBytes, err := CreateCertificate(rand.Reader, &template, &template, &testPrivateKey.PublicKey, testPrivateKey) + if err != nil { + t.Fatalf("failed to create certificate: %s", err) + } + + cert, err := ParseCertificate(derBytes) + if err != nil { + t.Fatalf("failed to parse certificate: %s", err) + } + + for _, ext := range cert.Extensions { + if ext.Id.Equal(oidExtensionSubjectAltName) { + if !ext.Critical { + t.Fatal("SAN extension is not critical") + } + return + } + } + + t.Fatal("SAN extension is missing") +} diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go index 4983181fe75..b79ec3f7b27 100644 --- a/libgo/go/database/sql/convert.go +++ b/libgo/go/database/sql/convert.go @@ -12,7 +12,6 @@ import ( "fmt" "reflect" "strconv" - "sync" "time" "unicode" "unicode/utf8" @@ -38,17 +37,10 @@ func validateNamedValueName(name string) error { return fmt.Errorf("name %q does not begin with a letter", name) } -func driverNumInput(ds *driverStmt) int { - ds.Lock() - defer ds.Unlock() // in case NumInput panics - return ds.si.NumInput() -} - // ccChecker wraps the driver.ColumnConverter and allows it to be used // as if it were a NamedValueChecker. If the driver ColumnConverter // is not present then the NamedValueChecker will return driver.ErrSkip. type ccChecker struct { - sync.Locker cci driver.ColumnConverter want int } @@ -88,9 +80,7 @@ func (c ccChecker) CheckNamedValue(nv *driver.NamedValue) error { // same error. var err error arg := nv.Value - c.Lock() nv.Value, err = c.cci.ColumnConverter(index).ConvertValue(arg) - c.Unlock() if err != nil { return err } @@ -112,7 +102,7 @@ func defaultCheckNamedValue(nv *driver.NamedValue) (err error) { // Stmt.Query into driver Values. // // The statement ds may be nil, if no statement is available. -func driverArgs(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) { +func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) { nvargs := make([]driver.NamedValue, len(args)) // -1 means the driver doesn't know how to count the number of @@ -124,8 +114,7 @@ func driverArgs(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.Na var cc ccChecker if ds != nil { si = ds.si - want = driverNumInput(ds) - cc.Locker = ds.Locker + want = ds.si.NumInput() cc.want = want } @@ -204,7 +193,7 @@ func driverArgs(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.Na } } - // Check the length of arguments after convertion to allow for omitted + // Check the length of arguments after conversion to allow for omitted // arguments. if want != -1 && len(nvargs) != want { return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(nvargs)) @@ -234,6 +223,12 @@ func convertAssign(dest, src interface{}) error { } *d = []byte(s) return nil + case *RawBytes: + if d == nil { + return errNilPtr + } + *d = append((*d)[:0], s...) + return nil } case []byte: switch d := dest.(type) { @@ -264,6 +259,9 @@ func convertAssign(dest, src interface{}) error { } case time.Time: switch d := dest.(type) { + case *time.Time: + *d = s + return nil case *string: *d = s.Format(time.RFC3339Nano) return nil @@ -273,6 +271,12 @@ func convertAssign(dest, src interface{}) error { } *d = []byte(s.Format(time.RFC3339Nano)) return nil + case *RawBytes: + if d == nil { + return errNilPtr + } + *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) + return nil } case nil: switch d := dest.(type) { diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go index cfe52d7f548..47098c81ec1 100644 --- a/libgo/go/database/sql/convert_test.go +++ b/libgo/go/database/sql/convert_test.go @@ -106,6 +106,7 @@ var conversionTests = []conversionTest{ // To RawBytes {s: nil, d: &scanraw, wantraw: nil}, {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")}, + {s: "string", d: &scanraw, wantraw: RawBytes("string")}, {s: 123, d: &scanraw, wantraw: RawBytes("123")}, {s: int8(123), d: &scanraw, wantraw: RawBytes("123")}, {s: int64(123), d: &scanraw, wantraw: RawBytes("123")}, @@ -114,6 +115,9 @@ var conversionTests = []conversionTest{ {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")}, {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")}, {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")}, + // time.Time has been placed here to check that the RawBytes slice gets + // correctly reset when calling time.Time.AppendFormat. + {s: time.Unix(2, 5).UTC(), d: &scanraw, wantraw: RawBytes("1970-01-01T00:00:02.000000005Z")}, // Strings to integers {s: "255", d: &scanuint8, wantuint: 255}, @@ -222,6 +226,12 @@ func TestConversions(t *testing.T) { if ct.wantstr != "" && ct.wantstr != scanstr { errf("want string %q, got %q", ct.wantstr, scanstr) } + if ct.wantbytes != nil && string(ct.wantbytes) != string(scanbytes) { + errf("want byte %q, got %q", ct.wantbytes, scanbytes) + } + if ct.wantraw != nil && string(ct.wantraw) != string(scanraw) { + errf("want RawBytes %q, got %q", ct.wantraw, scanraw) + } if ct.wantint != 0 && ct.wantint != intValue(ct.d) { errf("want int %d, got %d", ct.wantint, intValue(ct.d)) } @@ -341,6 +351,7 @@ func TestRawBytesAllocs(t *testing.T) { {"float32", float32(1.5), "1.5"}, {"float64", float64(64), "64"}, {"bool", false, "false"}, + {"time", time.Unix(2, 5).UTC(), "1970-01-01T00:00:02.000000005Z"}, } buf := make(RawBytes, 10) @@ -387,7 +398,7 @@ func TestRawBytesAllocs(t *testing.T) { } } -// https://github.com/golang/go/issues/13905 +// https://golang.org/issues/13905 func TestUserDefinedBytes(t *testing.T) { type userDefinedBytes []byte var u userDefinedBytes @@ -470,7 +481,7 @@ func TestDriverArgs(t *testing.T) { } for i, tt := range tests { ds := &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{nil}} - got, err := driverArgs(nil, ds, tt.args) + got, err := driverArgsConnLocked(nil, ds, tt.args) if err != nil { t.Errorf("test[%d]: %v", i, err) continue diff --git a/libgo/go/database/sql/ctxutil.go b/libgo/go/database/sql/ctxutil.go index bd652b54625..af2afd5aa57 100644 --- a/libgo/go/database/sql/ctxutil.go +++ b/libgo/go/database/sql/ctxutil.go @@ -26,8 +26,8 @@ func ctxDriverPrepare(ctx context.Context, ci driver.Conn, query string) (driver return si, err } -func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvdargs []driver.NamedValue) (driver.Result, error) { - if execerCtx, is := execer.(driver.ExecerContext); is { +func ctxDriverExec(ctx context.Context, execerCtx driver.ExecerContext, execer driver.Execer, query string, nvdargs []driver.NamedValue) (driver.Result, error) { + if execerCtx != nil { return execerCtx.ExecContext(ctx, query, nvdargs) } dargs, err := namedValueToValue(nvdargs) @@ -43,10 +43,9 @@ func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvda return execer.Exec(query, dargs) } -func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) { - if queryerCtx, is := queryer.(driver.QueryerContext); is { - ret, err := queryerCtx.QueryContext(ctx, query, nvdargs) - return ret, err +func ctxDriverQuery(ctx context.Context, queryerCtx driver.QueryerContext, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) { + if queryerCtx != nil { + return queryerCtx.QueryContext(ctx, query, nvdargs) } dargs, err := namedValueToValue(nvdargs) if err != nil { @@ -107,10 +106,6 @@ func ctxDriverBegin(ctx context.Context, opts *TxOptions, ci driver.Conn) (drive return ciCtx.BeginTx(ctx, dopts) } - if ctx.Done() == context.Background().Done() { - return ci.Begin() - } - if opts != nil { // Check the transaction level. If the transaction level is non-default // then return an error here as the BeginTx driver value is not supported. @@ -125,6 +120,10 @@ func ctxDriverBegin(ctx context.Context, opts *TxOptions, ci driver.Conn) (drive } } + if ctx.Done() == nil { + return ci.Begin() + } + txi, err := ci.Begin() if err == nil { select { diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go index 0262ca24ba2..83b2b3f535e 100644 --- a/libgo/go/database/sql/driver/driver.go +++ b/libgo/go/database/sql/driver/driver.go @@ -42,6 +42,10 @@ type NamedValue struct { // Driver is the interface that must be implemented by a database // driver. +// +// Database drivers may implement DriverContext for access +// to contexts and to parse the name only once for a pool of connections, +// instead of once per connection. type Driver interface { // Open returns a new connection to the database. // The name is a string in a driver-specific format. @@ -55,6 +59,47 @@ type Driver interface { Open(name string) (Conn, error) } +// If a Driver implements DriverContext, then sql.DB will call +// OpenConnector to obtain a Connector and then invoke +// that Connector's Conn method to obtain each needed connection, +// instead of invoking the Driver's Open method for each connection. +// The two-step sequence allows drivers to parse the name just once +// and also provides access to per-Conn contexts. +type DriverContext interface { + // OpenConnector must parse the name in the same format that Driver.Open + // parses the name parameter. + OpenConnector(name string) (Connector, error) +} + +// A Connector represents a driver in a fixed configuration +// and can create any number of equivalent Conns for use +// by multiple goroutines. +// +// A Connector can be passed to sql.OpenDB, to allow drivers +// to implement their own sql.DB constructors, or returned by +// DriverContext's OpenConnector method, to allow drivers +// access to context and to avoid repeated parsing of driver +// configuration. +type Connector interface { + // Connect returns a connection to the database. + // Connect may return a cached connection (one previously + // closed), but doing so is unnecessary; the sql package + // maintains a pool of idle connections for efficient re-use. + // + // The provided context.Context is for dialing purposes only + // (see net.DialContext) and should not be stored or used for + // other purposes. + // + // The returned connection is only used by one goroutine at a + // time. + Connect(context.Context) (Conn, error) + + // Driver returns the underlying Driver of the Connector, + // mainly to maintain compatibility with the Driver method + // on sql.DB. + Driver() Driver +} + // ErrSkip may be returned by some optional interfaces' methods to // indicate at runtime that the fast path is unavailable and the sql // package should continue as if the optional interface was not @@ -86,22 +131,23 @@ type Pinger interface { // Execer is an optional interface that may be implemented by a Conn. // -// If a Conn does not implement Execer, the sql package's DB.Exec will -// first prepare a query, execute the statement, and then close the -// statement. +// If a Conn implements neither ExecerContext nor Execer Execer, +// the sql package's DB.Exec will first prepare a query, execute the statement, +// and then close the statement. // // Exec may return ErrSkip. // -// Deprecated: Drivers should implement ExecerContext instead (or additionally). +// Deprecated: Drivers should implement ExecerContext instead. type Execer interface { Exec(query string, args []Value) (Result, error) } // ExecerContext is an optional interface that may be implemented by a Conn. // -// If a Conn does not implement ExecerContext, the sql package's DB.Exec will -// first prepare a query, execute the statement, and then close the -// statement. +// If a Conn does not implement ExecerContext, the sql package's DB.Exec +// will fall back to Execer; if the Conn does not implement Execer either, +// DB.Exec will first prepare a query, execute the statement, and then +// close the statement. // // ExecerContext may return ErrSkip. // @@ -112,22 +158,23 @@ type ExecerContext interface { // Queryer is an optional interface that may be implemented by a Conn. // -// If a Conn does not implement Queryer, the sql package's DB.Query will -// first prepare a query, execute the statement, and then close the -// statement. +// If a Conn implements neither QueryerContext nor Queryer, +// the sql package's DB.Query will first prepare a query, execute the statement, +// and then close the statement. // // Query may return ErrSkip. // -// Deprecated: Drivers should implement QueryerContext instead (or additionally). +// Deprecated: Drivers should implement QueryerContext instead. type Queryer interface { Query(query string, args []Value) (Rows, error) } // QueryerContext is an optional interface that may be implemented by a Conn. // -// If a Conn does not implement QueryerContext, the sql package's DB.Query will -// first prepare a query, execute the statement, and then close the -// statement. +// If a Conn does not implement QueryerContext, the sql package's DB.Query +// will fall back to Queryer; if the Conn does not implement Queryer either, +// DB.Query will first prepare a query, execute the statement, and then +// close the statement. // // QueryerContext may return ErrSkip. // @@ -199,6 +246,18 @@ type ConnBeginTx interface { BeginTx(ctx context.Context, opts TxOptions) (Tx, error) } +// SessionResetter may be implemented by Conn to allow drivers to reset the +// session state associated with the connection and to signal a bad connection. +type SessionResetter interface { + // ResetSession is called while a connection is in the connection + // pool. No queries will run on this connection until this method returns. + // + // If the connection is bad this should return driver.ErrBadConn to prevent + // the connection from being returned to the connection pool. Any other + // error will be discarded. + ResetSession(ctx context.Context) error +} + // Result is the result of a query execution. type Result interface { // LastInsertId returns the database's auto-generated ID diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go index 4dcd096ca4d..e795412de01 100644 --- a/libgo/go/database/sql/fakedb_test.go +++ b/libgo/go/database/sql/fakedb_test.go @@ -55,6 +55,32 @@ type fakeDriver struct { dbs map[string]*fakeDB } +type fakeConnector struct { + name string + + waiter func(context.Context) +} + +func (c *fakeConnector) Connect(context.Context) (driver.Conn, error) { + conn, err := fdriver.Open(c.name) + conn.(*fakeConn).waiter = c.waiter + return conn, err +} + +func (c *fakeConnector) Driver() driver.Driver { + return fdriver +} + +type fakeDriverCtx struct { + fakeDriver +} + +var _ driver.DriverContext = &fakeDriverCtx{} + +func (cc *fakeDriverCtx) OpenConnector(name string) (driver.Connector, error) { + return &fakeConnector{name: name}, nil +} + type fakeDB struct { name string @@ -107,6 +133,16 @@ type fakeConn struct { // bad connection tests; see isBad() bad bool stickyBad bool + + skipDirtySession bool // tests that use Conn should set this to true. + + // dirtySession tests ResetSession, true if a query has executed + // until ResetSession is called. + dirtySession bool + + // The waiter is called before each query. May be used in place of the "WAIT" + // directive. + waiter func(context.Context) } func (c *fakeConn) touchMem() { @@ -298,6 +334,9 @@ func (c *fakeConn) isBad() bool { if c.stickyBad { return true } else if c.bad { + if c.db == nil { + return false + } // alternate between bad conn and not bad conn c.db.badConn = !c.db.badConn return c.db.badConn @@ -306,6 +345,21 @@ func (c *fakeConn) isBad() bool { } } +func (c *fakeConn) isDirtyAndMark() bool { + if c.skipDirtySession { + return false + } + if c.currTx != nil { + c.dirtySession = true + return false + } + if c.dirtySession { + return true + } + c.dirtySession = true + return false +} + func (c *fakeConn) Begin() (driver.Tx, error) { if c.isBad() { return nil, driver.ErrBadConn @@ -337,6 +391,14 @@ func setStrictFakeConnClose(t *testing.T) { testStrictClose = t } +func (c *fakeConn) ResetSession(ctx context.Context) error { + c.dirtySession = false + if c.isBad() { + return driver.ErrBadConn + } + return nil +} + func (c *fakeConn) Close() (err error) { drv := fdriver.(*fakeDriver) defer func() { @@ -572,6 +634,10 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm stmt.cmd = cmd parts = parts[1:] + if c.waiter != nil { + c.waiter(ctx) + } + if stmt.wait > 0 { wait := time.NewTimer(stmt.wait) select { @@ -662,6 +728,9 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) { return nil, driver.ErrBadConn } + if s.c.isDirtyAndMark() { + return nil, errors.New("session is dirty") + } err := checkSubsetTypes(s.c.db.allowAny, args) if err != nil { @@ -774,6 +843,9 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) ( if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) { return nil, driver.ErrBadConn } + if s.c.isDirtyAndMark() { + return nil, errors.New("session is dirty") + } err := checkSubsetTypes(s.c.db.allowAny, args) if err != nil { @@ -943,6 +1015,7 @@ type rowsCursor struct { } func (rc *rowsCursor) touchMem() { + rc.parentMem.touchMem() rc.line++ } diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go index c609fe4cc43..9f4fa14534d 100644 --- a/libgo/go/database/sql/sql.go +++ b/libgo/go/database/sql/sql.go @@ -285,7 +285,7 @@ type Scanner interface { // Example usage: // // var outArg string -// _, err := db.ExecContext(ctx, "ProcName", sql.Named("Arg1", Out{Dest: &outArg})) +// _, err := db.ExecContext(ctx, "ProcName", sql.Named("Arg1", sql.Out{Dest: &outArg})) type Out struct { _Named_Fields_Required struct{} @@ -317,8 +317,7 @@ var ErrNoRows = errors.New("sql: no rows in result set") // connection is returned to DB's idle connection pool. The pool size // can be controlled with SetMaxIdleConns. type DB struct { - driver driver.Driver - dsn string + connector driver.Connector // numClosed is an atomic counter which represents a total number of // closed connections. Stmt.openStmt checks it before cleaning closed // connections in Stmt.css. @@ -335,6 +334,7 @@ type DB struct { // It is closed during db.Close(). The close tells the connectionOpener // goroutine to exit. openerCh chan struct{} + resetterCh chan *driverConn closed bool dep map[finalCloser]depSet lastPut map[*driverConn]string // stacktrace of last conn's put; debug only @@ -342,6 +342,8 @@ type DB struct { maxOpen int // <= 0 means unlimited maxLifetime time.Duration // maximum amount of time a connection may be reused cleanerCh chan struct{} + + stop func() // stop cancels the connection opener and the session resetter. } // connReuseStrategy determines how (*DB).conn returns database connections. @@ -369,6 +371,7 @@ type driverConn struct { closed bool finalClosed bool // ci.Close has been called openStmt map[*driverStmt]bool + lastErr error // lastError captures the result of the session resetter. // guarded by db.mu inUse bool @@ -377,7 +380,7 @@ type driverConn struct { } func (dc *driverConn) releaseConn(err error) { - dc.db.putConn(dc, err) + dc.db.putConn(dc, err, true) } func (dc *driverConn) removeOpenStmt(ds *driverStmt) { @@ -418,6 +421,19 @@ func (dc *driverConn) prepareLocked(ctx context.Context, cg stmtConnGrabber, que return ds, nil } +// resetSession resets the connection session and sets the lastErr +// that is checked before returning the connection to another query. +// +// resetSession assumes that the embedded mutex is locked when the connection +// was returned to the pool. This unlocks the mutex. +func (dc *driverConn) resetSession(ctx context.Context) { + defer dc.Unlock() // In case of panic. + if dc.closed { // Check if the database has been closed. + return + } + dc.lastErr = dc.ci.(driver.SessionResetter).ResetSession(ctx) +} + // the dc.db's Mutex is held. func (dc *driverConn) closeDBLocked() func() error { dc.Lock() @@ -575,6 +591,52 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error { // to block until the connectionOpener can satisfy the backlog of requests. var connectionRequestQueueSize = 1000000 +type dsnConnector struct { + dsn string + driver driver.Driver +} + +func (t dsnConnector) Connect(_ context.Context) (driver.Conn, error) { + return t.driver.Open(t.dsn) +} + +func (t dsnConnector) Driver() driver.Driver { + return t.driver +} + +// OpenDB opens a database using a Connector, allowing drivers to +// bypass a string based data source name. +// +// Most users will open a database via a driver-specific connection +// helper function that returns a *DB. No database drivers are included +// in the Go standard library. See https://golang.org/s/sqldrivers for +// a list of third-party drivers. +// +// OpenDB 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 OpenDB +// function should be called just once. It is rarely necessary to +// close a DB. +func OpenDB(c driver.Connector) *DB { + ctx, cancel := context.WithCancel(context.Background()) + db := &DB{ + connector: c, + openerCh: make(chan struct{}, connectionRequestQueueSize), + resetterCh: make(chan *driverConn, 50), + lastPut: make(map[*driverConn]string), + connRequests: make(map[uint64]chan connRequest), + stop: cancel, + } + + go db.connectionOpener(ctx) + go db.connectionResetter(ctx) + + return db +} + // Open opens a database specified by its database driver name and a // driver-specific data source name, usually consisting of at least a // database name and connection information. @@ -599,15 +661,16 @@ func Open(driverName, dataSourceName string) (*DB, error) { if !ok { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) } - db := &DB{ - driver: driveri, - dsn: dataSourceName, - openerCh: make(chan struct{}, connectionRequestQueueSize), - lastPut: make(map[*driverConn]string), - connRequests: make(map[uint64]chan connRequest), + + if driverCtx, ok := driveri.(driver.DriverContext); ok { + connector, err := driverCtx.OpenConnector(dataSourceName) + if err != nil { + return nil, err + } + return OpenDB(connector), nil } - go db.connectionOpener() - return db, nil + + return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil } func (db *DB) pingDC(ctx context.Context, dc *driverConn, release func(error)) error { @@ -659,7 +722,6 @@ func (db *DB) Close() error { db.mu.Unlock() return nil } - close(db.openerCh) if db.cleanerCh != nil { close(db.cleanerCh) } @@ -680,6 +742,7 @@ func (db *DB) Close() error { err = err1 } } + db.stop() return err } @@ -867,18 +930,40 @@ func (db *DB) maybeOpenNewConnections() { } // Runs in a separate goroutine, opens new connections when requested. -func (db *DB) connectionOpener() { - for range db.openerCh { - db.openNewConnection() +func (db *DB) connectionOpener(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case <-db.openerCh: + db.openNewConnection(ctx) + } + } +} + +// connectionResetter runs in a separate goroutine to reset connections async +// to exported API. +func (db *DB) connectionResetter(ctx context.Context) { + for { + select { + case <-ctx.Done(): + close(db.resetterCh) + for dc := range db.resetterCh { + dc.Unlock() + } + return + case dc := <-db.resetterCh: + dc.resetSession(ctx) + } } } // Open one new connection -func (db *DB) openNewConnection() { +func (db *DB) openNewConnection(ctx context.Context) { // maybeOpenNewConnctions has already executed db.numOpen++ before it sent // on db.openerCh. This function must execute db.numOpen-- if the // connection fails or is closed before returning. - ci, err := db.driver.Open(db.dsn) + ci, err := db.connector.Connect(ctx) db.mu.Lock() defer db.mu.Unlock() if db.closed { @@ -953,6 +1038,14 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn conn.Close() return nil, driver.ErrBadConn } + // Lock around reading lastErr to ensure the session resetter finished. + conn.Lock() + err := conn.lastErr + conn.Unlock() + if err == driver.ErrBadConn { + conn.Close() + return nil, driver.ErrBadConn + } return conn, nil } @@ -978,7 +1071,7 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn default: case ret, ok := <-req: if ok { - db.putConn(ret.conn, ret.err) + db.putConn(ret.conn, ret.err, false) } } return nil, ctx.Err() @@ -990,13 +1083,24 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn ret.conn.Close() return nil, driver.ErrBadConn } + if ret.conn == nil { + return nil, ret.err + } + // Lock around reading lastErr to ensure the session resetter finished. + ret.conn.Lock() + err := ret.conn.lastErr + ret.conn.Unlock() + if err == driver.ErrBadConn { + ret.conn.Close() + return nil, driver.ErrBadConn + } return ret.conn, ret.err } } db.numOpen++ // optimistically db.mu.Unlock() - ci, err := db.driver.Open(db.dsn) + ci, err := db.connector.Connect(ctx) if err != nil { db.mu.Lock() db.numOpen-- // correct for earlier optimism @@ -1045,7 +1149,7 @@ const debugGetPut = false // putConn adds a connection to the db's free pool. // err is optionally the last error that occurred on this connection. -func (db *DB) putConn(dc *driverConn, err error) { +func (db *DB) putConn(dc *driverConn, err error, resetSession bool) { db.mu.Lock() if !dc.inUse { if debugGetPut { @@ -1076,11 +1180,40 @@ func (db *DB) putConn(dc *driverConn, err error) { if putConnHook != nil { putConnHook(db, dc) } + if db.closed { + // Connections do not need to be reset if they will be closed. + // Prevents writing to resetterCh after the DB has closed. + resetSession = false + } + if resetSession { + if _, resetSession = dc.ci.(driver.SessionResetter); resetSession { + // Lock the driverConn here so it isn't released until + // the connection is reset. + // The lock must be taken before the connection is put into + // the pool to prevent it from being taken out before it is reset. + dc.Lock() + } + } added := db.putConnDBLocked(dc, nil) db.mu.Unlock() if !added { + if resetSession { + dc.Unlock() + } dc.Close() + return + } + if !resetSession { + return + } + select { + default: + // If the resetterCh is blocking then mark the connection + // as bad and continue on. + dc.lastErr = driver.ErrBadConn + dc.Unlock() + case db.resetterCh <- dc: } } @@ -1242,15 +1375,20 @@ func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), q defer func() { release(err) }() - if execer, ok := dc.ci.(driver.Execer); ok { - var dargs []driver.NamedValue - dargs, err = driverArgs(dc.ci, nil, args) - if err != nil { - return nil, err - } + execerCtx, ok := dc.ci.(driver.ExecerContext) + var execer driver.Execer + if !ok { + execer, ok = dc.ci.(driver.Execer) + } + if ok { + var nvdargs []driver.NamedValue var resi driver.Result withLock(dc, func() { - resi, err = ctxDriverExec(ctx, execer, query, dargs) + nvdargs, err = driverArgsConnLocked(dc.ci, nil, args) + if err != nil { + return + } + resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs) }) if err != driver.ErrSkip { if err != nil { @@ -1309,15 +1447,21 @@ func (db *DB) query(ctx context.Context, query string, args []interface{}, strat // The ctx context is from a query method and the txctx context is from an // optional transaction context. func (db *DB) queryDC(ctx, txctx context.Context, dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) { - if queryer, ok := dc.ci.(driver.Queryer); ok { - dargs, err := driverArgs(dc.ci, nil, args) - if err != nil { - releaseConn(err) - return nil, err - } + queryerCtx, ok := dc.ci.(driver.QueryerContext) + var queryer driver.Queryer + if !ok { + queryer, ok = dc.ci.(driver.Queryer) + } + if ok { + var nvdargs []driver.NamedValue var rowsi driver.Rows + var err error withLock(dc, func() { - rowsi, err = ctxDriverQuery(ctx, queryer, query, dargs) + nvdargs, err = driverArgsConnLocked(dc.ci, nil, args) + if err != nil { + return + } + rowsi, err = ctxDriverQuery(ctx, queryerCtx, queryer, query, nvdargs) }) if err != driver.ErrSkip { if err != nil { @@ -1454,11 +1598,11 @@ func (db *DB) beginDC(ctx context.Context, dc *driverConn, release func(error), // Driver returns the database's underlying driver. func (db *DB) Driver() driver.Driver { - return db.driver + return db.connector.Driver() } // ErrConnDone is returned by any operation that is performed on a connection -// that has already been committed or rolled back. +// that has already been returned to the connection pool. var ErrConnDone = errors.New("database/sql: connection is already closed") // Conn returns a single connection by either opening a new connection @@ -1493,9 +1637,9 @@ func (db *DB) Conn(ctx context.Context) (*Conn, error) { type releaseConn func(error) -// Conn represents a single database session rather a pool of database -// sessions. Prefer running queries from DB unless there is a specific -// need for a continuous single database session. +// Conn represents a single database connection rather than a pool of database +// connections. Prefer running queries from DB unless there is a specific +// need for a continuous single database connection. // // A Conn must call Close to return the connection to the database pool // and may do so concurrently with a running query. @@ -1769,14 +1913,20 @@ func (tx *Tx) closePrepared() { // Commit commits the transaction. func (tx *Tx) Commit() error { - if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { - return ErrTxDone - } + // Check context first to avoid transaction leak. + // If put it behind tx.done CompareAndSwap statement, we cant't ensure + // the consistency between tx.done and the real COMMIT operation. select { default: case <-tx.ctx.Done(): + if atomic.LoadInt32(&tx.done) == 1 { + return ErrTxDone + } return tx.ctx.Err() } + if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { + return ErrTxDone + } var err error withLock(tx.dc, func() { err = tx.txi.Commit() @@ -1859,6 +2009,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { // ... // res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203) // +// The provided context is used for the preparation of the statement, not for the +// execution of the statement. +// // The returned statement operates within the transaction and will be closed // when the transaction has been committed or rolled back. func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { @@ -1902,11 +2055,14 @@ func (tx *Tx) StmtContext(ctx context.Context, stmt *Stmt) *Stmt { stmt.mu.Unlock() if si == nil { - cs, err := stmt.prepareOnConnLocked(ctx, dc) + withLock(dc, func() { + var ds *driverStmt + ds, err = stmt.prepareOnConnLocked(ctx, dc) + si = ds.si + }) if err != nil { return &Stmt{stickyErr: err} } - si = cs.si } parentStmt = stmt } @@ -2098,13 +2254,20 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) { } func resultFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (Result, error) { - dargs, err := driverArgs(ci, ds, args) + ds.Lock() + defer ds.Unlock() + + dargs, err := driverArgsConnLocked(ci, ds, args) if err != nil { return nil, err } - ds.Lock() - defer ds.Unlock() + // -1 means the driver doesn't know how to count the number of + // placeholders, so we won't sanity check input here and instead let the + // driver deal with errors. + if want := ds.si.NumInput(); want >= 0 && want != len(dargs) { + return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(dargs)) + } resi, err := ctxDriverStmtExec(ctx, ds.si, dargs) if err != nil { @@ -2269,25 +2432,20 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) { } func rowsiFromStatement(ctx context.Context, ci driver.Conn, ds *driverStmt, args ...interface{}) (driver.Rows, error) { - var want int - withLock(ds, func() { - want = ds.si.NumInput() - }) - - // -1 means the driver doesn't know how to count the number of - // placeholders, so we won't sanity check input here and instead let the - // driver deal with errors. - if want != -1 && len(args) != want { - return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args)) - } + ds.Lock() + defer ds.Unlock() - dargs, err := driverArgs(ci, ds, args) + dargs, err := driverArgsConnLocked(ci, ds, args) if err != nil { return nil, err } - ds.Lock() - defer ds.Unlock() + // -1 means the driver doesn't know how to count the number of + // placeholders, so we won't sanity check input here and instead let the + // driver deal with errors. + if want := ds.si.NumInput(); want >= 0 && want != len(dargs) { + return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(dargs)) + } rowsi, err := ctxDriverStmtQuery(ctx, ds.si, dargs) if err != nil { @@ -2451,9 +2609,16 @@ func (rs *Rows) nextLocked() (doClose, ok bool) { if rs.closed { return false, false } + + // Lock the driver connection before calling the driver interface + // rowsi to prevent a Tx from rolling back the connection at the same time. + rs.dc.Lock() + defer rs.dc.Unlock() + if rs.lastcols == nil { rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns())) } + rs.lasterr = rs.rowsi.Next(rs.lastcols) if rs.lasterr != nil { // Close the connection if there is a driver error. @@ -2503,6 +2668,12 @@ func (rs *Rows) NextResultSet() bool { doClose = true return false } + + // Lock the driver connection before calling the driver interface + // rowsi to prevent a Tx from rolling back the connection at the same time. + rs.dc.Lock() + defer rs.dc.Unlock() + rs.lasterr = nextResultSet.NextResultSet() if rs.lasterr != nil { doClose = true @@ -2534,6 +2705,9 @@ func (rs *Rows) Columns() ([]string, error) { if rs.rowsi == nil { return nil, errors.New("sql: no Rows available") } + rs.dc.Lock() + defer rs.dc.Unlock() + return rs.rowsi.Columns(), nil } @@ -2548,7 +2722,10 @@ func (rs *Rows) ColumnTypes() ([]*ColumnType, error) { if rs.rowsi == nil { return nil, errors.New("sql: no Rows available") } - return rowsColumnInfoSetup(rs.rowsi), nil + rs.dc.Lock() + defer rs.dc.Unlock() + + return rowsColumnInfoSetupConnLocked(rs.rowsi), nil } // ColumnType contains the name and type of a column. @@ -2609,7 +2786,7 @@ func (ci *ColumnType) DatabaseTypeName() string { return ci.databaseType } -func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType { +func rowsColumnInfoSetupConnLocked(rowsi driver.Rows) []*ColumnType { names := rowsi.Columns() list := make([]*ColumnType, len(names)) diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go index c935eb43480..8137eff82b4 100644 --- a/libgo/go/database/sql/sql_test.go +++ b/libgo/go/database/sql/sql_test.go @@ -60,10 +60,12 @@ const fakeDBName = "foo" var chrisBirthday = time.Unix(123456789, 0) func newTestDB(t testing.TB, name string) *DB { - db, err := Open("test", fakeDBName) - if err != nil { - t.Fatalf("Open: %v", err) - } + return newTestDBConnector(t, &fakeConnector{name: fakeDBName}, name) +} + +func newTestDBConnector(t testing.TB, fc *fakeConnector, name string) *DB { + fc.name = fakeDBName + db := OpenDB(fc) if _, err := db.Exec("WIPE"); err != nil { t.Fatalf("exec wipe: %v", err) } @@ -81,6 +83,13 @@ func newTestDB(t testing.TB, name string) *DB { return db } +func TestOpenDB(t *testing.T) { + db := OpenDB(dsnConnector{dsn: fakeDBName, driver: fdriver}) + if db.Driver() != fdriver { + t.Fatalf("OpenDB should return the driver of the Connector") + } +} + func TestDriverPanic(t *testing.T) { // Test that if driver panics, database/sql does not deadlock. db, err := Open("test", fakeDBName) @@ -439,6 +448,20 @@ func TestTxContextWait(t *testing.T) { waitForFree(t, db, 5*time.Second, 0) } +// TestUnsupportedOptions checks that the database fails when a driver that +// doesn't implement ConnBeginTx is used with non-default options and an +// un-cancellable context. +func TestUnsupportedOptions(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + _, err := db.BeginTx(context.Background(), &TxOptions{ + Isolation: LevelSerializable, ReadOnly: true, + }) + if err == nil { + t.Fatal("expected error when using unsupported options, got nil") + } +} + func TestMultiResultSetQuery(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -564,24 +587,46 @@ func TestPoolExhaustOnCancel(t *testing.T) { if testing.Short() { t.Skip("long test") } - db := newTestDB(t, "people") - defer closeDB(t, db) max := 3 + var saturate, saturateDone sync.WaitGroup + saturate.Add(max) + saturateDone.Add(max) + + donePing := make(chan bool) + state := 0 + + // waiter will be called for all queries, including + // initial setup queries. The state is only assigned when no + // no queries are made. + // + // Only allow the first batch of queries to finish once the + // second batch of Ping queries have finished. + waiter := func(ctx context.Context) { + switch state { + case 0: + // Nothing. Initial database setup. + case 1: + saturate.Done() + select { + case <-ctx.Done(): + case <-donePing: + } + case 2: + } + } + db := newTestDBConnector(t, &fakeConnector{waiter: waiter}, "people") + defer closeDB(t, db) db.SetMaxOpenConns(max) // First saturate the connection pool. // Then start new requests for a connection that is cancelled after it is requested. - var saturate, saturateDone sync.WaitGroup - saturate.Add(max) - saturateDone.Add(max) - + state = 1 for i := 0; i < max; i++ { go func() { - saturate.Done() - rows, err := db.Query("WAIT|500ms|SELECT|people|name,photo|") + rows, err := db.Query("SELECT|people|name,photo|") if err != nil { t.Fatalf("Query: %v", err) } @@ -591,6 +636,7 @@ func TestPoolExhaustOnCancel(t *testing.T) { } saturate.Wait() + state = 2 // Now cancel the request while it is waiting. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) @@ -607,7 +653,7 @@ func TestPoolExhaustOnCancel(t *testing.T) { t.Fatalf("PingContext (Exhaust): %v", err) } } - + close(donePing) saturateDone.Wait() // Now try to open a normal connection. @@ -705,15 +751,15 @@ func TestRowsColumnTypes(t *testing.T) { if err != nil { t.Fatalf("failed to scan values in %v", err) } - ct++ - if ct == 0 { - if values[0].(string) != "Bob" { - t.Errorf("Expected Bob, got %v", values[0]) + if ct == 1 { + if age := *values[0].(*int32); age != 2 { + t.Errorf("Expected 2, got %v", age) } - if values[1].(int) != 2 { - t.Errorf("Expected 2, got %v", values[1]) + if name := *values[1].(*string); name != "Bob" { + t.Errorf("Expected Bob, got %v", name) } } + ct++ } if ct != 3 { t.Errorf("expected 3 rows, got %d", ct) @@ -1311,6 +1357,7 @@ func TestConnQuery(t *testing.T) { if err != nil { t.Fatal(err) } + conn.dc.ci.(*fakeConn).skipDirtySession = true defer conn.Close() var name string @@ -1338,6 +1385,7 @@ func TestConnTx(t *testing.T) { if err != nil { t.Fatal(err) } + conn.dc.ci.(*fakeConn).skipDirtySession = true defer conn.Close() tx, err := conn.BeginTx(ctx, nil) @@ -1658,7 +1706,7 @@ func TestIssue4902(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - driver := db.driver.(*fakeDriver) + driver := db.Driver().(*fakeDriver) opens0 := driver.openCount var stmt *Stmt @@ -1751,7 +1799,7 @@ func TestMaxOpenConns(t *testing.T) { db := newTestDB(t, "magicquery") defer closeDB(t, db) - driver := db.driver.(*fakeDriver) + driver := db.Driver().(*fakeDriver) // Force the number of open connections to 0 so we can get an accurate // count for the test @@ -2043,7 +2091,7 @@ func TestConnMaxLifetime(t *testing.T) { db := newTestDB(t, "magicquery") defer closeDB(t, db) - driver := db.driver.(*fakeDriver) + driver := db.Driver().(*fakeDriver) // Force the number of open connections to 0 so we can get an accurate // count for the test @@ -2132,7 +2180,7 @@ func TestStmtCloseDeps(t *testing.T) { db := newTestDB(t, "magicquery") defer closeDB(t, db) - driver := db.driver.(*fakeDriver) + driver := db.Driver().(*fakeDriver) driver.mu.Lock() opens0 := driver.openCount @@ -2363,7 +2411,9 @@ func TestManyErrBadConn(t *testing.T) { t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn) } for _, conn := range db.freeConn { + conn.Lock() conn.ci.(*fakeConn).stickyBad = true + conn.Unlock() } return db } @@ -2453,6 +2503,7 @@ func TestManyErrBadConn(t *testing.T) { if err != nil { t.Fatal(err) } + conn.dc.ci.(*fakeConn).skipDirtySession = true err = conn.Close() if err != nil { t.Fatal(err) @@ -3057,7 +3108,7 @@ func TestIssue6081(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - drv := db.driver.(*fakeDriver) + drv := db.Driver().(*fakeDriver) drv.mu.Lock() opens0 := drv.openCount closes0 := drv.closeCount @@ -3106,6 +3157,9 @@ func TestIssue6081(t *testing.T) { // In the test, a context is canceled while the query is in process so // the internal rollback will run concurrently with the explicitly called // Tx.Rollback. +// +// The addition of calling rows.Next also tests +// Issue 21117. func TestIssue18429(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -3138,6 +3192,9 @@ func TestIssue18429(t *testing.T) { // reported. rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|") if rows != nil { + // Call Next to test Issue 21117 and check for races. + for rows.Next() { + } rows.Close() } // This call will race with the context cancel rollback to complete @@ -3217,9 +3274,8 @@ func TestIssue18719(t *testing.T) { // This call will grab the connection and cancel the context // after it has done so. Code after must deal with the canceled state. - rows, err := tx.QueryContext(ctx, "SELECT|people|name|") + _, err = tx.QueryContext(ctx, "SELECT|people|name|") if err != nil { - rows.Close() t.Fatalf("expected error %v but got %v", nil, err) } @@ -3242,6 +3298,7 @@ func TestIssue20647(t *testing.T) { if err != nil { t.Fatal(err) } + conn.dc.ci.(*fakeConn).skipDirtySession = true defer conn.Close() stmt, err := conn.PrepareContext(ctx, "SELECT|people|name|") @@ -3312,7 +3369,7 @@ func TestConnectionLeak(t *testing.T) { // Now we have defaultMaxIdleConns busy connections. Open // a new one, but wait until the busy connections are released // before returning control to DB. - drv := db.driver.(*fakeDriver) + drv := db.Driver().(*fakeDriver) drv.waitCh = make(chan struct{}, 1) drv.waitingCh = make(chan struct{}, 1) var wg sync.WaitGroup @@ -3376,7 +3433,7 @@ func (c *nvcConn) CheckNamedValue(nv *driver.NamedValue) error { case Out: switch ov := v.Dest.(type) { default: - return errors.New("unkown NameValueCheck OUTPUT type") + return errors.New("unknown NameValueCheck OUTPUT type") case *string: *ov = "from-server" nv.Value = "OUT:*string" @@ -3466,6 +3523,141 @@ func TestNamedValueCheckerSkip(t *testing.T) { } } +func TestOpenConnector(t *testing.T) { + Register("testctx", &fakeDriverCtx{}) + db, err := Open("testctx", "people") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + if _, is := db.connector.(*fakeConnector); !is { + t.Fatal("not using *fakeConnector") + } +} + +type ctxOnlyDriver struct { + fakeDriver +} + +func (d *ctxOnlyDriver) Open(dsn string) (driver.Conn, error) { + conn, err := d.fakeDriver.Open(dsn) + if err != nil { + return nil, err + } + return &ctxOnlyConn{fc: conn.(*fakeConn)}, nil +} + +var ( + _ driver.Conn = &ctxOnlyConn{} + _ driver.QueryerContext = &ctxOnlyConn{} + _ driver.ExecerContext = &ctxOnlyConn{} +) + +type ctxOnlyConn struct { + fc *fakeConn + + queryCtxCalled bool + execCtxCalled bool +} + +func (c *ctxOnlyConn) Begin() (driver.Tx, error) { + return c.fc.Begin() +} + +func (c *ctxOnlyConn) Close() error { + return c.fc.Close() +} + +// Prepare is still part of the Conn interface, so while it isn't used +// must be defined for compatibility. +func (c *ctxOnlyConn) Prepare(q string) (driver.Stmt, error) { + panic("not used") +} + +func (c *ctxOnlyConn) PrepareContext(ctx context.Context, q string) (driver.Stmt, error) { + return c.fc.PrepareContext(ctx, q) +} + +func (c *ctxOnlyConn) QueryContext(ctx context.Context, q string, args []driver.NamedValue) (driver.Rows, error) { + c.queryCtxCalled = true + return c.fc.QueryContext(ctx, q, args) +} + +func (c *ctxOnlyConn) ExecContext(ctx context.Context, q string, args []driver.NamedValue) (driver.Result, error) { + c.execCtxCalled = true + return c.fc.ExecContext(ctx, q, args) +} + +// TestQueryExecContextOnly ensures drivers only need to implement QueryContext +// and ExecContext methods. +func TestQueryExecContextOnly(t *testing.T) { + // Ensure connection does not implment non-context interfaces. + var connType driver.Conn = &ctxOnlyConn{} + if _, ok := connType.(driver.Execer); ok { + t.Fatalf("%T must not implement driver.Execer", connType) + } + if _, ok := connType.(driver.Queryer); ok { + t.Fatalf("%T must not implement driver.Queryer", connType) + } + + Register("ContextOnly", &ctxOnlyDriver{}) + db, err := Open("ContextOnly", "") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + conn, err := db.Conn(ctx) + if err != nil { + t.Fatal("db.Conn", err) + } + defer conn.Close() + coc := conn.dc.ci.(*ctxOnlyConn) + coc.fc.skipDirtySession = true + + _, err = conn.ExecContext(ctx, "WIPE") + if err != nil { + t.Fatal("exec wipe", err) + } + + _, err = conn.ExecContext(ctx, "CREATE|keys|v1=string") + if err != nil { + t.Fatal("exec create", err) + } + expectedValue := "value1" + _, err = conn.ExecContext(ctx, "INSERT|keys|v1=?", expectedValue) + if err != nil { + t.Fatal("exec insert", err) + } + rows, err := conn.QueryContext(ctx, "SELECT|keys|v1|") + if err != nil { + t.Fatal("query select", err) + } + v1 := "" + for rows.Next() { + err = rows.Scan(&v1) + if err != nil { + t.Fatal("rows scan", err) + } + } + rows.Close() + + if v1 != expectedValue { + t.Fatalf("expected %q, got %q", expectedValue, v1) + } + + if !coc.execCtxCalled { + t.Error("ExecContext not called") + } + if !coc.queryCtxCalled { + t.Error("QueryContext not called") + } +} + // badConn implements a bad driver.Conn, for TestBadDriver. // The Exec method panics. type badConn struct{} diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go index 9b39078a6fb..4352092ed0d 100644 --- a/libgo/go/debug/dwarf/type.go +++ b/libgo/go/debug/dwarf/type.go @@ -154,7 +154,7 @@ type StructField struct { Name string Type Type ByteOffset int64 - ByteSize int64 + ByteSize int64 // usually zero; use Type.Size() for normal fields BitOffset int64 // within the ByteSize bytes at ByteOffset BitSize int64 // zero if not a bit field } @@ -514,48 +514,49 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off var lastFieldType *Type var lastFieldBitOffset int64 for kid := next(); kid != nil; kid = next() { - if kid.Tag == TagMember { - f := new(StructField) - if f.Type = typeOf(kid); err != nil { + if kid.Tag != TagMember { + continue + } + f := new(StructField) + if f.Type = typeOf(kid); err != nil { + goto Error + } + 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{name, kid.Offset, "unexpected opcode"} goto Error } - 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{name, kid.Offset, "unexpected opcode"} - goto Error - } - f.ByteOffset = int64(b.uint()) - if b.err != nil { - err = b.err - goto Error - } - case int64: - f.ByteOffset = loc + f.ByteOffset = int64(b.uint()) + if b.err != nil { + err = b.err + goto Error } + case int64: + f.ByteOffset = loc + } - haveBitOffset := false - f.Name, _ = kid.Val(AttrName).(string) - f.ByteSize, _ = kid.Val(AttrByteSize).(int64) - f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) - f.BitSize, _ = kid.Val(AttrBitSize).(int64) - t.Field = append(t.Field, f) - - bito := f.BitOffset - if !haveBitOffset { - bito = f.ByteOffset * 8 - } - if bito == lastFieldBitOffset && t.Kind != "union" { - // Last field was zero width. Fix array length. - // (DWARF writes out 0-length arrays as if they were 1-length arrays.) - zeroArray(lastFieldType) - } - lastFieldType = &f.Type - lastFieldBitOffset = bito + haveBitOffset := false + f.Name, _ = kid.Val(AttrName).(string) + f.ByteSize, _ = kid.Val(AttrByteSize).(int64) + f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) + f.BitSize, _ = kid.Val(AttrBitSize).(int64) + t.Field = append(t.Field, f) + + bito := f.BitOffset + if !haveBitOffset { + bito = f.ByteOffset * 8 + } + if bito == lastFieldBitOffset && t.Kind != "union" { + // Last field was zero width. Fix array length. + // (DWARF writes out 0-length arrays as if they were 1-length arrays.) + zeroArray(lastFieldType) } + lastFieldType = &f.Type + lastFieldBitOffset = bito } if t.Kind != "union" { b, ok := e.Val(AttrByteSize).(int64) diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go index 6e6c801a49a..c8a4fe6e610 100644 --- a/libgo/go/debug/elf/elf.go +++ b/libgo/go/debug/elf/elf.go @@ -744,30 +744,49 @@ func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, tru type R_X86_64 int const ( - R_X86_64_NONE R_X86_64 = 0 /* No relocation. */ - R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */ - R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */ - R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */ - R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */ - R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */ - R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */ - R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */ - R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */ - R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */ - R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */ - R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */ - R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */ - R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */ - R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */ - R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */ - R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */ - R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */ - R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */ - R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */ - R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */ - R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */ - R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */ - R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */ + R_X86_64_NONE R_X86_64 = 0 /* No relocation. */ + R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */ + R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */ + R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */ + R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */ + R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */ + R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */ + R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */ + R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */ + R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */ + R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */ + R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */ + R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */ + R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */ + R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */ + R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */ + R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */ + R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */ + R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */ + R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */ + R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */ + R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */ + R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */ + R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */ + R_X86_64_PC64 R_X86_64 = 24 /* PC relative 64-bit sign extended symbol value. */ + R_X86_64_GOTOFF64 R_X86_64 = 25 + R_X86_64_GOTPC32 R_X86_64 = 26 + R_X86_64_GOT64 R_X86_64 = 27 + R_X86_64_GOTPCREL64 R_X86_64 = 28 + R_X86_64_GOTPC64 R_X86_64 = 29 + R_X86_64_GOTPLT64 R_X86_64 = 30 + R_X86_64_PLTOFF64 R_X86_64 = 31 + R_X86_64_SIZE32 R_X86_64 = 32 + R_X86_64_SIZE64 R_X86_64 = 33 + R_X86_64_GOTPC32_TLSDESC R_X86_64 = 34 + R_X86_64_TLSDESC_CALL R_X86_64 = 35 + R_X86_64_TLSDESC R_X86_64 = 36 + R_X86_64_IRELATIVE R_X86_64 = 37 + R_X86_64_RELATIVE64 R_X86_64 = 38 + R_X86_64_PC32_BND R_X86_64 = 39 + R_X86_64_PLT32_BND R_X86_64 = 40 + R_X86_64_GOTPCRELX R_X86_64 = 41 + R_X86_64_REX_GOTPCRELX R_X86_64 = 42 ) var rx86_64Strings = []intName{ @@ -795,6 +814,25 @@ var rx86_64Strings = []intName{ {21, "R_X86_64_DTPOFF32"}, {22, "R_X86_64_GOTTPOFF"}, {23, "R_X86_64_TPOFF32"}, + {24, "R_X86_64_PC64"}, + {25, "R_X86_64_GOTOFF64"}, + {26, "R_X86_64_GOTPC32"}, + {27, "R_X86_64_GOT64"}, + {28, "R_X86_64_GOTPCREL64"}, + {29, "R_X86_64_GOTPC64"}, + {30, "R_X86_64_GOTPLT64"}, + {31, "R_X86_64_PLTOFF64"}, + {32, "R_X86_64_SIZE32"}, + {33, "R_X86_64_SIZE64"}, + {34, "R_X86_64_GOTPC32_TLSDESC"}, + {35, "R_X86_64_TLSDESC_CALL"}, + {36, "R_X86_64_TLSDESC"}, + {37, "R_X86_64_IRELATIVE"}, + {38, "R_X86_64_RELATIVE64"}, + {39, "R_X86_64_PC32_BND"}, + {40, "R_X86_64_PLT32_BND"}, + {41, "R_X86_64_GOTPCRELX"}, + {42, "R_X86_64_REX_GOTPCRELX"}, } func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) } @@ -887,10 +925,17 @@ const ( R_AARCH64_LDST64_ABS_LO12_NC R_AARCH64 = 286 R_AARCH64_LDST128_ABS_LO12_NC R_AARCH64 = 299 R_AARCH64_GOT_LD_PREL19 R_AARCH64 = 309 + R_AARCH64_LD64_GOTOFF_LO15 R_AARCH64 = 310 R_AARCH64_ADR_GOT_PAGE R_AARCH64 = 311 R_AARCH64_LD64_GOT_LO12_NC R_AARCH64 = 312 + R_AARCH64_LD64_GOTPAGE_LO15 R_AARCH64 = 313 + R_AARCH64_TLSGD_ADR_PREL21 R_AARCH64 = 512 R_AARCH64_TLSGD_ADR_PAGE21 R_AARCH64 = 513 R_AARCH64_TLSGD_ADD_LO12_NC R_AARCH64 = 514 + R_AARCH64_TLSGD_MOVW_G1 R_AARCH64 = 515 + R_AARCH64_TLSGD_MOVW_G0_NC R_AARCH64 = 516 + R_AARCH64_TLSLD_ADR_PREL21 R_AARCH64 = 517 + R_AARCH64_TLSLD_ADR_PAGE21 R_AARCH64 = 518 R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 R_AARCH64 = 539 R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC R_AARCH64 = 540 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 541 @@ -914,6 +959,10 @@ const ( R_AARCH64_TLSDESC_LDR R_AARCH64 = 567 R_AARCH64_TLSDESC_ADD R_AARCH64 = 568 R_AARCH64_TLSDESC_CALL R_AARCH64 = 569 + R_AARCH64_TLSLE_LDST128_TPREL_LO12 R_AARCH64 = 570 + R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC R_AARCH64 = 571 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12 R_AARCH64 = 572 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC R_AARCH64 = 573 R_AARCH64_COPY R_AARCH64 = 1024 R_AARCH64_GLOB_DAT R_AARCH64 = 1025 R_AARCH64_JUMP_SLOT R_AARCH64 = 1026 @@ -1009,10 +1058,17 @@ var raarch64Strings = []intName{ {286, "R_AARCH64_LDST64_ABS_LO12_NC"}, {299, "R_AARCH64_LDST128_ABS_LO12_NC"}, {309, "R_AARCH64_GOT_LD_PREL19"}, + {310, "R_AARCH64_LD64_GOTOFF_LO15"}, {311, "R_AARCH64_ADR_GOT_PAGE"}, {312, "R_AARCH64_LD64_GOT_LO12_NC"}, + {313, "R_AARCH64_LD64_GOTPAGE_LO15"}, + {512, "R_AARCH64_TLSGD_ADR_PREL21"}, {513, "R_AARCH64_TLSGD_ADR_PAGE21"}, {514, "R_AARCH64_TLSGD_ADD_LO12_NC"}, + {515, "R_AARCH64_TLSGD_MOVW_G1"}, + {516, "R_AARCH64_TLSGD_MOVW_G0_NC"}, + {517, "R_AARCH64_TLSLD_ADR_PREL21"}, + {518, "R_AARCH64_TLSLD_ADR_PAGE21"}, {539, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1"}, {540, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC"}, {541, "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21"}, @@ -1036,6 +1092,10 @@ var raarch64Strings = []intName{ {567, "R_AARCH64_TLSDESC_LDR"}, {568, "R_AARCH64_TLSDESC_ADD"}, {569, "R_AARCH64_TLSDESC_CALL"}, + {570, "R_AARCH64_TLSLE_LDST128_TPREL_LO12"}, + {571, "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC"}, + {572, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12"}, + {573, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC"}, {1024, "R_AARCH64_COPY"}, {1025, "R_AARCH64_GLOB_DAT"}, {1026, "R_AARCH64_JUMP_SLOT"}, @@ -1122,39 +1182,150 @@ func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, type R_ARM int const ( - R_ARM_NONE R_ARM = 0 /* No relocation. */ - R_ARM_PC24 R_ARM = 1 - R_ARM_ABS32 R_ARM = 2 - R_ARM_REL32 R_ARM = 3 - R_ARM_PC13 R_ARM = 4 - R_ARM_ABS16 R_ARM = 5 - R_ARM_ABS12 R_ARM = 6 - R_ARM_THM_ABS5 R_ARM = 7 - R_ARM_ABS8 R_ARM = 8 - R_ARM_SBREL32 R_ARM = 9 - R_ARM_THM_PC22 R_ARM = 10 - R_ARM_THM_PC8 R_ARM = 11 - R_ARM_AMP_VCALL9 R_ARM = 12 - R_ARM_SWI24 R_ARM = 13 - R_ARM_THM_SWI8 R_ARM = 14 - R_ARM_XPC25 R_ARM = 15 - R_ARM_THM_XPC22 R_ARM = 16 - R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */ - R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */ - R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */ - R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */ - R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */ - R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */ - R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */ - R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */ - R_ARM_GNU_VTENTRY R_ARM = 100 - R_ARM_GNU_VTINHERIT R_ARM = 101 - R_ARM_RSBREL32 R_ARM = 250 - R_ARM_THM_RPC22 R_ARM = 251 - R_ARM_RREL32 R_ARM = 252 - R_ARM_RABS32 R_ARM = 253 - R_ARM_RPC24 R_ARM = 254 - R_ARM_RBASE R_ARM = 255 + R_ARM_NONE R_ARM = 0 /* No relocation. */ + R_ARM_PC24 R_ARM = 1 + R_ARM_ABS32 R_ARM = 2 + R_ARM_REL32 R_ARM = 3 + R_ARM_PC13 R_ARM = 4 + R_ARM_ABS16 R_ARM = 5 + R_ARM_ABS12 R_ARM = 6 + R_ARM_THM_ABS5 R_ARM = 7 + R_ARM_ABS8 R_ARM = 8 + R_ARM_SBREL32 R_ARM = 9 + R_ARM_THM_PC22 R_ARM = 10 + R_ARM_THM_PC8 R_ARM = 11 + R_ARM_AMP_VCALL9 R_ARM = 12 + R_ARM_SWI24 R_ARM = 13 + R_ARM_THM_SWI8 R_ARM = 14 + R_ARM_XPC25 R_ARM = 15 + R_ARM_THM_XPC22 R_ARM = 16 + R_ARM_TLS_DTPMOD32 R_ARM = 17 + R_ARM_TLS_DTPOFF32 R_ARM = 18 + R_ARM_TLS_TPOFF32 R_ARM = 19 + R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */ + R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */ + R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */ + R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */ + R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */ + R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */ + R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */ + R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */ + R_ARM_CALL R_ARM = 28 + R_ARM_JUMP24 R_ARM = 29 + R_ARM_THM_JUMP24 R_ARM = 30 + R_ARM_BASE_ABS R_ARM = 31 + R_ARM_ALU_PCREL_7_0 R_ARM = 32 + R_ARM_ALU_PCREL_15_8 R_ARM = 33 + R_ARM_ALU_PCREL_23_15 R_ARM = 34 + R_ARM_LDR_SBREL_11_10_NC R_ARM = 35 + R_ARM_ALU_SBREL_19_12_NC R_ARM = 36 + R_ARM_ALU_SBREL_27_20_CK R_ARM = 37 + R_ARM_TARGET1 R_ARM = 38 + R_ARM_SBREL31 R_ARM = 39 + R_ARM_V4BX R_ARM = 40 + R_ARM_TARGET2 R_ARM = 41 + R_ARM_PREL31 R_ARM = 42 + R_ARM_MOVW_ABS_NC R_ARM = 43 + R_ARM_MOVT_ABS R_ARM = 44 + R_ARM_MOVW_PREL_NC R_ARM = 45 + R_ARM_MOVT_PREL R_ARM = 46 + R_ARM_THM_MOVW_ABS_NC R_ARM = 47 + R_ARM_THM_MOVT_ABS R_ARM = 48 + R_ARM_THM_MOVW_PREL_NC R_ARM = 49 + R_ARM_THM_MOVT_PREL R_ARM = 50 + R_ARM_THM_JUMP19 R_ARM = 51 + R_ARM_THM_JUMP6 R_ARM = 52 + R_ARM_THM_ALU_PREL_11_0 R_ARM = 53 + R_ARM_THM_PC12 R_ARM = 54 + R_ARM_ABS32_NOI R_ARM = 55 + R_ARM_REL32_NOI R_ARM = 56 + R_ARM_ALU_PC_G0_NC R_ARM = 57 + R_ARM_ALU_PC_G0 R_ARM = 58 + R_ARM_ALU_PC_G1_NC R_ARM = 59 + R_ARM_ALU_PC_G1 R_ARM = 60 + R_ARM_ALU_PC_G2 R_ARM = 61 + R_ARM_LDR_PC_G1 R_ARM = 62 + R_ARM_LDR_PC_G2 R_ARM = 63 + R_ARM_LDRS_PC_G0 R_ARM = 64 + R_ARM_LDRS_PC_G1 R_ARM = 65 + R_ARM_LDRS_PC_G2 R_ARM = 66 + R_ARM_LDC_PC_G0 R_ARM = 67 + R_ARM_LDC_PC_G1 R_ARM = 68 + R_ARM_LDC_PC_G2 R_ARM = 69 + R_ARM_ALU_SB_G0_NC R_ARM = 70 + R_ARM_ALU_SB_G0 R_ARM = 71 + R_ARM_ALU_SB_G1_NC R_ARM = 72 + R_ARM_ALU_SB_G1 R_ARM = 73 + R_ARM_ALU_SB_G2 R_ARM = 74 + R_ARM_LDR_SB_G0 R_ARM = 75 + R_ARM_LDR_SB_G1 R_ARM = 76 + R_ARM_LDR_SB_G2 R_ARM = 77 + R_ARM_LDRS_SB_G0 R_ARM = 78 + R_ARM_LDRS_SB_G1 R_ARM = 79 + R_ARM_LDRS_SB_G2 R_ARM = 80 + R_ARM_LDC_SB_G0 R_ARM = 81 + R_ARM_LDC_SB_G1 R_ARM = 82 + R_ARM_LDC_SB_G2 R_ARM = 83 + R_ARM_MOVW_BREL_NC R_ARM = 84 + R_ARM_MOVT_BREL R_ARM = 85 + R_ARM_MOVW_BREL R_ARM = 86 + R_ARM_THM_MOVW_BREL_NC R_ARM = 87 + R_ARM_THM_MOVT_BREL R_ARM = 88 + R_ARM_THM_MOVW_BREL R_ARM = 89 + R_ARM_TLS_GOTDESC R_ARM = 90 + R_ARM_TLS_CALL R_ARM = 91 + R_ARM_TLS_DESCSEQ R_ARM = 92 + R_ARM_THM_TLS_CALL R_ARM = 93 + R_ARM_PLT32_ABS R_ARM = 94 + R_ARM_GOT_ABS R_ARM = 95 + R_ARM_GOT_PREL R_ARM = 96 + R_ARM_GOT_BREL12 R_ARM = 97 + R_ARM_GOTOFF12 R_ARM = 98 + R_ARM_GOTRELAX R_ARM = 99 + R_ARM_GNU_VTENTRY R_ARM = 100 + R_ARM_GNU_VTINHERIT R_ARM = 101 + R_ARM_THM_JUMP11 R_ARM = 102 + R_ARM_THM_JUMP8 R_ARM = 103 + R_ARM_TLS_GD32 R_ARM = 104 + R_ARM_TLS_LDM32 R_ARM = 105 + R_ARM_TLS_LDO32 R_ARM = 106 + R_ARM_TLS_IE32 R_ARM = 107 + R_ARM_TLS_LE32 R_ARM = 108 + R_ARM_TLS_LDO12 R_ARM = 109 + R_ARM_TLS_LE12 R_ARM = 110 + R_ARM_TLS_IE12GP R_ARM = 111 + R_ARM_PRIVATE_0 R_ARM = 112 + R_ARM_PRIVATE_1 R_ARM = 113 + R_ARM_PRIVATE_2 R_ARM = 114 + R_ARM_PRIVATE_3 R_ARM = 115 + R_ARM_PRIVATE_4 R_ARM = 116 + R_ARM_PRIVATE_5 R_ARM = 117 + R_ARM_PRIVATE_6 R_ARM = 118 + R_ARM_PRIVATE_7 R_ARM = 119 + R_ARM_PRIVATE_8 R_ARM = 120 + R_ARM_PRIVATE_9 R_ARM = 121 + R_ARM_PRIVATE_10 R_ARM = 122 + R_ARM_PRIVATE_11 R_ARM = 123 + R_ARM_PRIVATE_12 R_ARM = 124 + R_ARM_PRIVATE_13 R_ARM = 125 + R_ARM_PRIVATE_14 R_ARM = 126 + R_ARM_PRIVATE_15 R_ARM = 127 + R_ARM_ME_TOO R_ARM = 128 + R_ARM_THM_TLS_DESCSEQ16 R_ARM = 129 + R_ARM_THM_TLS_DESCSEQ32 R_ARM = 130 + R_ARM_THM_GOT_BREL12 R_ARM = 131 + R_ARM_THM_ALU_ABS_G0_NC R_ARM = 132 + R_ARM_THM_ALU_ABS_G1_NC R_ARM = 133 + R_ARM_THM_ALU_ABS_G2_NC R_ARM = 134 + R_ARM_THM_ALU_ABS_G3 R_ARM = 135 + R_ARM_IRELATIVE R_ARM = 160 + R_ARM_RXPC25 R_ARM = 249 + R_ARM_RSBREL32 R_ARM = 250 + R_ARM_THM_RPC22 R_ARM = 251 + R_ARM_RREL32 R_ARM = 252 + R_ARM_RABS32 R_ARM = 253 + R_ARM_RPC24 R_ARM = 254 + R_ARM_RBASE R_ARM = 255 ) var rarmStrings = []intName{ @@ -1175,6 +1346,9 @@ var rarmStrings = []intName{ {14, "R_ARM_THM_SWI8"}, {15, "R_ARM_XPC25"}, {16, "R_ARM_THM_XPC22"}, + {17, "R_ARM_TLS_DTPMOD32"}, + {18, "R_ARM_TLS_DTPOFF32"}, + {19, "R_ARM_TLS_TPOFF32"}, {20, "R_ARM_COPY"}, {21, "R_ARM_GLOB_DAT"}, {22, "R_ARM_JUMP_SLOT"}, @@ -1183,8 +1357,116 @@ var rarmStrings = []intName{ {25, "R_ARM_GOTPC"}, {26, "R_ARM_GOT32"}, {27, "R_ARM_PLT32"}, + {28, "R_ARM_CALL"}, + {29, "R_ARM_JUMP24"}, + {30, "R_ARM_THM_JUMP24"}, + {31, "R_ARM_BASE_ABS"}, + {32, "R_ARM_ALU_PCREL_7_0"}, + {33, "R_ARM_ALU_PCREL_15_8"}, + {34, "R_ARM_ALU_PCREL_23_15"}, + {35, "R_ARM_LDR_SBREL_11_10_NC"}, + {36, "R_ARM_ALU_SBREL_19_12_NC"}, + {37, "R_ARM_ALU_SBREL_27_20_CK"}, + {38, "R_ARM_TARGET1"}, + {39, "R_ARM_SBREL31"}, + {40, "R_ARM_V4BX"}, + {41, "R_ARM_TARGET2"}, + {42, "R_ARM_PREL31"}, + {43, "R_ARM_MOVW_ABS_NC"}, + {44, "R_ARM_MOVT_ABS"}, + {45, "R_ARM_MOVW_PREL_NC"}, + {46, "R_ARM_MOVT_PREL"}, + {47, "R_ARM_THM_MOVW_ABS_NC"}, + {48, "R_ARM_THM_MOVT_ABS"}, + {49, "R_ARM_THM_MOVW_PREL_NC"}, + {50, "R_ARM_THM_MOVT_PREL"}, + {51, "R_ARM_THM_JUMP19"}, + {52, "R_ARM_THM_JUMP6"}, + {53, "R_ARM_THM_ALU_PREL_11_0"}, + {54, "R_ARM_THM_PC12"}, + {55, "R_ARM_ABS32_NOI"}, + {56, "R_ARM_REL32_NOI"}, + {57, "R_ARM_ALU_PC_G0_NC"}, + {58, "R_ARM_ALU_PC_G0"}, + {59, "R_ARM_ALU_PC_G1_NC"}, + {60, "R_ARM_ALU_PC_G1"}, + {61, "R_ARM_ALU_PC_G2"}, + {62, "R_ARM_LDR_PC_G1"}, + {63, "R_ARM_LDR_PC_G2"}, + {64, "R_ARM_LDRS_PC_G0"}, + {65, "R_ARM_LDRS_PC_G1"}, + {66, "R_ARM_LDRS_PC_G2"}, + {67, "R_ARM_LDC_PC_G0"}, + {68, "R_ARM_LDC_PC_G1"}, + {69, "R_ARM_LDC_PC_G2"}, + {70, "R_ARM_ALU_SB_G0_NC"}, + {71, "R_ARM_ALU_SB_G0"}, + {72, "R_ARM_ALU_SB_G1_NC"}, + {73, "R_ARM_ALU_SB_G1"}, + {74, "R_ARM_ALU_SB_G2"}, + {75, "R_ARM_LDR_SB_G0"}, + {76, "R_ARM_LDR_SB_G1"}, + {77, "R_ARM_LDR_SB_G2"}, + {78, "R_ARM_LDRS_SB_G0"}, + {79, "R_ARM_LDRS_SB_G1"}, + {80, "R_ARM_LDRS_SB_G2"}, + {81, "R_ARM_LDC_SB_G0"}, + {82, "R_ARM_LDC_SB_G1"}, + {83, "R_ARM_LDC_SB_G2"}, + {84, "R_ARM_MOVW_BREL_NC"}, + {85, "R_ARM_MOVT_BREL"}, + {86, "R_ARM_MOVW_BREL"}, + {87, "R_ARM_THM_MOVW_BREL_NC"}, + {88, "R_ARM_THM_MOVT_BREL"}, + {89, "R_ARM_THM_MOVW_BREL"}, + {90, "R_ARM_TLS_GOTDESC"}, + {91, "R_ARM_TLS_CALL"}, + {92, "R_ARM_TLS_DESCSEQ"}, + {93, "R_ARM_THM_TLS_CALL"}, + {94, "R_ARM_PLT32_ABS"}, + {95, "R_ARM_GOT_ABS"}, + {96, "R_ARM_GOT_PREL"}, + {97, "R_ARM_GOT_BREL12"}, + {98, "R_ARM_GOTOFF12"}, + {99, "R_ARM_GOTRELAX"}, {100, "R_ARM_GNU_VTENTRY"}, {101, "R_ARM_GNU_VTINHERIT"}, + {102, "R_ARM_THM_JUMP11"}, + {103, "R_ARM_THM_JUMP8"}, + {104, "R_ARM_TLS_GD32"}, + {105, "R_ARM_TLS_LDM32"}, + {106, "R_ARM_TLS_LDO32"}, + {107, "R_ARM_TLS_IE32"}, + {108, "R_ARM_TLS_LE32"}, + {109, "R_ARM_TLS_LDO12"}, + {110, "R_ARM_TLS_LE12"}, + {111, "R_ARM_TLS_IE12GP"}, + {112, "R_ARM_PRIVATE_0"}, + {113, "R_ARM_PRIVATE_1"}, + {114, "R_ARM_PRIVATE_2"}, + {115, "R_ARM_PRIVATE_3"}, + {116, "R_ARM_PRIVATE_4"}, + {117, "R_ARM_PRIVATE_5"}, + {118, "R_ARM_PRIVATE_6"}, + {119, "R_ARM_PRIVATE_7"}, + {120, "R_ARM_PRIVATE_8"}, + {121, "R_ARM_PRIVATE_9"}, + {122, "R_ARM_PRIVATE_10"}, + {123, "R_ARM_PRIVATE_11"}, + {124, "R_ARM_PRIVATE_12"}, + {125, "R_ARM_PRIVATE_13"}, + {126, "R_ARM_PRIVATE_14"}, + {127, "R_ARM_PRIVATE_15"}, + {128, "R_ARM_ME_TOO"}, + {129, "R_ARM_THM_TLS_DESCSEQ16"}, + {130, "R_ARM_THM_TLS_DESCSEQ32"}, + {131, "R_ARM_THM_GOT_BREL12"}, + {132, "R_ARM_THM_ALU_ABS_G0_NC"}, + {133, "R_ARM_THM_ALU_ABS_G1_NC"}, + {134, "R_ARM_THM_ALU_ABS_G2_NC"}, + {135, "R_ARM_THM_ALU_ABS_G3"}, + {160, "R_ARM_IRELATIVE"}, + {249, "R_ARM_RXPC25"}, {250, "R_ARM_RSBREL32"}, {251, "R_ARM_THM_RPC22"}, {252, "R_ARM_RREL32"}, @@ -1200,37 +1482,48 @@ func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, tru type R_386 int const ( - R_386_NONE R_386 = 0 /* No relocation. */ - R_386_32 R_386 = 1 /* Add symbol value. */ - R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */ - R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */ - R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */ - R_386_COPY R_386 = 5 /* Copy data from shared object. */ - R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */ - R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */ - R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */ - R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */ - R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */ - R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */ - R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */ - R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */ - R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */ - R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */ - R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */ - R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */ - R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */ - R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */ - R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */ - R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */ - R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */ - R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */ - R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */ - R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */ - R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */ - R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */ - R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */ - R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */ - R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */ + R_386_NONE R_386 = 0 /* No relocation. */ + R_386_32 R_386 = 1 /* Add symbol value. */ + R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */ + R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */ + R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */ + R_386_COPY R_386 = 5 /* Copy data from shared object. */ + R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */ + R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */ + R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */ + R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */ + R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */ + R_386_32PLT R_386 = 11 + R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */ + R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */ + R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */ + R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */ + R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */ + R_386_16 R_386 = 20 + R_386_PC16 R_386 = 21 + R_386_8 R_386 = 22 + R_386_PC8 R_386 = 23 + R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */ + R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */ + R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */ + R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */ + R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */ + R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */ + R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */ + R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */ + R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */ + R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */ + R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */ + R_386_SIZE32 R_386 = 38 + R_386_TLS_GOTDESC R_386 = 39 + R_386_TLS_DESC_CALL R_386 = 40 + R_386_TLS_DESC R_386 = 41 + R_386_IRELATIVE R_386 = 42 + R_386_GOT32X R_386 = 43 ) var r386Strings = []intName{ @@ -1245,12 +1538,17 @@ var r386Strings = []intName{ {8, "R_386_RELATIVE"}, {9, "R_386_GOTOFF"}, {10, "R_386_GOTPC"}, + {11, "R_386_32PLT"}, {14, "R_386_TLS_TPOFF"}, {15, "R_386_TLS_IE"}, {16, "R_386_TLS_GOTIE"}, {17, "R_386_TLS_LE"}, {18, "R_386_TLS_GD"}, {19, "R_386_TLS_LDM"}, + {20, "R_386_16"}, + {21, "R_386_PC16"}, + {22, "R_386_8"}, + {23, "R_386_PC8"}, {24, "R_386_TLS_GD_32"}, {25, "R_386_TLS_GD_PUSH"}, {26, "R_386_TLS_GD_CALL"}, @@ -1265,6 +1563,12 @@ var r386Strings = []intName{ {35, "R_386_TLS_DTPMOD32"}, {36, "R_386_TLS_DTPOFF32"}, {37, "R_386_TLS_TPOFF32"}, + {38, "R_386_SIZE32"}, + {39, "R_386_TLS_GOTDESC"}, + {40, "R_386_TLS_DESC_CALL"}, + {41, "R_386_TLS_DESC"}, + {42, "R_386_IRELATIVE"}, + {43, "R_386_GOT32X"}, } func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) } @@ -1380,70 +1684,75 @@ func (i R_MIPS) String() string { return stringName(uint32(i), rmipsStrings, f func (i R_MIPS) GoString() string { return stringName(uint32(i), rmipsStrings, true) } // Relocation types for PowerPC. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC type, the relevant +// shared relocations have been renamed with the prefix R_PPC_. +// The original name follows the value in a comment. type R_PPC int const ( - R_PPC_NONE R_PPC = 0 /* No relocation. */ - R_PPC_ADDR32 R_PPC = 1 - R_PPC_ADDR24 R_PPC = 2 - R_PPC_ADDR16 R_PPC = 3 - R_PPC_ADDR16_LO R_PPC = 4 - R_PPC_ADDR16_HI R_PPC = 5 - R_PPC_ADDR16_HA R_PPC = 6 - R_PPC_ADDR14 R_PPC = 7 - R_PPC_ADDR14_BRTAKEN R_PPC = 8 - R_PPC_ADDR14_BRNTAKEN R_PPC = 9 - R_PPC_REL24 R_PPC = 10 - R_PPC_REL14 R_PPC = 11 - R_PPC_REL14_BRTAKEN R_PPC = 12 - R_PPC_REL14_BRNTAKEN R_PPC = 13 - R_PPC_GOT16 R_PPC = 14 - R_PPC_GOT16_LO R_PPC = 15 - R_PPC_GOT16_HI R_PPC = 16 - R_PPC_GOT16_HA R_PPC = 17 + R_PPC_NONE R_PPC = 0 // R_POWERPC_NONE + R_PPC_ADDR32 R_PPC = 1 // R_POWERPC_ADDR32 + R_PPC_ADDR24 R_PPC = 2 // R_POWERPC_ADDR24 + R_PPC_ADDR16 R_PPC = 3 // R_POWERPC_ADDR16 + R_PPC_ADDR16_LO R_PPC = 4 // R_POWERPC_ADDR16_LO + R_PPC_ADDR16_HI R_PPC = 5 // R_POWERPC_ADDR16_HI + R_PPC_ADDR16_HA R_PPC = 6 // R_POWERPC_ADDR16_HA + R_PPC_ADDR14 R_PPC = 7 // R_POWERPC_ADDR14 + R_PPC_ADDR14_BRTAKEN R_PPC = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC_ADDR14_BRNTAKEN R_PPC = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC_REL24 R_PPC = 10 // R_POWERPC_REL24 + R_PPC_REL14 R_PPC = 11 // R_POWERPC_REL14 + R_PPC_REL14_BRTAKEN R_PPC = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC_REL14_BRNTAKEN R_PPC = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC_GOT16 R_PPC = 14 // R_POWERPC_GOT16 + R_PPC_GOT16_LO R_PPC = 15 // R_POWERPC_GOT16_LO + R_PPC_GOT16_HI R_PPC = 16 // R_POWERPC_GOT16_HI + R_PPC_GOT16_HA R_PPC = 17 // R_POWERPC_GOT16_HA R_PPC_PLTREL24 R_PPC = 18 - R_PPC_COPY R_PPC = 19 - R_PPC_GLOB_DAT R_PPC = 20 - R_PPC_JMP_SLOT R_PPC = 21 - R_PPC_RELATIVE R_PPC = 22 + R_PPC_COPY R_PPC = 19 // R_POWERPC_COPY + R_PPC_GLOB_DAT R_PPC = 20 // R_POWERPC_GLOB_DAT + R_PPC_JMP_SLOT R_PPC = 21 // R_POWERPC_JMP_SLOT + R_PPC_RELATIVE R_PPC = 22 // R_POWERPC_RELATIVE R_PPC_LOCAL24PC R_PPC = 23 - R_PPC_UADDR32 R_PPC = 24 - R_PPC_UADDR16 R_PPC = 25 - R_PPC_REL32 R_PPC = 26 - R_PPC_PLT32 R_PPC = 27 - R_PPC_PLTREL32 R_PPC = 28 - R_PPC_PLT16_LO R_PPC = 29 - R_PPC_PLT16_HI R_PPC = 30 - R_PPC_PLT16_HA R_PPC = 31 + R_PPC_UADDR32 R_PPC = 24 // R_POWERPC_UADDR32 + R_PPC_UADDR16 R_PPC = 25 // R_POWERPC_UADDR16 + R_PPC_REL32 R_PPC = 26 // R_POWERPC_REL32 + R_PPC_PLT32 R_PPC = 27 // R_POWERPC_PLT32 + R_PPC_PLTREL32 R_PPC = 28 // R_POWERPC_PLTREL32 + R_PPC_PLT16_LO R_PPC = 29 // R_POWERPC_PLT16_LO + R_PPC_PLT16_HI R_PPC = 30 // R_POWERPC_PLT16_HI + R_PPC_PLT16_HA R_PPC = 31 // R_POWERPC_PLT16_HA R_PPC_SDAREL16 R_PPC = 32 - R_PPC_SECTOFF R_PPC = 33 - R_PPC_SECTOFF_LO R_PPC = 34 - R_PPC_SECTOFF_HI R_PPC = 35 - R_PPC_SECTOFF_HA R_PPC = 36 - R_PPC_TLS R_PPC = 67 - R_PPC_DTPMOD32 R_PPC = 68 - R_PPC_TPREL16 R_PPC = 69 - R_PPC_TPREL16_LO R_PPC = 70 - R_PPC_TPREL16_HI R_PPC = 71 - R_PPC_TPREL16_HA R_PPC = 72 - R_PPC_TPREL32 R_PPC = 73 - R_PPC_DTPREL16 R_PPC = 74 - R_PPC_DTPREL16_LO R_PPC = 75 - R_PPC_DTPREL16_HI R_PPC = 76 - R_PPC_DTPREL16_HA R_PPC = 77 - R_PPC_DTPREL32 R_PPC = 78 - R_PPC_GOT_TLSGD16 R_PPC = 79 - R_PPC_GOT_TLSGD16_LO R_PPC = 80 - R_PPC_GOT_TLSGD16_HI R_PPC = 81 - R_PPC_GOT_TLSGD16_HA R_PPC = 82 - R_PPC_GOT_TLSLD16 R_PPC = 83 - R_PPC_GOT_TLSLD16_LO R_PPC = 84 - R_PPC_GOT_TLSLD16_HI R_PPC = 85 - R_PPC_GOT_TLSLD16_HA R_PPC = 86 - R_PPC_GOT_TPREL16 R_PPC = 87 - R_PPC_GOT_TPREL16_LO R_PPC = 88 - R_PPC_GOT_TPREL16_HI R_PPC = 89 - R_PPC_GOT_TPREL16_HA R_PPC = 90 + R_PPC_SECTOFF R_PPC = 33 // R_POWERPC_SECTOFF + R_PPC_SECTOFF_LO R_PPC = 34 // R_POWERPC_SECTOFF_LO + R_PPC_SECTOFF_HI R_PPC = 35 // R_POWERPC_SECTOFF_HI + R_PPC_SECTOFF_HA R_PPC = 36 // R_POWERPC_SECTOFF_HA + R_PPC_TLS R_PPC = 67 // R_POWERPC_TLS + R_PPC_DTPMOD32 R_PPC = 68 // R_POWERPC_DTPMOD32 + R_PPC_TPREL16 R_PPC = 69 // R_POWERPC_TPREL16 + R_PPC_TPREL16_LO R_PPC = 70 // R_POWERPC_TPREL16_LO + R_PPC_TPREL16_HI R_PPC = 71 // R_POWERPC_TPREL16_HI + R_PPC_TPREL16_HA R_PPC = 72 // R_POWERPC_TPREL16_HA + R_PPC_TPREL32 R_PPC = 73 // R_POWERPC_TPREL32 + R_PPC_DTPREL16 R_PPC = 74 // R_POWERPC_DTPREL16 + R_PPC_DTPREL16_LO R_PPC = 75 // R_POWERPC_DTPREL16_LO + R_PPC_DTPREL16_HI R_PPC = 76 // R_POWERPC_DTPREL16_HI + R_PPC_DTPREL16_HA R_PPC = 77 // R_POWERPC_DTPREL16_HA + R_PPC_DTPREL32 R_PPC = 78 // R_POWERPC_DTPREL32 + R_PPC_GOT_TLSGD16 R_PPC = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC_GOT_TLSGD16_LO R_PPC = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC_GOT_TLSGD16_HI R_PPC = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC_GOT_TLSGD16_HA R_PPC = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC_GOT_TLSLD16 R_PPC = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC_GOT_TLSLD16_LO R_PPC = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC_GOT_TLSLD16_HI R_PPC = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC_GOT_TLSLD16_HA R_PPC = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC_GOT_TPREL16 R_PPC = 87 // R_POWERPC_GOT_TPREL16 + R_PPC_GOT_TPREL16_LO R_PPC = 88 // R_POWERPC_GOT_TPREL16_LO + R_PPC_GOT_TPREL16_HI R_PPC = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC_GOT_TPREL16_HA R_PPC = 90 // R_POWERPC_GOT_TPREL16_HA R_PPC_EMB_NADDR32 R_PPC = 101 R_PPC_EMB_NADDR16 R_PPC = 102 R_PPC_EMB_NADDR16_LO R_PPC = 103 @@ -1500,7 +1809,6 @@ var rppcStrings = []intName{ {34, "R_PPC_SECTOFF_LO"}, {35, "R_PPC_SECTOFF_HI"}, {36, "R_PPC_SECTOFF_HA"}, - {67, "R_PPC_TLS"}, {68, "R_PPC_DTPMOD32"}, {69, "R_PPC_TPREL16"}, @@ -1525,7 +1833,6 @@ var rppcStrings = []intName{ {88, "R_PPC_GOT_TPREL16_LO"}, {89, "R_PPC_GOT_TPREL16_HI"}, {90, "R_PPC_GOT_TPREL16_HA"}, - {101, "R_PPC_EMB_NADDR32"}, {102, "R_PPC_EMB_NADDR16"}, {103, "R_PPC_EMB_NADDR16_LO"}, @@ -1548,29 +1855,34 @@ func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, fal func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) } // Relocation types for 64-bit PowerPC or Power Architecture processors. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC64 type, the relevant +// shared relocations have been renamed with the prefix R_PPC64_. +// The original name follows the value in a comment. type R_PPC64 int const ( - R_PPC64_NONE R_PPC64 = 0 - R_PPC64_ADDR32 R_PPC64 = 1 - R_PPC64_ADDR24 R_PPC64 = 2 - R_PPC64_ADDR16 R_PPC64 = 3 - R_PPC64_ADDR16_LO R_PPC64 = 4 - R_PPC64_ADDR16_HI R_PPC64 = 5 - R_PPC64_ADDR16_HA R_PPC64 = 6 - R_PPC64_ADDR14 R_PPC64 = 7 - R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8 - R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9 - R_PPC64_REL24 R_PPC64 = 10 - R_PPC64_REL14 R_PPC64 = 11 - R_PPC64_REL14_BRTAKEN R_PPC64 = 12 - R_PPC64_REL14_BRNTAKEN R_PPC64 = 13 - R_PPC64_GOT16 R_PPC64 = 14 - R_PPC64_GOT16_LO R_PPC64 = 15 - R_PPC64_GOT16_HI R_PPC64 = 16 - R_PPC64_GOT16_HA R_PPC64 = 17 - R_PPC64_JMP_SLOT R_PPC64 = 21 - R_PPC64_REL32 R_PPC64 = 26 + R_PPC64_NONE R_PPC64 = 0 // R_POWERPC_NONE + R_PPC64_ADDR32 R_PPC64 = 1 // R_POWERPC_ADDR32 + R_PPC64_ADDR24 R_PPC64 = 2 // R_POWERPC_ADDR24 + R_PPC64_ADDR16 R_PPC64 = 3 // R_POWERPC_ADDR16 + R_PPC64_ADDR16_LO R_PPC64 = 4 // R_POWERPC_ADDR16_LO + R_PPC64_ADDR16_HI R_PPC64 = 5 // R_POWERPC_ADDR16_HI + R_PPC64_ADDR16_HA R_PPC64 = 6 // R_POWERPC_ADDR16_HA + R_PPC64_ADDR14 R_PPC64 = 7 // R_POWERPC_ADDR14 + R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC64_REL24 R_PPC64 = 10 // R_POWERPC_REL24 + R_PPC64_REL14 R_PPC64 = 11 // R_POWERPC_REL14 + R_PPC64_REL14_BRTAKEN R_PPC64 = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC64_REL14_BRNTAKEN R_PPC64 = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC64_GOT16 R_PPC64 = 14 // R_POWERPC_GOT16 + R_PPC64_GOT16_LO R_PPC64 = 15 // R_POWERPC_GOT16_LO + R_PPC64_GOT16_HI R_PPC64 = 16 // R_POWERPC_GOT16_HI + R_PPC64_GOT16_HA R_PPC64 = 17 // R_POWERPC_GOT16_HA + R_PPC64_JMP_SLOT R_PPC64 = 21 // R_POWERPC_JMP_SLOT + R_PPC64_REL32 R_PPC64 = 26 // R_POWERPC_REL32 R_PPC64_ADDR64 R_PPC64 = 38 R_PPC64_ADDR16_HIGHER R_PPC64 = 39 R_PPC64_ADDR16_HIGHERA R_PPC64 = 40 @@ -1582,40 +1894,49 @@ const ( R_PPC64_TOC16_HI R_PPC64 = 49 R_PPC64_TOC16_HA R_PPC64 = 50 R_PPC64_TOC R_PPC64 = 51 + R_PPC64_PLTGOT16 R_PPC64 = 52 + R_PPC64_PLTGOT16_LO R_PPC64 = 53 + R_PPC64_PLTGOT16_HI R_PPC64 = 54 + R_PPC64_PLTGOT16_HA R_PPC64 = 55 R_PPC64_ADDR16_DS R_PPC64 = 56 R_PPC64_ADDR16_LO_DS R_PPC64 = 57 R_PPC64_GOT16_DS R_PPC64 = 58 R_PPC64_GOT16_LO_DS R_PPC64 = 59 + R_PPC64_PLT16_LO_DS R_PPC64 = 60 + R_PPC64_SECTOFF_DS R_PPC64 = 61 + R_PPC64_SECTOFF_LO_DS R_PPC64 = 61 R_PPC64_TOC16_DS R_PPC64 = 63 R_PPC64_TOC16_LO_DS R_PPC64 = 64 - R_PPC64_TLS R_PPC64 = 67 - R_PPC64_DTPMOD64 R_PPC64 = 68 - R_PPC64_TPREL16 R_PPC64 = 69 - R_PPC64_TPREL16_LO R_PPC64 = 70 - R_PPC64_TPREL16_HI R_PPC64 = 71 - R_PPC64_TPREL16_HA R_PPC64 = 72 - R_PPC64_TPREL64 R_PPC64 = 73 - R_PPC64_DTPREL16 R_PPC64 = 74 - R_PPC64_DTPREL16_LO R_PPC64 = 75 - R_PPC64_DTPREL16_HI R_PPC64 = 76 - R_PPC64_DTPREL16_HA R_PPC64 = 77 - R_PPC64_DTPREL64 R_PPC64 = 78 - R_PPC64_GOT_TLSGD16 R_PPC64 = 79 - R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80 - R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81 - R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82 - R_PPC64_GOT_TLSLD16 R_PPC64 = 83 - R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84 - R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85 - R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86 - R_PPC64_GOT_TPREL16_DS R_PPC64 = 87 - R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88 - R_PPC64_GOT_TPREL16_HI R_PPC64 = 89 - R_PPC64_GOT_TPREL16_HA R_PPC64 = 90 - R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91 - R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92 - R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93 - R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94 + R_PPC64_PLTGOT16_DS R_PPC64 = 65 + R_PPC64_PLTGOT_LO_DS R_PPC64 = 66 + R_PPC64_TLS R_PPC64 = 67 // R_POWERPC_TLS + R_PPC64_DTPMOD64 R_PPC64 = 68 // R_POWERPC_DTPMOD64 + R_PPC64_TPREL16 R_PPC64 = 69 // R_POWERPC_TPREL16 + R_PPC64_TPREL16_LO R_PPC64 = 70 // R_POWERPC_TPREL16_LO + R_PPC64_TPREL16_HI R_PPC64 = 71 // R_POWERPC_TPREL16_HI + R_PPC64_TPREL16_HA R_PPC64 = 72 // R_POWERPC_TPREL16_HA + R_PPC64_TPREL64 R_PPC64 = 73 // R_POWERPC_TPREL64 + R_PPC64_DTPREL16 R_PPC64 = 74 // R_POWERPC_DTPREL16 + R_PPC64_DTPREL16_LO R_PPC64 = 75 // R_POWERPC_DTPREL16_LO + R_PPC64_DTPREL16_HI R_PPC64 = 76 // R_POWERPC_DTPREL16_HI + R_PPC64_DTPREL16_HA R_PPC64 = 77 // R_POWERPC_DTPREL16_HA + R_PPC64_DTPREL64 R_PPC64 = 78 // R_POWERPC_DTPREL64 + R_PPC64_GOT_TLSGD16 R_PPC64 = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC64_GOT_TLSLD16 R_PPC64 = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC64_GOT_TPREL16_DS R_PPC64 = 87 // R_POWERPC_GOT_TPREL16_DS + R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88 // R_POWERPC_GOT_TPREL16_LO_DS + R_PPC64_GOT_TPREL16_HI R_PPC64 = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC64_GOT_TPREL16_HA R_PPC64 = 90 // R_POWERPC_GOT_TPREL16_HA + R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91 // R_POWERPC_GOT_DTPREL16_DS + R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92 // R_POWERPC_GOT_DTPREL16_LO_DS + R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93 // R_POWERPC_GOT_DTPREL16_HI + R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94 // R_POWERPC_GOT_DTPREL16_HA R_PPC64_TPREL16_DS R_PPC64 = 95 R_PPC64_TPREL16_LO_DS R_PPC64 = 96 R_PPC64_TPREL16_HIGHER R_PPC64 = 97 @@ -1630,10 +1951,23 @@ const ( R_PPC64_DTPREL16_HIGHESTA R_PPC64 = 106 R_PPC64_TLSGD R_PPC64 = 107 R_PPC64_TLSLD R_PPC64 = 108 - R_PPC64_REL16 R_PPC64 = 249 - R_PPC64_REL16_LO R_PPC64 = 250 - R_PPC64_REL16_HI R_PPC64 = 251 - R_PPC64_REL16_HA R_PPC64 = 252 + R_PPC64_TOCSAVE R_PPC64 = 109 + R_PPC64_ADDR16_HIGH R_PPC64 = 110 + R_PPC64_ADDR16_HIGHA R_PPC64 = 111 + R_PPC64_TPREL16_HIGH R_PPC64 = 112 + R_PPC64_TPREL16_HIGHA R_PPC64 = 113 + R_PPC64_DTPREL16_HIGH R_PPC64 = 114 + R_PPC64_DTPREL16_HIGHA R_PPC64 = 115 + R_PPC64_REL24_NOTOC R_PPC64 = 116 + R_PPC64_ADDR64_LOCAL R_PPC64 = 117 + R_PPC64_ENTRY R_PPC64 = 118 + R_PPC64_REL16DX_HA R_PPC64 = 246 // R_POWERPC_REL16DX_HA + R_PPC64_JMP_IREL R_PPC64 = 247 + R_PPC64_IRELATIVE R_PPC64 = 248 // R_POWERPC_IRELATIVE + R_PPC64_REL16 R_PPC64 = 249 // R_POWERPC_REL16 + R_PPC64_REL16_LO R_PPC64 = 250 // R_POWERPC_REL16_LO + R_PPC64_REL16_HI R_PPC64 = 251 // R_POWERPC_REL16_HI + R_PPC64_REL16_HA R_PPC64 = 252 // R_POWERPC_REL16_HA ) var rppc64Strings = []intName{ @@ -1668,12 +2002,21 @@ var rppc64Strings = []intName{ {49, "R_PPC64_TOC16_HI"}, {50, "R_PPC64_TOC16_HA"}, {51, "R_PPC64_TOC"}, + {52, "R_PPC64_PLTGOT16"}, + {53, "R_PPC64_PLTGOT16_LO"}, + {54, "R_PPC64_PLTGOT16_HI"}, + {55, "R_PPC64_PLTGOT16_HA"}, {56, "R_PPC64_ADDR16_DS"}, {57, "R_PPC64_ADDR16_LO_DS"}, {58, "R_PPC64_GOT16_DS"}, {59, "R_PPC64_GOT16_LO_DS"}, + {60, "R_PPC64_PLT16_LO_DS"}, + {61, "R_PPC64_SECTOFF_DS"}, + {61, "R_PPC64_SECTOFF_LO_DS"}, {63, "R_PPC64_TOC16_DS"}, {64, "R_PPC64_TOC16_LO_DS"}, + {65, "R_PPC64_PLTGOT16_DS"}, + {66, "R_PPC64_PLTGOT_LO_DS"}, {67, "R_PPC64_TLS"}, {68, "R_PPC64_DTPMOD64"}, {69, "R_PPC64_TPREL16"}, @@ -1716,6 +2059,19 @@ var rppc64Strings = []intName{ {106, "R_PPC64_DTPREL16_HIGHESTA"}, {107, "R_PPC64_TLSGD"}, {108, "R_PPC64_TLSLD"}, + {109, "R_PPC64_TOCSAVE"}, + {110, "R_PPC64_ADDR16_HIGH"}, + {111, "R_PPC64_ADDR16_HIGHA"}, + {112, "R_PPC64_TPREL16_HIGH"}, + {113, "R_PPC64_TPREL16_HIGHA"}, + {114, "R_PPC64_DTPREL16_HIGH"}, + {115, "R_PPC64_DTPREL16_HIGHA"}, + {116, "R_PPC64_REL24_NOTOC"}, + {117, "R_PPC64_ADDR64_LOCAL"}, + {118, "R_PPC64_ENTRY"}, + {246, "R_PPC64_REL16DX_HA"}, + {247, "R_PPC64_JMP_IREL"}, + {248, "R_PPC64_IRELATIVE"}, {249, "R_PPC64_REL16"}, {250, "R_PPC64_REL16_LO"}, {251, "R_PPC64_REL16_HI"}, diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index b415bb1bbc9..f28ae27cc01 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -17,6 +17,17 @@ import ( "strings" ) +// seekStart, seekCurrent, seekEnd are copies of +// io.SeekStart, io.SeekCurrent, and io.SeekEnd. +// We can't use the ones from package io because +// we want this code to build with Go 1.4 during +// cmd/dist bootstrap. +const ( + seekStart int = 0 + seekCurrent int = 1 + seekEnd int = 2 +) + // TODO: error reporting detail /* @@ -269,7 +280,7 @@ func NewFile(r io.ReaderAt) (*File, error) { switch f.Class { case ELFCLASS32: hdr := new(Header32) - sr.Seek(0, io.SeekStart) + sr.Seek(0, seekStart) if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { return nil, err } @@ -288,7 +299,7 @@ func NewFile(r io.ReaderAt) (*File, error) { shstrndx = int(hdr.Shstrndx) case ELFCLASS64: hdr := new(Header64) - sr.Seek(0, io.SeekStart) + sr.Seek(0, seekStart) if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { return nil, err } @@ -315,7 +326,7 @@ func NewFile(r io.ReaderAt) (*File, error) { f.Progs = make([]*Prog, phnum) for i := 0; i < phnum; i++ { off := phoff + int64(i)*int64(phentsize) - sr.Seek(off, io.SeekStart) + sr.Seek(off, seekStart) p := new(Prog) switch f.Class { case ELFCLASS32: @@ -359,7 +370,7 @@ func NewFile(r io.ReaderAt) (*File, error) { names := make([]uint32, shnum) for i := 0; i < shnum; i++ { off := shoff + int64(i)*int64(shentsize) - sr.Seek(off, io.SeekStart) + sr.Seek(off, seekStart) s := new(Section) switch f.Class { case ELFCLASS32: diff --git a/libgo/go/debug/elf/reader.go b/libgo/go/debug/elf/reader.go index eab437318d6..a45843619e5 100644 --- a/libgo/go/debug/elf/reader.go +++ b/libgo/go/debug/elf/reader.go @@ -63,11 +63,11 @@ func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { var newOffset int64 switch whence { - case io.SeekStart: + case seekStart: newOffset = offset - case io.SeekCurrent: + case seekCurrent: newOffset = r.offset + offset - case io.SeekEnd: + case seekEnd: newOffset = r.size + offset default: return 0, os.ErrInvalid diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go index f5f99630950..a995209934f 100644 --- a/libgo/go/debug/gosym/symtab.go +++ b/libgo/go/debug/gosym/symtab.go @@ -79,8 +79,8 @@ type Func struct { Entry uint64 *Sym End uint64 - Params []*Sym - Locals []*Sym + Params []*Sym // nil for Go 1.3 and later binaries + Locals []*Sym // nil for Go 1.3 and later binaries FrameSize int LineTable *LineTable Obj *Obj @@ -116,7 +116,7 @@ type Obj struct { // symbols decoded from the program and provides methods to translate // between symbols, names, and addresses. type Table struct { - Syms []Sym + Syms []Sym // nil for Go 1.3 and later binaries Funcs []Func Files map[string]*Obj // nil for Go 1.2 and later binaries Objs []Obj // nil for Go 1.2 and later binaries @@ -277,8 +277,9 @@ func walksymtab(data []byte, fn func(sym) error) error { return nil } -// NewTable decodes the Go symbol table in data, +// NewTable decodes the Go symbol table (the ".gosymtab" section in ELF), // returning an in-memory representation. +// Starting with Go 1.3, the Go symbol table no longer includes symbol data. func NewTable(symtab []byte, pcln *LineTable) (*Table, error) { var n int err := walksymtab(symtab, func(s sym) error { diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go index 223346f10d7..7b9e83e5a87 100644 --- a/libgo/go/debug/macho/file.go +++ b/libgo/go/debug/macho/file.go @@ -94,8 +94,23 @@ type SectionHeader struct { Flags uint32 } +// A Reloc represents a Mach-O relocation. +type Reloc struct { + Addr uint32 + Value uint32 + // when Scattered == false && Extern == true, Value is the symbol number. + // when Scattered == false && Extern == false, Value is the section number. + // when Scattered == true, Value is the value that this reloc refers to. + Type uint8 + Len uint8 // 0=byte, 1=word, 2=long, 3=quad + Pcrel bool + Extern bool // valid if Scattered == false + Scattered bool +} + type Section struct { SectionHeader + Relocs []Reloc // Embed ReaderAt for ReadAt method. // Do not embed SectionReader directly @@ -143,6 +158,21 @@ type Dysymtab struct { IndirectSyms []uint32 // indices into Symtab.Syms } +// A Rpath represents a Mach-O rpath command. +type Rpath struct { + LoadBytes + Path string +} + +// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. +type Symbol struct { + Name string + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + /* * Mach-O reader */ @@ -249,6 +279,20 @@ func NewFile(r io.ReaderAt) (*File, error) { default: f.Loads[i] = LoadBytes(cmddat) + case LoadCmdRpath: + var hdr RpathCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + l := new(Rpath) + if hdr.Path >= uint32(len(cmddat)) { + return nil, &FormatError{offset, "invalid path in rpath command", hdr.Path} + } + l.Path = cstring(cmddat[hdr.Path:]) + l.LoadBytes = LoadBytes(cmddat) + f.Loads[i] = l + case LoadCmdDylib: var hdr DylibCmd b := bytes.NewReader(cmddat) @@ -349,7 +393,9 @@ func NewFile(r io.ReaderAt) (*File, error) { sh.Reloff = sh32.Reloff sh.Nreloc = sh32.Nreloc sh.Flags = sh32.Flags - f.pushSection(sh, r) + if err := f.pushSection(sh, r); err != nil { + return nil, err + } } case LoadCmdSegment64: @@ -387,7 +433,9 @@ func NewFile(r io.ReaderAt) (*File, error) { sh.Reloff = sh64.Reloff sh.Nreloc = sh64.Nreloc sh.Flags = sh64.Flags - f.pushSection(sh, r) + if err := f.pushSection(sh, r); err != nil { + return nil, err + } } } if s != nil { @@ -435,10 +483,65 @@ func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset return st, nil } -func (f *File) pushSection(sh *Section, r io.ReaderAt) { +type relocInfo struct { + Addr uint32 + Symnum uint32 +} + +func (f *File) pushSection(sh *Section, r io.ReaderAt) error { f.Sections = append(f.Sections, sh) sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) sh.ReaderAt = sh.sr + + if sh.Nreloc > 0 { + reldat := make([]byte, int(sh.Nreloc)*8) + if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil { + return err + } + b := bytes.NewReader(reldat) + + bo := f.ByteOrder + + sh.Relocs = make([]Reloc, sh.Nreloc) + for i := range sh.Relocs { + rel := &sh.Relocs[i] + + var ri relocInfo + if err := binary.Read(b, bo, &ri); err != nil { + return err + } + + if ri.Addr&(1<<31) != 0 { // scattered + rel.Addr = ri.Addr & (1<<24 - 1) + rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1)) + rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1)) + rel.Pcrel = ri.Addr&(1<<30) != 0 + rel.Value = ri.Symnum + rel.Scattered = true + } else { + switch bo { + case binary.LittleEndian: + rel.Addr = ri.Addr + rel.Value = ri.Symnum & (1<<24 - 1) + rel.Pcrel = ri.Symnum&(1<<24) != 0 + rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1)) + rel.Extern = ri.Symnum&(1<<27) != 0 + rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1)) + case binary.BigEndian: + rel.Addr = ri.Addr + rel.Value = ri.Symnum >> 8 + rel.Pcrel = ri.Symnum&(1<<7) != 0 + rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1)) + rel.Extern = ri.Symnum&(1<<4) != 0 + rel.Type = uint8(ri.Symnum & (1<<4 - 1)) + default: + panic("unreachable") + } + } + } + } + + return nil } func cstring(b []byte) string { diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go index 9ff6c5d96e3..003c14e69b1 100644 --- a/libgo/go/debug/macho/file_test.go +++ b/libgo/go/debug/macho/file_test.go @@ -10,29 +10,30 @@ import ( ) type fileTest struct { - file string - hdr FileHeader - segments []*SegmentHeader - sections []*SectionHeader + file string + hdr FileHeader + loads []interface{} + sections []*SectionHeader + relocations map[string][]Reloc } var fileTests = []fileTest{ { "testdata/gcc-386-darwin-exec", FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85}, - []*SegmentHeader{ - {LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, - {LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0}, - {LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0}, - {LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0}, - {LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0}, - nil, - nil, - nil, - nil, - nil, - nil, - nil, + []interface{}{ + &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0}, + &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0}, + &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0}, + &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0}, + nil, // LC_SYMTAB + nil, // LC_DYSYMTAB + nil, // LC_LOAD_DYLINKER + nil, // LC_UUID + nil, // LC_UNIXTHREAD + &Dylib{nil, "/usr/lib/libgcc_s.1.dylib", 0x2, 0x10000, 0x10000}, + &Dylib{nil, "/usr/lib/libSystem.B.dylib", 0x2, 0x6f0104, 0x10000}, }, []*SectionHeader{ {"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400}, @@ -41,22 +42,23 @@ var fileTests = []fileTest{ {"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0}, {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008}, }, + nil, }, { "testdata/gcc-amd64-darwin-exec", FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85}, - []*SegmentHeader{ - {LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, - {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0}, - {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0}, - {LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0}, - nil, - nil, - nil, - nil, - nil, - nil, - nil, + []interface{}{ + &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0}, + &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0}, + &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0}, + nil, // LC_SYMTAB + nil, // LC_DYSYMTAB + nil, // LC_LOAD_DYLINKER + nil, // LC_UUID + nil, // LC_UNIXTHREAD + &Dylib{nil, "/usr/lib/libgcc_s.1.dylib", 0x2, 0x10000, 0x10000}, + &Dylib{nil, "/usr/lib/libSystem.B.dylib", 0x2, 0x6f0104, 0x10000}, }, []*SectionHeader{ {"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400}, @@ -68,15 +70,16 @@ var fileTests = []fileTest{ {"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0}, {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7}, }, + nil, }, { "testdata/gcc-amd64-darwin-exec-debug", FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0}, - []*SegmentHeader{ - nil, - {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0}, - {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0}, - {LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0}, + []interface{}{ + nil, // LC_UUID + &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0}, + &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0}, + &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0}, }, []*SectionHeader{ {"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400}, @@ -95,6 +98,126 @@ var fileTests = []fileTest{ {"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0}, {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0}, }, + nil, + }, + { + "testdata/clang-386-darwin-exec-with-rpath", + FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0x10, 0x42c, 0x1200085}, + []interface{}{ + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_DYLD_INFO_ONLY + nil, // LC_SYMTAB + nil, // LC_DYSYMTAB + nil, // LC_LOAD_DYLINKER + nil, // LC_UUID + nil, // LC_VERSION_MIN_MACOSX + nil, // LC_SOURCE_VERSION + nil, // LC_MAIN + nil, // LC_LOAD_DYLIB + &Rpath{nil, "/my/rpath"}, + nil, // LC_FUNCTION_STARTS + nil, // LC_DATA_IN_CODE + }, + nil, + nil, + }, + { + "testdata/clang-amd64-darwin-exec-with-rpath", + FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0x10, 0x4c8, 0x200085}, + []interface{}{ + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_SEGMENT + nil, // LC_DYLD_INFO_ONLY + nil, // LC_SYMTAB + nil, // LC_DYSYMTAB + nil, // LC_LOAD_DYLINKER + nil, // LC_UUID + nil, // LC_VERSION_MIN_MACOSX + nil, // LC_SOURCE_VERSION + nil, // LC_MAIN + nil, // LC_LOAD_DYLIB + &Rpath{nil, "/my/rpath"}, + nil, // LC_FUNCTION_STARTS + nil, // LC_DATA_IN_CODE + }, + nil, + nil, + }, + { + "testdata/clang-386-darwin.obj", + FileHeader{0xfeedface, Cpu386, 0x3, 0x1, 0x4, 0x138, 0x2000}, + nil, + nil, + map[string][]Reloc{ + "__text": []Reloc{ + { + Addr: 0x1d, + Type: uint8(GENERIC_RELOC_VANILLA), + Len: 2, + Pcrel: true, + Extern: true, + Value: 1, + Scattered: false, + }, + { + Addr: 0xe, + Type: uint8(GENERIC_RELOC_LOCAL_SECTDIFF), + Len: 2, + Pcrel: false, + Value: 0x2d, + Scattered: true, + }, + { + Addr: 0x0, + Type: uint8(GENERIC_RELOC_PAIR), + Len: 2, + Pcrel: false, + Value: 0xb, + Scattered: true, + }, + }, + }, + }, + { + "testdata/clang-amd64-darwin.obj", + FileHeader{0xfeedfacf, CpuAmd64, 0x3, 0x1, 0x4, 0x200, 0x2000}, + nil, + nil, + map[string][]Reloc{ + "__text": []Reloc{ + { + Addr: 0x19, + Type: uint8(X86_64_RELOC_BRANCH), + Len: 2, + Pcrel: true, + Extern: true, + Value: 1, + }, + { + Addr: 0xb, + Type: uint8(X86_64_RELOC_SIGNED), + Len: 2, + Pcrel: true, + Extern: false, + Value: 2, + }, + }, + "__compact_unwind": []Reloc{ + { + Addr: 0x0, + Type: uint8(X86_64_RELOC_UNSIGNED), + Len: 3, + Pcrel: false, + Extern: false, + Value: 1, + }, + }, + }, }, } @@ -112,49 +235,77 @@ func TestOpen(t *testing.T) { continue } for i, l := range f.Loads { - if i >= len(tt.segments) { - break + if len(l.Raw()) < 8 { + t.Errorf("open %s, command %d:\n\tload command %T don't have enough data\n", tt.file, i, l) } - sh := tt.segments[i] - s, ok := l.(*Segment) - if sh == nil { - if ok { - t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader) + } + if tt.loads != nil { + for i, l := range f.Loads { + if i >= len(tt.loads) { + break + } + + want := tt.loads[i] + if want == nil { + continue + } + + switch l := l.(type) { + case *Segment: + have := &l.SegmentHeader + if !reflect.DeepEqual(have, want) { + t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) + } + case *Dylib: + have := l + have.LoadBytes = nil + if !reflect.DeepEqual(have, want) { + t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) + } + case *Rpath: + have := l + have.LoadBytes = nil + if !reflect.DeepEqual(have, want) { + t.Errorf("open %s, command %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) + } + default: + t.Errorf("open %s, command %d: unknown load command\n\thave %#v\n\twant %#v\n", tt.file, i, l, want) } - continue - } - if !ok { - t.Errorf("open %s, section %d: not *Segment\n", tt.file, i) - continue } - have := &s.SegmentHeader - want := sh - if !reflect.DeepEqual(have, want) { - t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) + tn := len(tt.loads) + fn := len(f.Loads) + if tn != fn { + t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn) } } - tn := len(tt.segments) - fn := len(f.Loads) - if tn != fn { - t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn) - } - for i, sh := range f.Sections { - if i >= len(tt.sections) { - break + if tt.sections != nil { + 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) + } } - 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) } } - tn = len(tt.sections) - fn = len(f.Sections) - if tn != fn { - t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) - } + if tt.relocations != nil { + for i, sh := range f.Sections { + have := sh.Relocs + want := tt.relocations[sh.Name] + if !reflect.DeepEqual(have, want) { + t.Errorf("open %s, relocations in section %d (%s):\n\thave %#v\n\twant %#v\n", tt.file, i, sh.Name, have, want) + } + } + } } } @@ -208,3 +359,21 @@ func TestOpenFatFailure(t *testing.T) { t.Errorf("OpenFat %s: got %v, want nil", filename, ff) } } + +func TestRelocTypeString(t *testing.T) { + if X86_64_RELOC_BRANCH.String() != "X86_64_RELOC_BRANCH" { + t.Errorf("got %v, want %v", X86_64_RELOC_BRANCH.String(), "X86_64_RELOC_BRANCH") + } + if X86_64_RELOC_BRANCH.GoString() != "macho.X86_64_RELOC_BRANCH" { + t.Errorf("got %v, want %v", X86_64_RELOC_BRANCH.GoString(), "macho.X86_64_RELOC_BRANCH") + } +} + +func TestTypeString(t *testing.T) { + if TypeExec.String() != "Exec" { + t.Errorf("got %v, want %v", TypeExec.String(), "Exec") + } + if TypeExec.GoString() != "macho.Exec" { + t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec") + } +} diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go index 40ac74e9a14..fed8eb25a43 100644 --- a/libgo/go/debug/macho/macho.go +++ b/libgo/go/debug/macho/macho.go @@ -41,6 +41,16 @@ const ( TypeBundle Type = 8 ) +var typeStrings = []intName{ + {uint32(TypeObj), "Obj"}, + {uint32(TypeExec), "Exec"}, + {uint32(TypeDylib), "Dylib"}, + {uint32(TypeBundle), "Bundle"}, +} + +func (t Type) String() string { return stringName(uint32(t), typeStrings, false) } +func (t Type) GoString() string { return stringName(uint32(t), typeStrings, true) } + // A Cpu is a Mach-O cpu type. type Cpu uint32 @@ -69,14 +79,15 @@ func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) type LoadCmd uint32 const ( - LoadCmdSegment LoadCmd = 1 - LoadCmdSymtab LoadCmd = 2 - LoadCmdThread LoadCmd = 4 - LoadCmdUnixThread LoadCmd = 5 // thread+stack - LoadCmdDysymtab LoadCmd = 11 - LoadCmdDylib LoadCmd = 12 - LoadCmdDylinker LoadCmd = 15 - LoadCmdSegment64 LoadCmd = 25 + LoadCmdSegment LoadCmd = 0x1 + LoadCmdSymtab LoadCmd = 0x2 + LoadCmdThread LoadCmd = 0x4 + LoadCmdUnixThread LoadCmd = 0x5 // thread+stack + LoadCmdDysymtab LoadCmd = 0xb + LoadCmdDylib LoadCmd = 0xc // load dylib command + LoadCmdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command) + LoadCmdSegment64 LoadCmd = 0x19 + LoadCmdRpath LoadCmd = 0x8000001c ) var cmdStrings = []intName{ @@ -85,50 +96,131 @@ var cmdStrings = []intName{ {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, {uint32(LoadCmdDylib), "LoadCmdDylib"}, {uint32(LoadCmdSegment64), "LoadCmdSegment64"}, + {uint32(LoadCmdRpath), "LoadCmdRpath"}, } func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } -// A Segment64 is a 64-bit Mach-O segment load command. -type Segment64 struct { - Cmd LoadCmd - Len uint32 - Name [16]byte - Addr uint64 - Memsz uint64 - Offset uint64 - Filesz uint64 - Maxprot uint32 - Prot uint32 - Nsect uint32 - Flag uint32 -} +type ( + // A Segment32 is a 32-bit Mach-O segment load command. + Segment32 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint32 + Memsz uint32 + Offset uint32 + Filesz uint32 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 + } -// A Segment32 is a 32-bit Mach-O segment load command. -type Segment32 struct { - Cmd LoadCmd - Len uint32 - Name [16]byte - Addr uint32 - Memsz uint32 - Offset uint32 - Filesz uint32 - Maxprot uint32 - Prot uint32 - Nsect uint32 - Flag uint32 -} + // A Segment64 is a 64-bit Mach-O segment load command. + Segment64 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint64 + Memsz uint64 + Offset uint64 + Filesz uint64 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 + } -// A DylibCmd is a Mach-O load dynamic library command. -type DylibCmd struct { - Cmd LoadCmd - Len uint32 - Name uint32 - Time uint32 - CurrentVersion uint32 - CompatVersion uint32 -} + // A SymtabCmd is a Mach-O symbol table command. + SymtabCmd struct { + Cmd LoadCmd + Len uint32 + Symoff uint32 + Nsyms uint32 + Stroff uint32 + Strsize uint32 + } + + // A DysymtabCmd is a Mach-O dynamic symbol table command. + DysymtabCmd struct { + Cmd LoadCmd + Len uint32 + Ilocalsym uint32 + Nlocalsym uint32 + Iextdefsym uint32 + Nextdefsym uint32 + Iundefsym uint32 + Nundefsym uint32 + Tocoffset uint32 + Ntoc uint32 + Modtaboff uint32 + Nmodtab uint32 + Extrefsymoff uint32 + Nextrefsyms uint32 + Indirectsymoff uint32 + Nindirectsyms uint32 + Extreloff uint32 + Nextrel uint32 + Locreloff uint32 + Nlocrel uint32 + } + + // A DylibCmd is a Mach-O load dynamic library command. + DylibCmd struct { + Cmd LoadCmd + Len uint32 + Name uint32 + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 + } + + // A RpathCmd is a Mach-O rpath command. + RpathCmd struct { + Cmd LoadCmd + Len uint32 + Path uint32 + } + + // A Thread is a Mach-O thread state command. + Thread struct { + Cmd LoadCmd + Len uint32 + Type uint32 + Data []uint32 + } +) + +const ( + FlagNoUndefs uint32 = 0x1 + FlagIncrLink uint32 = 0x2 + FlagDyldLink uint32 = 0x4 + FlagBindAtLoad uint32 = 0x8 + FlagPrebound uint32 = 0x10 + FlagSplitSegs uint32 = 0x20 + FlagLazyInit uint32 = 0x40 + FlagTwoLevel uint32 = 0x80 + FlagForceFlat uint32 = 0x100 + FlagNoMultiDefs uint32 = 0x200 + FlagNoFixPrebinding uint32 = 0x400 + FlagPrebindable uint32 = 0x800 + FlagAllModsBound uint32 = 0x1000 + FlagSubsectionsViaSymbols uint32 = 0x2000 + FlagCanonical uint32 = 0x4000 + FlagWeakDefines uint32 = 0x8000 + FlagBindsToWeak uint32 = 0x10000 + FlagAllowStackExecution uint32 = 0x20000 + FlagRootSafe uint32 = 0x40000 + FlagSetuidSafe uint32 = 0x80000 + FlagNoReexportedDylibs uint32 = 0x100000 + FlagPIE uint32 = 0x200000 + FlagDeadStrippableDylib uint32 = 0x400000 + FlagHasTLVDescriptors uint32 = 0x800000 + FlagNoHeapExecution uint32 = 0x1000000 + FlagAppExtensionSafe uint32 = 0x2000000 +) // A Section32 is a 32-bit Mach-O section header. type Section32 struct { @@ -161,40 +253,6 @@ type Section64 struct { Reserve3 uint32 } -// A SymtabCmd is a Mach-O symbol table command. -type SymtabCmd struct { - Cmd LoadCmd - Len uint32 - Symoff uint32 - Nsyms uint32 - Stroff uint32 - Strsize uint32 -} - -// A DysymtabCmd is a Mach-O dynamic symbol table command. -type DysymtabCmd struct { - Cmd LoadCmd - Len uint32 - Ilocalsym uint32 - Nlocalsym uint32 - Iextdefsym uint32 - Nextdefsym uint32 - Iundefsym uint32 - Nundefsym uint32 - Tocoffset uint32 - Ntoc uint32 - Modtaboff uint32 - Nmodtab uint32 - Extrefsymoff uint32 - Nextrefsyms uint32 - Indirectsymoff uint32 - Nindirectsyms uint32 - Extreloff uint32 - Nextrel uint32 - Locreloff uint32 - Nlocrel uint32 -} - // An Nlist32 is a Mach-O 32-bit symbol table entry. type Nlist32 struct { Name uint32 @@ -213,23 +271,6 @@ type Nlist64 struct { Value uint64 } -// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. -type Symbol struct { - Name string - Type uint8 - Sect uint8 - Desc uint16 - Value uint64 -} - -// A Thread is a Mach-O thread state command. -type Thread struct { - Cmd LoadCmd - Len uint32 - Type uint32 - Data []uint32 -} - // Regs386 is the Mach-O 386 register structure. type Regs386 struct { AX uint32 diff --git a/libgo/go/debug/macho/reloctype.go b/libgo/go/debug/macho/reloctype.go new file mode 100644 index 00000000000..496dfce7ec1 --- /dev/null +++ b/libgo/go/debug/macho/reloctype.go @@ -0,0 +1,72 @@ +// Copyright 2017 The Go Authors. 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 + +//go:generate stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go + +type RelocTypeGeneric int + +const ( + GENERIC_RELOC_VANILLA RelocTypeGeneric = 0 + GENERIC_RELOC_PAIR RelocTypeGeneric = 1 + GENERIC_RELOC_SECTDIFF RelocTypeGeneric = 2 + GENERIC_RELOC_PB_LA_PTR RelocTypeGeneric = 3 + GENERIC_RELOC_LOCAL_SECTDIFF RelocTypeGeneric = 4 + GENERIC_RELOC_TLV RelocTypeGeneric = 5 +) + +func (r RelocTypeGeneric) GoString() string { return "macho." + r.String() } + +type RelocTypeX86_64 int + +const ( + X86_64_RELOC_UNSIGNED RelocTypeX86_64 = 0 + X86_64_RELOC_SIGNED RelocTypeX86_64 = 1 + X86_64_RELOC_BRANCH RelocTypeX86_64 = 2 + X86_64_RELOC_GOT_LOAD RelocTypeX86_64 = 3 + X86_64_RELOC_GOT RelocTypeX86_64 = 4 + X86_64_RELOC_SUBTRACTOR RelocTypeX86_64 = 5 + X86_64_RELOC_SIGNED_1 RelocTypeX86_64 = 6 + X86_64_RELOC_SIGNED_2 RelocTypeX86_64 = 7 + X86_64_RELOC_SIGNED_4 RelocTypeX86_64 = 8 + X86_64_RELOC_TLV RelocTypeX86_64 = 9 +) + +func (r RelocTypeX86_64) GoString() string { return "macho." + r.String() } + +type RelocTypeARM int + +const ( + ARM_RELOC_VANILLA RelocTypeARM = 0 + ARM_RELOC_PAIR RelocTypeARM = 1 + ARM_RELOC_SECTDIFF RelocTypeARM = 2 + ARM_RELOC_LOCAL_SECTDIFF RelocTypeARM = 3 + ARM_RELOC_PB_LA_PTR RelocTypeARM = 4 + ARM_RELOC_BR24 RelocTypeARM = 5 + ARM_THUMB_RELOC_BR22 RelocTypeARM = 6 + ARM_THUMB_32BIT_BRANCH RelocTypeARM = 7 + ARM_RELOC_HALF RelocTypeARM = 8 + ARM_RELOC_HALF_SECTDIFF RelocTypeARM = 9 +) + +func (r RelocTypeARM) GoString() string { return "macho." + r.String() } + +type RelocTypeARM64 int + +const ( + ARM64_RELOC_UNSIGNED RelocTypeARM64 = 0 + ARM64_RELOC_SUBTRACTOR RelocTypeARM64 = 1 + ARM64_RELOC_BRANCH26 RelocTypeARM64 = 2 + ARM64_RELOC_PAGE21 RelocTypeARM64 = 3 + ARM64_RELOC_PAGEOFF12 RelocTypeARM64 = 4 + ARM64_RELOC_GOT_LOAD_PAGE21 RelocTypeARM64 = 5 + ARM64_RELOC_GOT_LOAD_PAGEOFF12 RelocTypeARM64 = 6 + ARM64_RELOC_POINTER_TO_GOT RelocTypeARM64 = 7 + ARM64_RELOC_TLVP_LOAD_PAGE21 RelocTypeARM64 = 8 + ARM64_RELOC_TLVP_LOAD_PAGEOFF12 RelocTypeARM64 = 9 + ARM64_RELOC_ADDEND RelocTypeARM64 = 10 +) + +func (r RelocTypeARM64) GoString() string { return "macho." + r.String() } diff --git a/libgo/go/debug/macho/reloctype_string.go b/libgo/go/debug/macho/reloctype_string.go new file mode 100644 index 00000000000..6d5c5d87e82 --- /dev/null +++ b/libgo/go/debug/macho/reloctype_string.go @@ -0,0 +1,49 @@ +// Code generated by "stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go"; DO NOT EDIT. + +package macho + +import "fmt" + +const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV" + +var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129} + +func (i RelocTypeGeneric) String() string { + if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) { + return fmt.Sprintf("RelocTypeGeneric(%d)", i) + } + return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]] +} + +const _RelocTypeX86_64_name = "X86_64_RELOC_UNSIGNEDX86_64_RELOC_SIGNEDX86_64_RELOC_BRANCHX86_64_RELOC_GOT_LOADX86_64_RELOC_GOTX86_64_RELOC_SUBTRACTORX86_64_RELOC_SIGNED_1X86_64_RELOC_SIGNED_2X86_64_RELOC_SIGNED_4X86_64_RELOC_TLV" + +var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 182, 198} + +func (i RelocTypeX86_64) String() string { + if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) { + return fmt.Sprintf("RelocTypeX86_64(%d)", i) + } + return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]] +} + +const _RelocTypeARM_name = "ARM_RELOC_VANILLAARM_RELOC_PAIRARM_RELOC_SECTDIFFARM_RELOC_LOCAL_SECTDIFFARM_RELOC_PB_LA_PTRARM_RELOC_BR24ARM_THUMB_RELOC_BR22ARM_THUMB_32BIT_BRANCHARM_RELOC_HALFARM_RELOC_HALF_SECTDIFF" + +var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, 185} + +func (i RelocTypeARM) String() string { + if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) { + return fmt.Sprintf("RelocTypeARM(%d)", i) + } + return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]] +} + +const _RelocTypeARM64_name = "ARM64_RELOC_UNSIGNEDARM64_RELOC_SUBTRACTORARM64_RELOC_BRANCH26ARM64_RELOC_PAGE21ARM64_RELOC_PAGEOFF12ARM64_RELOC_GOT_LOAD_PAGE21ARM64_RELOC_GOT_LOAD_PAGEOFF12ARM64_RELOC_POINTER_TO_GOTARM64_RELOC_TLVP_LOAD_PAGE21ARM64_RELOC_TLVP_LOAD_PAGEOFF12ARM64_RELOC_ADDEND" + +var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 212, 243, 261} + +func (i RelocTypeARM64) String() string { + if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) { + return fmt.Sprintf("RelocTypeARM64(%d)", i) + } + return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]] +} diff --git a/libgo/go/debug/macho/testdata/clang-386-darwin-exec-with-rpath b/libgo/go/debug/macho/testdata/clang-386-darwin-exec-with-rpath new file mode 100644 index 0000000000000000000000000000000000000000..a8720feb923693232bce4fa9642988c86a28c372 GIT binary patch literal 8416 zcmeHM&r1|h9Dl284Q8nwN-%O14GVJ%f;rQo=QFb}r?L72;(gigy!ZY2zV9<{Vc&k&zkU9( zQwY%rZUDD|2ckmU5@sZV`4Cvj@sYFf>+vg>At<8bUx;yc@Q`vcK0O(5VvLHz$aS0Q zOfM;2Yr*Brr*QmCmk>u`nrRgRC2mnvEGj|DVmX`4+p_4El2C?oEF;Gb=$Da$bt*EN z{2a6)2ZCkVvI~~u$-nPo1v&OXzk(dZ>=)H@P?mDG=sKC)&AKsM$0~B{fo&Bzf)var zWhpnG$)#i_H<)dNWfrXuHHxeU8plaFDY}t(1)_% zI)98e=!n>0&BRaPDy5zHR}RDU-=h)Aq0S@IGnan`FOFTh5FZ^==jj*>h!ds|8yFa) z*2Prx2(d^P+UeGYu>+%`e$&?vVH|*xd!RiHnP=+}My|UHJPr;LeH91w!TEhNbVln& zzVid%7I3UobYgZU8B3Mz6y#1YYv_D;@9X-tleZu5KmX)``Q~XablihzY4-StlBomr zW3P);ax#(Ki!83!XA(QlK^KyChWy>+AkZ{w8KLlnC zDbwHA;krz`G-(7h0vZ90fJQ(gpb^jrXaqC@J_1vf_e-BTHYrTsT|AB9W&As(O0;)# zH^$?yEAcOtS4%HCZalBn`V13ykSHFtK3-j_{Ov71e5}=KxQ^QS0dqd@*r{gkuETo- zDLC?XKJNki-B0E{m&7^mcP)r)^P;KUqKCLkYSIX31T+E~0gZr0KqH_L&+L^w1_lOZAZ7$&79h3&F%%&D13)G=U=0)u0jdMhApIcB1jHZ^A77GMQ37E@ z_#v(lAqYN*r3=I${UG}$0BMl@Ku!aQ0)hDWT|%)E367sy971Eil1h#P@=kpavN zATbpn7637LxIiS>eG))=1yB!2-2osClII5E03b#NAY)+|S)3SlXy?=BHxe&EN+Wt3 zlz`N6*FPX$CyUC9`~Uy{H$2(t`lIti^AU;I!x^bLIr%yY<@rT9DL`k+0+j*n6X&9mRy#6Y0Wp+gUP^kPWg#3orZLXs77!9;$qMRYZV; z2AwKj;P>;%tYw!h2SKg*)>Xbfm4KMM*JaoE=F6^=E8JB9t@)m-dYIfb}2hwt&9T-R-=l;g3PSjdC*Yg*S}eM9StJy*{yWx_qKcI-0548DPp$D93SsaA;?wZ}jcs|Ov{Ltkgj3bx!TOU*Tym98M zQKyu0vv8e;vfnw==k=_@Gy|Fe&46a$UomhivHCHw^2JE3T^dE7 zuj4=1^9!+k0A^%sHU52dGqLi@n0;9rSVq;v+VOiZvFX}C3U;0Ew&L@rTCIjpO1n5{ zE*2d-)8&0r;9c00u;sfn-?h)fQXi@JZkG8y(~Xvf*BYSt)5NQIg7}D6(htpmW{uc&%`;95irFV>%ecolbOyhnSm)BE{SQn1bJ0?rG zfOZ#vAQ6fC_%@l(N^8lQuecWOx>F24nNQ^kVt_v&+Qo+xjD-XRR`*2wn?e3xIOJjf nUj;G$VZhdZJ@8&JjQzBz6k?2J6F0=W#~{5i1moQ`BeeSkgV?^% literal 0 HcmV?d00001 diff --git a/libgo/go/debug/macho/testdata/clang-amd64-darwin.obj b/libgo/go/debug/macho/testdata/clang-amd64-darwin.obj new file mode 100644 index 0000000000000000000000000000000000000000..23cc3c1bcb18a3256f515a1fe69a8bd199a6ef53 GIT binary patch literal 768 zcma)4ze_?<6h6;Hqs-n=P}J~-rl_HsuOI$>sDdwxw1{E$@2%d1>9UGjPb!{ 0 { + if fieldType == rawValueType { + // The inner element should not be parsed for RawValues. + } else if t.length > 0 { t, offset, err = parseTagAndLength(bytes, offset) if err != nil { return @@ -727,6 +746,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam } } + matchAny, universalTag, compoundType, ok1 := getUniversalType(fieldType) + if !ok1 { + err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)} + return + } + // Special case for strings: all the ASN.1 string types map to the Go // type string. getUniversalType returns the tag for PrintableString // when it sees a string, so if we see a different string type on the @@ -734,7 +759,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if universalTag == TagPrintableString { if t.class == ClassUniversal { switch t.tag { - case TagIA5String, TagGeneralString, TagT61String, TagUTF8String: + case TagIA5String, TagGeneralString, TagT61String, TagUTF8String, TagNumericString: universalTag = t.tag } } else if params.stringType != 0 { @@ -752,21 +777,25 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam universalTag = TagSet } + matchAnyClassAndTag := matchAny expectedClass := ClassUniversal expectedTag := universalTag if !params.explicit && params.tag != nil { expectedClass = ClassContextSpecific expectedTag = *params.tag + matchAnyClassAndTag = false } if !params.explicit && params.application && params.tag != nil { expectedClass = ClassApplication expectedTag = *params.tag + matchAnyClassAndTag = false } // We have unwrapped any explicit tagging at this point. - if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType { + if !matchAnyClassAndTag && (t.class != expectedClass || t.tag != expectedTag) || + (!matchAny && t.isCompound != compoundType) { // Tags don't match. Again, it could be an optional element. ok := setDefaultValue(v, params) if ok { @@ -785,6 +814,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam // We deal with the structures defined in this package first. switch fieldType { + case rawValueType: + result := RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]} + v.Set(reflect.ValueOf(result)) + return case objectIdentifierType: newSlice, err1 := parseObjectIdentifier(innerBytes) v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice))) @@ -904,6 +937,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam switch universalTag { case TagPrintableString: v, err = parsePrintableString(innerBytes) + case TagNumericString: + v, err = parseNumericString(innerBytes) case TagIA5String: v, err = parseIA5String(innerBytes) case TagT61String: @@ -977,7 +1012,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // // An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time. // -// An ASN.1 PrintableString or IA5String can be written to a string. +// An ASN.1 PrintableString, IA5String, or NumericString can be written to a string. // // Any of the above ASN.1 values can be written to an interface{}. // The value stored in the interface has the corresponding Go type. @@ -992,7 +1027,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // // The following tags on struct fields have special meaning to Unmarshal: // -// application specifies that a APPLICATION tag is used +// application specifies that an APPLICATION tag is used // default:x sets the default value for optional integer fields (only used if optional is also present) // explicit specifies that an additional, explicit tag wraps the implicit one // optional marks the field as ASN.1 OPTIONAL diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go index c9eda4069dc..5e67dc5ee4d 100644 --- a/libgo/go/encoding/asn1/asn1_test.go +++ b/libgo/go/encoding/asn1/asn1_test.go @@ -424,6 +424,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame {"generalized", fieldParameters{timeType: TagGeneralizedTime}}, {"utc", fieldParameters{timeType: TagUTCTime}}, {"printable", fieldParameters{stringType: TagPrintableString}}, + {"numeric", fieldParameters{stringType: TagNumericString}}, {"optional", fieldParameters{optional: true}}, {"explicit", fieldParameters{explicit: true, tag: new(int)}}, {"application", fieldParameters{application: true, tag: new(int)}}, @@ -486,6 +487,8 @@ var unmarshalTestData = []struct { {[]byte{0x02, 0x01, 0x10}, newInt(16)}, {[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")}, {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")}, + // Ampersand is allowed in PrintableString due to mistakes by major CAs. + {[]byte{0x13, 0x05, 't', 'e', 's', 't', '&'}, newString("test&")}, {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test"), []byte("\x16\x04test")}}, {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}}, {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}}, @@ -496,6 +499,7 @@ var unmarshalTestData = []struct { {[]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}}}, + {[]byte{0x12, 0x0b, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '}, newString("0123456789 ")}, } func TestUnmarshal(t *testing.T) { @@ -1015,7 +1019,7 @@ func TestNull(t *testing.T) { t.Fatal(err) } if !bytes.Equal(NullBytes, marshaled) { - t.Errorf("Expected Marshal of NullRawValue to yeild %x, got %x", NullBytes, marshaled) + t.Errorf("Expected Marshal of NullRawValue to yield %x, got %x", NullBytes, marshaled) } unmarshaled := RawValue{} @@ -1033,3 +1037,60 @@ func TestNull(t *testing.T) { t.Errorf("Expected Unmarshal of NullBytes to yield %v, got %v", NullRawValue, unmarshaled) } } + +func TestExplicitTagRawValueStruct(t *testing.T) { + type foo struct { + A RawValue `asn1:"optional,explicit,tag:5"` + B []byte `asn1:"optional,explicit,tag:6"` + } + before := foo{B: []byte{1, 2, 3}} + derBytes, err := Marshal(before) + if err != nil { + t.Fatal(err) + } + + var after foo + if rest, err := Unmarshal(derBytes, &after); err != nil || len(rest) != 0 { + t.Fatal(err) + } + + got := fmt.Sprintf("%#v", after) + want := fmt.Sprintf("%#v", before) + if got != want { + t.Errorf("got %s, want %s (DER: %x)", got, want, derBytes) + } +} + +func TestTaggedRawValue(t *testing.T) { + type taggedRawValue struct { + A RawValue `asn1:"tag:5"` + } + type untaggedRawValue struct { + A RawValue + } + const isCompound = 0x20 + const tag = 5 + + tests := []struct { + shouldMatch bool + derBytes []byte + }{ + {false, []byte{0x30, 3, TagInteger, 1, 1}}, + {true, []byte{0x30, 3, (ClassContextSpecific << 6) | tag, 1, 1}}, + {true, []byte{0x30, 3, (ClassContextSpecific << 6) | tag | isCompound, 1, 1}}, + {false, []byte{0x30, 3, (ClassApplication << 6) | tag | isCompound, 1, 1}}, + } + + for i, test := range tests { + var tagged taggedRawValue + if _, err := Unmarshal(test.derBytes, &tagged); (err == nil) != test.shouldMatch { + t.Errorf("#%d: unexpected result parsing %x: %s", i, test.derBytes, err) + } + + // An untagged RawValue should accept anything. + var untagged untaggedRawValue + if _, err := Unmarshal(test.derBytes, &untagged); err != nil { + t.Errorf("#%d: unexpected failure parsing %x with untagged RawValue: %s", i, test.derBytes, err) + } + } +} diff --git a/libgo/go/encoding/asn1/common.go b/libgo/go/encoding/asn1/common.go index cd93b27ecb8..a6589a521af 100644 --- a/libgo/go/encoding/asn1/common.go +++ b/libgo/go/encoding/asn1/common.go @@ -30,6 +30,7 @@ const ( TagUTF8String = 12 TagSequence = 16 TagSet = 17 + TagNumericString = 18 TagPrintableString = 19 TagT61String = 20 TagIA5String = 22 @@ -106,6 +107,8 @@ func parseFieldParameters(str string) (ret fieldParameters) { ret.stringType = TagIA5String case part == "printable": ret.stringType = TagPrintableString + case part == "numeric": + ret.stringType = TagNumericString case part == "utf8": ret.stringType = TagUTF8String case strings.HasPrefix(part, "default:"): @@ -136,36 +139,38 @@ func parseFieldParameters(str string) (ret fieldParameters) { // Given a reflected Go type, getUniversalType returns the default tag number // and expected compound flag. -func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) { +func getUniversalType(t reflect.Type) (matchAny bool, tagNumber int, isCompound, ok bool) { switch t { + case rawValueType: + return true, -1, false, true case objectIdentifierType: - return TagOID, false, true + return false, TagOID, false, true case bitStringType: - return TagBitString, false, true + return false, TagBitString, false, true case timeType: - return TagUTCTime, false, true + return false, TagUTCTime, false, true case enumeratedType: - return TagEnum, false, true + return false, TagEnum, false, true case bigIntType: - return TagInteger, false, true + return false, TagInteger, false, true } switch t.Kind() { case reflect.Bool: - return TagBoolean, false, true + return false, TagBoolean, false, true case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return TagInteger, false, true + return false, TagInteger, false, true case reflect.Struct: - return TagSequence, true, true + return false, TagSequence, true, true case reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { - return TagOctetString, false, true + return false, TagOctetString, false, true } if strings.HasSuffix(t.Name(), "SET") { - return TagSet, true, true + return false, TagSet, true, true } - return TagSequence, true, true + return false, TagSequence, true, true case reflect.String: - return TagPrintableString, false, true + return false, TagPrintableString, false, true } - return 0, false, false + return false, 0, false, false } diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go index fdadb3996ef..3e85651ffd0 100644 --- a/libgo/go/encoding/asn1/marshal.go +++ b/libgo/go/encoding/asn1/marshal.go @@ -18,7 +18,7 @@ var ( byteFFEncoder encoder = byteEncoder(0xff) ) -// encoder represents a ASN.1 element that is waiting to be marshaled. +// encoder represents an ASN.1 element that is waiting to be marshaled. type encoder interface { // Len returns the number of bytes needed to marshal this element. Len() int @@ -268,7 +268,13 @@ func makeObjectIdentifier(oid []int) (e encoder, err error) { func makePrintableString(s string) (e encoder, err error) { for i := 0; i < len(s); i++ { - if !isPrintable(s[i]) { + // The asterisk is often used in PrintableString, even though + // it is invalid. If a PrintableString was specifically + // requested then the asterisk is permitted by this code. + // Ampersand is allowed in parsing due a handful of CA + // certificates, however when making new certificates + // it is rejected. + if !isPrintable(s[i], allowAsterisk, rejectAmpersand) { return nil, StructuralError{"PrintableString contains invalid character"} } } @@ -286,6 +292,16 @@ func makeIA5String(s string) (e encoder, err error) { return stringEncoder(s), nil } +func makeNumericString(s string) (e encoder, err error) { + for i := 0; i < len(s); i++ { + if !isNumeric(s[i]) { + return nil, StructuralError{"NumericString contains invalid character"} + } + } + + return stringEncoder(s), nil +} + func makeUTF8String(s string) encoder { return stringEncoder(s) } @@ -503,6 +519,8 @@ func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error return makeIA5String(v.String()) case TagPrintableString: return makePrintableString(v.String()) + case TagNumericString: + return makeNumericString(v.String()) default: return makeUTF8String(v.String()), nil } @@ -556,11 +574,10 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) { return t, nil } - tag, isCompound, ok := getUniversalType(v.Type()) - if !ok { + matchAny, tag, isCompound, ok := getUniversalType(v.Type()) + if !ok || matchAny { return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())} } - class := ClassUniversal if params.timeType != 0 && tag != TagUTCTime { return nil, StructuralError{"explicit time type given to non-time member"} @@ -577,7 +594,7 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) { // a PrintableString if the character set in the string is // sufficiently limited, otherwise we'll use a UTF8String. for _, r := range v.String() { - if r >= utf8.RuneSelf || !isPrintable(byte(r)) { + if r >= utf8.RuneSelf || !isPrintable(byte(r), rejectAsterisk, rejectAmpersand) { if !utf8.ValidString(v.String()) { return nil, errors.New("asn1: string not valid UTF-8") } @@ -610,27 +627,33 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) { bodyLen := t.body.Len() - if params.explicit { - t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound})) + class := ClassUniversal + if params.tag != nil { + if params.application { + class = ClassApplication + } else { + class = ClassContextSpecific + } + + if params.explicit { + t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{ClassUniversal, tag, bodyLen, isCompound})) - tt := new(taggedEncoder) + tt := new(taggedEncoder) - tt.body = t + tt.body = t - tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{ - class: ClassContextSpecific, - tag: *params.tag, - length: bodyLen + t.tag.Len(), - isCompound: true, - })) + tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{ + class: class, + tag: *params.tag, + length: bodyLen + t.tag.Len(), + isCompound: true, + })) - return tt, nil - } + return tt, nil + } - if params.tag != nil { // implicit tag. tag = *params.tag - class = ClassContextSpecific } t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound})) @@ -650,7 +673,13 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) { // utc: causes time.Time to be marshaled as ASN.1, UTCTime values // generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values func Marshal(val interface{}) ([]byte, error) { - e, err := makeField(reflect.ValueOf(val), fieldParameters{}) + return MarshalWithParams(val, "") +} + +// MarshalWithParams allows field parameters to be specified for the +// top-level element. The form of the params is the same as the field tags. +func MarshalWithParams(val interface{}, params string) ([]byte, error) { + e, err := makeField(reflect.ValueOf(val), parseFieldParameters(params)) if err != nil { return nil, err } diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go index 10db1aa575a..4f755a1f39f 100644 --- a/libgo/go/encoding/asn1/marshal_test.go +++ b/libgo/go/encoding/asn1/marshal_test.go @@ -59,6 +59,10 @@ type printableStringTest struct { A string `asn1:"printable"` } +type genericStringTest struct { + A string +} + type optionalRawValueTest struct { A RawValue `asn1:"optional"` } @@ -71,6 +75,15 @@ type defaultTest struct { A int `asn1:"optional,default:1"` } +type applicationTest struct { + A int `asn1:"application,tag:0"` + B int `asn1:"application,tag:1,explicit"` +} + +type numericStringTest struct { + A string `asn1:"numeric"` +} + type testSET []int var PST = time.FixedZone("PST", -8*60*60) @@ -142,6 +155,9 @@ var marshalTests = []marshalTest{ {optionalRawValueTest{}, "3000"}, {printableStringTest{"test"}, "3006130474657374"}, {printableStringTest{"test*"}, "30071305746573742a"}, + {genericStringTest{"test"}, "3006130474657374"}, + {genericStringTest{"test*"}, "30070c05746573742a"}, + {genericStringTest{"test&"}, "30070c057465737426"}, {rawContentsStruct{nil, 64}, "3003020140"}, {rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"}, {RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"}, @@ -152,6 +168,8 @@ var marshalTests = []marshalTest{ {defaultTest{0}, "3003020100"}, {defaultTest{1}, "3000"}, {defaultTest{2}, "3003020102"}, + {applicationTest{1, 2}, "30084001016103020102"}, + {numericStringTest{"1 9"}, "30051203312039"}, } func TestMarshal(t *testing.T) { @@ -168,6 +186,31 @@ func TestMarshal(t *testing.T) { } } +type marshalWithParamsTest struct { + in interface{} + params string + out string // hex encoded +} + +var marshalWithParamsTests = []marshalWithParamsTest{ + {intStruct{10}, "set", "310302010a"}, + {intStruct{10}, "application", "600302010a"}, +} + +func TestMarshalWithParams(t *testing.T) { + for i, test := range marshalWithParamsTests { + data, err := MarshalWithParams(test.in, test.params) + if err != nil { + t.Errorf("#%d failed: %s", i, err) + } + out, _ := hex.DecodeString(test.out) + if !bytes.Equal(out, data) { + t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out) + + } + } +} + type marshalErrTest struct { in interface{} err string @@ -175,6 +218,9 @@ type marshalErrTest struct { var marshalErrTests = []marshalErrTest{ {bigIntStruct{nil}, "empty integer"}, + {numericStringTest{"a"}, "invalid character"}, + {ia5StringTest{"\xb0"}, "invalid character"}, + {printableStringTest{"!"}, "invalid character"}, } func TestMarshalError(t *testing.T) { diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go index bf341b54f3d..e72ba74983e 100644 --- a/libgo/go/encoding/base32/base32.go +++ b/libgo/go/encoding/base32/base32.go @@ -130,8 +130,19 @@ func (enc *Encoding) Encode(dst, src []byte) { } // Encode 5-bit blocks using the base32 alphabet - for i := 0; i < 8; i++ { - if len(dst) > i { + size := len(dst) + if size >= 8 { + // Common case, unrolled for extra performance + dst[0] = enc.encode[b[0]] + dst[1] = enc.encode[b[1]] + dst[2] = enc.encode[b[2]] + dst[3] = enc.encode[b[3]] + dst[4] = enc.encode[b[4]] + dst[5] = enc.encode[b[5]] + dst[6] = enc.encode[b[6]] + dst[7] = enc.encode[b[7]] + } else { + for i := 0; i < size; i++ { dst[i] = enc.encode[b[i]] } } diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go index b208f9e4d8d..9a99370f1e5 100644 --- a/libgo/go/encoding/base64/base64.go +++ b/libgo/go/encoding/base64/base64.go @@ -6,6 +6,7 @@ package base64 import ( + "encoding/binary" "io" "strconv" ) @@ -269,121 +270,110 @@ func (e CorruptInputError) Error() string { return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10) } -// decode is like Decode but returns an additional 'end' value, which -// indicates if end-of-message padding or a partial quantum was encountered -// and thus any additional data is an error. -func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { - si := 0 - - for si < len(src) && !end { - // Decode quantum using the base64 alphabet - var dbuf [4]byte - dinc, dlen := 3, 4 - - for j := 0; j < len(dbuf); j++ { - if len(src) == si { - switch { - case j == 0: - return n, false, nil - case j == 1, enc.padChar != NoPadding: - return n, false, CorruptInputError(si - j) - } - dinc, dlen, end = j-1, j, true - break +// decodeQuantum decodes up to 4 base64 bytes. It takes for parameters +// the destination buffer dst, the source buffer src and an index in the +// source buffer si. +// It returns the number of bytes read from src, the number of bytes written +// to dst, and an error, if any. +func (enc *Encoding) decodeQuantum(dst, src []byte, si int) (nsi, n int, err error) { + // Decode quantum using the base64 alphabet + var dbuf [4]byte + dinc, dlen := 3, 4 + + for j := 0; j < len(dbuf); j++ { + if len(src) == si { + switch { + case j == 0: + return si, 0, nil + case j == 1, enc.padChar != NoPadding: + return si, 0, CorruptInputError(si - j) } - in := src[si] + dinc, dlen = j-1, j + break + } + in := src[si] + si++ - si++ + out := enc.decodeMap[in] + if out != 0xff { + dbuf[j] = out + continue + } - out := enc.decodeMap[in] - if out != 0xFF { - dbuf[j] = out - continue - } + if in == '\n' || in == '\r' { + j-- + continue + } - if in == '\n' || in == '\r' { - j-- - continue - } - if rune(in) == enc.padChar { - // We've reached the end and there's padding - switch j { - case 0, 1: - // incorrect padding - return n, false, CorruptInputError(si - 1) - case 2: - // "==" is expected, the first "=" is already consumed. - // skip over newlines - for si < len(src) && (src[si] == '\n' || src[si] == '\r') { - si++ - } - if si == len(src) { - // not enough padding - return n, false, CorruptInputError(len(src)) - } - if rune(src[si]) != enc.padChar { - // incorrect padding - return n, false, CorruptInputError(si - 1) - } - - si++ - } - // skip over newlines - for si < len(src) && (src[si] == '\n' || src[si] == '\r') { - si++ - } - if si < len(src) { - // trailing garbage - err = CorruptInputError(si) - } - dinc, dlen, end = 3, j, true - break - } - return n, false, CorruptInputError(si - 1) + if rune(in) != enc.padChar { + return si, 0, CorruptInputError(si - 1) } - // Convert 4x 6bit source bytes into 3 bytes - val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3]) - dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16) - switch dlen { - case 4: - dst[2] = dbuf[2] - dbuf[2] = 0 - fallthrough - case 3: - dst[1] = dbuf[1] - if enc.strict && dbuf[2] != 0 { - return n, end, CorruptInputError(si - 1) - } - dbuf[1] = 0 - fallthrough + // We've reached the end and there's padding + switch j { + case 0, 1: + // incorrect padding + return si, 0, CorruptInputError(si - 1) case 2: - dst[0] = dbuf[0] - if enc.strict && (dbuf[1] != 0 || dbuf[2] != 0) { - return n, end, CorruptInputError(si - 2) + // "==" is expected, the first "=" is already consumed. + // skip over newlines + for si < len(src) && (src[si] == '\n' || src[si] == '\r') { + si++ + } + if si == len(src) { + // not enough padding + return si, 0, CorruptInputError(len(src)) } + if rune(src[si]) != enc.padChar { + // incorrect padding + return si, 0, CorruptInputError(si - 1) + } + + si++ + } + + // skip over newlines + for si < len(src) && (src[si] == '\n' || src[si] == '\r') { + si++ + } + if si < len(src) { + // trailing garbage + err = CorruptInputError(si) } - dst = dst[dinc:] - n += dlen - 1 + dinc, dlen = 3, j + break } - return n, end, err -} + // Convert 4x 6bit source bytes into 3 bytes + val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3]) + dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16) + switch dlen { + case 4: + dst[2] = dbuf[2] + dbuf[2] = 0 + fallthrough + case 3: + dst[1] = dbuf[1] + if enc.strict && dbuf[2] != 0 { + return si, 0, CorruptInputError(si - 1) + } + dbuf[1] = 0 + fallthrough + case 2: + dst[0] = dbuf[0] + if enc.strict && (dbuf[1] != 0 || dbuf[2] != 0) { + return si, 0, CorruptInputError(si - 2) + } + } + dst = dst[dinc:] -// Decode decodes src using the encoding enc. It writes at most -// DecodedLen(len(src)) bytes to dst and returns the number of bytes -// written. If src contains invalid base64 data, it will return the -// number of bytes successfully written and CorruptInputError. -// New line characters (\r and \n) are ignored. -func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { - n, _, err = enc.decode(dst, src) - return + return si, dlen - 1, err } // DecodeString returns the bytes represented by the base64 string s. func (enc *Encoding) DecodeString(s string) ([]byte, error) { dbuf := make([]byte, enc.DecodedLen(len(s))) - n, _, err := enc.decode(dbuf, []byte(s)) + n, err := enc.Decode(dbuf, []byte(s)) return dbuf[:n], err } @@ -392,7 +382,6 @@ type decoder struct { readErr error // error from r.Read enc *Encoding r io.Reader - end bool // saw end of message buf [1024]byte // leftover input nbuf int out []byte // leftover decoded output @@ -430,9 +419,8 @@ func (d *decoder) Read(p []byte) (n int, err error) { if d.enc.padChar == NoPadding && d.nbuf > 0 { // Decode final fragment, without padding. var nw int - nw, _, d.err = d.enc.decode(d.outbuf[:], d.buf[:d.nbuf]) + nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:d.nbuf]) d.nbuf = 0 - d.end = true d.out = d.outbuf[:nw] n = copy(p, d.out) d.out = d.out[n:] @@ -454,18 +442,138 @@ func (d *decoder) Read(p []byte) (n int, err error) { nr := d.nbuf / 4 * 4 nw := d.nbuf / 4 * 3 if nw > len(p) { - nw, d.end, d.err = d.enc.decode(d.outbuf[:], d.buf[:nr]) + nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:nr]) d.out = d.outbuf[:nw] n = copy(p, d.out) d.out = d.out[n:] } else { - n, d.end, d.err = d.enc.decode(p, d.buf[:nr]) + n, d.err = d.enc.Decode(p, d.buf[:nr]) } d.nbuf -= nr copy(d.buf[:d.nbuf], d.buf[nr:]) return n, d.err } +// Decode decodes src using the encoding enc. It writes at most +// DecodedLen(len(src)) bytes to dst and returns the number of bytes +// written. If src contains invalid base64 data, it will return the +// number of bytes successfully written and CorruptInputError. +// New line characters (\r and \n) are ignored. +func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { + if len(src) == 0 { + return 0, nil + } + + si := 0 + ilen := len(src) + olen := len(dst) + for strconv.IntSize >= 64 && ilen-si >= 8 && olen-n >= 8 { + if ok := enc.decode64(dst[n:], src[si:]); ok { + n += 6 + si += 8 + } else { + var ninc int + si, ninc, err = enc.decodeQuantum(dst[n:], src, si) + n += ninc + if err != nil { + return n, err + } + } + } + + for ilen-si >= 4 && olen-n >= 4 { + if ok := enc.decode32(dst[n:], src[si:]); ok { + n += 3 + si += 4 + } else { + var ninc int + si, ninc, err = enc.decodeQuantum(dst[n:], src, si) + n += ninc + if err != nil { + return n, err + } + } + } + + for si < len(src) { + var ninc int + si, ninc, err = enc.decodeQuantum(dst[n:], src, si) + n += ninc + if err != nil { + return n, err + } + } + return n, err +} + +// decode32 tries to decode 4 base64 char into 3 bytes. +// len(dst) and len(src) must both be >= 4. +// Returns true if decode succeeded. +func (enc *Encoding) decode32(dst, src []byte) bool { + var dn, n uint32 + if n = uint32(enc.decodeMap[src[0]]); n == 0xff { + return false + } + dn |= n << 26 + if n = uint32(enc.decodeMap[src[1]]); n == 0xff { + return false + } + dn |= n << 20 + if n = uint32(enc.decodeMap[src[2]]); n == 0xff { + return false + } + dn |= n << 14 + if n = uint32(enc.decodeMap[src[3]]); n == 0xff { + return false + } + dn |= n << 8 + + binary.BigEndian.PutUint32(dst, dn) + return true +} + +// decode64 tries to decode 8 base64 char into 6 bytes. +// len(dst) and len(src) must both be >= 8. +// Returns true if decode succeeded. +func (enc *Encoding) decode64(dst, src []byte) bool { + var dn, n uint64 + if n = uint64(enc.decodeMap[src[0]]); n == 0xff { + return false + } + dn |= n << 58 + if n = uint64(enc.decodeMap[src[1]]); n == 0xff { + return false + } + dn |= n << 52 + if n = uint64(enc.decodeMap[src[2]]); n == 0xff { + return false + } + dn |= n << 46 + if n = uint64(enc.decodeMap[src[3]]); n == 0xff { + return false + } + dn |= n << 40 + if n = uint64(enc.decodeMap[src[4]]); n == 0xff { + return false + } + dn |= n << 34 + if n = uint64(enc.decodeMap[src[5]]); n == 0xff { + return false + } + dn |= n << 28 + if n = uint64(enc.decodeMap[src[6]]); n == 0xff { + return false + } + dn |= n << 22 + if n = uint64(enc.decodeMap[src[7]]); n == 0xff { + return false + } + dn |= n << 16 + + binary.BigEndian.PutUint64(dst, dn) + return true +} + type newlineFilteringReader struct { wrapped io.Reader } diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go index 05011fbdf38..9f5c493dbfe 100644 --- a/libgo/go/encoding/base64/base64_test.go +++ b/libgo/go/encoding/base64/base64_test.go @@ -152,12 +152,9 @@ func TestDecode(t *testing.T) { for _, tt := range encodingTests { encoded := tt.conv(p.encoded) dbuf := make([]byte, tt.enc.DecodedLen(len(encoded))) - count, end, err := tt.enc.decode(dbuf, []byte(encoded)) + count, err := tt.enc.Decode(dbuf, []byte(encoded)) testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil)) testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded)) - if len(encoded) > 0 { - testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0) - } testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded) dbuf, err = tt.enc.DecodeString(encoded) diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go index 0547bee4370..af402575e45 100644 --- a/libgo/go/encoding/binary/binary_test.go +++ b/libgo/go/encoding/binary/binary_test.go @@ -109,6 +109,7 @@ var little = []byte{ var src = []byte{1, 2, 3, 4, 5, 6, 7, 8} var res = []int32{0x01020304, 0x05060708} +var putbuf = []byte{0, 0, 0, 0, 0, 0, 0, 0} func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) { if err != nil { @@ -502,25 +503,42 @@ func BenchmarkWriteSlice1000Int32s(b *testing.B) { } func BenchmarkPutUint16(b *testing.B) { - buf := [2]byte{} b.SetBytes(2) for i := 0; i < b.N; i++ { - BigEndian.PutUint16(buf[:], uint16(i)) + BigEndian.PutUint16(putbuf[:], uint16(i)) } } func BenchmarkPutUint32(b *testing.B) { - buf := [4]byte{} b.SetBytes(4) for i := 0; i < b.N; i++ { - BigEndian.PutUint32(buf[:], uint32(i)) + BigEndian.PutUint32(putbuf[:], uint32(i)) } } func BenchmarkPutUint64(b *testing.B) { - buf := [8]byte{} b.SetBytes(8) for i := 0; i < b.N; i++ { - BigEndian.PutUint64(buf[:], uint64(i)) + BigEndian.PutUint64(putbuf[:], uint64(i)) + } +} +func BenchmarkLittleEndianPutUint16(b *testing.B) { + b.SetBytes(2) + for i := 0; i < b.N; i++ { + LittleEndian.PutUint16(putbuf[:], uint16(i)) + } +} + +func BenchmarkLittleEndianPutUint32(b *testing.B) { + b.SetBytes(4) + for i := 0; i < b.N; i++ { + LittleEndian.PutUint32(putbuf[:], uint32(i)) + } +} + +func BenchmarkLittleEndianPutUint64(b *testing.B) { + b.SetBytes(8) + for i := 0; i < b.N; i++ { + LittleEndian.PutUint64(putbuf[:], uint64(i)) } } diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go index a3497c84f96..2efc7ad0943 100644 --- a/libgo/go/encoding/csv/reader.go +++ b/libgo/go/encoding/csv/reader.go @@ -58,44 +58,67 @@ import ( "fmt" "io" "unicode" + "unicode/utf8" ) // A ParseError is returned for parsing errors. -// The first line is 1. The first column is 0. +// Line numbers are 1-indexed and columns are 0-indexed. type ParseError struct { - Line int // Line where the error occurred - Column int // Column (rune index) where the error occurred - Err error // The actual error + StartLine int // Line where the record starts + Line int // Line where the error occurred + Column int // Column (rune index) where the error occurred + Err error // The actual error } func (e *ParseError) Error() string { - return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Err) + if e.Err == ErrFieldCount { + return fmt.Sprintf("record on line %d: %v", e.Line, e.Err) + } + if e.StartLine != e.Line { + return fmt.Sprintf("record on line %d; parse error on line %d, column %d: %v", e.StartLine, e.Line, e.Column, e.Err) + } + return fmt.Sprintf("parse error on line %d, column %d: %v", e.Line, e.Column, e.Err) } -// These are the errors that can be returned in ParseError.Error +// These are the errors that can be returned in ParseError.Err. var ( - ErrTrailingComma = errors.New("extra delimiter at end of line") // no longer used + ErrTrailingComma = errors.New("extra delimiter at end of line") // Deprecated: No longer used. ErrBareQuote = errors.New("bare \" in non-quoted-field") - ErrQuote = errors.New("extraneous \" in field") - ErrFieldCount = errors.New("wrong number of fields in line") + ErrQuote = errors.New("extraneous or missing \" in quoted-field") + ErrFieldCount = errors.New("wrong number of fields") ) +var errInvalidDelim = errors.New("csv: invalid field or comment delimiter") + +func validDelim(r rune) bool { + return r != 0 && r != '\r' && r != '\n' && utf8.ValidRune(r) && r != utf8.RuneError +} + // A Reader reads records from a CSV-encoded file. // // As returned by NewReader, a Reader expects input conforming to RFC 4180. // The exported fields can be changed to customize the details before the // first call to Read or ReadAll. // -// +// The Reader converts all \r\n sequences in its input to plain \n, +// including in multiline field values, so that the returned data does +// not depend on which line-ending convention an input file uses. type Reader struct { // Comma is the field delimiter. // It is set to comma (',') by NewReader. + // Comma must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). Comma rune + // Comment, if not 0, is the comment character. Lines beginning with the // Comment character without preceding whitespace are ignored. // With leading whitespace the Comment character becomes part of the // field, even if TrimLeadingSpace is true. + // Comment must be a valid rune and must not be \r, \n, + // or the Unicode replacement character (0xFFFD). + // It must also not be equal to Comma. Comment rune + // FieldsPerRecord is the number of expected fields per record. // If FieldsPerRecord is positive, Read requires each record to // have the given number of fields. If FieldsPerRecord is 0, Read sets it to @@ -103,31 +126,41 @@ type Reader struct { // have the same field count. If FieldsPerRecord is negative, no check is // made and records may have a variable number of fields. FieldsPerRecord int + // If LazyQuotes is true, a quote may appear in an unquoted field and a // non-doubled quote may appear in a quoted field. - LazyQuotes bool - TrailingComma bool // ignored; here for backwards compatibility + LazyQuotes bool + // If TrimLeadingSpace is true, leading white space in a field is ignored. // This is done even if the field delimiter, Comma, is white space. TrimLeadingSpace bool + // ReuseRecord controls whether calls to Read may return a slice sharing // the backing array of the previous call's returned slice for performance. // By default, each call to Read returns newly allocated memory owned by the caller. ReuseRecord bool - line int - column int - r *bufio.Reader - // lineBuffer holds the unescaped fields read by readField, one after another. + TrailingComma bool // Deprecated: No longer used. + + r *bufio.Reader + + // numLine is the current line being read in the CSV file. + numLine int + + // rawBuffer is a line buffer only used by the readLine method. + rawBuffer []byte + + // recordBuffer holds the unescaped fields, one after another. // The fields can be accessed by using the indexes in fieldIndexes. - // Example: for the row `a,"b","c""d",e` lineBuffer will contain `abc"de` and - // fieldIndexes will contain the indexes 0, 1, 2, 5. - lineBuffer bytes.Buffer - // Indexes of fields inside lineBuffer - // The i'th field starts at offset fieldIndexes[i] in lineBuffer. + // E.g., For the row `a,"b","c""d",e`, recordBuffer will contain `abc"de` + // and fieldIndexes will contain the indexes [1, 2, 5, 6]. + recordBuffer []byte + + // fieldIndexes is an index of fields inside recordBuffer. + // The i'th field ends at offset fieldIndexes[i] in recordBuffer. fieldIndexes []int - // only used when ReuseRecord == true + // lastRecord is a record cache and only used when ReuseRecord == true. lastRecord []string } @@ -139,15 +172,6 @@ func NewReader(r io.Reader) *Reader { } } -// error creates a new ParseError based on err. -func (r *Reader) error(err error) error { - return &ParseError{ - Line: r.line, - Column: r.column, - Err: err, - } -} - // Read reads one record (a slice of fields) from r. // If the record has an unexpected number of fields, // Read returns the record along with the error ErrFieldCount. @@ -163,7 +187,6 @@ func (r *Reader) Read() (record []string, err error) { } else { record, err = r.readRecord(nil) } - return record, err } @@ -185,226 +208,192 @@ func (r *Reader) ReadAll() (records [][]string, err error) { } } -// readRecord reads and parses a single csv record from r. -// Unlike parseRecord, readRecord handles FieldsPerRecord. -// If dst has enough capacity it will be used for the returned record. -func (r *Reader) readRecord(dst []string) (record []string, err error) { - for { - record, err = r.parseRecord(dst) - if record != nil { - break - } - if err != nil { - return nil, err +// readLine reads the next line (with the trailing endline). +// If EOF is hit without a trailing endline, it will be omitted. +// If some bytes were read, then the error is never io.EOF. +// The result is only valid until the next call to readLine. +func (r *Reader) readLine() ([]byte, error) { + line, err := r.r.ReadSlice('\n') + if err == bufio.ErrBufferFull { + r.rawBuffer = append(r.rawBuffer[:0], line...) + for err == bufio.ErrBufferFull { + line, err = r.r.ReadSlice('\n') + r.rawBuffer = append(r.rawBuffer, line...) } + line = r.rawBuffer } - - if r.FieldsPerRecord > 0 { - if len(record) != r.FieldsPerRecord { - r.column = 0 // report at start of record - return record, r.error(ErrFieldCount) + if len(line) > 0 && err == io.EOF { + err = nil + // For backwards compatibility, drop trailing \r before EOF. + if line[len(line)-1] == '\r' { + line = line[:len(line)-1] } - } else if r.FieldsPerRecord == 0 { - r.FieldsPerRecord = len(record) } - return record, nil -} - -// readRune reads one rune from r, folding \r\n to \n and keeping track -// of how far into the line we have read. r.column will point to the start -// of this rune, not the end of this rune. -func (r *Reader) readRune() (rune, error) { - r1, _, err := r.r.ReadRune() - - // Handle \r\n here. We make the simplifying assumption that - // anytime \r is followed by \n that it can be folded to \n. - // We will not detect files which contain both \r\n and bare \n. - if r1 == '\r' { - r1, _, err = r.r.ReadRune() - if err == nil { - if r1 != '\n' { - r.r.UnreadRune() - r1 = '\r' - } - } + r.numLine++ + // Normalize \r\n to \n on all input lines. + if n := len(line); n >= 2 && line[n-2] == '\r' && line[n-1] == '\n' { + line[n-2] = '\n' + line = line[:n-1] } - r.column++ - return r1, err + return line, err } -// skip reads runes up to and including the rune delim or until error. -func (r *Reader) skip(delim rune) error { - for { - r1, err := r.readRune() - if err != nil { - return err - } - if r1 == delim { - return nil - } +// lengthNL reports the number of bytes for the trailing \n. +func lengthNL(b []byte) int { + if len(b) > 0 && b[len(b)-1] == '\n' { + return 1 } + return 0 } -// parseRecord reads and parses a single csv record from r. -// If dst has enough capacity it will be used for the returned fields. -func (r *Reader) parseRecord(dst []string) (fields []string, err error) { - // Each record starts on a new line. We increment our line - // number (lines start at 1, not 0) and set column to -1 - // so as we increment in readRune it points to the character we read. - r.line++ - r.column = -1 - - // Peek at the first rune. If it is an error we are done. - // If we support comments and it is the comment character - // then skip to the end of line. - - r1, _, err := r.r.ReadRune() - if err != nil { - return nil, err - } +// nextRune returns the next rune in b or utf8.RuneError. +func nextRune(b []byte) rune { + r, _ := utf8.DecodeRune(b) + return r +} - if r.Comment != 0 && r1 == r.Comment { - return nil, r.skip('\n') +func (r *Reader) readRecord(dst []string) ([]string, error) { + if r.Comma == r.Comment || !validDelim(r.Comma) || (r.Comment != 0 && !validDelim(r.Comment)) { + return nil, errInvalidDelim } - r.r.UnreadRune() - - r.lineBuffer.Reset() - r.fieldIndexes = r.fieldIndexes[:0] - - // At this point we have at least one field. - for { - idx := r.lineBuffer.Len() - - haveField, delim, err := r.parseField() - if haveField { - r.fieldIndexes = append(r.fieldIndexes, idx) - } - if delim == '\n' || err == io.EOF { - if len(r.fieldIndexes) == 0 { - return nil, err - } - break + // Read line (automatically skipping past empty lines and any comments). + var line, fullLine []byte + var errRead error + for errRead == nil { + line, errRead = r.readLine() + if r.Comment != 0 && nextRune(line) == r.Comment { + line = nil + continue // Skip comment lines } - - if err != nil { - return nil, err + if errRead == nil && len(line) == lengthNL(line) { + line = nil + continue // Skip empty lines } + fullLine = line + break } - - fieldCount := len(r.fieldIndexes) - // Using this approach (creating a single string and taking slices of it) - // means that a single reference to any of the fields will retain the whole - // string. The risk of a nontrivial space leak caused by this is considered - // minimal and a tradeoff for better performance through the combined - // allocations. - line := r.lineBuffer.String() - - if cap(dst) >= fieldCount { - fields = dst[:fieldCount] - } else { - fields = make([]string, fieldCount) + if errRead == io.EOF { + return nil, errRead } - for i, idx := range r.fieldIndexes { - if i == fieldCount-1 { - fields[i] = line[idx:] - } else { - fields[i] = line[idx:r.fieldIndexes[i+1]] - } - } - - return fields, nil -} - -// parseField parses the next field in the record. The read field is -// appended to r.lineBuffer. Delim is the first character not part of the field -// (r.Comma or '\n'). -func (r *Reader) parseField() (haveField bool, delim rune, err error) { - r1, err := r.readRune() - for err == nil && r.TrimLeadingSpace && r1 != '\n' && unicode.IsSpace(r1) { - r1, err = r.readRune() - } - - if err == io.EOF && r.column != 0 { - return true, 0, err - } - if err != nil { - return false, 0, err - } - - switch r1 { - case r.Comma: - // will check below - - case '\n': - // We are a trailing empty field or a blank line - if r.column == 0 { - return false, r1, nil + // Parse each field in the record. + var err error + const quoteLen = len(`"`) + commaLen := utf8.RuneLen(r.Comma) + recLine := r.numLine // Starting line for record + r.recordBuffer = r.recordBuffer[:0] + r.fieldIndexes = r.fieldIndexes[:0] +parseField: + for { + if r.TrimLeadingSpace { + line = bytes.TrimLeftFunc(line, unicode.IsSpace) } - return true, r1, nil - - case '"': - // quoted field - Quoted: - for { - r1, err = r.readRune() - if err != nil { - if err == io.EOF { - if r.LazyQuotes { - return true, 0, err - } - return false, 0, r.error(ErrQuote) - } - return false, 0, err + if len(line) == 0 || line[0] != '"' { + // Non-quoted string field + i := bytes.IndexRune(line, r.Comma) + field := line + if i >= 0 { + field = field[:i] + } else { + field = field[:len(field)-lengthNL(field)] } - switch r1 { - case '"': - r1, err = r.readRune() - if err != nil || r1 == r.Comma { - break Quoted + // Check to make sure a quote does not appear in field. + if !r.LazyQuotes { + if j := bytes.IndexByte(field, '"'); j >= 0 { + col := utf8.RuneCount(fullLine[:len(fullLine)-len(line[j:])]) + err = &ParseError{StartLine: recLine, Line: r.numLine, Column: col, Err: ErrBareQuote} + break parseField } - if r1 == '\n' { - return true, r1, nil - } - if r1 != '"' { - if !r.LazyQuotes { - r.column-- - return false, 0, r.error(ErrQuote) + } + r.recordBuffer = append(r.recordBuffer, field...) + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + if i >= 0 { + line = line[i+commaLen:] + continue parseField + } + break parseField + } else { + // Quoted string field + line = line[quoteLen:] + for { + i := bytes.IndexByte(line, '"') + if i >= 0 { + // Hit next quote. + r.recordBuffer = append(r.recordBuffer, line[:i]...) + line = line[i+quoteLen:] + switch rn := nextRune(line); { + case rn == '"': + // `""` sequence (append quote). + r.recordBuffer = append(r.recordBuffer, '"') + line = line[quoteLen:] + case rn == r.Comma: + // `",` sequence (end of field). + line = line[commaLen:] + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + continue parseField + case lengthNL(line) == len(line): + // `"\n` sequence (end of line). + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + break parseField + case r.LazyQuotes: + // `"` sequence (bare quote). + r.recordBuffer = append(r.recordBuffer, '"') + default: + // `"*` sequence (invalid non-escaped quote). + col := utf8.RuneCount(fullLine[:len(fullLine)-len(line)-quoteLen]) + err = &ParseError{StartLine: recLine, Line: r.numLine, Column: col, Err: ErrQuote} + break parseField + } + } else if len(line) > 0 { + // Hit end of line (copy all data so far). + r.recordBuffer = append(r.recordBuffer, line...) + if errRead != nil { + break parseField + } + line, errRead = r.readLine() + if errRead == io.EOF { + errRead = nil } - // accept the bare quote - r.lineBuffer.WriteRune('"') + fullLine = line + } else { + // Abrupt end of file (EOF or error). + if !r.LazyQuotes && errRead == nil { + col := utf8.RuneCount(fullLine) + err = &ParseError{StartLine: recLine, Line: r.numLine, Column: col, Err: ErrQuote} + break parseField + } + r.fieldIndexes = append(r.fieldIndexes, len(r.recordBuffer)) + break parseField } - case '\n': - r.line++ - r.column = -1 } - r.lineBuffer.WriteRune(r1) } + } + if err == nil { + err = errRead + } - default: - // unquoted field - for { - r.lineBuffer.WriteRune(r1) - r1, err = r.readRune() - if err != nil || r1 == r.Comma { - break - } - if r1 == '\n' { - return true, r1, nil - } - if !r.LazyQuotes && r1 == '"' { - return false, 0, r.error(ErrBareQuote) - } - } + // Create a single string and create slices out of it. + // This pins the memory of the fields together, but allocates once. + str := string(r.recordBuffer) // Convert to string once to batch allocations + dst = dst[:0] + if cap(dst) < len(r.fieldIndexes) { + dst = make([]string, len(r.fieldIndexes)) + } + dst = dst[:len(r.fieldIndexes)] + var preIdx int + for i, idx := range r.fieldIndexes { + dst[i] = str[preIdx:idx] + preIdx = idx } - if err != nil { - if err == io.EOF { - return true, 0, err + // Check or update the expected fields per record. + if r.FieldsPerRecord > 0 { + if len(dst) != r.FieldsPerRecord && err == nil { + err = &ParseError{StartLine: recLine, Line: recLine, Err: ErrFieldCount} } - return false, 0, err + } else if r.FieldsPerRecord == 0 { + r.FieldsPerRecord = len(dst) } - - return true, r1, nil + return dst, err } diff --git a/libgo/go/encoding/csv/reader_test.go b/libgo/go/encoding/csv/reader_test.go index 5ab1b61256c..1fc69f9ab88 100644 --- a/libgo/go/encoding/csv/reader_test.go +++ b/libgo/go/encoding/csv/reader_test.go @@ -9,45 +9,38 @@ import ( "reflect" "strings" "testing" + "unicode/utf8" ) -var readTests = []struct { - Name string - Input string - Output [][]string - UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1 - - // These fields are copied into the Reader - Comma rune - Comment rune - FieldsPerRecord int - LazyQuotes bool - TrailingComma bool - TrimLeadingSpace bool - ReuseRecord bool +func TestRead(t *testing.T) { + tests := []struct { + Name string + Input string + Output [][]string + Error error - Error string - Line int // Expected error line if != 0 - Column int // Expected error column if line != 0 -}{ - { + // These fields are copied into the Reader + Comma rune + Comment rune + UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1 + FieldsPerRecord int + LazyQuotes bool + TrimLeadingSpace bool + ReuseRecord bool + }{{ Name: "Simple", Input: "a,b,c\n", Output: [][]string{{"a", "b", "c"}}, - }, - { + }, { Name: "CRLF", Input: "a,b\r\nc,d\r\n", Output: [][]string{{"a", "b"}, {"c", "d"}}, - }, - { + }, { Name: "BareCR", Input: "a,b\rc,d\r\n", Output: [][]string{{"a", "b\rc", "d"}}, - }, - { - Name: "RFC4180test", - UseFieldsPerRecord: true, + }, { + Name: "RFC4180test", Input: `#field1,field2,field3 "aaa","bb b","ccc" @@ -60,163 +53,139 @@ zzz,yyy,xxx {"a,a", `b"bb`, "ccc"}, {"zzz", "yyy", "xxx"}, }, - }, - { + UseFieldsPerRecord: true, + FieldsPerRecord: 0, + }, { Name: "NoEOLTest", Input: "a,b,c", Output: [][]string{{"a", "b", "c"}}, - }, - { + }, { Name: "Semicolon", - Comma: ';', Input: "a;b;c\n", Output: [][]string{{"a", "b", "c"}}, - }, - { + Comma: ';', + }, { Name: "MultiLine", Input: `"two line","one line","three line field"`, Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}}, - }, - { + }, { Name: "BlankLine", Input: "a,b,c\n\nd,e,f\n\n", Output: [][]string{ {"a", "b", "c"}, {"d", "e", "f"}, }, - }, - { - Name: "BlankLineFieldCount", - Input: "a,b,c\n\nd,e,f\n\n", - UseFieldsPerRecord: true, + }, { + Name: "BlankLineFieldCount", + Input: "a,b,c\n\nd,e,f\n\n", Output: [][]string{ {"a", "b", "c"}, {"d", "e", "f"}, }, - }, - { + UseFieldsPerRecord: true, + FieldsPerRecord: 0, + }, { Name: "TrimSpace", Input: " a, b, c\n", - TrimLeadingSpace: true, Output: [][]string{{"a", "b", "c"}}, - }, - { + TrimLeadingSpace: true, + }, { Name: "LeadingSpace", Input: " a, b, c\n", Output: [][]string{{" a", " b", " c"}}, - }, - { + }, { Name: "Comment", - Comment: '#', Input: "#1,2,3\na,b,c\n#comment", Output: [][]string{{"a", "b", "c"}}, - }, - { + Comment: '#', + }, { Name: "NoComment", Input: "#1,2,3\na,b,c", Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}}, - }, - { + }, { Name: "LazyQuotes", - LazyQuotes: true, Input: `a "word","1"2",a","b`, Output: [][]string{{`a "word"`, `1"2`, `a"`, `b`}}, - }, - { - Name: "BareQuotes", LazyQuotes: true, + }, { + Name: "BareQuotes", Input: `a "word","1"2",a"`, Output: [][]string{{`a "word"`, `1"2`, `a"`}}, - }, - { - Name: "BareDoubleQuotes", LazyQuotes: true, + }, { + Name: "BareDoubleQuotes", Input: `a""b,c`, Output: [][]string{{`a""b`, `c`}}, - }, - { + LazyQuotes: true, + }, { Name: "BadDoubleQuotes", Input: `a""b,c`, - Error: `bare " in non-quoted-field`, Line: 1, Column: 1, - }, - { + Error: &ParseError{StartLine: 1, Line: 1, Column: 1, Err: ErrBareQuote}, + }, { Name: "TrimQuote", Input: ` "a"," b",c`, - TrimLeadingSpace: true, Output: [][]string{{"a", " b", "c"}}, - }, - { + TrimLeadingSpace: true, + }, { Name: "BadBareQuote", Input: `a "word","b"`, - Error: `bare " in non-quoted-field`, Line: 1, Column: 2, - }, - { + Error: &ParseError{StartLine: 1, Line: 1, Column: 2, Err: ErrBareQuote}, + }, { Name: "BadTrailingQuote", Input: `"a word",b"`, - Error: `bare " in non-quoted-field`, Line: 1, Column: 10, - }, - { + Error: &ParseError{StartLine: 1, Line: 1, Column: 10, Err: ErrBareQuote}, + }, { Name: "ExtraneousQuote", Input: `"a "word","b"`, - Error: `extraneous " in field`, Line: 1, Column: 3, - }, - { + Error: &ParseError{StartLine: 1, Line: 1, Column: 3, Err: ErrQuote}, + }, { Name: "BadFieldCount", - UseFieldsPerRecord: true, Input: "a,b,c\nd,e", - Error: "wrong number of fields", Line: 2, - }, - { + Error: &ParseError{StartLine: 2, Line: 2, Err: ErrFieldCount}, + UseFieldsPerRecord: true, + FieldsPerRecord: 0, + }, { Name: "BadFieldCount1", + Input: `a,b,c`, + Error: &ParseError{StartLine: 1, Line: 1, Err: ErrFieldCount}, UseFieldsPerRecord: true, FieldsPerRecord: 2, - Input: `a,b,c`, - Error: "wrong number of fields", Line: 1, - }, - { + }, { Name: "FieldCount", Input: "a,b,c\nd,e", Output: [][]string{{"a", "b", "c"}, {"d", "e"}}, - }, - { + }, { Name: "TrailingCommaEOF", Input: "a,b,c,", Output: [][]string{{"a", "b", "c", ""}}, - }, - { + }, { Name: "TrailingCommaEOL", Input: "a,b,c,\n", Output: [][]string{{"a", "b", "c", ""}}, - }, - { + }, { Name: "TrailingCommaSpaceEOF", - TrimLeadingSpace: true, Input: "a,b,c, ", Output: [][]string{{"a", "b", "c", ""}}, - }, - { - Name: "TrailingCommaSpaceEOL", TrimLeadingSpace: true, + }, { + Name: "TrailingCommaSpaceEOL", Input: "a,b,c, \n", Output: [][]string{{"a", "b", "c", ""}}, - }, - { - Name: "TrailingCommaLine3", TrimLeadingSpace: true, + }, { + Name: "TrailingCommaLine3", Input: "a,b,c\nd,e,f\ng,hi,", Output: [][]string{{"a", "b", "c"}, {"d", "e", "f"}, {"g", "hi", ""}}, - }, - { + TrimLeadingSpace: true, + }, { Name: "NotTrailingComma3", Input: "a,b,c, \n", Output: [][]string{{"a", "b", "c", " "}}, - }, - { - Name: "CommaFieldTest", - TrailingComma: true, + }, { + Name: "CommaFieldTest", Input: `x,y,z,w x,y,z, x,y,, @@ -240,67 +209,201 @@ x,,, {"x", "", "", ""}, {"", "", "", ""}, }, - }, - { - Name: "TrailingCommaIneffective1", - TrailingComma: true, - TrimLeadingSpace: true, - Input: "a,b,\nc,d,e", + }, { + Name: "TrailingCommaIneffective1", + Input: "a,b,\nc,d,e", Output: [][]string{ {"a", "b", ""}, {"c", "d", "e"}, }, - }, - { - Name: "TrailingCommaIneffective2", - TrailingComma: false, TrimLeadingSpace: true, - Input: "a,b,\nc,d,e", + }, { + Name: "ReadAllReuseRecord", + Input: "a,b\nc,d", Output: [][]string{ - {"a", "b", ""}, - {"c", "d", "e"}, + {"a", "b"}, + {"c", "d"}, }, - }, - { - Name: "ReadAllReuseRecord", ReuseRecord: true, - Input: "a,b\nc,d", + }, { + Name: "StartLine1", // Issue 19019 + Input: "a,\"b\nc\"d,e", + Error: &ParseError{StartLine: 1, Line: 2, Column: 1, Err: ErrQuote}, + }, { + Name: "StartLine2", + Input: "a,b\n\"d\n\n,e", + Error: &ParseError{StartLine: 2, Line: 5, Column: 0, Err: ErrQuote}, + }, { + Name: "CRLFInQuotedField", // Issue 21201 + Input: "A,\"Hello\r\nHi\",B\r\n", Output: [][]string{ - {"a", "b"}, - {"c", "d"}, + {"A", "Hello\nHi", "B"}, }, - }, -} + }, { + Name: "BinaryBlobField", // Issue 19410 + Input: "x09\x41\xb4\x1c,aktau", + Output: [][]string{{"x09A\xb4\x1c", "aktau"}}, + }, { + Name: "TrailingCR", + Input: "field1,field2\r", + Output: [][]string{{"field1", "field2"}}, + }, { + Name: "QuotedTrailingCR", + Input: "\"field\"\r", + Output: [][]string{{"field"}}, + }, { + Name: "QuotedTrailingCRCR", + Input: "\"field\"\r\r", + Error: &ParseError{StartLine: 1, Line: 1, Column: 6, Err: ErrQuote}, + }, { + Name: "FieldCR", + Input: "field\rfield\r", + Output: [][]string{{"field\rfield"}}, + }, { + Name: "FieldCRCR", + Input: "field\r\rfield\r\r", + Output: [][]string{{"field\r\rfield\r"}}, + }, { + Name: "FieldCRCRLF", + Input: "field\r\r\nfield\r\r\n", + Output: [][]string{{"field\r"}, {"field\r"}}, + }, { + Name: "FieldCRCRLFCR", + Input: "field\r\r\n\rfield\r\r\n\r", + Output: [][]string{{"field\r"}, {"\rfield\r"}}, + }, { + Name: "FieldCRCRLFCRCR", + Input: "field\r\r\n\r\rfield\r\r\n\r\r", + Output: [][]string{{"field\r"}, {"\r\rfield\r"}, {"\r"}}, + }, { + Name: "MultiFieldCRCRLFCRCR", + Input: "field1,field2\r\r\n\r\rfield1,field2\r\r\n\r\r,", + Output: [][]string{ + {"field1", "field2\r"}, + {"\r\rfield1", "field2\r"}, + {"\r\r", ""}, + }, + }, { + Name: "NonASCIICommaAndComment", + Input: "a£b,c£ \td,e\n€ comment\n", + Output: [][]string{{"a", "b,c", "d,e"}}, + TrimLeadingSpace: true, + Comma: '£', + Comment: '€', + }, { + Name: "NonASCIICommaAndCommentWithQuotes", + Input: "a€\" b,\"€ c\nλ comment\n", + Output: [][]string{{"a", " b,", " c"}}, + Comma: '€', + Comment: 'λ', + }, { + // λ and θ start with the same byte. + // This tests that the parser doesn't confuse such characters. + Name: "NonASCIICommaConfusion", + Input: "\"abθcd\"λefθgh", + Output: [][]string{{"abθcd", "efθgh"}}, + Comma: 'λ', + Comment: '€', + }, { + Name: "NonASCIICommentConfusion", + Input: "λ\nλ\nθ\nλ\n", + Output: [][]string{{"λ"}, {"λ"}, {"λ"}}, + Comment: 'θ', + }, { + Name: "QuotedFieldMultipleLF", + Input: "\"\n\n\n\n\"", + Output: [][]string{{"\n\n\n\n"}}, + }, { + Name: "MultipleCRLF", + Input: "\r\n\r\n\r\n\r\n", + }, { + // The implementation may read each line in several chunks if it doesn't fit entirely + // in the read buffer, so we should test the code to handle that condition. + Name: "HugeLines", + Input: strings.Repeat("#ignore\n", 10000) + strings.Repeat("@", 5000) + "," + strings.Repeat("*", 5000), + Output: [][]string{{strings.Repeat("@", 5000), strings.Repeat("*", 5000)}}, + Comment: '#', + }, { + Name: "QuoteWithTrailingCRLF", + Input: "\"foo\"bar\"\r\n", + Error: &ParseError{StartLine: 1, Line: 1, Column: 4, Err: ErrQuote}, + }, { + Name: "LazyQuoteWithTrailingCRLF", + Input: "\"foo\"bar\"\r\n", + Output: [][]string{{`foo"bar`}}, + LazyQuotes: true, + }, { + Name: "DoubleQuoteWithTrailingCRLF", + Input: "\"foo\"\"bar\"\r\n", + Output: [][]string{{`foo"bar`}}, + }, { + Name: "EvenQuotes", + Input: `""""""""`, + Output: [][]string{{`"""`}}, + }, { + Name: "OddQuotes", + Input: `"""""""`, + Error: &ParseError{StartLine: 1, Line: 1, Column: 7, Err: ErrQuote}, + }, { + Name: "LazyOddQuotes", + Input: `"""""""`, + Output: [][]string{{`"""`}}, + LazyQuotes: true, + }, { + Name: "BadComma1", + Comma: '\n', + Error: errInvalidDelim, + }, { + Name: "BadComma2", + Comma: '\r', + Error: errInvalidDelim, + }, { + Name: "BadComma3", + Comma: utf8.RuneError, + Error: errInvalidDelim, + }, { + Name: "BadComment1", + Comment: '\n', + Error: errInvalidDelim, + }, { + Name: "BadComment2", + Comment: '\r', + Error: errInvalidDelim, + }, { + Name: "BadComment3", + Comment: utf8.RuneError, + Error: errInvalidDelim, + }, { + Name: "BadCommaComment", + Comma: 'X', + Comment: 'X', + Error: errInvalidDelim, + }} -func TestRead(t *testing.T) { - for _, tt := range readTests { - r := NewReader(strings.NewReader(tt.Input)) - r.Comment = tt.Comment - if tt.UseFieldsPerRecord { - r.FieldsPerRecord = tt.FieldsPerRecord - } else { - r.FieldsPerRecord = -1 - } - r.LazyQuotes = tt.LazyQuotes - r.TrailingComma = tt.TrailingComma - r.TrimLeadingSpace = tt.TrimLeadingSpace - r.ReuseRecord = tt.ReuseRecord - if tt.Comma != 0 { - r.Comma = tt.Comma - } - out, err := r.ReadAll() - perr, _ := err.(*ParseError) - if tt.Error != "" { - if err == nil || !strings.Contains(err.Error(), tt.Error) { - t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error) - } else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) { - t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column) + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + r := NewReader(strings.NewReader(tt.Input)) + + if tt.Comma != 0 { + r.Comma = tt.Comma } - } else if err != nil { - t.Errorf("%s: unexpected error %v", tt.Name, err) - } else if !reflect.DeepEqual(out, tt.Output) { - t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output) - } + r.Comment = tt.Comment + if tt.UseFieldsPerRecord { + r.FieldsPerRecord = tt.FieldsPerRecord + } else { + r.FieldsPerRecord = -1 + } + r.LazyQuotes = tt.LazyQuotes + r.TrimLeadingSpace = tt.TrimLeadingSpace + r.ReuseRecord = tt.ReuseRecord + + out, err := r.ReadAll() + if !reflect.DeepEqual(err, tt.Error) { + t.Errorf("ReadAll() error:\ngot %v\nwant %v", err, tt.Error) + } else if !reflect.DeepEqual(out, tt.Output) { + t.Errorf("ReadAll() output:\ngot %q\nwant %q", out, tt.Output) + } + }) } } diff --git a/libgo/go/encoding/csv/writer.go b/libgo/go/encoding/csv/writer.go index 84b7aa1ed10..ef3594e523c 100644 --- a/libgo/go/encoding/csv/writer.go +++ b/libgo/go/encoding/csv/writer.go @@ -20,7 +20,7 @@ import ( // // Comma is the field delimiter. // -// If UseCRLF is true, the Writer ends each record with \r\n instead of \n. +// If UseCRLF is true, the Writer ends each output line with \r\n instead of \n. type Writer struct { Comma rune // Field delimiter (set to ',' by NewWriter) UseCRLF bool // True to use \r\n as the line terminator @@ -38,6 +38,10 @@ func NewWriter(w io.Writer) *Writer { // Writer writes a single CSV record to w along with any necessary quoting. // A record is a slice of strings with each string being one field. func (w *Writer) Write(record []string) error { + if !validDelim(w.Comma) { + return errInvalidDelim + } + for n, field := range record { if n > 0 { if _, err := w.w.WriteRune(w.Comma); err != nil { diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go index eb9f306bcf5..8f7b6f3c62e 100644 --- a/libgo/go/encoding/gob/codec_test.go +++ b/libgo/go/encoding/gob/codec_test.go @@ -1321,6 +1321,7 @@ func TestUnexportedFields(t *testing.T) { var singletons = []interface{}{ true, 7, + uint(10), 3.2, "hello", [3]int{11, 22, 33}, diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go index d69d36f5164..8f93742f499 100644 --- a/libgo/go/encoding/gob/debug.go +++ b/libgo/go/encoding/gob/debug.go @@ -594,7 +594,7 @@ func (deb *debugger) printBuiltin(indent tab, id typeId) { x := deb.int64() fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) case tUint: - x := deb.int64() + x := deb.uint64() fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) case tFloat: x := deb.uint64() diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go index 8e0b1dd3750..5ef03888621 100644 --- a/libgo/go/encoding/gob/decoder.go +++ b/libgo/go/encoding/gob/decoder.go @@ -55,7 +55,7 @@ func NewDecoder(r io.Reader) *Decoder { // recvType loads the definition of a type. func (dec *Decoder) recvType(id typeId) { - // Have we already seen this type? That's an error + // Have we already seen this type? That's an error if id < firstUserId || dec.wireType[id] != nil { dec.err = errors.New("gob: duplicate type received") return @@ -99,10 +99,8 @@ func (dec *Decoder) readMessage(nbytes int) { // Read the data dec.buf.Size(nbytes) _, dec.err = io.ReadFull(dec.r, dec.buf.Bytes()) - if dec.err != nil { - if dec.err == io.EOF { - dec.err = io.ErrUnexpectedEOF - } + if dec.err == io.EOF { + dec.err = io.ErrUnexpectedEOF } } diff --git a/libgo/go/encoding/gob/doc.go b/libgo/go/encoding/gob/doc.go index db734ecc1ec..fa534313cc9 100644 --- a/libgo/go/encoding/gob/doc.go +++ b/libgo/go/encoding/gob/doc.go @@ -381,7 +381,7 @@ Now we can send the Point value. Again the field number resets to -1: 07 // this value is 7 bytes long ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1) 01 // add one to field number, yielding field 0 - 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22 + 2c // encoding of signed "22" (0x2c = 44 = 22<<1); Point.x = 22 01 // add one to field number, yielding field 1 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33 00 // end of structure diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go index 2768f1bac69..e4df6cbd4d1 100644 --- a/libgo/go/encoding/hex/hex.go +++ b/libgo/go/encoding/hex/hex.go @@ -31,7 +31,9 @@ func Encode(dst, src []byte) int { return len(src) * 2 } -// ErrLength results from decoding an odd length slice. +// ErrLength reports an attempt to decode an odd-length input +// using Decode or DecodeString. +// The stream-based Decoder returns io.ErrUnexpectedEOF instead of ErrLength. var ErrLength = errors.New("encoding/hex: odd length hex string") // InvalidByteError values describe errors resulting from an invalid byte in a hex string. @@ -50,24 +52,30 @@ func DecodedLen(x int) int { return x / 2 } // // Decode expects that src contain only hexadecimal // characters and that src should have an even length. +// If the input is malformed, Decode returns the number +// of bytes decoded before the error. func Decode(dst, src []byte) (int, error) { - if len(src)%2 == 1 { - return 0, ErrLength - } - - for i := 0; i < len(src)/2; i++ { + var i int + for i = 0; i < len(src)/2; i++ { a, ok := fromHexChar(src[i*2]) if !ok { - return 0, InvalidByteError(src[i*2]) + return i, InvalidByteError(src[i*2]) } b, ok := fromHexChar(src[i*2+1]) if !ok { - return 0, InvalidByteError(src[i*2+1]) + return i, InvalidByteError(src[i*2+1]) } dst[i] = (a << 4) | b } - - return len(src) / 2, nil + if len(src)%2 == 1 { + // Check for invalid char before reporting bad length, + // since the invalid char (if present) is an earlier problem. + if _, ok := fromHexChar(src[i*2]); !ok { + return i, InvalidByteError(src[i*2]) + } + return i, ErrLength + } + return i, nil } // fromHexChar converts a hex character into its value and a success flag. @@ -92,14 +100,17 @@ func EncodeToString(src []byte) string { } // DecodeString returns the bytes represented by the hexadecimal string s. +// +// DecodeString expects that src contain only hexadecimal +// characters and that src should have an even length. +// If the input is malformed, DecodeString returns a string +// containing the bytes decoded before the error. func DecodeString(s string) ([]byte, error) { src := []byte(s) - dst := make([]byte, DecodedLen(len(src))) - _, err := Decode(dst, src) - if err != nil { - return nil, err - } - return dst, nil + // We can use the source slice itself as the destination + // because the decode loop increments by one and then the 'seen' byte is not used anymore. + n, err := Decode(src, src) + return src[:n], err } // Dump returns a string that contains a hex dump of the given data. The format @@ -112,6 +123,81 @@ func Dump(data []byte) string { return buf.String() } +// bufferSize is the number of hexadecimal characters to buffer in encoder and decoder. +const bufferSize = 1024 + +type encoder struct { + w io.Writer + err error + out [bufferSize]byte // output buffer +} + +// NewEncoder returns an io.Writer that writes lowercase hexadecimal characters to w. +func NewEncoder(w io.Writer) io.Writer { + return &encoder{w: w} +} + +func (e *encoder) Write(p []byte) (n int, err error) { + for len(p) > 0 && e.err == nil { + chunkSize := bufferSize / 2 + if len(p) < chunkSize { + chunkSize = len(p) + } + + var written int + encoded := Encode(e.out[:], p[:chunkSize]) + written, e.err = e.w.Write(e.out[:encoded]) + n += written / 2 + p = p[chunkSize:] + } + return n, e.err +} + +type decoder struct { + r io.Reader + err error + in []byte // input buffer (encoded form) + arr [bufferSize]byte // backing array for in +} + +// NewDecoder returns an io.Reader that decodes hexadecimal characters from r. +// NewDecoder expects that r contain only an even number of hexadecimal characters. +func NewDecoder(r io.Reader) io.Reader { + return &decoder{r: r} +} + +func (d *decoder) Read(p []byte) (n int, err error) { + // Fill internal buffer with sufficient bytes to decode + if len(d.in) < 2 && d.err == nil { + var numCopy, numRead int + numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes + numRead, d.err = d.r.Read(d.arr[numCopy:]) + d.in = d.arr[:numCopy+numRead] + if d.err == io.EOF && len(d.in)%2 != 0 { + if _, ok := fromHexChar(d.in[len(d.in)-1]); !ok { + d.err = InvalidByteError(d.in[len(d.in)-1]) + } else { + d.err = io.ErrUnexpectedEOF + } + } + } + + // Decode internal buffer into output buffer + if numAvail := len(d.in) / 2; len(p) > numAvail { + p = p[:numAvail] + } + numDec, err := Decode(p, d.in[:len(p)*2]) + d.in = d.in[2*numDec:] + if err != nil { + d.in, d.err = nil, err // Decode error; discard input remainder + } + + if len(d.in) < 2 { + return numDec, d.err // Only expose errors when buffer fully consumed + } + return numDec, nil +} + // Dumper returns a WriteCloser that writes a hex dump of all written data to // w. The format of the dump matches the output of `hexdump -C` on the command // line. diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go index 64dabbd10a2..b6bab21c480 100644 --- a/libgo/go/encoding/hex/hex_test.go +++ b/libgo/go/encoding/hex/hex_test.go @@ -7,6 +7,9 @@ package hex import ( "bytes" "fmt" + "io" + "io/ioutil" + "strings" "testing" ) @@ -75,37 +78,86 @@ func TestDecodeString(t *testing.T) { } } -type errTest struct { +var errTests = []struct { in string - err string + out string + err error +}{ + {"", "", nil}, + {"0", "", ErrLength}, + {"zd4aa", "", InvalidByteError('z')}, + {"d4aaz", "\xd4\xaa", InvalidByteError('z')}, + {"30313", "01", ErrLength}, + {"0g", "", InvalidByteError('g')}, + {"00gg", "\x00", InvalidByteError('g')}, + {"0\x01", "", InvalidByteError('\x01')}, + {"ffeed", "\xff\xee", ErrLength}, } -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"}, +func TestDecodeErr(t *testing.T) { + for _, tt := range errTests { + out := make([]byte, len(tt.in)+10) + n, err := Decode(out, []byte(tt.in)) + if string(out[:n]) != tt.out || err != tt.err { + t.Errorf("Decode(%q) = %q, %v, want %q, %v", tt.in, string(out[:n]), err, tt.out, tt.err) + } + } } -func TestInvalidErr(t *testing.T) { - for i, test := range errTests { - dst := make([]byte, DecodedLen(len(test.in))) - _, err := Decode(dst, []byte(test.in)) - if err == nil { - t.Errorf("#%d: expected error; got none", i) - } else if err.Error() != test.err { - t.Errorf("#%d: got: %v want: %v", i, err, test.err) +func TestDecodeStringErr(t *testing.T) { + for _, tt := range errTests { + out, err := DecodeString(tt.in) + if string(out) != tt.out || err != tt.err { + t.Errorf("DecodeString(%q) = %q, %v, want %q, %v", tt.in, out, err, tt.out, tt.err) + } + } +} + +func TestEncoderDecoder(t *testing.T) { + for _, multiplier := range []int{1, 128, 192} { + for _, test := range encDecTests { + input := bytes.Repeat(test.dec, multiplier) + output := strings.Repeat(test.enc, multiplier) + + var buf bytes.Buffer + enc := NewEncoder(&buf) + r := struct{ io.Reader }{bytes.NewReader(input)} // io.Reader only; not io.WriterTo + if n, err := io.CopyBuffer(enc, r, make([]byte, 7)); n != int64(len(input)) || err != nil { + t.Errorf("encoder.Write(%q*%d) = (%d, %v), want (%d, nil)", test.dec, multiplier, n, err, len(input)) + continue + } + + if encDst := buf.String(); encDst != output { + t.Errorf("buf(%q*%d) = %v, want %v", test.dec, multiplier, encDst, output) + continue + } + + dec := NewDecoder(&buf) + var decBuf bytes.Buffer + w := struct{ io.Writer }{&decBuf} // io.Writer only; not io.ReaderFrom + if _, err := io.CopyBuffer(w, dec, make([]byte, 7)); err != nil || decBuf.Len() != len(input) { + t.Errorf("decoder.Read(%q*%d) = (%d, %v), want (%d, nil)", test.enc, multiplier, decBuf.Len(), err, len(input)) + } + + if !bytes.Equal(decBuf.Bytes(), input) { + t.Errorf("decBuf(%q*%d) = %v, want %v", test.dec, multiplier, decBuf.Bytes(), input) + continue + } } } } -func TestInvalidStringErr(t *testing.T) { - for i, test := range errTests { - _, err := DecodeString(test.in) - if err == nil { - t.Errorf("#%d: expected error; got none", i) - } else if err.Error() != test.err { - t.Errorf("#%d: got: %v want: %v", i, err, test.err) +func TestDecoderErr(t *testing.T) { + for _, tt := range errTests { + dec := NewDecoder(strings.NewReader(tt.in)) + out, err := ioutil.ReadAll(dec) + wantErr := tt.err + // Decoder is reading from stream, so it reports io.ErrUnexpectedEOF instead of ErrLength. + if wantErr == ErrLength { + wantErr = io.ErrUnexpectedEOF + } + if string(out) != tt.out || err != wantErr { + t.Errorf("NewDecoder(%q) = %q, %v, want %q, %v", tt.in, out, err, tt.out, wantErr) } } } diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go index 85d7ae043b8..42439eb7054 100644 --- a/libgo/go/encoding/json/bench_test.go +++ b/libgo/go/encoding/json/bench_test.go @@ -133,6 +133,21 @@ func BenchmarkCodeDecoder(b *testing.B) { b.SetBytes(int64(len(codeJSON))) } +func BenchmarkUnicodeDecoder(b *testing.B) { + j := []byte(`"\uD83D\uDE01"`) + b.SetBytes(int64(len(j))) + r := bytes.NewReader(j) + dec := NewDecoder(r) + var out string + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := dec.Decode(&out); err != nil { + b.Fatal("Decode:", err) + } + r.Seek(0, 0) + } +} + func BenchmarkDecoderStream(b *testing.B) { b.StopTimer() var buf bytes.Buffer diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 420a07e1549..536f25dc7c5 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -44,8 +44,9 @@ import ( // // To unmarshal JSON into a struct, Unmarshal matches incoming object // keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. -// Unmarshal will only set exported fields of the struct. +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). // // To unmarshal JSON into an interface value, // Unmarshal stores one of these in the interface value: @@ -138,7 +139,8 @@ func (e *UnmarshalTypeError) Error() string { // An UnmarshalFieldError describes a JSON object key that // led to an unexported (and therefore unwritable) struct field. -// (No longer used; kept for compatibility.) +// +// Deprecated: No longer used; kept for compatibility. type UnmarshalFieldError struct { Key string Type reflect.Type @@ -274,8 +276,9 @@ type decodeState struct { Struct string Field string } - savedError error - useNumber bool + savedError error + useNumber bool + disallowUnknownFields bool } // errPhase is used for errors that should not happen unless @@ -508,7 +511,7 @@ func (d *decodeState) array(v reflect.Value) { switch v.Kind() { case reflect.Interface: if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. + // Decoding into nil interface? Switch to non-reflect code. v.Set(reflect.ValueOf(d.arrayInterface())) return } @@ -612,7 +615,7 @@ func (d *decodeState) object(v reflect.Value) { } v = pv - // Decoding into nil interface? Switch to non-reflect code. + // Decoding into nil interface? Switch to non-reflect code. if v.Kind() == reflect.Interface && v.NumMethod() == 0 { v.Set(reflect.ValueOf(d.objectInterface())) return @@ -704,6 +707,19 @@ func (d *decodeState) object(v reflect.Value) { for _, i := range f.index { if subv.Kind() == reflect.Ptr { if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } subv.Set(reflect.New(subv.Type().Elem())) } subv = subv.Elem() @@ -712,6 +728,8 @@ func (d *decodeState) object(v reflect.Value) { } d.errorContext.Field = f.name d.errorContext.Struct = v.Type().Name() + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) } } @@ -1143,11 +1161,21 @@ func getu4(s []byte) rune { if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { return -1 } - r, err := strconv.ParseUint(string(s[2:6]), 16, 64) - if err != nil { - return -1 + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) } - return rune(r) + return r } // unquote converts a quoted JSON string literal s into an actual string t. @@ -1190,7 +1218,7 @@ func unquoteBytes(s []byte) (t []byte, ok bool) { b := make([]byte, len(s)+2*utf8.UTFMax) w := copy(b, s[0:r]) for r < len(s) { - // Out of room? Can only happen if s is full of + // Out of room? Can only happen if s is full of // malformed UTF-8 and we're replacing each // byte with RuneError. if w >= len(b)-2*utf8.UTFMax { diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index bd38ddd3190..34b7ec6d97a 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -88,7 +88,7 @@ func (u unmarshalerText) MarshalText() ([]byte, error) { } func (u *unmarshalerText) UnmarshalText(b []byte) error { - pos := bytes.Index(b, []byte(":")) + pos := bytes.IndexByte(b, ':') if pos == -1 { return errors.New("missing separator") } @@ -372,12 +372,13 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { } type unmarshalTest struct { - in string - ptr interface{} - out interface{} - err error - useNumber bool - golden bool + in string + ptr interface{} + out interface{} + err error + useNumber bool + golden bool + disallowUnknownFields bool } type B struct { @@ -401,6 +402,7 @@ var unmarshalTests = []unmarshalTest{ {in: "null", ptr: new(interface{}), out: nil}, {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, + {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, @@ -415,10 +417,13 @@ var unmarshalTests = []unmarshalTest{ // Z has a "-" tag. {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, + {in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, + {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, + {in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, // syntax errors {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, @@ -609,11 +614,23 @@ var unmarshalTests = []unmarshalTest{ ptr: new(S5), out: S5{S8: S8{S9: S9{Y: 2}}}, }, + { + in: `{"X": 1,"Y":2}`, + ptr: new(S5), + err: fmt.Errorf("json: unknown field \"X\""), + disallowUnknownFields: true, + }, { in: `{"X": 1,"Y":2}`, ptr: new(S10), out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, }, + { + in: `{"X": 1,"Y":2}`, + ptr: new(S10), + err: fmt.Errorf("json: unknown field \"X\""), + disallowUnknownFields: true, + }, // invalid UTF-8 is coerced to valid UTF-8. { @@ -793,6 +810,62 @@ var unmarshalTests = []unmarshalTest{ {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, {in: `{"B": "null"}`, ptr: new(B), out: B{false}}, {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, + + // additional tests for disallowUnknownFields + { + in: `{ + "Level0": 1, + "Level1b": 2, + "Level1c": 3, + "x": 4, + "Level1a": 5, + "LEVEL1B": 6, + "e": { + "Level1a": 8, + "Level1b": 9, + "Level1c": 10, + "Level1d": 11, + "x": 12 + }, + "Loop1": 13, + "Loop2": 14, + "X": 15, + "Y": 16, + "Z": 17, + "Q": 18, + "extra": true + }`, + ptr: new(Top), + err: fmt.Errorf("json: unknown field \"extra\""), + disallowUnknownFields: true, + }, + { + in: `{ + "Level0": 1, + "Level1b": 2, + "Level1c": 3, + "x": 4, + "Level1a": 5, + "LEVEL1B": 6, + "e": { + "Level1a": 8, + "Level1b": 9, + "Level1c": 10, + "Level1d": 11, + "x": 12, + "extra": null + }, + "Loop1": 13, + "Loop2": 14, + "X": 15, + "Y": 16, + "Z": 17, + "Q": 18 + }`, + ptr: new(Top), + err: fmt.Errorf("json: unknown field \"extra\""), + disallowUnknownFields: true, + }, } func TestMarshal(t *testing.T) { @@ -911,6 +984,9 @@ func TestUnmarshal(t *testing.T) { if tt.useNumber { dec.UseNumber() } + if tt.disallowUnknownFields { + dec.DisallowUnknownFields() + } if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { t.Errorf("#%d: %v, want %v", i, err, tt.err) continue @@ -1117,7 +1193,8 @@ type All struct { Foo string `json:"bar"` Foo2 string `json:"bar2,dummyopt"` - IntStr int64 `json:",string"` + IntStr int64 `json:",string"` + UintptrStr uintptr `json:",string"` PBool *bool PInt *int @@ -1171,24 +1248,25 @@ type Small struct { } var allValue = All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Uintptr: 12, - Float32: 14.1, - Float64: 15.1, - Foo: "foo", - Foo2: "foo2", - IntStr: 42, - String: "16", + Bool: true, + Int: 2, + Int8: 3, + Int16: 4, + Int32: 5, + Int64: 6, + Uint: 7, + Uint8: 8, + Uint16: 9, + Uint32: 10, + Uint64: 11, + Uintptr: 12, + Float32: 14.1, + Float64: 15.1, + Foo: "foo", + Foo2: "foo2", + IntStr: 42, + UintptrStr: 44, + String: "16", Map: map[string]Small{ "17": {Tag: "tag17"}, "18": {Tag: "tag18"}, @@ -1250,6 +1328,7 @@ var allValueIndent = `{ "bar": "foo", "bar2": "foo2", "IntStr": "42", + "UintptrStr": "44", "PBool": null, "PInt": null, "PInt8": null, @@ -1342,6 +1421,7 @@ var pallValueIndent = `{ "bar": "", "bar2": "", "IntStr": "0", + "UintptrStr": "0", "PBool": true, "PInt": 2, "PInt8": 3, @@ -2008,3 +2088,81 @@ func TestInvalidStringOption(t *testing.T) { t.Fatalf("Unmarshal: %v", err) } } + +// Test unmarshal behavior with regards to embedded pointers to unexported structs. +// If unallocated, this returns an error because unmarshal cannot set the field. +// Issue 21357. +func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) { + type ( + embed1 struct{ Q int } + embed2 struct{ Q int } + embed3 struct { + Q int64 `json:",string"` + } + S1 struct { + *embed1 + R int + } + S2 struct { + *embed1 + Q int + } + S3 struct { + embed1 + R int + } + S4 struct { + *embed1 + embed2 + } + S5 struct { + *embed3 + R int + } + ) + + tests := []struct { + in string + ptr interface{} + out interface{} + err error + }{{ + // Error since we cannot set S1.embed1, but still able to set S1.R. + in: `{"R":2,"Q":1}`, + ptr: new(S1), + out: &S1{R: 2}, + err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"), + }, { + // The top level Q field takes precedence. + in: `{"Q":1}`, + ptr: new(S2), + out: &S2{Q: 1}, + }, { + // No issue with non-pointer variant. + in: `{"R":2,"Q":1}`, + ptr: new(S3), + out: &S3{embed1: embed1{Q: 1}, R: 2}, + }, { + // No error since both embedded structs have field R, which annihilate each other. + // Thus, no attempt is made at setting S4.embed1. + in: `{"R":2}`, + ptr: new(S4), + out: new(S4), + }, { + // Error since we cannot set S5.embed1, but still able to set S5.R. + in: `{"R":2,"Q":1}`, + ptr: new(S5), + out: &S5{R: 2}, + err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"), + }} + + for i, tt := range tests { + err := Unmarshal([]byte(tt.in), tt.ptr) + if !reflect.DeepEqual(err, tt.err) { + t.Errorf("#%d: %v, want %v", i, err, tt.err) + } + if !reflect.DeepEqual(tt.ptr, tt.out) { + t.Errorf("#%d: mismatch\ngot: %#+v\nwant: %#+v", i, tt.ptr, tt.out) + } + } +} diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 0371f0a24dd..1e45e445d92 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package json implements encoding and decoding of JSON as defined in -// RFC 4627. The mapping between JSON and Go values is described +// RFC 7159. The mapping between JSON and Go values is described // in the documentation for the Marshal and Unmarshal functions. // // See "JSON and Go" for an introduction to this package: @@ -166,6 +166,8 @@ func Marshal(v interface{}) ([]byte, error) { } // MarshalIndent is like Marshal but applies Indent to format the output. +// Each JSON element in the output will begin on a new line beginning with prefix +// followed by one or more copies of indent according to the indentation nesting. func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { b, err := Marshal(v) if err != nil { @@ -243,8 +245,8 @@ func (e *UnsupportedValueError) Error() string { // attempting to encode a string value with invalid UTF-8 sequences. // As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by // replacing invalid bytes with the Unicode replacement rune U+FFFD. -// This error is no longer generated but is kept for backwards compatibility -// with programs that might mention it. +// +// Deprecated: No longer used; kept for compatibility. type InvalidUTF8Error struct { S string // the whole string value that caused the error } @@ -871,8 +873,7 @@ func (w *reflectWithString) resolve() error { } // NOTE: keep in sync with stringBytes below. -func (e *encodeState) string(s string, escapeHTML bool) int { - len0 := e.Len() +func (e *encodeState) string(s string, escapeHTML bool) { e.WriteByte('"') start := 0 for i := 0; i < len(s); { @@ -944,12 +945,10 @@ func (e *encodeState) string(s string, escapeHTML bool) int { e.WriteString(s[start:]) } e.WriteByte('"') - return e.Len() - len0 } // NOTE: keep in sync with string above. -func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int { - len0 := e.Len() +func (e *encodeState) stringBytes(s []byte, escapeHTML bool) { e.WriteByte('"') start := 0 for i := 0; i < len(s); { @@ -1021,7 +1020,6 @@ func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int { e.Write(s[start:]) } e.WriteByte('"') - return e.Len() - len0 } // A field represents a single field found in a struct. @@ -1093,21 +1091,19 @@ func typeFields(t reflect.Type) []field { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) + isUnexported := sf.PkgPath != "" if sf.Anonymous { t := sf.Type if t.Kind() == reflect.Ptr { t = t.Elem() } - // If embedded, StructField.PkgPath is not a reliable - // indicator of whether the field is exported. - // See https://golang.org/issue/21122 - if !isExported(t.Name()) && t.Kind() != reflect.Struct { + if isUnexported && t.Kind() != reflect.Struct { // Ignore embedded fields of unexported non-struct types. - // Do not ignore embedded fields of unexported struct types - // since they may have exported fields. continue } - } else if sf.PkgPath != "" { + // Do not ignore embedded fields of unexported struct types + // since they may have exported fields. + } else if isUnexported { // Ignore unexported non-embedded fields. continue } @@ -1135,7 +1131,7 @@ func typeFields(t reflect.Type) []field { switch ft.Kind() { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.String: quoted = true @@ -1226,12 +1222,6 @@ func typeFields(t reflect.Type) []field { return fields } -// isExported reports whether the identifier is exported. -func isExported(id string) bool { - r, _ := utf8.DecodeRuneInString(id) - return unicode.IsUpper(r) -} - // dominantField looks through the fields, all of which are known to // have the same name, to find the single field that dominates the // others using Go's embedding rules, modified by the presence of diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go index 3fda6a0c719..0f194e13d26 100644 --- a/libgo/go/encoding/json/encode_test.go +++ b/libgo/go/encoding/json/encode_test.go @@ -71,14 +71,16 @@ func TestOmitEmpty(t *testing.T) { } type StringTag struct { - BoolStr bool `json:",string"` - IntStr int64 `json:",string"` - StrStr string `json:",string"` + BoolStr bool `json:",string"` + IntStr int64 `json:",string"` + UintptrStr uintptr `json:",string"` + StrStr string `json:",string"` } var stringTagExpected = `{ "BoolStr": "true", "IntStr": "42", + "UintptrStr": "44", "StrStr": "\"xzbit\"" }` @@ -86,6 +88,7 @@ func TestStringTag(t *testing.T) { var s StringTag s.BoolStr = true s.IntStr = 42 + s.UintptrStr = 44 s.StrStr = "xzbit" got, err := MarshalIndent(&s, "", " ") if err != nil { @@ -943,7 +946,7 @@ func TestMarshalRawMessageValue(t *testing.T) { // // The tests below marked with Issue6458 used to generate "ImZvbyI=" instead "foo". // This behavior was intentionally changed in Go 1.8. - // See https://github.com/golang/go/issues/14493#issuecomment-255857318 + // See https://golang.org/issues/14493#issuecomment-255857318 {rawText, `"foo"`, true}, // Issue6458 {&rawText, `"foo"`, true}, {[]interface{}{rawText}, `["foo"]`, true}, // Issue6458 diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go index 95e30ce36d5..75a4270df7d 100644 --- a/libgo/go/encoding/json/stream.go +++ b/libgo/go/encoding/json/stream.go @@ -12,12 +12,13 @@ import ( // A Decoder reads and decodes JSON values from an input stream. type Decoder struct { - r io.Reader - buf []byte - d decodeState - scanp int // start of unread data in buf - scan scanner - err error + r io.Reader + buf []byte + d decodeState + scanp int // start of unread data in buf + scanned int64 // amount of data already scanned + scan scanner + err error tokenState int tokenStack []int @@ -35,6 +36,11 @@ func NewDecoder(r io.Reader) *Decoder { // Number instead of as a float64. func (dec *Decoder) UseNumber() { dec.d.useNumber = true } +// DisallowUnknownFields causes the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true } + // Decode reads the next JSON-encoded value from its // input and stores it in the value pointed to by v. // @@ -50,7 +56,7 @@ func (dec *Decoder) Decode(v interface{}) error { } if !dec.tokenValueAllowed() { - return &SyntaxError{msg: "not at beginning of value"} + return &SyntaxError{msg: "not at beginning of value", Offset: dec.offset()} } // Read whole value into buffer. @@ -135,6 +141,7 @@ func (dec *Decoder) refill() error { // Make room to read more into the buffer. // First slide down data already consumed. if dec.scanp > 0 { + dec.scanned += int64(dec.scanp) n := copy(dec.buf, dec.buf[dec.scanp:]) dec.buf = dec.buf[:n] dec.scanp = 0 @@ -301,7 +308,7 @@ func (dec *Decoder) tokenPrepareForDecode() error { return err } if c != ',' { - return &SyntaxError{"expected comma after array element", 0} + return &SyntaxError{"expected comma after array element", dec.offset()} } dec.scanp++ dec.tokenState = tokenArrayValue @@ -311,7 +318,7 @@ func (dec *Decoder) tokenPrepareForDecode() error { return err } if c != ':' { - return &SyntaxError{"expected colon after object key", 0} + return &SyntaxError{"expected colon after object key", dec.offset()} } dec.scanp++ dec.tokenState = tokenObjectValue @@ -428,7 +435,6 @@ func (dec *Decoder) Token() (Token, error) { err := dec.Decode(&x) dec.tokenState = old if err != nil { - clearOffset(err) return nil, err } dec.tokenState = tokenObjectColon @@ -442,7 +448,6 @@ func (dec *Decoder) Token() (Token, error) { } var x interface{} if err := dec.Decode(&x); err != nil { - clearOffset(err) return nil, err } return x, nil @@ -450,12 +455,6 @@ func (dec *Decoder) Token() (Token, error) { } } -func clearOffset(err error) { - if s, ok := err.(*SyntaxError); ok { - s.Offset = 0 - } -} - func (dec *Decoder) tokenError(c byte) (Token, error) { var context string switch dec.tokenState { @@ -472,7 +471,7 @@ func (dec *Decoder) tokenError(c byte) (Token, error) { case tokenObjectComma: context = " after object key:value pair" } - return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0} + return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, dec.offset()} } // More reports whether there is another element in the @@ -501,19 +500,6 @@ func (dec *Decoder) peek() (byte, error) { } } -/* -TODO - -// EncodeToken writes the given JSON token to the stream. -// It returns an error if the delimiters [ ] { } are not properly used. -// -// EncodeToken does not call Flush, because usually it is part of -// a larger operation such as Encode, and those will call Flush when finished. -// Callers that create an Encoder and then invoke EncodeToken directly, -// without using Encode, need to call Flush when finished to ensure that -// the JSON is written to the underlying writer. -func (e *Encoder) EncodeToken(t Token) error { - ... +func (dec *Decoder) offset() int64 { + return dec.scanned + int64(dec.scanp) } - -*/ diff --git a/libgo/go/encoding/json/stream_test.go b/libgo/go/encoding/json/stream_test.go index d0b3ffbce93..83c01d170c0 100644 --- a/libgo/go/encoding/json/stream_test.go +++ b/libgo/go/encoding/json/stream_test.go @@ -342,11 +342,18 @@ var tokenStreamCases []tokenStreamCase = []tokenStreamCase{ {json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{ Delim('['), decodeThis{map[string]interface{}{"a": float64(1)}}, - decodeThis{&SyntaxError{"expected comma after array element", 0}}, + decodeThis{&SyntaxError{"expected comma after array element", 11}}, }}, - {json: `{ "a" 1 }`, expTokens: []interface{}{ - Delim('{'), "a", - decodeThis{&SyntaxError{"expected colon after object key", 0}}, + {json: `{ "` + strings.Repeat("a", 513) + `" 1 }`, expTokens: []interface{}{ + Delim('{'), strings.Repeat("a", 513), + decodeThis{&SyntaxError{"expected colon after object key", 518}}, + }}, + {json: `{ "\a" }`, expTokens: []interface{}{ + Delim('{'), + &SyntaxError{"invalid character 'a' in string escape code", 3}, + }}, + {json: ` \a`, expTokens: []interface{}{ + &SyntaxError{"invalid character '\\\\' looking for beginning of value", 1}, }}, } @@ -367,15 +374,15 @@ func TestDecodeInStream(t *testing.T) { tk, err = dec.Token() } if experr, ok := etk.(error); ok { - if err == nil || err.Error() != experr.Error() { - t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err) + if err == nil || !reflect.DeepEqual(err, experr) { + t.Errorf("case %v: Expected error %#v in %q, but was %#v", ci, experr, tcase.json, err) } break } else if err == io.EOF { t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json) break } else if err != nil { - t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json) + t.Errorf("case %v: Unexpected error '%#v' in %q", ci, err, tcase.json) break } if !reflect.DeepEqual(tk, etk) { diff --git a/libgo/go/encoding/pem/example_test.go b/libgo/go/encoding/pem/example_test.go index ffd962bd68f..22081b4d8ac 100644 --- a/libgo/go/encoding/pem/example_test.go +++ b/libgo/go/encoding/pem/example_test.go @@ -11,6 +11,7 @@ import ( "encoding/pem" "fmt" "log" + "os" ) func ExampleDecode() { @@ -44,3 +45,23 @@ and some more`) fmt.Printf("Got a %T, with remaining data: %q", pub, rest) // Output: Got a *rsa.PublicKey, with remaining data: "and some more" } + +func ExampleEncode() { + block := &pem.Block{ + Type: "MESSAGE", + Headers: map[string]string{ + "Animal": "Gopher", + }, + Bytes: []byte("test"), + } + + if err := pem.Encode(os.Stdout, block); err != nil { + log.Fatal(err) + } + // Output: + // -----BEGIN MESSAGE----- + // Animal: Gopher + // + // dGVzdA== + // -----END MESSAGE----- +} diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go index 5e1ab90cffc..35058c306bc 100644 --- a/libgo/go/encoding/pem/pem.go +++ b/libgo/go/encoding/pem/pem.go @@ -36,7 +36,7 @@ type Block struct { // bytes) is also returned and this will always be smaller than the original // argument. func getLine(data []byte) (line, rest []byte) { - i := bytes.Index(data, []byte{'\n'}) + i := bytes.IndexByte(data, '\n') var j int if i < 0 { i = len(data) @@ -106,7 +106,7 @@ func Decode(data []byte) (p *Block, rest []byte) { } line, next := getLine(rest) - i := bytes.Index(line, []byte{':'}) + i := bytes.IndexByte(line, ':') if i == -1 { break } @@ -252,7 +252,18 @@ func writeHeader(out io.Writer, k, v string) error { return err } +// Encode writes the PEM encoding of b to out. func Encode(out io.Writer, b *Block) error { + // Check for invalid block before writing any output. + for k := range b.Headers { + if strings.Contains(k, ":") { + return errors.New("pem: cannot encode a header key that contains a colon") + } + } + + // All errors below are relayed from underlying io.Writer, + // so it is now safe to write data. + if _, err := out.Write(pemStart[1:]); err != nil { return err } @@ -281,9 +292,6 @@ func Encode(out io.Writer, b *Block) error { // For consistency of output, write other headers sorted by key. sort.Strings(h) for _, k := range h { - if strings.Contains(k, ":") { - return errors.New("pem: cannot encode a header key that contains a colon") - } if err := writeHeader(out, k, b.Headers[k]); err != nil { return err } @@ -310,8 +318,15 @@ func Encode(out io.Writer, b *Block) error { return err } +// EncodeToMemory returns the PEM encoding of b. +// +// If b has invalid headers and cannot be encoded, +// EncodeToMemory returns nil. If it is important to +// report details about this error case, use Encode instead. func EncodeToMemory(b *Block) []byte { var buf bytes.Buffer - Encode(&buf, b) + if err := Encode(&buf, b); err != nil { + return nil + } return buf.Bytes() } diff --git a/libgo/go/encoding/pem/pem_test.go b/libgo/go/encoding/pem/pem_test.go index 1a1250a52f4..6a175162183 100644 --- a/libgo/go/encoding/pem/pem_test.go +++ b/libgo/go/encoding/pem/pem_test.go @@ -590,3 +590,17 @@ N4XPksobn/NO2IDvPM7N9ZCe+aeyDEkE8QmP6mPScLuGvzSrsgOxWTMWF7Dbdzj0 tJQLJRZ+ItT5Irl4owSEBNLahC1j3fhQavbj9WVAfKk= -----END RSA PRIVATE KEY----- ` + +func TestBadEncode(t *testing.T) { + b := &Block{Type: "BAD", Headers: map[string]string{"X:Y": "Z"}} + var buf bytes.Buffer + if err := Encode(&buf, b); err == nil { + t.Fatalf("Encode did not report invalid header") + } + if buf.Len() != 0 { + t.Fatalf("Encode wrote data before reporting invalid header") + } + if data := EncodeToMemory(b); data != nil { + t.Fatalf("EncodeToMemory returned non-nil data") + } +} diff --git a/libgo/go/encoding/xml/atom_test.go b/libgo/go/encoding/xml/atom_test.go index a71284312af..f394dab6f09 100644 --- a/libgo/go/encoding/xml/atom_test.go +++ b/libgo/go/encoding/xml/atom_test.go @@ -12,20 +12,20 @@ var atomValue = &Feed{ Link: []Link{{Href: "http://example.org/"}}, Updated: ParseTime("2003-12-13T18:30:02Z"), Author: Person{Name: "John Doe"}, - Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", + ID: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", Entry: []Entry{ { Title: "Atom-Powered Robots Run Amok", Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}}, - Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", + ID: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", Updated: ParseTime("2003-12-13T18:30:02Z"), Summary: NewText("Some text."), }, }, } -var atomXml = `` + +var atomXML = `` + `` + `Example Feed` + `urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6` + diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 4c6ba8c1a5a..d393d0610bf 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -16,7 +16,7 @@ import ( ) const ( - // A generic XML header suitable for use with the output of Marshal. + // Header is a generic XML header suitable for use with the output of Marshal. // This is not automatically added to any output of this package, // it is provided as a convenience. Header = `` + "\n" @@ -66,6 +66,9 @@ const ( // parent elements a and b. Fields that appear next to each other that name // the same parent will be enclosed in one XML element. // +// If the XML name for a struct field is defined by both the field tag and the +// struct's XMLName field, the names must match. +// // See MarshalIndent for an example. // // Marshal will return an error if asked to marshal a channel, function, or map. @@ -320,7 +323,7 @@ func (p *printer) createAttrPrefix(url string) string { // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns", // but users should not be trying to use that one directly - that's our job.) if url == xmlURL { - return "xml" + return xmlPrefix } // Need to define a new name space. @@ -1011,7 +1014,7 @@ func (s *parentStack) push(parents []string) error { return nil } -// A MarshalXMLError is returned when Marshal encounters a type +// UnsupportedTypeError is returned when Marshal encounters a type // that cannot be converted into XML. type UnsupportedTypeError struct { Type reflect.Type diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index 674c6b5b3f4..5c79a48e7ad 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -646,7 +646,7 @@ var marshalTests = []struct { {Value: &Universe{Visible: 9.3e13}, ExpectXML: `9.3e+13`}, {Value: &Particle{HasMass: true}, ExpectXML: `true`}, {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `2013-01-09T00:15:00-09:00`}, - {Value: atomValue, ExpectXML: atomXml}, + {Value: atomValue, ExpectXML: atomXML}, { Value: &Ship{ Name: "Heart of Gold", @@ -1910,7 +1910,7 @@ func BenchmarkMarshal(b *testing.B) { func BenchmarkUnmarshal(b *testing.B) { b.ReportAllocs() - xml := []byte(atomXml) + xml := []byte(atomXML) b.RunParallel(func(pb *testing.PB) { for pb.Next() { Unmarshal(xml, &Feed{}) @@ -2441,3 +2441,22 @@ func TestIssue16158(t *testing.T) { t.Errorf("Unmarshal: expected error, got nil") } } + +// Issue 20953. Crash on invalid XMLName attribute. + +type InvalidXMLName struct { + XMLName Name `xml:"error"` + Type struct { + XMLName Name `xml:"type,attr"` + } +} + +func TestInvalidXMLName(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + if err := enc.Encode(InvalidXMLName{}); err == nil { + t.Error("unexpected success") + } else if want := "invalid tag"; !strings.Contains(err.Error(), want) { + t.Errorf("error %q does not contain %q", err, want) + } +} diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 000d9fbd0ef..36c7ba63111 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -107,12 +107,13 @@ import ( // to the newly created value. // // Unmarshal maps an XML element or attribute value to a bool by -// setting it to the boolean value represented by the string. +// setting it to the boolean value represented by the string. Whitespace +// is trimmed and ignored. // // Unmarshal maps an XML element or attribute value to an integer or // floating-point field by setting the field to the result of // interpreting the string value in decimal. There is no check for -// overflow. +// overflow. Whitespace is trimmed and ignored. // // Unmarshal maps an XML element to a Name by recording the element // name. @@ -160,7 +161,7 @@ func (e UnmarshalError) Error() string { return string(e) } // UnmarshalXML must consume exactly one XML element. // One common implementation strategy is to unmarshal into // a separate value with a layout matching the expected XML -// using d.DecodeElement, and then to copy the data from +// using d.DecodeElement, and then to copy the data from // that value into the receiver. // Another common strategy is to use d.Token to process the // XML object one token at a time. @@ -192,19 +193,19 @@ func receiverType(val interface{}) string { // unmarshalInterface unmarshals a single XML element into val. // start is the opening tag of the element. -func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { +func (d *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { // Record that decoder must stop at end tag corresponding to start. - p.pushEOF() + d.pushEOF() - p.unmarshalDepth++ - err := val.UnmarshalXML(p, *start) - p.unmarshalDepth-- + d.unmarshalDepth++ + err := val.UnmarshalXML(d, *start) + d.unmarshalDepth-- if err != nil { - p.popEOF() + d.popEOF() return err } - if !p.popEOF() { + if !d.popEOF() { return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local) } @@ -214,11 +215,11 @@ func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error // unmarshalTextInterface unmarshals a single XML element into val. // The chardata contained in the element (but not its children) // is passed to the text unmarshaler. -func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error { +func (d *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error { var buf []byte depth := 1 for depth > 0 { - t, err := p.Token() + t, err := d.Token() if err != nil { return err } @@ -237,7 +238,7 @@ func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error { } // unmarshalAttr unmarshals a single XML attribute into val. -func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { +func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) @@ -276,7 +277,7 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem()))) // Recur to read element into slice. - if err := p.unmarshalAttr(val.Index(n), attr); err != nil { + if err := d.unmarshalAttr(val.Index(n), attr); err != nil { val.SetLen(n) return err } @@ -299,11 +300,11 @@ var ( ) // Unmarshal a single XML element into val. -func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { +func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // Find start element if we need it. if start == nil { for { - tok, err := p.Token() + tok, err := d.Token() if err != nil { return err } @@ -333,24 +334,24 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { if val.CanInterface() && val.Type().Implements(unmarshalerType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. - return p.unmarshalInterface(val.Interface().(Unmarshaler), start) + return d.unmarshalInterface(val.Interface().(Unmarshaler), start) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(unmarshalerType) { - return p.unmarshalInterface(pv.Interface().(Unmarshaler), start) + return d.unmarshalInterface(pv.Interface().(Unmarshaler), start) } } if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { - return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler)) + return d.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { - return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler)) + return d.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler)) } } @@ -376,7 +377,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // TODO: For now, simply ignore the field. In the near // future we may choose to unmarshal the start // element on it, if not nil. - return p.Skip() + return d.Skip() case reflect.Slice: typ := v.Type() @@ -392,7 +393,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem()))) // Recur to read element into slice. - if err := p.unmarshal(v.Index(n), start); err != nil { + if err := d.unmarshal(v.Index(n), start); err != nil { v.SetLen(n) return err } @@ -445,7 +446,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { case fAttr: strv := finfo.value(sv) if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { - if err := p.unmarshalAttr(strv, a); err != nil { + if err := d.unmarshalAttr(strv, a); err != nil { return err } handled = true @@ -460,7 +461,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { if !handled && any >= 0 { finfo := &tinfo.fields[any] strv := finfo.value(sv) - if err := p.unmarshalAttr(strv, a); err != nil { + if err := d.unmarshalAttr(strv, a); err != nil { return err } } @@ -488,11 +489,11 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { case fInnerXml: if !saveXML.IsValid() { saveXML = finfo.value(sv) - if p.saved == nil { + if d.saved == nil { saveXMLIndex = 0 - p.saved = new(bytes.Buffer) + d.saved = new(bytes.Buffer) } else { - saveXMLIndex = p.savedOffset() + saveXMLIndex = d.savedOffset() } } } @@ -505,9 +506,9 @@ Loop: for { var savedOffset int if saveXML.IsValid() { - savedOffset = p.savedOffset() + savedOffset = d.savedOffset() } - tok, err := p.Token() + tok, err := d.Token() if err != nil { return err } @@ -515,28 +516,28 @@ Loop: case StartElement: consumed := false if sv.IsValid() { - consumed, err = p.unmarshalPath(tinfo, sv, nil, &t) + consumed, err = d.unmarshalPath(tinfo, sv, nil, &t) if err != nil { return err } if !consumed && saveAny.IsValid() { consumed = true - if err := p.unmarshal(saveAny, &t); err != nil { + if err := d.unmarshal(saveAny, &t); err != nil { return err } } } if !consumed { - if err := p.Skip(); err != nil { + if err := d.Skip(); err != nil { return err } } case EndElement: if saveXML.IsValid() { - saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] + saveXMLData = d.saved.Bytes()[saveXMLIndex:savedOffset] if saveXMLIndex == 0 { - p.saved = nil + d.saved = nil } } break Loop @@ -614,7 +615,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { dst.SetInt(0) return nil } - itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits()) + itmp, err := strconv.ParseInt(strings.TrimSpace(string(src)), 10, dst.Type().Bits()) if err != nil { return err } @@ -624,7 +625,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { dst.SetUint(0) return nil } - utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits()) + utmp, err := strconv.ParseUint(strings.TrimSpace(string(src)), 10, dst.Type().Bits()) if err != nil { return err } @@ -634,7 +635,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { dst.SetFloat(0) return nil } - ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits()) + ftmp, err := strconv.ParseFloat(strings.TrimSpace(string(src)), dst.Type().Bits()) if err != nil { return err } @@ -666,7 +667,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { // The consumed result tells whether XML elements have been consumed // from the Decoder until start's matching end element, or if it's // still untouched because start is uninteresting for sv's fields. -func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { +func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { recurse := false Loop: for i := range tinfo.fields { @@ -681,7 +682,7 @@ Loop: } if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { // It's a perfect match, unmarshal the field. - return true, p.unmarshal(finfo.value(sv), start) + return true, d.unmarshal(finfo.value(sv), start) } if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { // It's a prefix for the field. Break and recurse @@ -704,18 +705,18 @@ Loop: // prefix. Recurse and attempt to match these. for { var tok Token - tok, err = p.Token() + tok, err = d.Token() if err != nil { return true, err } switch t := tok.(type) { case StartElement: - consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t) + consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t) if err != nil { return true, err } if !consumed2 { - if err := p.Skip(); err != nil { + if err := d.Skip(); err != nil { return true, err } } diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go index a1eb5161877..8c2e70fa22e 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -83,7 +83,7 @@ not being used from outside intra_region_diff.py. type Feed struct { XMLName Name `xml:"http://www.w3.org/2005/Atom feed"` Title string `xml:"title"` - Id string `xml:"id"` + ID string `xml:"id"` Link []Link `xml:"link"` Updated time.Time `xml:"updated,attr"` Author Person `xml:"author"` @@ -92,7 +92,7 @@ type Feed struct { type Entry struct { Title string `xml:"title"` - Id string `xml:"id"` + ID string `xml:"id"` Link []Link `xml:"link"` Updated time.Time `xml:"updated"` Author Person `xml:"author"` @@ -123,7 +123,7 @@ var atomFeed = Feed{ {Rel: "alternate", Href: "http://codereview.appspot.com/"}, {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"}, }, - Id: "http://codereview.appspot.com/", + ID: "http://codereview.appspot.com/", Updated: ParseTime("2009-10-04T01:35:58+00:00"), Author: Person{ Name: "rietveld<>", @@ -140,7 +140,7 @@ var atomFeed = Feed{ Name: "email-address-removed", InnerXML: "email-address-removed", }, - Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a", + ID: "urn:md5:134d9179c41f806be79b3a5f7877d19a", Summary: Text{ Type: "html", Body: ` @@ -187,7 +187,7 @@ the top of feeds.py marked NOTE(rsc). Name: "email-address-removed", InnerXML: "email-address-removed", }, - Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a", + ID: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a", Summary: Text{ Type: "html", Body: ` @@ -819,7 +819,7 @@ const ( ` ) -// github.com/golang/go/issues/13417 +// golang.org/issues/13417 func TestUnmarshalEmptyValues(t *testing.T) { // Test first with a zero-valued dst. v := new(Parent) @@ -908,3 +908,174 @@ func TestUnmarshalEmptyValues(t *testing.T) { t.Fatalf("populated: Unmarshal:\nhave: %#+v\nwant: %#+v", v, want) } } + +type WhitespaceValuesParent struct { + BFalse bool + BTrue bool + I int + INeg int + I8 int8 + I8Neg int8 + I16 int16 + I16Neg int16 + I32 int32 + I32Neg int32 + I64 int64 + I64Neg int64 + UI uint + UI8 uint8 + UI16 uint16 + UI32 uint32 + UI64 uint64 + F32 float32 + F32Neg float32 + F64 float64 + F64Neg float64 +} + +const whitespaceValuesXML = ` + + false + true + 266703 + -266703 + 112 + -112 + 6703 + -6703 + 266703 + -266703 + 266703 + -266703 + 266703 + 112 + 6703 + 266703 + 266703 + 266.703 + -266.703 + 266.703 + -266.703 + +` + +// golang.org/issues/22146 +func TestUnmarshalWhitespaceValues(t *testing.T) { + v := WhitespaceValuesParent{} + if err := Unmarshal([]byte(whitespaceValuesXML), &v); err != nil { + t.Fatalf("whitespace values: Unmarshal failed: got %v", err) + } + + want := WhitespaceValuesParent{ + BFalse: false, + BTrue: true, + I: 266703, + INeg: -266703, + I8: 112, + I8Neg: -112, + I16: 6703, + I16Neg: -6703, + I32: 266703, + I32Neg: -266703, + I64: 266703, + I64Neg: -266703, + UI: 266703, + UI8: 112, + UI16: 6703, + UI32: 266703, + UI64: 266703, + F32: 266.703, + F32Neg: -266.703, + F64: 266.703, + F64Neg: -266.703, + } + if v != want { + t.Fatalf("whitespace values: Unmarshal:\nhave: %#+v\nwant: %#+v", v, want) + } +} + +type WhitespaceAttrsParent struct { + BFalse bool `xml:",attr"` + BTrue bool `xml:",attr"` + I int `xml:",attr"` + INeg int `xml:",attr"` + I8 int8 `xml:",attr"` + I8Neg int8 `xml:",attr"` + I16 int16 `xml:",attr"` + I16Neg int16 `xml:",attr"` + I32 int32 `xml:",attr"` + I32Neg int32 `xml:",attr"` + I64 int64 `xml:",attr"` + I64Neg int64 `xml:",attr"` + UI uint `xml:",attr"` + UI8 uint8 `xml:",attr"` + UI16 uint16 `xml:",attr"` + UI32 uint32 `xml:",attr"` + UI64 uint64 `xml:",attr"` + F32 float32 `xml:",attr"` + F32Neg float32 `xml:",attr"` + F64 float64 `xml:",attr"` + F64Neg float64 `xml:",attr"` +} + +const whitespaceAttrsXML = ` + + +` + +// golang.org/issues/22146 +func TestUnmarshalWhitespaceAttrs(t *testing.T) { + v := WhitespaceAttrsParent{} + if err := Unmarshal([]byte(whitespaceAttrsXML), &v); err != nil { + t.Fatalf("whitespace attrs: Unmarshal failed: got %v", err) + } + + want := WhitespaceAttrsParent{ + BFalse: false, + BTrue: true, + I: 266703, + INeg: -266703, + I8: 112, + I8Neg: -112, + I16: 6703, + I16Neg: -6703, + I32: 266703, + I32Neg: -266703, + I64: 266703, + I64Neg: -266703, + UI: 266703, + UI8: 112, + UI16: 6703, + UI32: 266703, + UI64: 266703, + F32: 266.703, + F32Neg: -266.703, + F64: 266.703, + F64Neg: -266.703, + } + if v != want { + t.Fatalf("whitespace attrs: Unmarshal:\nhave: %#+v\nwant: %#+v", v, want) + } +} diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 751caa97aa1..48de3d7e9e9 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -40,6 +40,8 @@ const ( fOmitEmpty fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny + + xmlName = "XMLName" ) var tinfoMap sync.Map // map[reflect.Type]*typeInfo @@ -91,7 +93,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) { return nil, err } - if f.Name == "XMLName" { + if f.Name == xmlName { tinfo.xmlname = finfo continue } @@ -148,7 +150,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro case 0: finfo.flags |= fElement case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr: - if f.Name == "XMLName" || tag != "" && mode != fAttr { + if f.Name == xmlName || tag != "" && mode != fAttr { valid = false } default: @@ -173,7 +175,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro f.Name, typ, f.Tag.Get("xml")) } - if f.Name == "XMLName" { + if f.Name == xmlName { // The XMLName field records the XML element name. Don't // process it as usual because its name should default to // empty rather than to the field name. @@ -235,11 +237,11 @@ func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) { } for i, n := 0, typ.NumField(); i < n; i++ { f := typ.Field(i) - if f.Name != "XMLName" { + if f.Name != xmlName { continue } finfo, err := structFieldInfo(typ, &f) - if finfo.name != "" && err == nil { + if err == nil && finfo.name != "" { return finfo } // Also consider errors as a non-existent field tag diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index 9a3b7929559..f408623de5e 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -60,6 +60,7 @@ type StartElement struct { Attr []Attr } +// Copy creates a new copy of StartElement. func (e StartElement) Copy() StartElement { attrs := make([]Attr, len(e.Attr)) copy(attrs, e.Attr) @@ -88,12 +89,14 @@ func makeCopy(b []byte) []byte { return b1 } +// Copy creates a new copy of CharData. func (c CharData) Copy() CharData { return CharData(makeCopy(c)) } // A Comment represents an XML comment of the form . // The bytes do not include the comment markers. type Comment []byte +// Copy creates a new copy of Comment. func (c Comment) Copy() Comment { return Comment(makeCopy(c)) } // A ProcInst represents an XML processing instruction of the form @@ -102,6 +105,7 @@ type ProcInst struct { Inst []byte } +// Copy creates a new copy of ProcInst. func (p ProcInst) Copy() ProcInst { p.Inst = makeCopy(p.Inst) return p @@ -111,6 +115,7 @@ func (p ProcInst) Copy() ProcInst { // The bytes do not include the markers. type Directive []byte +// Copy creates a new copy of Directive. func (d Directive) Copy() Directive { return Directive(makeCopy(d)) } // CopyToken returns a copy of a Token. @@ -130,6 +135,23 @@ func CopyToken(t Token) Token { return t } +// A TokenReader is anything that can decode a stream of XML tokens, including a +// Decoder. +// +// When Token encounters an error or end-of-file condition after successfully +// reading a token, it returns the token. It may return the (non-nil) error from +// the same call or return the error (and a nil token) from a subsequent call. +// An instance of this general case is that a TokenReader returning a non-nil +// token at the end of the token stream may return either io.EOF or a nil error. +// The next Read should return nil, io.EOF. +// +// Implementations of Token are discouraged from returning a nil token with a +// nil error. Callers should treat a return of nil, nil as indicating that +// nothing happened; in particular it does not indicate EOF. +type TokenReader interface { + Token() (Token, error) +} + // A Decoder represents an XML parser reading a particular input stream. // The parser assumes that its input is encoded in UTF-8. type Decoder struct { @@ -185,6 +207,7 @@ type Decoder struct { DefaultSpace string r io.ByteReader + t TokenReader buf bytes.Buffer saved *bytes.Buffer stk *stack @@ -214,6 +237,22 @@ func NewDecoder(r io.Reader) *Decoder { return d } +// NewTokenDecoder creates a new XML parser using an underlying token stream. +func NewTokenDecoder(t TokenReader) *Decoder { + // Is it already a Decoder? + if d, ok := t.(*Decoder); ok { + return d + } + d := &Decoder{ + ns: make(map[string]string), + t: t, + nextByte: -1, + line: 1, + Strict: true, + } + return d +} + // Token returns the next XML token in the input stream. // At the end of the input stream, Token returns nil, io.EOF. // @@ -266,12 +305,12 @@ func (d *Decoder) Token() (Token, error) { // to the other attribute names, so process // the translations first. for _, a := range t1.Attr { - if a.Name.Space == "xmlns" { + if a.Name.Space == xmlnsPrefix { v, ok := d.ns[a.Name.Local] d.pushNs(a.Name.Local, v, ok) d.ns[a.Name.Local] = a.Value } - if a.Name.Space == "" && a.Name.Local == "xmlns" { + if a.Name.Space == "" && a.Name.Local == xmlnsPrefix { // Default space for untagged names v, ok := d.ns[""] d.pushNs("", v, ok) @@ -296,20 +335,24 @@ func (d *Decoder) Token() (Token, error) { return t, err } -const xmlURL = "http://www.w3.org/XML/1998/namespace" +const ( + xmlURL = "http://www.w3.org/XML/1998/namespace" + xmlnsPrefix = "xmlns" + xmlPrefix = "xml" +) // Apply name space translation to name n. // The default name space (for Space=="") // applies only to element names, not to attribute names. func (d *Decoder) translate(n *Name, isElementName bool) { switch { - case n.Space == "xmlns": + case n.Space == xmlnsPrefix: return case n.Space == "" && !isElementName: return - case n.Space == "xml": + case n.Space == xmlPrefix: n.Space = xmlURL - case n.Space == "" && n.Local == "xmlns": + case n.Space == "" && n.Local == xmlnsPrefix: return } if v, ok := d.ns[n.Space]; ok { @@ -503,6 +546,9 @@ func (d *Decoder) RawToken() (Token, error) { } func (d *Decoder) rawToken() (Token, error) { + if d.t != nil { + return d.t.Token() + } if d.err != nil { return nil, d.err } @@ -786,10 +832,9 @@ func (d *Decoder) rawToken() (Token, error) { if d.Strict { d.err = d.syntaxError("attribute name without = in element") return nil, d.err - } else { - d.ungetc(b) - a.Value = a.Name.Local } + d.ungetc(b) + a.Value = a.Name.Local } else { d.space() data := d.attrval() @@ -1027,7 +1072,6 @@ Input: if d.err != nil { return nil } - ok = false } if b, ok = d.mustgetc(); !ok { return nil @@ -1837,15 +1881,15 @@ var htmlAutoClose = []string{ } var ( - esc_quot = []byte(""") // shorter than """ - esc_apos = []byte("'") // shorter than "'" - esc_amp = []byte("&") - esc_lt = []byte("<") - esc_gt = []byte(">") - esc_tab = []byte(" ") - esc_nl = []byte(" ") - esc_cr = []byte(" ") - esc_fffd = []byte("\uFFFD") // Unicode replacement character + escQuot = []byte(""") // shorter than """ + escApos = []byte("'") // shorter than "'" + escAmp = []byte("&") + escLT = []byte("<") + escGT = []byte(">") + escTab = []byte(" ") + escNL = []byte(" ") + escCR = []byte(" ") + escFFFD = []byte("\uFFFD") // Unicode replacement character ) // EscapeText writes to w the properly escaped XML equivalent @@ -1865,27 +1909,27 @@ func escapeText(w io.Writer, s []byte, escapeNewline bool) error { i += width switch r { case '"': - esc = esc_quot + esc = escQuot case '\'': - esc = esc_apos + esc = escApos case '&': - esc = esc_amp + esc = escAmp case '<': - esc = esc_lt + esc = escLT case '>': - esc = esc_gt + esc = escGT case '\t': - esc = esc_tab + esc = escTab case '\n': if !escapeNewline { continue } - esc = esc_nl + esc = escNL case '\r': - esc = esc_cr + esc = escCR default: if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { - esc = esc_fffd + esc = escFFFD break } continue @@ -1914,24 +1958,24 @@ func (p *printer) EscapeString(s string) { i += width switch r { case '"': - esc = esc_quot + esc = escQuot case '\'': - esc = esc_apos + esc = escApos case '&': - esc = esc_amp + esc = escAmp case '<': - esc = esc_lt + esc = escLT case '>': - esc = esc_gt + esc = escGT case '\t': - esc = esc_tab + esc = escTab case '\n': - esc = esc_nl + esc = escNL case '\r': - esc = esc_cr + esc = escCR default: if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { - esc = esc_fffd + esc = escFFFD break } continue diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index dad6ed98c1b..7a3511d5832 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -479,15 +479,15 @@ func TestAllScalars(t *testing.T) { } type item struct { - Field_a string + FieldA string } func TestIssue569(t *testing.T) { - data := `abcd` + data := `abcd` var i item err := Unmarshal([]byte(data), &i) - if err != nil || i.Field_a != "abcd" { + if err != nil || i.FieldA != "abcd" { t.Fatal("Expecting abcd") } } @@ -797,3 +797,90 @@ func TestIssue12417(t *testing.T) { } } } + +func tokenMap(mapping func(t Token) Token) func(TokenReader) TokenReader { + return func(src TokenReader) TokenReader { + return mapper{ + t: src, + f: mapping, + } + } +} + +type mapper struct { + t TokenReader + f func(Token) Token +} + +func (m mapper) Token() (Token, error) { + tok, err := m.t.Token() + if err != nil { + return nil, err + } + return m.f(tok), nil +} + +func TestNewTokenDecoderIdempotent(t *testing.T) { + d := NewDecoder(strings.NewReader(`
`)) + d2 := NewTokenDecoder(d) + if d != d2 { + t.Error("NewTokenDecoder did not detect underlying Decoder") + } +} + +func TestWrapDecoder(t *testing.T) { + d := NewDecoder(strings.NewReader(`[Re-enter Clown with a letter, and FABIAN]`)) + m := tokenMap(func(t Token) Token { + switch tok := t.(type) { + case StartElement: + if tok.Name.Local == "quote" { + tok.Name.Local = "blocking" + return tok + } + case EndElement: + if tok.Name.Local == "quote" { + tok.Name.Local = "blocking" + return tok + } + } + return t + }) + + d = NewTokenDecoder(m(d)) + + o := struct { + XMLName Name `xml:"blocking"` + Chardata string `xml:",chardata"` + }{} + + if err := d.Decode(&o); err != nil { + t.Fatal("Got unexpected error while decoding:", err) + } + + if o.Chardata != "[Re-enter Clown with a letter, and FABIAN]" { + t.Fatalf("Got unexpected chardata: `%s`\n", o.Chardata) + } +} + +type tokReader struct{} + +func (tokReader) Token() (Token, error) { + return StartElement{}, nil +} + +type Failure struct{} + +func (Failure) UnmarshalXML(*Decoder, StartElement) error { + return nil +} + +func TestTokenUnmarshaler(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Error("Unexpected panic using custom token unmarshaler") + } + }() + + d := NewTokenDecoder(tokReader{}) + d.Decode(&Failure{}) +} diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go index 64dae70c627..8290e0bd72b 100644 --- a/libgo/go/expvar/expvar.go +++ b/libgo/go/expvar/expvar.go @@ -125,7 +125,17 @@ func (v *Map) String() string { return b.String() } -func (v *Map) Init() *Map { return v } +// Init removes all keys from the map. +func (v *Map) Init() *Map { + v.keysMu.Lock() + defer v.keysMu.Unlock() + v.keys = v.keys[:0] + v.m.Range(func(k, _ interface{}) bool { + v.m.Delete(k) + return true + }) + return v +} // updateKeys updates the sorted list of keys in v.keys. func (v *Map) addKey(key string) { diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go index 7014063d4f7..728e763896c 100644 --- a/libgo/go/expvar/expvar_test.go +++ b/libgo/go/expvar/expvar_test.go @@ -161,6 +161,28 @@ func BenchmarkStringSet(b *testing.B) { }) } +func TestMapInit(t *testing.T) { + RemoveAll() + colors := NewMap("bike-shed-colors") + colors.Add("red", 1) + colors.Add("blue", 1) + colors.Add("chartreuse", 1) + + n := 0 + colors.Do(func(KeyValue) { n++ }) + if n != 3 { + t.Errorf("after three Add calls with distinct keys, Do should invoke f 3 times; got %v", n) + } + + colors.Init() + + n = 0 + colors.Do(func(KeyValue) { n++ }) + if n != 0 { + t.Errorf("after Init, Do should invoke f 0 times; got %v", n) + } +} + func TestMapCounter(t *testing.T) { RemoveAll() colors := NewMap("bike-shed-colors") diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go index edbe83c6648..838cfaf6a4c 100644 --- a/libgo/go/flag/export_test.go +++ b/libgo/go/flag/export_test.go @@ -8,6 +8,8 @@ import "os" // Additional routines compiled into the package only during testing. +var DefaultUsage = Usage + // ResetForTesting clears all flag state and sets the usage function as directed. // After calling ResetForTesting, parse errors in flag handling will not // exit the program. diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go index b166c5753ad..edde5282cf4 100644 --- a/libgo/go/flag/flag.go +++ b/libgo/go/flag/flag.go @@ -43,8 +43,9 @@ The last form is not permitted for boolean flags because the meaning of the command cmd -x * - will change if there is a file called 0, false, etc. You must - use the -flag=false form to turn off a boolean flag. + where * is a Unix shell wildcard, will change if there is a file + called 0, false, etc. You must use the -flag=false form to turn + off a boolean flag. Flag parsing stops just before the first non-flag argument ("-" is a non-flag argument) or after the terminator "--". @@ -71,6 +72,7 @@ import ( "reflect" "sort" "strconv" + "strings" "time" ) @@ -269,7 +271,9 @@ const ( type FlagSet struct { // Usage is the function called when an error occurs while parsing flags. // The field is a function (not a method) that may be changed to point to - // a custom error handler. + // a custom error handler. What happens after Usage is called depends + // on the ErrorHandling setting; for the command line, this defaults + // to ExitOnError, which exits the program after calling Usage. Usage func() name string @@ -305,13 +309,25 @@ func sortFlags(flags map[string]*Flag) []*Flag { return result } -func (f *FlagSet) out() io.Writer { +// Output returns the destination for usage and error messages. os.Stderr is returned if +// output was not set or was set to nil. +func (f *FlagSet) Output() io.Writer { if f.output == nil { return os.Stderr } return f.output } +// Name returns the name of the flag set. +func (f *FlagSet) Name() string { + return f.name +} + +// ErrorHandling returns the error handling behavior of the flag set. +func (f *FlagSet) ErrorHandling() ErrorHandling { + return f.errorHandling +} + // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (f *FlagSet) SetOutput(output io.Writer) { @@ -397,11 +413,7 @@ func isZeroValue(flag *Flag, value string) bool { } switch value { - case "false": - return true - case "": - return true - case "0": + case "false", "", "0": return true } return false @@ -446,9 +458,9 @@ func UnquoteUsage(flag *Flag) (name string, usage string) { return } -// PrintDefaults prints to standard error the default values of all -// defined command-line flags in the set. See the documentation for -// the global function PrintDefaults for more information. +// PrintDefaults prints, to standard error unless configured otherwise, the +// default values of all defined command-line flags in the set. See the +// documentation for the global function PrintDefaults for more information. func (f *FlagSet) PrintDefaults() { f.VisitAll(func(flag *Flag) { s := fmt.Sprintf(" -%s", flag.Name) // Two spaces before -; see next two comments. @@ -465,7 +477,8 @@ func (f *FlagSet) PrintDefaults() { // for both 4- and 8-space tab stops. s += "\n \t" } - s += usage + s += strings.Replace(usage, "\n", "\n \t", -1) + if !isZeroValue(flag, flag.DefValue) { if _, ok := flag.Value.(*stringValue); ok { // put quotes on the value @@ -474,7 +487,7 @@ func (f *FlagSet) PrintDefaults() { s += fmt.Sprintf(" (default %v)", flag.DefValue) } } - fmt.Fprint(f.out(), s, "\n") + fmt.Fprint(f.Output(), s, "\n") }) } @@ -504,9 +517,9 @@ func PrintDefaults() { // defaultUsage is the default function to print a usage message. func (f *FlagSet) defaultUsage() { if f.name == "" { - fmt.Fprintf(f.out(), "Usage:\n") + fmt.Fprintf(f.Output(), "Usage:\n") } else { - fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) + fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name) } f.PrintDefaults() } @@ -515,13 +528,17 @@ func (f *FlagSet) defaultUsage() { // because it serves (via godoc flag Usage) as the example // for how to write your own usage function. -// Usage prints to standard error a usage message documenting all defined command-line flags. +// Usage prints a usage message documenting all defined command-line flags +// to CommandLine's output, which by default is os.Stderr. // It is called when an error occurs while parsing flags. // The function is a variable that may be changed to point to a custom function. // By default it prints a simple header and calls PrintDefaults; for details about the // format of the output and how to control it, see the documentation for PrintDefaults. +// Custom usage functions may choose to exit the program; by default exiting +// happens anyway as the command line's error handling strategy is set to +// ExitOnError. var Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) + fmt.Fprintf(CommandLine.Output(), "Usage of %s:\n", os.Args[0]) PrintDefaults() } @@ -645,13 +662,13 @@ func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { } // UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. +// The argument p points to a uint variable in which to store the value of the flag. func UintVar(p *uint, name string, value uint, usage string) { CommandLine.Var(newUintValue(value, p), name, usage) } // Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. +// The return value is the address of a uint variable that stores the value of the flag. func (f *FlagSet) Uint(name string, value uint, usage string) *uint { p := new(uint) f.UintVar(p, name, value, usage) @@ -659,7 +676,7 @@ func (f *FlagSet) Uint(name string, value uint, usage string) *uint { } // Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. +// The return value is the address of a uint variable that stores the value of the flag. func Uint(name string, value uint, usage string) *uint { return CommandLine.Uint(name, value, usage) } @@ -789,7 +806,7 @@ func (f *FlagSet) Var(value Value, name string, usage string) { } else { msg = fmt.Sprintf("%s flag redefined: %s", f.name, name) } - fmt.Fprintln(f.out(), msg) + fmt.Fprintln(f.Output(), msg) panic(msg) // Happens only if flags are declared with identical names } if f.formal == nil { @@ -812,7 +829,7 @@ func Var(value Value, name string, usage string) { // returns the error. func (f *FlagSet) failf(format string, a ...interface{}) error { err := fmt.Errorf(format, a...) - fmt.Fprintln(f.out(), err) + fmt.Fprintln(f.Output(), err) f.usage() return err } @@ -833,7 +850,7 @@ func (f *FlagSet) parseOne() (bool, error) { return false, nil } s := f.args[0] - if len(s) == 0 || s[0] != '-' || len(s) == 1 { + if len(s) < 2 || s[0] != '-' { return false, nil } numMinuses := 1 @@ -934,7 +951,7 @@ func (f *FlagSet) Parsed() bool { return f.parsed } -// Parse parses the command-line flags from os.Args[1:]. Must be called +// Parse parses the command-line flags from os.Args[1:]. Must be called // after all flags are defined and before flags are accessed by the program. func Parse() { // Ignore errors; CommandLine is set for ExitOnError. diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go index 02da2c77506..67c409f29ba 100644 --- a/libgo/go/flag/flag_test.go +++ b/libgo/go/flag/flag_test.go @@ -8,6 +8,7 @@ import ( "bytes" . "flag" "fmt" + "io" "os" "sort" "strconv" @@ -389,8 +390,14 @@ const defaultOutput = ` -A for bootstrapping, allow 'any' type a non-zero number (default 2.7) -G float a float that defaults to zero + -M string + a multiline + help + string -N int a non-zero int (default 27) + -O a flag + multiline help string (default true) -Z int an int that defaults to zero -maxT timeout @@ -407,7 +414,9 @@ func TestPrintDefaults(t *testing.T) { fs.String("D", "", "set relative `path` for local imports") fs.Float64("F", 2.7, "a non-zero `number`") fs.Float64("G", 0, "a float that defaults to zero") + fs.String("M", "", "a multiline\nhelp\nstring") fs.Int("N", 27, "a non-zero int") + fs.Bool("O", true, "a flag\nmultiline help string") fs.Int("Z", 0, "an int that defaults to zero") fs.Duration("maxT", 0, "set `timeout` for dial") fs.PrintDefaults() @@ -432,3 +441,50 @@ func TestIntFlagOverflow(t *testing.T) { t.Error("unexpected success setting Uint") } } + +// Issue 20998: Usage should respect CommandLine.output. +func TestUsageOutput(t *testing.T) { + ResetForTesting(DefaultUsage) + var buf bytes.Buffer + CommandLine.SetOutput(&buf) + defer func(old []string) { os.Args = old }(os.Args) + os.Args = []string{"app", "-i=1", "-unknown"} + Parse() + const want = "flag provided but not defined: -i\nUsage of app:\n" + if got := buf.String(); got != want { + t.Errorf("output = %q; want %q", got, want) + } +} + +func TestGetters(t *testing.T) { + expectedName := "flag set" + expectedErrorHandling := ContinueOnError + expectedOutput := io.Writer(os.Stderr) + fs := NewFlagSet(expectedName, expectedErrorHandling) + + if fs.Name() != expectedName { + t.Errorf("unexpected name: got %s, expected %s", fs.Name(), expectedName) + } + if fs.ErrorHandling() != expectedErrorHandling { + t.Errorf("unexpected ErrorHandling: got %d, expected %d", fs.ErrorHandling(), expectedErrorHandling) + } + if fs.Output() != expectedOutput { + t.Errorf("unexpected output: got %#v, expected %#v", fs.Output(), expectedOutput) + } + + expectedName = "gopher" + expectedErrorHandling = ExitOnError + expectedOutput = os.Stdout + fs.Init(expectedName, expectedErrorHandling) + fs.SetOutput(expectedOutput) + + if fs.Name() != expectedName { + t.Errorf("unexpected name: got %s, expected %s", fs.Name(), expectedName) + } + if fs.ErrorHandling() != expectedErrorHandling { + t.Errorf("unexpected ErrorHandling: got %d, expected %d", fs.ErrorHandling(), expectedErrorHandling) + } + if fs.Output() != expectedOutput { + t.Errorf("unexpected output: got %v, expected %v", fs.Output(), expectedOutput) + } +} diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index 014ba06948d..375cdb4266d 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -47,6 +47,8 @@ %X base 16, upper-case, two characters per byte Pointer: %p base 16 notation, with leading 0x + The %b, %d, %o, %x and %X verbs also work with pointers, + formatting the value exactly as if it were an integer. The default format for %v is: bool: %t @@ -79,7 +81,8 @@ that is, runes. (This differs from C's printf where the units are always measured in bytes.) Either or both of the flags may be replaced with the character '*', causing their values to be - obtained from the next operand, which must be of type int. + obtained from the next operand (preceding the one to format), + which must be of type int. For most values, width is the minimum number of runes to output, padding the formatted form with spaces if necessary. diff --git a/libgo/go/fmt/example_test.go b/libgo/go/fmt/example_test.go new file mode 100644 index 00000000000..aa3cd05e3ef --- /dev/null +++ b/libgo/go/fmt/example_test.go @@ -0,0 +1,31 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package fmt_test + +import ( + "fmt" +) + +// Animal has a Name and an Age to represent an animal. +type Animal struct { + Name string + Age uint +} + +// String makes Animal satisfy the Stringer interface. +func (a Animal) String() string { + return fmt.Sprintf("%v (%d)", a.Name, a.Age) +} + +func ExampleStringer() { + a := Animal{ + Name: "Gopher", + Age: 2, + } + fmt.Println(a) + // Output: Gopher (2) +} diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index 9e6fcfa7016..b56b84fd9c0 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -131,6 +131,19 @@ func (byteFormatter) Format(f State, _ rune) { var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'} +// Copy of io.stringWriter interface used by writeStringFormatter for type assertion. +type stringWriter interface { + WriteString(s string) (n int, err error) +} + +type writeStringFormatter string + +func (sf writeStringFormatter) Format(f State, c rune) { + if sw, ok := f.(stringWriter); ok { + sw.WriteString("***" + string(sf) + "***") + } +} + var fmtTests = []struct { fmt string val interface{} @@ -977,6 +990,11 @@ var fmtTests = []struct { // This next case seems wrong, but the docs say the Formatter wins here. {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X, X}"}, + // pp.WriteString + {"%s", writeStringFormatter(""), "******"}, + {"%s", writeStringFormatter("xyz"), "***xyz***"}, + {"%s", writeStringFormatter("⌘/⌘"), "***⌘/⌘***"}, + // reflect.Value handled specially in Go 1.5, making it possible to // see inside non-exported fields (which cannot be accessed with Interface()). // Issue 8965. @@ -1201,6 +1219,14 @@ func BenchmarkSprintfTruncateString(b *testing.B) { }) } +func BenchmarkSprintfSlowParsingPath(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%.v", nil) + } + }) +} + func BenchmarkSprintfQuoteString(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { @@ -1709,12 +1735,14 @@ func TestIsSpace(t *testing.T) { } } +func hideFromVet(s string) string { return s } + func TestNilDoesNotBecomeTyped(t *testing.T) { type A struct{} type B struct{} var a *A = nil var b B = B{} - got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line. + got := Sprintf(hideFromVet("%s %s %s %s %s"), nil, a, nil, b, nil) const expect = "%!s() %!s(*fmt_test.A=) %!s() {} %!s()" if got != expect { t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 2bd88f95a2b..98c156a1217 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -172,6 +172,13 @@ func (p *pp) Write(b []byte) (ret int, err error) { return len(b), nil } +// Implement WriteString so that we can call io.WriteString +// on a pp (through state), for efficiency. +func (p *pp) WriteString(s string) (ret int, err error) { + p.buf.WriteString(s) + return len(s), nil +} + // These routines end in 'f' and take a format string. // Fprintf formats according to a format specifier and writes to w. @@ -837,7 +844,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { p.buf.WriteByte(']') } case reflect.Ptr: - // pointer to array or slice or struct? ok at top level + // pointer to array or slice or struct? ok at top level // but not embedded (avoid loops) if depth == 0 && f.Pointer() != 0 { switch a := f.Elem(); a.Kind() { @@ -1067,8 +1074,11 @@ formatLoop: break } - verb, w := utf8.DecodeRuneInString(format[i:]) - i += w + verb, size := rune(format[i]), 1 + if verb >= utf8.RuneSelf { + verb, size = utf8.DecodeRuneInString(format[i:]) + } + i += size switch { case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec. diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go index cd7232c33c4..ae79e39deea 100644 --- a/libgo/go/fmt/scan.go +++ b/libgo/go/fmt/scan.go @@ -298,13 +298,6 @@ func notSpace(r rune) bool { return !isSpace(r) } -// SkipSpace provides Scan methods the ability to skip space and newline -// characters in keeping with the current scanning mode set by format strings -// and Scan/Scanln. -func (s *ss) SkipSpace() { - s.skipSpace(false) -} - // readRune is a structure to enable reading UTF-8 encoded code points // from an io.Reader. It is used if the Reader given to the scanner does // not already implement io.RuneScanner. @@ -421,8 +414,10 @@ func (s *ss) free(old ssave) { ssFree.Put(s) } -// skipSpace skips spaces and maybe newlines. -func (s *ss) skipSpace(stopAtNewline bool) { +// SkipSpace provides Scan methods the ability to skip space and newline +// characters in keeping with the current scanning mode set by format strings +// and Scan/Scanln. +func (s *ss) SkipSpace() { for { r := s.getRune() if r == eof { @@ -432,9 +427,6 @@ func (s *ss) skipSpace(stopAtNewline bool) { continue } if r == '\n' { - if stopAtNewline { - break - } if s.nlIsSpace { continue } @@ -453,7 +445,7 @@ func (s *ss) skipSpace(stopAtNewline bool) { // newlines are treated as spaces. func (s *ss) token(skipSpace bool, f func(rune) bool) []byte { if skipSpace { - s.skipSpace(false) + s.SkipSpace() } // read until white space or newline for { @@ -537,7 +529,7 @@ func (s *ss) okVerb(verb rune, okVerbs, typ string) bool { // scanBool returns the value of the boolean represented by the next token. func (s *ss) scanBool(verb rune) bool { - s.skipSpace(false) + s.SkipSpace() s.notEOF() if !s.okVerb(verb, "tv", "boolean") { return false @@ -641,7 +633,7 @@ func (s *ss) scanInt(verb rune, bitSize int) int64 { if verb == 'c' { return s.scanRune(bitSize) } - s.skipSpace(false) + s.SkipSpace() s.notEOF() base, digits := s.getBase(verb) haveDigits := false @@ -674,7 +666,7 @@ func (s *ss) scanUint(verb rune, bitSize int) uint64 { if verb == 'c' { return uint64(s.scanRune(bitSize)) } - s.skipSpace(false) + s.SkipSpace() s.notEOF() base, digits := s.getBase(verb) haveDigits := false @@ -795,7 +787,7 @@ func (s *ss) scanComplex(verb rune, n int) complex128 { if !s.okVerb(verb, floatVerbs, "complex") { return 0 } - s.skipSpace(false) + s.SkipSpace() s.notEOF() sreal, simag := s.complexTokens() real := s.convertFloat(sreal, n/2) @@ -809,7 +801,7 @@ func (s *ss) convertString(verb rune) (str string) { if !s.okVerb(verb, "svqxX", "string") { return "" } - s.skipSpace(false) + s.SkipSpace() s.notEOF() switch verb { case 'q': @@ -973,13 +965,13 @@ func (s *ss) scanOne(verb rune, arg interface{}) { // scan in high precision and convert, in order to preserve the correct error condition. case *float32: if s.okVerb(verb, floatVerbs, "float32") { - s.skipSpace(false) + s.SkipSpace() s.notEOF() *v = float32(s.convertFloat(s.floatToken(), 32)) } case *float64: if s.okVerb(verb, floatVerbs, "float64") { - s.skipSpace(false) + s.SkipSpace() s.notEOF() *v = s.convertFloat(s.floatToken(), 64) } @@ -1017,7 +1009,7 @@ func (s *ss) scanOne(verb rune, arg interface{}) { v.Index(i).SetUint(uint64(str[i])) } case reflect.Float32, reflect.Float64: - s.skipSpace(false) + s.SkipSpace() s.notEOF() v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits())) case reflect.Complex64, reflect.Complex128: diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go index 9ab7b1e6256..c07dd5a91ee 100644 --- a/libgo/go/go/ast/ast.go +++ b/libgo/go/go/ast/ast.go @@ -356,8 +356,8 @@ type ( } ) -// The direction of a channel type is indicated by one -// of the following constants. +// The direction of a channel type is indicated by a bit +// mask including one or both of the following constants. // type ChanDir int diff --git a/libgo/go/go/ast/import.go b/libgo/go/go/ast/import.go index 6b27fe822e5..be23c7fc432 100644 --- a/libgo/go/go/ast/import.go +++ b/libgo/go/go/ast/import.go @@ -123,14 +123,14 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { comments := f.Comments[cstart:cend] // Assign each comment to the import spec preceding it. - importComment := map[*ImportSpec][]*CommentGroup{} + importComments := map[*ImportSpec][]*CommentGroup{} specIndex := 0 for _, g := range comments { for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { specIndex++ } s := specs[specIndex].(*ImportSpec) - importComment[s] = append(importComment[s], g) + importComments[s] = append(importComments[s], g) } // Sort the import specs by import path. @@ -138,7 +138,19 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { // Reassign the import paths to have the same position sequence. // Reassign each comment to abut the end of its spec. // Sort the comments by new position. - sort.Sort(byImportSpec(specs)) + sort.Slice(specs, func(i, j int) bool { + ipath := importPath(specs[i]) + jpath := importPath(specs[j]) + if ipath != jpath { + return ipath < jpath + } + iname := importName(specs[i]) + jname := importName(specs[j]) + if iname != jname { + return iname < jname + } + return importComment(specs[i]) < importComment(specs[j]) + }) // Dedup. Thanks to our sorting, we can just consider // adjacent pairs of imports. @@ -161,38 +173,16 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { } s.Path.ValuePos = pos[i].Start s.EndPos = pos[i].End - for _, g := range importComment[s] { + for _, g := range importComments[s] { for _, c := range g.List { c.Slash = pos[i].End } } } - sort.Sort(byCommentPos(comments)) + sort.Slice(comments, func(i, j int) bool { + return comments[i].Pos() < comments[j].Pos() + }) return specs } - -type byImportSpec []Spec // slice of *ImportSpec - -func (x byImportSpec) Len() int { return len(x) } -func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byImportSpec) Less(i, j int) bool { - ipath := importPath(x[i]) - jpath := importPath(x[j]) - if ipath != jpath { - return ipath < jpath - } - iname := importName(x[i]) - jname := importName(x[j]) - if iname != jname { - return iname < jname - } - return importComment(x[i]) < importComment(x[j]) -} - -type byCommentPos []*CommentGroup - -func (x byCommentPos) Len() int { return len(x) } -func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index 5aa32d0ae44..79024042136 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -292,7 +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". // NOTE: If you add to this list, also update the doc comment in doc.go. - c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.9"} + const version = 10 // go1.10 + for i := 1; i <= version; i++ { + c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i)) + } env := os.Getenv("CGO_ENABLED") // No defaultCGO_ENABLED in gccgo. @@ -543,6 +546,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa p.Goroot = true p.ImportPath = sub p.Root = ctxt.GOROOT + setPkga() // p.ImportPath changed goto Found } } @@ -570,6 +574,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa // Record it. p.ImportPath = sub p.Root = root + setPkga() // p.ImportPath changed goto Found } } @@ -1197,25 +1202,26 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binary p = p[len(p):] } line = bytes.TrimSpace(line) - if bytes.HasPrefix(line, slashslash) { - if bytes.Equal(line, binaryOnlyComment) { - sawBinaryOnly = true - } - line = bytes.TrimSpace(line[len(slashslash):]) - if len(line) > 0 && line[0] == '+' { - // Looks like a comment +line. - f := strings.Fields(string(line)) - if f[0] == "+build" { - ok := false - for _, tok := range f[1:] { - if ctxt.match(tok, allTags) { - ok = true - } - } - if !ok { - allok = false + if !bytes.HasPrefix(line, slashslash) { + continue + } + if bytes.Equal(line, binaryOnlyComment) { + sawBinaryOnly = true + } + line = bytes.TrimSpace(line[len(slashslash):]) + if len(line) > 0 && line[0] == '+' { + // Looks like a comment +line. + f := strings.Fields(string(line)) + if f[0] == "+build" { + ok := false + for _, tok := range f[1:] { + if ctxt.match(tok, allTags) { + ok = true } } + if !ok { + allok = false + } } } } diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go index 38e2e8ad881..87d8d0445e8 100644 --- a/libgo/go/go/build/build_test.go +++ b/libgo/go/go/build/build_test.go @@ -384,3 +384,16 @@ func TestImportVendorParentFailure(t *testing.T) { t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e) } } + +func TestImportDirTarget(t *testing.T) { + testenv.MustHaveGoBuild(t) // really must just have source + ctxt := Default + ctxt.GOPATH = "" + p, err := ctxt.ImportDir(filepath.Join(ctxt.GOROOT, "src/path"), 0) + if err != nil { + t.Fatal(err) + } + if p.PkgTargetRoot == "" || p.PkgObj == "" { + t.Errorf("p.PkgTargetRoot == %q, p.PkgObj == %q, want non-empty", p.PkgTargetRoot, p.PkgObj) + } +} diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go index 655c37c52a4..3c7f8db106c 100644 --- a/libgo/go/go/build/deps_test.go +++ b/libgo/go/go/build/deps_test.go @@ -35,7 +35,7 @@ import ( var pkgDeps = map[string][]string{ // L0 is the lowest level, core, nearly unavoidable packages. "errors": {}, - "io": {"errors", "sync"}, + "io": {"errors", "sync", "sync/atomic"}, "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys"}, "runtime/internal/sys": {}, "runtime/internal/atomic": {"unsafe", "runtime/internal/sys"}, @@ -101,7 +101,7 @@ var pkgDeps = map[string][]string{ "crypto/cipher": {"L2", "crypto/subtle"}, "crypto/subtle": {}, "encoding/base32": {"L2"}, - "encoding/base64": {"L2"}, + "encoding/base64": {"L2", "encoding/binary"}, "encoding/binary": {"L2", "reflect"}, "hash": {"L2"}, // interfaces "hash/adler32": {"L2", "hash"}, @@ -154,9 +154,9 @@ var pkgDeps = map[string][]string{ "syscall", }, - "internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8"}, + "internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"}, "os": {"L1", "os", "syscall", "time", "internal/poll", "internal/syscall/windows"}, - "path/filepath": {"L2", "os", "syscall"}, + "path/filepath": {"L2", "os", "syscall", "internal/syscall/windows"}, "io/ioutil": {"L2", "os", "path/filepath", "time"}, "os/exec": {"L2", "os", "context", "path/filepath", "syscall"}, "os/signal": {"L2", "os", "syscall"}, @@ -226,7 +226,7 @@ var pkgDeps = map[string][]string{ "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, // One of a kind. - "archive/tar": {"L4", "OS", "syscall"}, + "archive/tar": {"L4", "OS", "syscall", "os/user"}, "archive/zip": {"L4", "OS", "compress/flate"}, "container/heap": {"sort"}, "compress/bzip2": {"L4"}, @@ -267,7 +267,7 @@ var pkgDeps = map[string][]string{ "math/big": {"L4"}, "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, "mime/quotedprintable": {"L4"}, - "net/internal/socktest": {"L4", "OS", "syscall"}, + "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, "net/url": {"L4"}, "plugin": {"L0", "OS", "CGO"}, "runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"}, @@ -300,6 +300,9 @@ var pkgDeps = map[string][]string{ // Plan 9 alone needs io/ioutil and os. "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"}, + // Internal package used only for testing. + "os/signal/internal/pty": {"CGO", "fmt", "os"}, + // Basic networking. // Because net must be used by any package that wants to // do networking portably, it must have a small dependency set: just L0+basic os. @@ -378,9 +381,10 @@ var pkgDeps = map[string][]string{ }, "crypto/x509": { "L4", "CRYPTO-MATH", "OS", "CGO", - "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall", + "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall", "net/url", + "golang_org/x/crypto/cryptobyte", "golang_org/x/crypto/cryptobyte/asn1", }, - "crypto/x509/pkix": {"L4", "CRYPTO-MATH"}, + "crypto/x509/pkix": {"L4", "CRYPTO-MATH", "encoding/hex"}, // Simple net+crypto-aware packages. "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"}, diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go index 422e1a5ffd2..daa9a756714 100644 --- a/libgo/go/go/build/doc.go +++ b/libgo/go/go/build/doc.go @@ -106,6 +106,7 @@ // - "go1.7", from Go version 1.7 onward // - "go1.8", from Go version 1.8 onward // - "go1.9", from Go version 1.9 onward +// - "go1.10", from Go version 1.10 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/libgo/go/go/constant/value.go b/libgo/go/go/constant/value.go index 5474e73e24b..513151a38fd 100644 --- a/libgo/go/go/constant/value.go +++ b/libgo/go/go/constant/value.go @@ -10,7 +10,7 @@ // values produce unknown values unless specified // otherwise. // -package constant // import "go/constant" +package constant import ( "fmt" diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go index bbf8096ce29..a89f29b40f4 100644 --- a/libgo/go/go/doc/example.go +++ b/libgo/go/go/doc/example.go @@ -94,7 +94,10 @@ func Examples(files ...*ast.File) []*Example { } list = append(list, flist...) } - sort.Sort(exampleByName(list)) + // sort by name + sort.Slice(list, func(i, j int) bool { + return list[i].Name < list[j].Name + }) return list } @@ -135,12 +138,6 @@ func isTest(name, prefix string) bool { return !unicode.IsLower(rune) } -type exampleByName []*Example - -func (s exampleByName) Len() int { return len(s) } -func (s exampleByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s exampleByName) Less(i, j int) bool { return s[i].Name < s[j].Name } - // playExample synthesizes a new *ast.File based on the provided // file with the provided function body as the body of main. func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go index da9ea1f027d..40cbb22797e 100644 --- a/libgo/go/go/doc/exports.go +++ b/libgo/go/go/doc/exports.go @@ -200,7 +200,7 @@ func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec { var prevType ast.Expr for _, spec := range list { spec := spec.(*ast.ValueSpec) - if spec.Type == nil && prevType != nil { + if spec.Type == nil && len(spec.Values) == 0 && prevType != nil { // provide current spec with an explicit type spec.Type = copyConstType(prevType, spec.Pos()) } diff --git a/libgo/go/go/doc/reader.go b/libgo/go/go/doc/reader.go index 8e823538689..140f5872336 100644 --- a/libgo/go/go/doc/reader.go +++ b/libgo/go/go/doc/reader.go @@ -154,6 +154,7 @@ type reader struct { imports map[string]int hasDotImp bool // if set, package contains a dot import values []*Value // consts and vars + order int // sort order of const and var declarations (when we can't use a name) types map[string]*namedType funcs methodSet @@ -256,11 +257,9 @@ func (r *reader) readValue(decl *ast.GenDecl) { if n, imp := baseTypeName(s.Type); !imp { name = n } - case decl.Tok == token.CONST: - // no type is present but we have a constant declaration; - // use the previous type name (w/o more type information - // we cannot handle the case of unnamed variables with - // initializer expressions except for some trivial cases) + case decl.Tok == token.CONST && len(s.Values) == 0: + // no type or value is present but we have a constant declaration; + // use the previous type name (possibly the empty string) name = prev } if name != "" { @@ -297,9 +296,15 @@ func (r *reader) readValue(decl *ast.GenDecl) { Doc: decl.Doc.Text(), Names: specNames(decl.Specs), Decl: decl, - order: len(*values), + order: r.order, }) decl.Doc = nil // doc consumed - remove from AST + + // Note: It's important that the order used here is global because the cleanupTypes + // methods may move values associated with types back into the global list. If the + // order is list-specific, sorting is not deterministic because the same order value + // may appear multiple times (was bug, found when fixing #16153). + r.order++ } // fields returns a struct's fields or an interface's methods. @@ -391,7 +396,13 @@ func (r *reader) readFunc(fun *ast.FuncDecl) { // exactly one (named or anonymous) result associated // with the first type in result signature (there may // be more than one result) - if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) { + factoryType := res.Type + if t, ok := factoryType.(*ast.ArrayType); ok && t.Len == nil { + // We consider functions that return slices of type T (or + // pointers to T) as factory functions of T. + factoryType = t.Elt + } + if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) { if typ := r.lookupType(n); typ != nil { // associate function with typ typ.funcs.set(fun) diff --git a/libgo/go/go/doc/testdata/blank.0.golden b/libgo/go/go/doc/testdata/blank.0.golden index c2987cf140e..70f2929f8a6 100644 --- a/libgo/go/go/doc/testdata/blank.0.golden +++ b/libgo/go/go/doc/testdata/blank.0.golden @@ -21,11 +21,18 @@ CONSTANTS C4 int ) - // Constants with an imported type that needs to be propagated. + // Constants with a single type that is not propagated. const ( - Default os.FileMode = 0644 - Useless = 0312 - WideOpen = 0777 + Default = 0644 + Useless = 0312 + WideOpen = 0777 + ) + + // Constants with an imported type that is propagated. + const ( + M1 os.FileMode + M2 + M3 ) // Package constants. diff --git a/libgo/go/go/doc/testdata/blank.1.golden b/libgo/go/go/doc/testdata/blank.1.golden index ee5054a4ed6..8098cb6e885 100644 --- a/libgo/go/go/doc/testdata/blank.1.golden +++ b/libgo/go/go/doc/testdata/blank.1.golden @@ -23,14 +23,7 @@ CONSTANTS C4 ) - // Package constants. - const ( - _ int = iota - I1 - I2 - ) - - // Constants with an imported type that needs to be propagated. + // Constants with a single type that is not propagated. const ( zero os.FileMode = 0 Default = 0644 @@ -38,6 +31,21 @@ CONSTANTS WideOpen = 0777 ) + // Constants with an imported type that is propagated. + const ( + zero os.FileMode = 0 + M1 + M2 + M3 + ) + + // Package constants. + const ( + _ int = iota + I1 + I2 + ) + // Unexported constants counting from blank iota. See issue 9615. const ( _ = iota diff --git a/libgo/go/go/doc/testdata/blank.2.golden b/libgo/go/go/doc/testdata/blank.2.golden index c2987cf140e..70f2929f8a6 100644 --- a/libgo/go/go/doc/testdata/blank.2.golden +++ b/libgo/go/go/doc/testdata/blank.2.golden @@ -21,11 +21,18 @@ CONSTANTS C4 int ) - // Constants with an imported type that needs to be propagated. + // Constants with a single type that is not propagated. const ( - Default os.FileMode = 0644 - Useless = 0312 - WideOpen = 0777 + Default = 0644 + Useless = 0312 + WideOpen = 0777 + ) + + // Constants with an imported type that is propagated. + const ( + M1 os.FileMode + M2 + M3 ) // Package constants. diff --git a/libgo/go/go/doc/testdata/blank.go b/libgo/go/go/doc/testdata/blank.go index 419a78f7d51..5ea6186935a 100644 --- a/libgo/go/go/doc/testdata/blank.go +++ b/libgo/go/go/doc/testdata/blank.go @@ -29,7 +29,7 @@ const ( C4 ) -// Constants with an imported type that needs to be propagated. +// Constants with a single type that is not propagated. const ( zero os.FileMode = 0 Default = 0644 @@ -37,6 +37,14 @@ const ( WideOpen = 0777 ) +// Constants with an imported type that is propagated. +const ( + zero os.FileMode = 0 + M1 + M2 + M3 +) + // Package constants. const ( _ int = iota diff --git a/libgo/go/go/doc/testdata/issue16153.0.golden b/libgo/go/go/doc/testdata/issue16153.0.golden new file mode 100644 index 00000000000..189260b4d09 --- /dev/null +++ b/libgo/go/go/doc/testdata/issue16153.0.golden @@ -0,0 +1,32 @@ +// +PACKAGE issue16153 + +IMPORTPATH + testdata/issue16153 + +FILENAMES + testdata/issue16153.go + +CONSTANTS + // + const ( + X3 int64 = iota + Y3 = 1 + ) + + // + const ( + X4 int64 = iota + Y4 + ) + + // original test case + const ( + Y1 = 256 + ) + + // variations + const ( + Y2 uint8 + ) + diff --git a/libgo/go/go/doc/testdata/issue16153.1.golden b/libgo/go/go/doc/testdata/issue16153.1.golden new file mode 100644 index 00000000000..803df3e7090 --- /dev/null +++ b/libgo/go/go/doc/testdata/issue16153.1.golden @@ -0,0 +1,34 @@ +// +PACKAGE issue16153 + +IMPORTPATH + testdata/issue16153 + +FILENAMES + testdata/issue16153.go + +CONSTANTS + // original test case + const ( + x1 uint8 = 255 + Y1 = 256 + ) + + // variations + const ( + x2 uint8 = 255 + Y2 + ) + + // + const ( + X3 int64 = iota + Y3 = 1 + ) + + // + const ( + X4 int64 = iota + Y4 + ) + diff --git a/libgo/go/go/doc/testdata/issue16153.2.golden b/libgo/go/go/doc/testdata/issue16153.2.golden new file mode 100644 index 00000000000..189260b4d09 --- /dev/null +++ b/libgo/go/go/doc/testdata/issue16153.2.golden @@ -0,0 +1,32 @@ +// +PACKAGE issue16153 + +IMPORTPATH + testdata/issue16153 + +FILENAMES + testdata/issue16153.go + +CONSTANTS + // + const ( + X3 int64 = iota + Y3 = 1 + ) + + // + const ( + X4 int64 = iota + Y4 + ) + + // original test case + const ( + Y1 = 256 + ) + + // variations + const ( + Y2 uint8 + ) + diff --git a/libgo/go/go/doc/testdata/issue16153.go b/libgo/go/go/doc/testdata/issue16153.go new file mode 100644 index 00000000000..528be423560 --- /dev/null +++ b/libgo/go/go/doc/testdata/issue16153.go @@ -0,0 +1,27 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue16153 + +// original test case +const ( + x1 uint8 = 255 + Y1 = 256 +) + +// variations +const ( + x2 uint8 = 255 + Y2 +) + +const ( + X3 int64 = iota + Y3 = 1 +) + +const ( + X4 int64 = iota + Y4 +) diff --git a/libgo/go/go/doc/testdata/issue18063.0.golden b/libgo/go/go/doc/testdata/issue18063.0.golden new file mode 100644 index 00000000000..0afbc169c2c --- /dev/null +++ b/libgo/go/go/doc/testdata/issue18063.0.golden @@ -0,0 +1,45 @@ +// +PACKAGE issue18063 + +IMPORTPATH + testdata/issue18063 + +FILENAMES + testdata/issue18063.go + +FUNCTIONS + // NewArray is not a factory function because arrays of type T are ... + func NewArray() [1]T + + // NewPointerArray is not a factory function because arrays of ... + func NewPointerArray() [1]*T + + // NewPointerSliceOfSlice is not a factory function because slices ... + func NewPointerSliceOfSlice() [][]*T + + // NewSlice3 is not a factory function because 3 nested slices of ... + func NewSlice3() [][][]T + + // NewSliceOfSlice is not a factory function because slices of a ... + func NewSliceOfSlice() [][]T + + +TYPES + // + type T struct{} + + // + func New() T + + // + func NewPointer() *T + + // + func NewPointerOfPointer() **T + + // + func NewPointerSlice() []*T + + // + func NewSlice() []T + diff --git a/libgo/go/go/doc/testdata/issue18063.1.golden b/libgo/go/go/doc/testdata/issue18063.1.golden new file mode 100644 index 00000000000..0afbc169c2c --- /dev/null +++ b/libgo/go/go/doc/testdata/issue18063.1.golden @@ -0,0 +1,45 @@ +// +PACKAGE issue18063 + +IMPORTPATH + testdata/issue18063 + +FILENAMES + testdata/issue18063.go + +FUNCTIONS + // NewArray is not a factory function because arrays of type T are ... + func NewArray() [1]T + + // NewPointerArray is not a factory function because arrays of ... + func NewPointerArray() [1]*T + + // NewPointerSliceOfSlice is not a factory function because slices ... + func NewPointerSliceOfSlice() [][]*T + + // NewSlice3 is not a factory function because 3 nested slices of ... + func NewSlice3() [][][]T + + // NewSliceOfSlice is not a factory function because slices of a ... + func NewSliceOfSlice() [][]T + + +TYPES + // + type T struct{} + + // + func New() T + + // + func NewPointer() *T + + // + func NewPointerOfPointer() **T + + // + func NewPointerSlice() []*T + + // + func NewSlice() []T + diff --git a/libgo/go/go/doc/testdata/issue18063.2.golden b/libgo/go/go/doc/testdata/issue18063.2.golden new file mode 100644 index 00000000000..0afbc169c2c --- /dev/null +++ b/libgo/go/go/doc/testdata/issue18063.2.golden @@ -0,0 +1,45 @@ +// +PACKAGE issue18063 + +IMPORTPATH + testdata/issue18063 + +FILENAMES + testdata/issue18063.go + +FUNCTIONS + // NewArray is not a factory function because arrays of type T are ... + func NewArray() [1]T + + // NewPointerArray is not a factory function because arrays of ... + func NewPointerArray() [1]*T + + // NewPointerSliceOfSlice is not a factory function because slices ... + func NewPointerSliceOfSlice() [][]*T + + // NewSlice3 is not a factory function because 3 nested slices of ... + func NewSlice3() [][][]T + + // NewSliceOfSlice is not a factory function because slices of a ... + func NewSliceOfSlice() [][]T + + +TYPES + // + type T struct{} + + // + func New() T + + // + func NewPointer() *T + + // + func NewPointerOfPointer() **T + + // + func NewPointerSlice() []*T + + // + func NewSlice() []T + diff --git a/libgo/go/go/doc/testdata/issue18063.go b/libgo/go/go/doc/testdata/issue18063.go new file mode 100644 index 00000000000..1193af51e7c --- /dev/null +++ b/libgo/go/go/doc/testdata/issue18063.go @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue18063 + +type T struct{} + +func New() T { return T{} } +func NewPointer() *T { return &T{} } +func NewPointerSlice() []*T { return []*T{&T{}} } +func NewSlice() []T { return []T{T{}} } +func NewPointerOfPointer() **T { x := &T{}; return &x } + +// NewArray is not a factory function because arrays of type T are not +// factory functions of type T. +func NewArray() [1]T { return [1]T{T{}} } + +// NewPointerArray is not a factory function because arrays of type *T are not +// factory functions of type T. +func NewPointerArray() [1]*T { return [1]*T{&T{}} } + +// NewSliceOfSlice is not a factory function because slices of a slice of +// type *T are not factory functions of type T. +func NewSliceOfSlice() [][]T { return []T{[]T{}} } + +// NewPointerSliceOfSlice is not a factory function because slices of a +// slice of type *T are not factory functions of type T. +func NewPointerSliceOfSlice() [][]*T { return []*T{[]*T{}} } + +// NewSlice3 is not a factory function because 3 nested slices of type T +// are not factory functions of type T. +func NewSlice3() [][][]T { return []T{[]T{[]T{}}} } diff --git a/libgo/go/go/format/format.go b/libgo/go/go/format/format.go index b9cacfebd80..cad5958e5c5 100644 --- a/libgo/go/go/format/format.go +++ b/libgo/go/go/format/format.go @@ -24,8 +24,8 @@ const parserMode = parser.ParseComments // The node type must be *ast.File, *printer.CommentedNode, []ast.Decl, // []ast.Stmt, or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, // or ast.Stmt. Node does not modify node. Imports are not sorted for -// nodes representing partial source files (i.e., if the node is not an -// *ast.File or a *printer.CommentedNode not wrapping an *ast.File). +// nodes representing partial source files (for instance, if the node is +// not an *ast.File or a *printer.CommentedNode not wrapping an *ast.File). // // The function may return early (before the entire result is written) // and return a formatting error, for instance due to an incorrect AST. @@ -79,6 +79,10 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { // space as src), and the result is indented by the same amount as the first // line of src containing code. Imports are not sorted for partial source files. // +// Caution: Tools relying on consistent formatting based on the installed +// version of gofmt (for instance, such as for presubmit checks) should +// execute that gofmt binary instead of calling Source. +// func Source(src []byte) ([]byte, error) { fset := token.NewFileSet() file, sourceAdj, indentAdj, err := parse(fset, "", src, true) diff --git a/libgo/go/go/importer/importer.go b/libgo/go/go/importer/importer.go index fab65181cd8..f99dd65f3de 100644 --- a/libgo/go/go/importer/importer.go +++ b/libgo/go/go/importer/importer.go @@ -13,6 +13,7 @@ import ( "go/token" "go/types" "io" + "os" "runtime" ) @@ -29,30 +30,37 @@ type Lookup func(path string) (io.ReadCloser, error) // checker won't have access to those). // // If lookup is nil, the default package lookup mechanism for the -// given compiler is used. +// given compiler is used, and the resulting importer attempts +// to resolve relative and absolute import paths to canonical +// import path IDs before finding the imported file. // -// BUG(issue13847): For does not support non-nil lookup functions. +// If lookup is non-nil, then the returned importer calls lookup +// each time it needs to resolve an import path. In this mode +// the importer can only be invoked with canonical import paths +// (not relative or absolute ones); it is assumed that the translation +// to canonical import paths is being done by the client of the +// importer. func For(compiler string, lookup Lookup) types.Importer { switch compiler { case "gc": - if lookup != nil { - panic("gc importer for custom import path lookup not supported (issue #13847).") + return &gcimports{ + packages: make(map[string]*types.Package), + lookup: lookup, } - return make(gcimports) - case "gccgo": - if lookup != nil { - panic("gccgo importer for custom import path lookup not supported (issue #13847).") - } - var inst gccgoimporter.GccgoInstallation - if err := inst.InitFromDriver("gccgo"); err != nil { + gccgo := os.Getenv("GCCGO") + if gccgo == "" { + gccgo = "gccgo" + } + if err := inst.InitFromDriver(gccgo); err != nil { return nil } return &gccgoimports{ packages: make(map[string]*types.Package), importer: inst.GetImporter(nil, nil), + lookup: lookup, } case "source": @@ -75,17 +83,20 @@ func Default() types.Importer { // gc importer -type gcimports map[string]*types.Package +type gcimports struct { + packages map[string]*types.Package + lookup Lookup +} -func (m gcimports) Import(path string) (*types.Package, error) { +func (m *gcimports) Import(path string) (*types.Package, error) { return m.ImportFrom(path, "" /* no vendoring */, 0) } -func (m gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) { +func (m *gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) { if mode != 0 { panic("mode must be 0") } - return gcimporter.Import(m, path, srcDir) + return gcimporter.Import(m.packages, path, srcDir, m.lookup) } // gccgo importer @@ -93,6 +104,7 @@ func (m gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*type type gccgoimports struct { packages map[string]*types.Package importer gccgoimporter.Importer + lookup Lookup } func (m *gccgoimports) Import(path string) (*types.Package, error) { @@ -103,6 +115,5 @@ func (m *gccgoimports) ImportFrom(path, srcDir string, mode types.ImportMode) (* if mode != 0 { panic("mode must be 0") } - // TODO(gri) pass srcDir - return m.importer(m.packages, path) + return m.importer(m.packages, path, srcDir, m.lookup) } diff --git a/libgo/go/go/importer/importer_test.go b/libgo/go/go/importer/importer_test.go new file mode 100644 index 00000000000..8fa90ef0977 --- /dev/null +++ b/libgo/go/go/importer/importer_test.go @@ -0,0 +1,68 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package importer + +import ( + "internal/testenv" + "io" + "os" + "os/exec" + "strings" + "testing" +) + +func TestFor(t *testing.T) { + testenv.MustHaveGoBuild(t) + + const thePackage = "math/big" + out, err := exec.Command("go", "list", "-f={{context.Compiler}}:{{.Target}}", thePackage).CombinedOutput() + if err != nil { + t.Fatalf("go list %s: %v\n%s", thePackage, err, out) + } + target := strings.TrimSpace(string(out)) + i := strings.Index(target, ":") + compiler, target := target[:i], target[i+1:] + if !strings.HasSuffix(target, ".a") { + t.Fatalf("unexpected package %s target %q (not *.a)", thePackage, target) + } + + if compiler == "gccgo" { + t.Skip("golang.org/issue/22500") + } + + t.Run("LookupDefault", func(t *testing.T) { + imp := For(compiler, nil) + pkg, err := imp.Import(thePackage) + if err != nil { + t.Fatal(err) + } + if pkg.Path() != thePackage { + t.Fatalf("Path() = %q, want %q", pkg.Path(), thePackage) + } + }) + + t.Run("LookupCustom", func(t *testing.T) { + lookup := func(path string) (io.ReadCloser, error) { + if path != "math/bigger" { + t.Fatalf("lookup called with unexpected path %q", path) + } + f, err := os.Open(target) + if err != nil { + t.Fatal(err) + } + return f, nil + } + imp := For(compiler, lookup) + pkg, err := imp.Import("math/bigger") + if err != nil { + t.Fatal(err) + } + // Even though we open math/big.a, the import request was for math/bigger + // and that should be recorded in pkg.Path(), at least for the gc toolchain. + if pkg.Path() != "math/bigger" { + t.Fatalf("Path() = %q, want %q", pkg.Path(), "math/bigger") + } + }) +} diff --git a/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go index a2acaf7331a..52a34433233 100644 --- a/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go +++ b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -152,7 +152,6 @@ func TestInstallationImporter(t *testing.T) { // were compiled with gccgo. if runtime.Compiler != "gccgo" { t.Skip("This test needs gccgo") - return } // Even when we have gccgo, this doesn't work while building @@ -170,14 +169,14 @@ func TestInstallationImporter(t *testing.T) { // all packages into the same map and then each individually. pkgMap := make(map[string]*types.Package) for _, pkg := range importablePackages { - _, err = imp(pkgMap, pkg) + _, err = imp(pkgMap, pkg, ".", nil) if err != nil { t.Error(err) } } for _, pkg := range importablePackages { - _, err = imp(make(map[string]*types.Package), pkg) + _, err = imp(make(map[string]*types.Package), pkg, ".", nil) if err != nil { t.Error(err) } diff --git a/libgo/go/go/internal/gccgoimporter/importer.go b/libgo/go/go/internal/gccgoimporter/importer.go index 923f3689011..843d196aedc 100644 --- a/libgo/go/go/internal/gccgoimporter/importer.go +++ b/libgo/go/go/internal/gccgoimporter/importer.go @@ -157,25 +157,53 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e // the map entry. Otherwise, the importer must load the package data for the // given path into a new *Package, record it in imports map, and return the // package. -type Importer func(imports map[string]*types.Package, path string) (*types.Package, error) +type Importer func(imports map[string]*types.Package, path, srcDir string, lookup func(string) (io.ReadCloser, error)) (*types.Package, error) func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Importer { - return func(imports map[string]*types.Package, pkgpath string) (pkg *types.Package, err error) { + return func(imports map[string]*types.Package, pkgpath, srcDir string, lookup func(string) (io.ReadCloser, error)) (pkg *types.Package, err error) { + // TODO(gri): Use srcDir. + // Or not. It's possible that srcDir will fade in importance as + // the go command and other tools provide a translation table + // for relative imports (like ./foo or vendored imports). if pkgpath == "unsafe" { return types.Unsafe, nil } - fpath, err := findExportFile(searchpaths, pkgpath) - if err != nil { - return + var reader io.ReadSeeker + var fpath string + if lookup != nil { + if p := imports[pkgpath]; p != nil && p.Complete() { + return p, nil + } + rc, err := lookup(pkgpath) + if err == nil { + defer rc.Close() + rs, ok := rc.(io.ReadSeeker) + if !ok { + return nil, fmt.Errorf("gccgo importer requires lookup to return an io.ReadSeeker, have %T", rc) + } + reader = rs + fpath = "" + // Take name from Name method (like on os.File) if present. + if n, ok := rc.(interface{ Name() string }); ok { + fpath = n.Name() + } + } } + if reader == nil { + fpath, err = findExportFile(searchpaths, pkgpath) + if err != nil { + return nil, err + } - reader, closer, err := openExportFile(fpath) - if err != nil { - return - } - if closer != nil { - defer closer.Close() + r, closer, err := openExportFile(fpath) + if err != nil { + return nil, err + } + if closer != nil { + defer closer.Close() + } + reader = r } var magic [4]byte diff --git a/libgo/go/go/internal/gccgoimporter/importer_test.go b/libgo/go/go/internal/gccgoimporter/importer_test.go index 4fca828bf60..26f5d9f5b7e 100644 --- a/libgo/go/go/internal/gccgoimporter/importer_test.go +++ b/libgo/go/go/internal/gccgoimporter/importer_test.go @@ -21,7 +21,7 @@ type importerTest struct { } func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) { - pkg, err := imp(make(map[string]*types.Package), test.pkgpath) + pkg, err := imp(make(map[string]*types.Package), test.pkgpath, ".", nil) if err != nil { t.Error(err) return @@ -122,7 +122,6 @@ func TestObjImporter(t *testing.T) { // were compiled with gccgo. if runtime.Compiler != "gccgo" { t.Skip("This test needs gccgo") - return } tmpdir, err := ioutil.TempDir("", "") diff --git a/libgo/go/go/internal/gccgoimporter/parser_test.go b/libgo/go/go/internal/gccgoimporter/parser_test.go index b96486f20ad..4a103dc462a 100644 --- a/libgo/go/go/internal/gccgoimporter/parser_test.go +++ b/libgo/go/go/internal/gccgoimporter/parser_test.go @@ -45,6 +45,11 @@ func TestTypeParser(t *testing.T) { t.Errorf("expected full parse, stopped at %q", p.lit) } + // interfaces must be explicitly completed + if ityp, _ := typ.(*types.Interface); ityp != nil { + ityp.Complete() + } + got := typ.String() if got != test.want { t.Errorf("got type %q, expected %q", got, test.want) diff --git a/libgo/go/go/internal/gcimporter/bimport.go b/libgo/go/go/internal/gcimporter/bimport.go index 2045f5517b1..23c1d2f76a9 100644 --- a/libgo/go/go/internal/gcimporter/bimport.go +++ b/libgo/go/go/internal/gcimporter/bimport.go @@ -123,7 +123,7 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // read package data pkg = p.pkg() - // read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go) + // read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go) objcount := 0 for { tag := p.tagOrIndex() diff --git a/libgo/go/go/internal/gcimporter/gcimporter.go b/libgo/go/go/internal/gcimporter/gcimporter.go index f3f90f25911..2185f5b8910 100644 --- a/libgo/go/go/internal/gcimporter/gcimporter.go +++ b/libgo/go/go/internal/gcimporter/gcimporter.go @@ -11,6 +11,7 @@ import ( "go/build" "go/token" "go/types" + "io" "io/ioutil" "os" "path/filepath" @@ -84,36 +85,60 @@ func FindPkg(path, srcDir string) (filename, id string) { // the corresponding package object to the packages map, and returns the object. // The packages map must contain all packages already imported. // -func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types.Package, err error) { - filename, id := FindPkg(path, srcDir) - if filename == "" { +func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { + var rc io.ReadCloser + var id string + if lookup != nil { + // With custom lookup specified, assume that caller has + // converted path to a canonical import path for use in the map. if path == "unsafe" { return types.Unsafe, nil } - err = fmt.Errorf("can't find import: %q", id) - return - } + id = path - // no need to re-import if the package was imported completely before - if pkg = packages[id]; pkg != nil && pkg.Complete() { - return - } + // No need to re-import if the package was imported completely before. + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + f, err := lookup(path) + if err != nil { + return nil, err + } + rc = f + } else { + var filename string + filename, id = FindPkg(path, srcDir) + if filename == "" { + if path == "unsafe" { + return types.Unsafe, nil + } + return nil, fmt.Errorf("can't find import: %q", id) + } - // open file - f, err := os.Open(filename) - if err != nil { - return - } - defer func() { - f.Close() + // no need to re-import if the package was imported completely before + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + + // open file + f, err := os.Open(filename) if err != nil { - // add file name to error - err = fmt.Errorf("%s: %v", filename, err) + return nil, err } + defer func() { + if err != nil { + // add file name to error + err = fmt.Errorf("%s: %v", filename, err) + } + }() + rc = f + } + defer func() { + rc.Close() }() var hdr string - buf := bufio.NewReader(f) + buf := bufio.NewReader(rc) if hdr, err = FindExportData(buf); err != nil { return } diff --git a/libgo/go/go/internal/gcimporter/gcimporter_test.go b/libgo/go/go/internal/gcimporter/gcimporter_test.go index c34f07c4c35..56870a14121 100644 --- a/libgo/go/go/internal/gcimporter/gcimporter_test.go +++ b/libgo/go/go/internal/gcimporter/gcimporter_test.go @@ -48,7 +48,7 @@ func compile(t *testing.T, dirname, filename string) string { func testPath(t *testing.T, path, srcDir string) *types.Package { t0 := time.Now() - pkg, err := Import(make(map[string]*types.Package), path, srcDir) + pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil) if err != nil { t.Errorf("testPath(%s): %s", path, err) return nil @@ -142,7 +142,7 @@ func TestVersionHandling(t *testing.T) { pkgpath := "./" + name[:len(name)-2] // test that export data can be imported - _, err := Import(make(map[string]*types.Package), pkgpath, dir) + _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil) if err != nil { t.Errorf("import %q failed: %v", pkgpath, err) continue @@ -171,7 +171,7 @@ func TestVersionHandling(t *testing.T) { defer os.Remove(filename) // test that importing the corrupted file results in an error - _, err = Import(make(map[string]*types.Package), pkgpath, dir) + _, err = Import(make(map[string]*types.Package), pkgpath, dir, nil) if err == nil { t.Errorf("import corrupted %q succeeded", pkgpath) } else if msg := err.Error(); !strings.Contains(msg, "version skew") { @@ -223,7 +223,7 @@ func TestImportedTypes(t *testing.T) { importPath := s[0] objName := s[1] - pkg, err := Import(make(map[string]*types.Package), importPath, ".") + pkg, err := Import(make(map[string]*types.Package), importPath, ".", nil) if err != nil { t.Error(err) continue @@ -280,7 +280,7 @@ func TestCorrectMethodPackage(t *testing.T) { } imports := make(map[string]*types.Package) - _, err := Import(imports, "net/http", ".") + _, err := Import(imports, "net/http", ".", nil) if err != nil { t.Fatal(err) } @@ -336,7 +336,7 @@ func TestIssue13898(t *testing.T) { // import go/internal/gcimporter which imports go/types partially imports := make(map[string]*types.Package) - _, err := Import(imports, "go/internal/gcimporter", ".") + _, err := Import(imports, "go/internal/gcimporter", ".", nil) if err != nil { t.Fatal(err) } @@ -404,7 +404,7 @@ func TestIssue15517(t *testing.T) { // The same issue occurs with vendoring.) imports := make(map[string]*types.Package) for i := 0; i < 3; i++ { - if _, err := Import(imports, "./././testdata/p", "."); err != nil { + if _, err := Import(imports, "./././testdata/p", ".", nil); err != nil { t.Fatal(err) } } @@ -458,7 +458,7 @@ func TestIssue20046(t *testing.T) { } func importPkg(t *testing.T, path string) *types.Package { - pkg, err := Import(make(map[string]*types.Package), path, ".") + pkg, err := Import(make(map[string]*types.Package), path, ".", nil) if err != nil { t.Fatal(err) } diff --git a/libgo/go/go/internal/srcimporter/srcimporter.go b/libgo/go/go/internal/srcimporter/srcimporter.go index 50cf361dbb0..b0dc8abfc2b 100644 --- a/libgo/go/go/internal/srcimporter/srcimporter.go +++ b/libgo/go/go/internal/srcimporter/srcimporter.go @@ -128,19 +128,33 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type } // type-check package files + var firstHardErr error conf := types.Config{ IgnoreFuncBodies: true, FakeImportC: true, - Importer: p, - Sizes: p.sizes, + // continue type-checking after the first error + Error: func(err error) { + if firstHardErr == nil && !err.(types.Error).Soft { + firstHardErr = err + } + }, + Importer: p, + Sizes: p.sizes, } pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil) if err != nil { - // Type-checking stops after the first error (types.Config.Error is not set), - // so the returned package is very likely incomplete. Don't return it since - // we don't know its condition: It's very likely unsafe to use and it's also - // not added to p.packages which may cause further problems (issue #20837). - return nil, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err) + // If there was a hard error it is possibly unsafe + // to use the package as it may not be fully populated. + // Do not return it (see also #20837, #20855). + if firstHardErr != nil { + pkg = nil + err = firstHardErr // give preference to first hard error over any soft error + } + return pkg, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err) + } + if firstHardErr != nil { + // this can only happen if we have a bug in go/types + panic("package is not safe yet no error was returned") } p.packages[bp.ImportPath] = pkg diff --git a/libgo/go/go/internal/srcimporter/srcimporter_test.go b/libgo/go/go/internal/srcimporter/srcimporter_test.go index 79921b5e785..356e71d1287 100644 --- a/libgo/go/go/internal/srcimporter/srcimporter_test.go +++ b/libgo/go/go/internal/srcimporter/srcimporter_test.go @@ -148,3 +148,17 @@ func TestReimport(t *testing.T) { t.Errorf("got %v; want reimport error", err) } } + +func TestIssue20855(t *testing.T) { + if !testenv.HasSrc() { + t.Skip("no source code available") + } + + pkg, err := importer.ImportFrom("go/internal/srcimporter/testdata/issue20855", ".", 0) + if err == nil || !strings.Contains(err.Error(), "missing function body") { + t.Fatalf("got unexpected or no error: %v", err) + } + if pkg == nil { + t.Error("got no package despite no hard errors") + } +} diff --git a/libgo/go/go/internal/srcimporter/testdata/issue20855/issue20855.go b/libgo/go/go/internal/srcimporter/testdata/issue20855/issue20855.go new file mode 100644 index 00000000000..d55448b44ce --- /dev/null +++ b/libgo/go/go/internal/srcimporter/testdata/issue20855/issue20855.go @@ -0,0 +1,7 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue20855 + +func init() // "missing function body" is a soft error diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index 4eaadeb448f..3e2ff4f5ae3 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -398,22 +398,33 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) // no blank between keyword and {} in this case p.print(lbrace, token.LBRACE, rbrace, token.RBRACE) return - } else if isStruct && p.isOneLineFieldList(list) { // for now ignore interfaces + } else if p.isOneLineFieldList(list) { // small enough - print on one line // (don't use identList and ignore source line breaks) p.print(lbrace, token.LBRACE, blank) f := list[0] - for i, x := range f.Names { - if i > 0 { - // no comments so no need for comma position - p.print(token.COMMA, blank) + if isStruct { + for i, x := range f.Names { + if i > 0 { + // no comments so no need for comma position + p.print(token.COMMA, blank) + } + p.expr(x) + } + if len(f.Names) > 0 { + p.print(blank) + } + p.expr(f.Type) + } else { // interface + if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { + // method + p.expr(f.Names[0]) + p.signature(ftyp.Params, ftyp.Results) + } else { + // embedded interface + p.expr(f.Type) } - p.expr(x) - } - if len(f.Names) > 0 { - p.print(blank) } - p.expr(f.Type) p.print(blank, rbrace, token.RBRACE) return } @@ -774,20 +785,35 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { if x.Max != nil { indices = append(indices, x.Max) } - for i, y := range indices { + // determine if we need extra blanks around ':' + var needsBlanks bool + if depth <= 1 { + var indexCount int + var hasBinaries bool + for _, x := range indices { + if x != nil { + indexCount++ + if isBinary(x) { + hasBinaries = true + } + } + } + if indexCount > 1 && hasBinaries { + needsBlanks = true + } + } + for i, x := range indices { if i > 0 { - // blanks around ":" if both sides exist and either side is a binary expression - // TODO(gri) once we have committed a variant of a[i:j:k] we may want to fine- - // tune the formatting here - x := indices[i-1] - if depth <= 1 && x != nil && y != nil && (isBinary(x) || isBinary(y)) { - p.print(blank, token.COLON, blank) - } else { - p.print(token.COLON) + if indices[i-1] != nil && needsBlanks { + p.print(blank) + } + p.print(token.COLON) + if x != nil && needsBlanks { + p.print(blank) } } - if y != nil { - p.expr0(y, depth+1) + if x != nil { + p.expr0(x, depth+1) } } p.print(x.Rbrack, token.RBRACK) @@ -837,7 +863,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { if len(x.Elts) > 0 { mode |= noExtraBlank } - p.print(mode, x.Rbrace, token.RBRACE, mode) + // need the initial indent to print lone comments with + // the proper level of indentation + p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode) p.level-- case *ast.Ellipsis: diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden index 4d92e653279..e1818e5fd53 100644 --- a/libgo/go/go/printer/testdata/comments.golden +++ b/libgo/go/go/printer/testdata/comments.golden @@ -728,4 +728,32 @@ func _() { */ } +var _ = []T{ /* lone comment */ } + +var _ = []T{ + /* lone comment */ +} + +var _ = []T{ + // lone comments + // in composite lit +} + +var _ = [][]T{ + { + // lone comments + // in composite lit + }, +} + +// TODO: gofmt doesn't add these tabs; make it so that these golden +// tests run the printer in a way that it's exactly like gofmt. + +var _ = []T{ // lone comment +} + +var _ = []T{ // lone comments + // in composite lit +} + /* This comment is the last entry in this file. It must be printed and should be followed by a newline */ diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input index 40351eeef69..f3eda12c229 100644 --- a/libgo/go/go/printer/testdata/comments.input +++ b/libgo/go/go/printer/testdata/comments.input @@ -725,4 +725,32 @@ func _() { */ } +var _ = []T{/* lone comment */} + +var _ = []T{ +/* lone comment */ +} + +var _ = []T{ +// lone comments +// in composite lit +} + +var _ = [][]T{ + { + // lone comments + // in composite lit + }, +} + +// TODO: gofmt doesn't add these tabs; make it so that these golden +// tests run the printer in a way that it's exactly like gofmt. + +var _ = []T{// lone comment +} + +var _ = []T{// lone comments +// in composite lit +} + /* This comment is the last entry in this file. It must be printed and should be followed by a newline */ diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden index cab991fd883..16a68c7bf74 100644 --- a/libgo/go/go/printer/testdata/expressions.golden +++ b/libgo/go/go/printer/testdata/expressions.golden @@ -122,18 +122,47 @@ func _() { // slice expressions with cap func _() { _ = x[a:b:c] - _ = x[a:b : c+d] + _ = x[a : b : c+d] _ = x[a : b+d : c] _ = x[a : b+d : c+d] - _ = x[a+d : b:c] + _ = x[a+d : b : c] _ = x[a+d : b : c+d] _ = x[a+d : b+d : c] _ = x[a+d : b+d : c+d] _ = x[:b:c] - _ = x[:b : c+d] - _ = x[:b+d : c] - _ = x[:b+d : c+d] + _ = x[: b : c+d] + _ = x[: b+d : c] + _ = x[: b+d : c+d] +} + +func issue22111() { + _ = x[:] + + _ = x[:b] + _ = x[:b+1] + + _ = x[a:] + _ = x[a+1:] + + _ = x[a:b] + _ = x[a+1 : b] + _ = x[a : b+1] + _ = x[a+1 : b+1] + + _ = x[:b:c] + _ = x[: b+1 : c] + _ = x[: b : c+1] + _ = x[: b+1 : c+1] + + _ = x[a:b:c] + _ = x[a+1 : b : c] + _ = x[a : b+1 : c] + _ = x[a+1 : b+1 : c] + _ = x[a : b : c+1] + _ = x[a+1 : b : c+1] + _ = x[a : b+1 : c+1] + _ = x[a+1 : b+1 : c+1] } func _() { @@ -261,6 +290,16 @@ func _() { _ = struct{ x, y, z int }{0, 1, 2} _ = struct{ int }{0} _ = struct{ s struct{ int } }{struct{ int }{0}} + + _ = (interface{})(nil) + _ = (interface{ String() string })(nil) + _ = (interface { + String() string + })(nil) + _ = (interface{ fmt.Stringer })(nil) + _ = (interface { + fmt.Stringer + })(nil) } func _() { diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input index 7c88042dc17..8c523b60221 100644 --- a/libgo/go/go/printer/testdata/expressions.input +++ b/libgo/go/go/printer/testdata/expressions.input @@ -138,6 +138,35 @@ func _() { _ = x[:b+d:c+d] } +func issue22111() { + _ = x[:] + + _ = x[:b] + _ = x[:b+1] + + _ = x[a:] + _ = x[a+1:] + + _ = x[a:b] + _ = x[a+1:b] + _ = x[a:b+1] + _ = x[a+1:b+1] + + _ = x[:b:c] + _ = x[:b+1:c] + _ = x[:b:c+1] + _ = x[:b+1:c+1] + + _ = x[a:b:c] + _ = x[a+1:b:c] + _ = x[a:b+1:c] + _ = x[a+1:b+1:c] + _ = x[a:b:c+1] + _ = x[a+1:b:c+1] + _ = x[a:b+1:c+1] + _ = x[a+1:b+1:c+1] +} + func _() { _ = a+b _ = a+b+c @@ -266,8 +295,17 @@ func _() { _ = struct{ x, y, z int }{0, 1, 2} _ = struct{ int }{0} _ = struct{ s struct { int } }{struct{ int}{0} } -} + _ = (interface{})(nil) + _ = (interface{String() string})(nil) + _ = (interface{ + String() string + })(nil) + _ = (interface{fmt.Stringer})(nil) + _ = (interface{ + fmt.Stringer + })(nil) +} func _() { // do not modify literals diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw index d9060621ced..058fded4474 100644 --- a/libgo/go/go/printer/testdata/expressions.raw +++ b/libgo/go/go/printer/testdata/expressions.raw @@ -122,18 +122,47 @@ func _() { // slice expressions with cap func _() { _ = x[a:b:c] - _ = x[a:b : c+d] + _ = x[a : b : c+d] _ = x[a : b+d : c] _ = x[a : b+d : c+d] - _ = x[a+d : b:c] + _ = x[a+d : b : c] _ = x[a+d : b : c+d] _ = x[a+d : b+d : c] _ = x[a+d : b+d : c+d] _ = x[:b:c] - _ = x[:b : c+d] - _ = x[:b+d : c] - _ = x[:b+d : c+d] + _ = x[: b : c+d] + _ = x[: b+d : c] + _ = x[: b+d : c+d] +} + +func issue22111() { + _ = x[:] + + _ = x[:b] + _ = x[:b+1] + + _ = x[a:] + _ = x[a+1:] + + _ = x[a:b] + _ = x[a+1 : b] + _ = x[a : b+1] + _ = x[a+1 : b+1] + + _ = x[:b:c] + _ = x[: b+1 : c] + _ = x[: b : c+1] + _ = x[: b+1 : c+1] + + _ = x[a:b:c] + _ = x[a+1 : b : c] + _ = x[a : b+1 : c] + _ = x[a+1 : b+1 : c] + _ = x[a : b : c+1] + _ = x[a+1 : b : c+1] + _ = x[a : b+1 : c+1] + _ = x[a+1 : b+1 : c+1] } func _() { @@ -261,6 +290,16 @@ func _() { _ = struct{ x, y, z int }{0, 1, 2} _ = struct{ int }{0} _ = struct{ s struct{ int } }{struct{ int }{0}} + + _ = (interface{})(nil) + _ = (interface{ String() string })(nil) + _ = (interface { + String() string + })(nil) + _ = (interface{ fmt.Stringer })(nil) + _ = (interface { + fmt.Stringer + })(nil) } func _() { diff --git a/libgo/go/go/types/api.go b/libgo/go/go/types/api.go index 11e76867a1f..9908f5c9738 100644 --- a/libgo/go/go/types/api.go +++ b/libgo/go/go/types/api.go @@ -24,7 +24,7 @@ // // For a tutorial, see https://golang.org/s/types-tutorial. // -package types // import "go/types" +package types import ( "bytes" @@ -176,11 +176,11 @@ type Info struct { // Implicits maps nodes to their implicitly declared objects, if any. // The following node and object types may appear: // - // node declared object + // node declared object // - // *ast.ImportSpec *PkgName for dot-imports and imports without renames - // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) - // *ast.Field anonymous parameter *Var + // *ast.ImportSpec *PkgName for imports without renames + // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) + // *ast.Field anonymous parameter *Var // Implicits map[ast.Node]Object @@ -200,16 +200,16 @@ type Info struct { // // The following node types may appear in Scopes: // - // *ast.File - // *ast.FuncType - // *ast.BlockStmt - // *ast.IfStmt - // *ast.SwitchStmt - // *ast.TypeSwitchStmt - // *ast.CaseClause - // *ast.CommClause - // *ast.ForStmt - // *ast.RangeStmt + // *ast.File + // *ast.FuncType + // *ast.BlockStmt + // *ast.IfStmt + // *ast.SwitchStmt + // *ast.TypeSwitchStmt + // *ast.CaseClause + // *ast.CommClause + // *ast.ForStmt + // *ast.RangeStmt // Scopes map[ast.Node]*Scope diff --git a/libgo/go/go/types/api_test.go b/libgo/go/go/types/api_test.go index 1b175796410..8a4f1ef9457 100644 --- a/libgo/go/go/types/api_test.go +++ b/libgo/go/go/types/api_test.go @@ -88,6 +88,10 @@ func TestValuesInfo(t *testing.T) { {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`}, {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`}, {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`}, + {`package c5d; var _ = string(65)`, `65`, `untyped int`, `65`}, + {`package c5e; var _ = string('A')`, `'A'`, `untyped rune`, `65`}, + {`package c5f; type T string; var _ = T('A')`, `'A'`, `untyped rune`, `65`}, + {`package c5g; var s uint; var _ = string(1 << s)`, `1 << s`, `untyped int`, ``}, {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`}, {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`}, @@ -115,6 +119,8 @@ func TestValuesInfo(t *testing.T) { {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`}, {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`}, {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`}, + + {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341 } for _, test := range tests { @@ -123,7 +129,7 @@ func TestValuesInfo(t *testing.T) { } name := mustTypecheck(t, "ValuesInfo", test.src, &info) - // look for constant expression + // look for expression var expr ast.Expr for e := range info.Types { if ExprString(e) == test.expr { @@ -143,9 +149,15 @@ func TestValuesInfo(t *testing.T) { continue } - // check that value is correct - if got := tv.Value.ExactString(); got != test.val { - t.Errorf("package %s: got value %s; want %s", name, got, test.val) + // if we have a constant, check that value is correct + if tv.Value != nil { + if got := tv.Value.ExactString(); got != test.val { + t.Errorf("package %s: got value %s; want %s", name, got, test.val) + } + } else { + if test.val != "" { + t.Errorf("package %s: no constant found; want %s", name, test.val) + } } } } @@ -258,6 +270,63 @@ func TestTypesInfo(t *testing.T) { } } +func TestImplicitsInfo(t *testing.T) { + testenv.MustHaveGoBuild(t) + + var tests = []struct { + src string + want string + }{ + {`package p2; import . "fmt"; var _ = Println`, ""}, // no Implicits entry + {`package p0; import local "fmt"; var _ = local.Println`, ""}, // no Implicits entry + {`package p1; import "fmt"; var _ = fmt.Println`, "importSpec: package fmt"}, + + {`package p3; func f(x interface{}) { switch x.(type) { case int: } }`, ""}, // no Implicits entry + {`package p4; func f(x interface{}) { switch t := x.(type) { case int: _ = t } }`, "caseClause: var t int"}, + {`package p5; func f(x interface{}) { switch t := x.(type) { case int, uint: _ = t } }`, "caseClause: var t interface{}"}, + {`package p6; func f(x interface{}) { switch t := x.(type) { default: _ = t } }`, "caseClause: var t interface{}"}, + + {`package p7; func f(x int) {}`, ""}, // no Implicits entry + {`package p8; func f(int) {}`, "field: var int"}, + {`package p9; func f() (complex64) { return 0 }`, "field: var complex64"}, + {`package p10; type T struct{}; func (*T) f() {}`, "field: var *p10.T"}, + } + + for _, test := range tests { + info := Info{ + Implicits: make(map[ast.Node]Object), + } + name := mustTypecheck(t, "ImplicitsInfo", test.src, &info) + + // the test cases expect at most one Implicits entry + if len(info.Implicits) > 1 { + t.Errorf("package %s: %d Implicits entries found", name, len(info.Implicits)) + continue + } + + // extract Implicits entry, if any + var got string + for n, obj := range info.Implicits { + switch x := n.(type) { + case *ast.ImportSpec: + got = "importSpec" + case *ast.CaseClause: + got = "caseClause" + case *ast.Field: + got = "field" + default: + t.Fatalf("package %s: unexpected %T", name, x) + } + got += ": " + obj.String() + } + + // verify entry + if got != test.want { + t.Errorf("package %s: got %q; want %q", name, got, test.want) + } + } +} + func predString(tv TypeAndValue) string { var buf bytes.Buffer pred := func(b bool, s string) { @@ -1306,7 +1375,7 @@ func TestFailedImport(t *testing.T) { const src = ` package p -import "foo" // should only see an error here +import foo "go/types/thisdirectorymustnotexistotherwisethistestmayfail/foo" // should only see an error here const c = foo.C type T = foo.T @@ -1326,7 +1395,7 @@ func f(x T) T { return foo.F(x) } conf := Config{ Error: func(err error) { // we should only see the import error - if errcount > 0 || !strings.Contains(err.Error(), "could not import foo") { + if errcount > 0 || !strings.Contains(err.Error(), "could not import") { t.Errorf("for %s importer, got unexpected error: %v", compiler, err) } errcount++ diff --git a/libgo/go/go/types/builtins.go b/libgo/go/go/types/builtins.go index 596a989a2df..66548231fe4 100644 --- a/libgo/go/go/types/builtins.go +++ b/libgo/go/go/types/builtins.go @@ -470,15 +470,14 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Panic: // panic(x) - T := new(Interface) - check.assignment(x, T, "argument to panic") + check.assignment(x, &emptyInterface, "argument to panic") if x.mode == invalid { return } x.mode = novalue if check.Types != nil { - check.recordBuiltinType(call.Fun, makeSig(nil, T)) + check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface)) } case _Print, _Println: @@ -508,7 +507,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Recover: // recover() interface{} x.mode = value - x.typ = new(Interface) + x.typ = &emptyInterface if check.Types != nil { check.recordBuiltinType(call.Fun, makeSig(x.typ)) } diff --git a/libgo/go/go/types/call.go b/libgo/go/go/types/call.go index ffd96297775..345df66a8a9 100644 --- a/libgo/go/go/types/call.go +++ b/libgo/go/go/types/call.go @@ -134,47 +134,46 @@ type getter func(x *operand, i int) // the incoming getter with that i. // func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) { - if n == 1 { - // possibly result of an n-valued function call or comma,ok value - var x0 operand - get(&x0, 0) - if x0.mode == invalid { - return nil, 0, false - } + if n != 1 { + // zero or multiple values + return get, n, false + } + // possibly result of an n-valued function call or comma,ok value + var x0 operand + get(&x0, 0) + if x0.mode == invalid { + return nil, 0, false + } + + if t, ok := x0.typ.(*Tuple); ok { + // result of an n-valued function call + return func(x *operand, i int) { + x.mode = value + x.expr = x0.expr + x.typ = t.At(i).typ + }, t.Len(), false + } - if t, ok := x0.typ.(*Tuple); ok { - // result of an n-valued function call + if x0.mode == mapindex || x0.mode == commaok { + // comma-ok value + if allowCommaOk { + a := [2]Type{x0.typ, Typ[UntypedBool]} return func(x *operand, i int) { x.mode = value x.expr = x0.expr - x.typ = t.At(i).typ - }, t.Len(), false - } - - if x0.mode == mapindex || x0.mode == commaok { - // comma-ok value - if allowCommaOk { - a := [2]Type{x0.typ, Typ[UntypedBool]} - return func(x *operand, i int) { - x.mode = value - x.expr = x0.expr - x.typ = a[i] - }, 2, true - } - x0.mode = value + x.typ = a[i] + }, 2, true } - - // single value - return func(x *operand, i int) { - if i != 0 { - unreachable() - } - *x = x0 - }, 1, false + x0.mode = value } - // zero or multiple values - return get, n, false + // single value + return func(x *operand, i int) { + if i != 0 { + unreachable() + } + *x = x0 + }, 1, false } // arguments checks argument passing for the call with the given signature. diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go index 24b3365717b..97e224f870f 100644 --- a/libgo/go/go/types/check_test.go +++ b/libgo/go/go/types/check_test.go @@ -69,6 +69,7 @@ var tests = [][]string{ {"testdata/decls2a.src", "testdata/decls2b.src"}, {"testdata/decls3.src"}, {"testdata/decls4.src"}, + {"testdata/decls5.src"}, {"testdata/const0.src"}, {"testdata/const1.src"}, {"testdata/constdecl.src"}, diff --git a/libgo/go/go/types/conversions.go b/libgo/go/go/types/conversions.go index 2bf1e2d5e38..81a65838fe0 100644 --- a/libgo/go/go/types/conversions.go +++ b/libgo/go/go/types/conversions.go @@ -46,16 +46,19 @@ func (check *Checker) conversion(x *operand, T Type) { // The conversion argument types are final. For untyped values the // conversion provides the type, per the spec: "A constant may be // given a type explicitly by a constant declaration or conversion,...". - final := x.typ if isUntyped(x.typ) { - final = T + final := T // - For conversions to interfaces, use the argument's default type. // - For conversions of untyped constants to non-constant types, also // use the default type (e.g., []byte("foo") should report string // not []byte as type for the constant "foo"). // - Keep untyped nil for untyped nil arguments. + // - For integer to string conversions, keep the argument type. + // (See also the TODO below.) if IsInterface(T) || constArg && !isConstType(T) { final = Default(x.typ) + } else if isInteger(x.typ) && isString(T) { + final = x.typ } check.updateExprType(x.expr, final, true) } @@ -63,6 +66,16 @@ func (check *Checker) conversion(x *operand, T Type) { x.typ = T } +// TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type +// of x is fully known, but that's not the case for say string(1<> 4 } + +func issue21727() { + var s uint + var a = make([]int, 1< 0 || len(t.methods) > 0 { buf.WriteString("; ") } writeType(buf, typ, qf, visited) + empty = false } } + if t.allMethods == nil || len(t.methods) > len(t.allMethods) { + if !empty { + buf.WriteByte(' ') + } + buf.WriteString("/* incomplete */") + } buf.WriteByte('}') case *Map: diff --git a/libgo/go/go/types/typestring_test.go b/libgo/go/go/types/typestring_test.go index 7f7c1064b0a..640ffb1c2c7 100644 --- a/libgo/go/go/types/typestring_test.go +++ b/libgo/go/go/types/typestring_test.go @@ -138,6 +138,26 @@ func TestTypeString(t *testing.T) { } } +func TestIncompleteInterfaces(t *testing.T) { + sig := NewSignature(nil, nil, nil, false) + for _, test := range []struct { + typ *Interface + want string + }{ + {new(Interface), "interface{/* incomplete */}"}, + {new(Interface).Complete(), "interface{}"}, + {NewInterface(nil, nil), "interface{/* incomplete */}"}, + {NewInterface(nil, nil).Complete(), "interface{}"}, + {NewInterface([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil), "interface{m() /* incomplete */}"}, + {NewInterface([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil).Complete(), "interface{m()}"}, + } { + got := test.typ.String() + if got != test.want { + t.Errorf("got: %s, want: %s", got, test.want) + } + } +} + func TestQualifiedTypeString(t *testing.T) { t.Skip("skipping for gccgo--no importer") p, _ := pkgFor("p.go", "package p; type T int", nil) diff --git a/libgo/go/go/types/typexpr.go b/libgo/go/go/types/typexpr.go index 5f1587bf0f5..0ab6dfdb79b 100644 --- a/libgo/go/go/types/typexpr.go +++ b/libgo/go/go/types/typexpr.go @@ -143,6 +143,7 @@ func (check *Checker) typ(e ast.Expr) Type { // funcType type-checks a function or method type. func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { scope := NewScope(check.scope, token.NoPos, token.NoPos, "function") + scope.isFunc = true check.recordScope(ftyp, scope) recvList, _ := check.collectParams(scope, recvPar, false) @@ -539,6 +540,9 @@ func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d } iface.embeddeds = append(iface.embeddeds, named) // collect embedded methods + if embed.allMethods == nil { + check.errorf(pos, "internal error: incomplete embedded interface %s (issue #18395)", named) + } for _, m := range embed.allMethods { if check.declareInSet(&mset, pos, m) { iface.allMethods = append(iface.allMethods, m) @@ -578,7 +582,11 @@ func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d // claim source order in the future. Revisit. sort.Sort(byUniqueTypeName(iface.embeddeds)) - sort.Sort(byUniqueMethodName(iface.allMethods)) + if iface.allMethods == nil { + iface.allMethods = make([]*Func, 0) // mark interface as complete + } else { + sort.Sort(byUniqueMethodName(iface.allMethods)) + } } // byUniqueTypeName named type lists can be sorted by their unique type names. diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/asn1.go b/libgo/go/golang_org/x/crypto/cryptobyte/asn1.go new file mode 100644 index 00000000000..225a49f8c12 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/asn1.go @@ -0,0 +1,732 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + encoding_asn1 "encoding/asn1" + "fmt" + "math/big" + "reflect" + "time" + + "golang_org/x/crypto/cryptobyte/asn1" +) + +// This file contains ASN.1-related methods for String and Builder. + +// Builder + +// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Int64(v int64) { + b.addASN1Signed(asn1.INTEGER, v) +} + +// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. +func (b *Builder) AddASN1Enum(v int64) { + b.addASN1Signed(asn1.ENUM, v) +} + +func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) { + b.AddASN1(tag, func(c *Builder) { + length := 1 + for i := v; i >= 0x80 || i < -0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Uint64(v uint64) { + b.AddASN1(asn1.INTEGER, func(c *Builder) { + length := 1 + for i := v; i >= 0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1BigInt(n *big.Int) { + if b.err != nil { + return + } + + b.AddASN1(asn1.INTEGER, func(c *Builder) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement form. So we + // invert and subtract 1. If the most-significant-bit isn't set then + // we'll need to pad the beginning with 0xff in order to keep the number + // negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if bytes[0]&0x80 == 0 { + c.add(0xff) + } + c.add(bytes...) + } else if n.Sign() == 0 { + c.add(0) + } else { + bytes := n.Bytes() + if bytes[0]&0x80 != 0 { + c.add(0) + } + c.add(bytes...) + } + }) +} + +// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING. +func (b *Builder) AddASN1OctetString(bytes []byte) { + b.AddASN1(asn1.OCTET_STRING, func(c *Builder) { + c.AddBytes(bytes) + }) +} + +const generalizedTimeFormatStr = "20060102150405Z0700" + +// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME. +func (b *Builder) AddASN1GeneralizedTime(t time.Time) { + if t.Year() < 0 || t.Year() > 9999 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t) + return + } + b.AddASN1(asn1.GeneralizedTime, func(c *Builder) { + c.AddBytes([]byte(t.Format(generalizedTimeFormatStr))) + }) +} + +// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not +// support BIT STRINGs that are not a whole number of bytes. +func (b *Builder) AddASN1BitString(data []byte) { + b.AddASN1(asn1.BIT_STRING, func(b *Builder) { + b.AddUint8(0) + b.AddBytes(data) + }) +} + +func (b *Builder) addBase128Int(n int64) { + var length int + if n == 0 { + length = 1 + } else { + for i := n; i > 0; i >>= 7 { + length++ + } + } + + for i := length - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + + b.add(o) + } +} + +func isValidOID(oid encoding_asn1.ObjectIdentifier) bool { + if len(oid) < 2 { + return false + } + + if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) { + return false + } + + for _, v := range oid { + if v < 0 { + return false + } + } + + return true +} + +func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) { + b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) { + if !isValidOID(oid) { + b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid) + return + } + + b.addBase128Int(int64(oid[0])*40 + int64(oid[1])) + for _, v := range oid[2:] { + b.addBase128Int(int64(v)) + } + }) +} + +func (b *Builder) AddASN1Boolean(v bool) { + b.AddASN1(asn1.BOOLEAN, func(b *Builder) { + if v { + b.AddUint8(0xff) + } else { + b.AddUint8(0) + } + }) +} + +func (b *Builder) AddASN1NULL() { + b.add(uint8(asn1.NULL), 0) +} + +// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if +// successful or records an error if one occurred. +func (b *Builder) MarshalASN1(v interface{}) { + // NOTE(martinkr): This is somewhat of a hack to allow propagation of + // encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a + // value embedded into a struct, its tag information is lost. + if b.err != nil { + return + } + bytes, err := encoding_asn1.Marshal(v) + if err != nil { + b.err = err + return + } + b.AddBytes(bytes) +} + +// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag. +// Tags greater than 30 are not supported and result in an error (i.e. +// low-tag-number form only). The child builder passed to the +// BuilderContinuation can be used to build the content of the ASN.1 object. +func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { + if b.err != nil { + return + } + // Identifiers with the low five bits set indicate high-tag-number format + // (two or more octets), which we don't support. + if tag&0x1f == 0x1f { + b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag) + return + } + b.AddUint8(uint8(tag)) + b.addLengthPrefixed(1, true, f) +} + +// String + +func (s *String) ReadASN1Boolean(out *bool) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 { + return false + } + + switch bytes[0] { + case 0: + *out = false + case 0xff: + *out = true + default: + return false + } + + return true +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() + +// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does +// not point to an integer or to a big.Int, it panics. It returns true on +// success and false on error. +func (s *String) ReadASN1Integer(out interface{}) bool { + if reflect.TypeOf(out).Kind() != reflect.Ptr { + panic("out is not a pointer") + } + switch reflect.ValueOf(out).Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var i int64 + if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) { + return false + } + reflect.ValueOf(out).Elem().SetInt(i) + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + var u uint64 + if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) { + return false + } + reflect.ValueOf(out).Elem().SetUint(u) + return true + case reflect.Struct: + if reflect.TypeOf(out).Elem() == bigIntType { + return s.readASN1BigInt(out.(*big.Int)) + } + } + panic("out does not point to an integer type") +} + +func checkASN1Integer(bytes []byte) bool { + if len(bytes) == 0 { + // An INTEGER is encoded with at least one octet. + return false + } + if len(bytes) == 1 { + return true + } + if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 { + // Value is not minimally encoded. + return false + } + return true +} + +var bigOne = big.NewInt(1) + +func (s *String) readASN1BigInt(out *big.Int) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + // Negative number. + neg := make([]byte, len(bytes)) + for i, b := range bytes { + neg[i] = ^b + } + out.SetBytes(neg) + out.Add(out, bigOne) + out.Neg(out) + } else { + out.SetBytes(bytes) + } + return true +} + +func (s *String) readASN1Int64(out *int64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) { + return false + } + return true +} + +func asn1Signed(out *int64, n []byte) bool { + length := len(n) + if length > 8 { + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= int64(n[i]) + } + // Shift up and down in order to sign extend the result. + *out <<= 64 - uint8(length)*8 + *out >>= 64 - uint8(length)*8 + return true +} + +func (s *String) readASN1Uint64(out *uint64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) { + return false + } + return true +} + +func asn1Unsigned(out *uint64, n []byte) bool { + length := len(n) + if length > 9 || length == 9 && n[0] != 0 { + // Too large for uint64. + return false + } + if n[0]&0x80 != 0 { + // Negative number. + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= uint64(n[i]) + } + return true +} + +// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns +// true on success and false on error. +func (s *String) ReadASN1Enum(out *int) bool { + var bytes String + var i int64 + if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) { + return false + } + if int64(int(i)) != i { + return false + } + *out = int(i) + return true +} + +func (s *String) readBase128Int(out *int) bool { + ret := 0 + for i := 0; len(*s) > 0; i++ { + if i == 4 { + return false + } + ret <<= 7 + b := s.read(1)[0] + ret |= int(b & 0x7f) + if b&0x80 == 0 { + *out = ret + return true + } + } + return false // truncated +} + +// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and +// advances. It returns true on success and false on error. +func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { + return false + } + + // In the worst case, we get two elements from the first byte (which is + // encoded differently) and then every varint is a single byte long. + components := make([]int, len(bytes)+1) + + // The first varint is 40*value1 + value2: + // According to this packing, value1 can take the values 0, 1 and 2 only. + // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, + // then there are no restrictions on value2. + var v int + if !bytes.readBase128Int(&v) { + return false + } + if v < 80 { + components[0] = v / 40 + components[1] = v % 40 + } else { + components[0] = 2 + components[1] = v - 80 + } + + i := 2 + for ; len(bytes) > 0; i++ { + if !bytes.readBase128Int(&v) { + return false + } + components[i] = v + } + *out = components[:i] + return true +} + +// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and +// advances. It returns true on success and false on error. +func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { + return false + } + t := string(bytes) + res, err := time.Parse(generalizedTimeFormatStr, t) + if err != nil { + return false + } + if serialized := res.Format(generalizedTimeFormatStr); serialized != t { + return false + } + *out = res + return true +} + +// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It +// returns true on success and false on error. +func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { + return false + } + + paddingBits := uint8(bytes[0]) + bytes = bytes[1:] + if paddingBits > 7 || + len(bytes) == 0 && paddingBits != 0 || + len(bytes) > 0 && bytes[len(bytes)-1]&(1< 4 || len(*s) < int(2+lenLen) { + return false + } + + lenBytes := String((*s)[2 : 2+lenLen]) + if !lenBytes.readUnsigned(&len32, int(lenLen)) { + return false + } + + // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length + // with the minimum number of octets. + if len32 < 128 { + // Length should have used short-form encoding. + return false + } + if len32>>((lenLen-1)*8) == 0 { + // Leading octet is 0. Length should have been at least one byte shorter. + return false + } + + headerLen = 2 + uint32(lenLen) + if headerLen+len32 < len32 { + // Overflow. + return false + } + length = headerLen + len32 + } + + if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) { + return false + } + if skipHeader && !out.Skip(int(headerLen)) { + panic("cryptobyte: internal error") + } + + return true +} diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/asn1/asn1.go b/libgo/go/golang_org/x/crypto/cryptobyte/asn1/asn1.go new file mode 100644 index 00000000000..cda8e3edfd5 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/asn1/asn1.go @@ -0,0 +1,46 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asn1 contains supporting types for parsing and building ASN.1 +// messages with the cryptobyte package. +package asn1 // import "golang.org/x/crypto/cryptobyte/asn1" + +// Tag represents an ASN.1 identifier octet, consisting of a tag number +// (indicating a type) and class (such as context-specific or constructed). +// +// Methods in the cryptobyte package only support the low-tag-number form, i.e. +// a single identifier octet with bits 7-8 encoding the class and bits 1-6 +// encoding the tag number. +type Tag uint8 + +const ( + classConstructed = 0x20 + classContextSpecific = 0x80 +) + +// Constructed returns t with the constructed class bit set. +func (t Tag) Constructed() Tag { return t | classConstructed } + +// ContextSpecific returns t with the context-specific class bit set. +func (t Tag) ContextSpecific() Tag { return t | classContextSpecific } + +// The following is a list of standard tag and class combinations. +const ( + BOOLEAN = Tag(1) + INTEGER = Tag(2) + BIT_STRING = Tag(3) + OCTET_STRING = Tag(4) + NULL = Tag(5) + OBJECT_IDENTIFIER = Tag(6) + ENUM = Tag(10) + UTF8String = Tag(12) + SEQUENCE = Tag(16 | classConstructed) + SET = Tag(17 | classConstructed) + PrintableString = Tag(19) + T61String = Tag(20) + IA5String = Tag(22) + UTCTime = Tag(23) + GeneralizedTime = Tag(24) + GeneralString = Tag(27) +) diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/asn1_test.go b/libgo/go/golang_org/x/crypto/cryptobyte/asn1_test.go new file mode 100644 index 00000000000..59e562dcee5 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/asn1_test.go @@ -0,0 +1,300 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + "bytes" + encoding_asn1 "encoding/asn1" + "math/big" + "reflect" + "testing" + "time" + + "golang_org/x/crypto/cryptobyte/asn1" +) + +type readASN1Test struct { + name string + in []byte + tag asn1.Tag + ok bool + out interface{} +} + +var readASN1TestData = []readASN1Test{ + {"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}}, + {"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil}, + {"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil}, + {"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil}, + {"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil}, + {"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil}, + {"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff /* actually 0x4001, but tag is uint8 */, false, nil}, +} + +func TestReadASN1(t *testing.T) { + for _, test := range readASN1TestData { + t.Run(test.name, func(t *testing.T) { + var in, out String = test.in, nil + ok := in.ReadASN1(&out, test.tag) + if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) { + t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out) + } + }) + } +} + +func TestReadASN1Optional(t *testing.T) { + var empty String + var present bool + ok := empty.ReadOptionalASN1(nil, &present, 0xa0) + if !ok || present { + t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present) + } + + var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil + ok = in.ReadOptionalASN1(&out, &present, 0xa0) + if !ok || present { + t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present) + } + ok = in.ReadOptionalASN1(&out, &present, 0xa1) + wantBytes := []byte{4, 1, 1} + if !ok || !present || !bytes.Equal(out, wantBytes) { + t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes) + } +} + +var optionalOctetStringTestData = []struct { + readASN1Test + present bool +}{ + {readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false}, + {readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true}, + {readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false}, + {readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true}, +} + +func TestReadASN1OptionalOctetString(t *testing.T) { + for _, test := range optionalOctetStringTestData { + t.Run(test.name, func(t *testing.T) { + in := String(test.in) + var out []byte + var present bool + ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag) + if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) { + t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out) + } + }) + } +} + +const defaultInt = -1 + +var optionalIntTestData = []readASN1Test{ + {"empty", []byte{}, 0xa0, true, defaultInt}, + {"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0}, + {"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt}, + {"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42}, +} + +func TestReadASN1OptionalInteger(t *testing.T) { + for _, test := range optionalIntTestData { + t.Run(test.name, func(t *testing.T) { + in := String(test.in) + var out int + ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt) + if ok != test.ok || ok && out != test.out.(int) { + t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out) + } + }) + } +} + +func TestReadASN1IntegerSigned(t *testing.T) { + testData64 := []struct { + in []byte + out int64 + }{ + {[]byte{2, 3, 128, 0, 0}, -0x800000}, + {[]byte{2, 2, 255, 0}, -256}, + {[]byte{2, 2, 255, 127}, -129}, + {[]byte{2, 1, 128}, -128}, + {[]byte{2, 1, 255}, -1}, + {[]byte{2, 1, 0}, 0}, + {[]byte{2, 1, 1}, 1}, + {[]byte{2, 1, 2}, 2}, + {[]byte{2, 1, 127}, 127}, + {[]byte{2, 2, 0, 128}, 128}, + {[]byte{2, 2, 1, 0}, 256}, + {[]byte{2, 4, 0, 128, 0, 0}, 0x800000}, + } + for i, test := range testData64 { + in := String(test.in) + var out int64 + ok := in.ReadASN1Integer(&out) + if !ok || out != test.out { + t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out) + } + } + + // Repeat the same cases, reading into a big.Int. + t.Run("big.Int", func(t *testing.T) { + for i, test := range testData64 { + in := String(test.in) + var out big.Int + ok := in.ReadASN1Integer(&out) + if !ok || out.Int64() != test.out { + t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out) + } + } + }) +} + +func TestReadASN1IntegerUnsigned(t *testing.T) { + testData := []struct { + in []byte + out uint64 + }{ + {[]byte{2, 1, 0}, 0}, + {[]byte{2, 1, 1}, 1}, + {[]byte{2, 1, 2}, 2}, + {[]byte{2, 1, 127}, 127}, + {[]byte{2, 2, 0, 128}, 128}, + {[]byte{2, 2, 1, 0}, 256}, + {[]byte{2, 4, 0, 128, 0, 0}, 0x800000}, + {[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff}, + {[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000}, + {[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff}, + } + for i, test := range testData { + in := String(test.in) + var out uint64 + ok := in.ReadASN1Integer(&out) + if !ok || out != test.out { + t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out) + } + } +} + +func TestReadASN1IntegerInvalid(t *testing.T) { + testData := []String{ + []byte{3, 1, 0}, // invalid tag + // truncated + []byte{2, 1}, + []byte{2, 2, 0}, + // not minimally encoded + []byte{2, 2, 0, 1}, + []byte{2, 2, 0xff, 0xff}, + } + + for i, test := range testData { + var out int64 + if test.ReadASN1Integer(&out) { + t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out) + } + } +} + +func TestASN1ObjectIdentifier(t *testing.T) { + testData := []struct { + in []byte + ok bool + out []int + }{ + {[]byte{}, false, []int{}}, + {[]byte{6, 0}, false, []int{}}, + {[]byte{5, 1, 85}, false, []int{2, 5}}, + {[]byte{6, 1, 85}, true, []int{2, 5}}, + {[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}}, + {[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}}, + {[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}}, + {[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}}, + } + + for i, test := range testData { + in := String(test.in) + var out encoding_asn1.ObjectIdentifier + ok := in.ReadASN1ObjectIdentifier(&out) + if ok != test.ok || ok && !out.Equal(test.out) { + t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out) + continue + } + + var b Builder + b.AddASN1ObjectIdentifier(out) + result, err := b.Bytes() + if builderOk := err == nil; test.ok != builderOk { + t.Errorf("#%d: error from Builder.Bytes: %s", i, err) + continue + } + if test.ok && !bytes.Equal(result, test.in) { + t.Errorf("#%d: reserialisation didn't match, got %x, want %x", i, result, test.in) + continue + } + } +} + +func TestReadASN1GeneralizedTime(t *testing.T) { + testData := []struct { + in string + ok bool + out time.Time + }{ + {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)}, + {"20100102030405", false, time.Time{}}, + {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}, + {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))}, + /* These are invalid times. However, the time package normalises times + * and they were accepted in some versions. See #11134. */ + {"00000100000000Z", false, time.Time{}}, + {"20101302030405Z", false, time.Time{}}, + {"20100002030405Z", false, time.Time{}}, + {"20100100030405Z", false, time.Time{}}, + {"20100132030405Z", false, time.Time{}}, + {"20100231030405Z", false, time.Time{}}, + {"20100102240405Z", false, time.Time{}}, + {"20100102036005Z", false, time.Time{}}, + {"20100102030460Z", false, time.Time{}}, + {"-20100102030410Z", false, time.Time{}}, + {"2010-0102030410Z", false, time.Time{}}, + {"2010-0002030410Z", false, time.Time{}}, + {"201001-02030410Z", false, time.Time{}}, + {"20100102-030410Z", false, time.Time{}}, + {"2010010203-0410Z", false, time.Time{}}, + {"201001020304-10Z", false, time.Time{}}, + } + for i, test := range testData { + in := String(append([]byte{byte(asn1.GeneralizedTime), byte(len(test.in))}, test.in...)) + var out time.Time + ok := in.ReadASN1GeneralizedTime(&out) + if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) { + t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out) + } + } +} + +func TestReadASN1BitString(t *testing.T) { + testData := []struct { + in []byte + ok bool + out encoding_asn1.BitString + }{ + {[]byte{}, false, encoding_asn1.BitString{}}, + {[]byte{0x00}, true, encoding_asn1.BitString{}}, + {[]byte{0x07, 0x00}, true, encoding_asn1.BitString{Bytes: []byte{0}, BitLength: 1}}, + {[]byte{0x07, 0x01}, false, encoding_asn1.BitString{}}, + {[]byte{0x07, 0x40}, false, encoding_asn1.BitString{}}, + {[]byte{0x08, 0x00}, false, encoding_asn1.BitString{}}, + {[]byte{0xff}, false, encoding_asn1.BitString{}}, + {[]byte{0xfe, 0x00}, false, encoding_asn1.BitString{}}, + } + for i, test := range testData { + in := String(append([]byte{3, byte(len(test.in))}, test.in...)) + var out encoding_asn1.BitString + ok := in.ReadASN1BitString(&out) + if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) { + t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out) + } + } +} diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/builder.go b/libgo/go/golang_org/x/crypto/cryptobyte/builder.go new file mode 100644 index 00000000000..29b4c764127 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/builder.go @@ -0,0 +1,309 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + "errors" + "fmt" +) + +// A Builder builds byte strings from fixed-length and length-prefixed values. +// Builders either allocate space as needed, or are ‘fixed’, which means that +// they write into a given buffer and produce an error if it's exhausted. +// +// The zero value is a usable Builder that allocates space as needed. +// +// Simple values are marshaled and appended to a Builder using methods on the +// Builder. Length-prefixed values are marshaled by providing a +// BuilderContinuation, which is a function that writes the inner contents of +// the value to a given Builder. See the documentation for BuilderContinuation +// for details. +type Builder struct { + err error + result []byte + fixedSize bool + child *Builder + offset int + pendingLenLen int + pendingIsASN1 bool + inContinuation *bool +} + +// NewBuilder creates a Builder that appends its output to the given buffer. +// Like append(), the slice will be reallocated if its capacity is exceeded. +// Use Bytes to get the final buffer. +func NewBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + } +} + +// NewFixedBuilder creates a Builder that appends its output into the given +// buffer. This builder does not reallocate the output buffer. Writes that +// would exceed the buffer's capacity are treated as an error. +func NewFixedBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + fixedSize: true, + } +} + +// Bytes returns the bytes written by the builder or an error if one has +// occurred during during building. +func (b *Builder) Bytes() ([]byte, error) { + if b.err != nil { + return nil, b.err + } + return b.result[b.offset:], nil +} + +// BytesOrPanic returns the bytes written by the builder or panics if an error +// has occurred during building. +func (b *Builder) BytesOrPanic() []byte { + if b.err != nil { + panic(b.err) + } + return b.result[b.offset:] +} + +// AddUint8 appends an 8-bit value to the byte string. +func (b *Builder) AddUint8(v uint8) { + b.add(byte(v)) +} + +// AddUint16 appends a big-endian, 16-bit value to the byte string. +func (b *Builder) AddUint16(v uint16) { + b.add(byte(v>>8), byte(v)) +} + +// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest +// byte of the 32-bit input value is silently truncated. +func (b *Builder) AddUint24(v uint32) { + b.add(byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint32 appends a big-endian, 32-bit value to the byte string. +func (b *Builder) AddUint32(v uint32) { + b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddBytes appends a sequence of bytes to the byte string. +func (b *Builder) AddBytes(v []byte) { + b.add(v...) +} + +// BuilderContinuation is continuation-passing interface for building +// length-prefixed byte sequences. Builder methods for length-prefixed +// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation +// supplied to them. The child builder passed to the continuation can be used +// to build the content of the length-prefixed sequence. For example: +// +// parent := cryptobyte.NewBuilder() +// parent.AddUint8LengthPrefixed(func (child *Builder) { +// child.AddUint8(42) +// child.AddUint8LengthPrefixed(func (grandchild *Builder) { +// grandchild.AddUint8(5) +// }) +// }) +// +// It is an error to write more bytes to the child than allowed by the reserved +// length prefix. After the continuation returns, the child must be considered +// invalid, i.e. users must not store any copies or references of the child +// that outlive the continuation. +// +// If the continuation panics with a value of type BuildError then the inner +// error will be returned as the error from Bytes. If the child panics +// otherwise then Bytes will repanic with the same value. +type BuilderContinuation func(child *Builder) + +// BuildError wraps an error. If a BuilderContinuation panics with this value, +// the panic will be recovered and the inner error will be returned from +// Builder.Bytes. +type BuildError struct { + Err error +} + +// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence. +func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(1, false, f) +} + +// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence. +func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(2, false, f) +} + +// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence. +func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(3, false, f) +} + +// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence. +func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(4, false, f) +} + +func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) { + if !*b.inContinuation { + *b.inContinuation = true + + defer func() { + *b.inContinuation = false + + r := recover() + if r == nil { + return + } + + if buildError, ok := r.(BuildError); ok { + b.err = buildError.Err + } else { + panic(r) + } + }() + } + + f(arg) +} + +func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) { + // Subsequent writes can be ignored if the builder has encountered an error. + if b.err != nil { + return + } + + offset := len(b.result) + b.add(make([]byte, lenLen)...) + + if b.inContinuation == nil { + b.inContinuation = new(bool) + } + + b.child = &Builder{ + result: b.result, + fixedSize: b.fixedSize, + offset: offset, + pendingLenLen: lenLen, + pendingIsASN1: isASN1, + inContinuation: b.inContinuation, + } + + b.callContinuation(f, b.child) + b.flushChild() + if b.child != nil { + panic("cryptobyte: internal error") + } +} + +func (b *Builder) flushChild() { + if b.child == nil { + return + } + b.child.flushChild() + child := b.child + b.child = nil + + if child.err != nil { + b.err = child.err + return + } + + length := len(child.result) - child.pendingLenLen - child.offset + + if length < 0 { + panic("cryptobyte: internal error") // result unexpectedly shrunk + } + + if child.pendingIsASN1 { + // For ASN.1, we reserved a single byte for the length. If that turned out + // to be incorrect, we have to move the contents along in order to make + // space. + if child.pendingLenLen != 1 { + panic("cryptobyte: internal error") + } + var lenLen, lenByte uint8 + if int64(length) > 0xfffffffe { + b.err = errors.New("pending ASN.1 child too long") + return + } else if length > 0xffffff { + lenLen = 5 + lenByte = 0x80 | 4 + } else if length > 0xffff { + lenLen = 4 + lenByte = 0x80 | 3 + } else if length > 0xff { + lenLen = 3 + lenByte = 0x80 | 2 + } else if length > 0x7f { + lenLen = 2 + lenByte = 0x80 | 1 + } else { + lenLen = 1 + lenByte = uint8(length) + length = 0 + } + + // Insert the initial length byte, make space for successive length bytes, + // and adjust the offset. + child.result[child.offset] = lenByte + extraBytes := int(lenLen - 1) + if extraBytes != 0 { + child.add(make([]byte, extraBytes)...) + childStart := child.offset + child.pendingLenLen + copy(child.result[childStart+extraBytes:], child.result[childStart:]) + } + child.offset++ + child.pendingLenLen = extraBytes + } + + l := length + for i := child.pendingLenLen - 1; i >= 0; i-- { + child.result[child.offset+i] = uint8(l) + l >>= 8 + } + if l != 0 { + b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen) + return + } + + if !b.fixedSize { + b.result = child.result // In case child reallocated result. + } +} + +func (b *Builder) add(bytes ...byte) { + if b.err != nil { + return + } + if b.child != nil { + panic("attempted write while child is pending") + } + if len(b.result)+len(bytes) < len(bytes) { + b.err = errors.New("cryptobyte: length overflow") + } + if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) { + b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer") + return + } + b.result = append(b.result, bytes...) +} + +// A MarshalingValue marshals itself into a Builder. +type MarshalingValue interface { + // Marshal is called by Builder.AddValue. It receives a pointer to a builder + // to marshal itself into. It may return an error that occurred during + // marshaling, such as unset or invalid values. + Marshal(b *Builder) error +} + +// AddValue calls Marshal on v, passing a pointer to the builder to append to. +// If Marshal returns an error, it is set on the Builder so that subsequent +// appends don't have an effect. +func (b *Builder) AddValue(v MarshalingValue) { + err := v.Marshal(b) + if err != nil { + b.err = err + } +} diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/cryptobyte_test.go b/libgo/go/golang_org/x/crypto/cryptobyte/cryptobyte_test.go new file mode 100644 index 00000000000..f294dd552b7 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/cryptobyte_test.go @@ -0,0 +1,428 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptobyte + +import ( + "bytes" + "errors" + "fmt" + "testing" +) + +func builderBytesEq(b *Builder, want ...byte) error { + got := b.BytesOrPanic() + if !bytes.Equal(got, want) { + return fmt.Errorf("Bytes() = %v, want %v", got, want) + } + return nil +} + +func TestContinuationError(t *testing.T) { + const errorStr = "TestContinuationError" + var b Builder + b.AddUint8LengthPrefixed(func(b *Builder) { + b.AddUint8(1) + panic(BuildError{Err: errors.New(errorStr)}) + }) + + ret, err := b.Bytes() + if ret != nil { + t.Error("expected nil result") + } + if err == nil { + t.Fatal("unexpected nil error") + } + if s := err.Error(); s != errorStr { + t.Errorf("expected error %q, got %v", errorStr, s) + } +} + +func TestContinuationNonError(t *testing.T) { + defer func() { + recover() + }() + + var b Builder + b.AddUint8LengthPrefixed(func(b *Builder) { + b.AddUint8(1) + panic(1) + }) + + t.Error("Builder did not panic") +} + +func TestGeneratedPanic(t *testing.T) { + defer func() { + recover() + }() + + var b Builder + b.AddUint8LengthPrefixed(func(b *Builder) { + var p *byte + *p = 0 + }) + + t.Error("Builder did not panic") +} + +func TestBytes(t *testing.T) { + var b Builder + v := []byte("foobarbaz") + b.AddBytes(v[0:3]) + b.AddBytes(v[3:4]) + b.AddBytes(v[4:9]) + if err := builderBytesEq(&b, v...); err != nil { + t.Error(err) + } + s := String(b.BytesOrPanic()) + for _, w := range []string{"foo", "bar", "baz"} { + var got []byte + if !s.ReadBytes(&got, 3) { + t.Errorf("ReadBytes() = false, want true (w = %v)", w) + } + want := []byte(w) + if !bytes.Equal(got, want) { + t.Errorf("ReadBytes(): got = %v, want %v", got, want) + } + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUint8(t *testing.T) { + var b Builder + b.AddUint8(42) + if err := builderBytesEq(&b, 42); err != nil { + t.Error(err) + } + + var s String = b.BytesOrPanic() + var v uint8 + if !s.ReadUint8(&v) { + t.Error("ReadUint8() = false, want true") + } + if v != 42 { + t.Errorf("v = %d, want 42", v) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUint16(t *testing.T) { + var b Builder + b.AddUint16(65534) + if err := builderBytesEq(&b, 255, 254); err != nil { + t.Error(err) + } + var s String = b.BytesOrPanic() + var v uint16 + if !s.ReadUint16(&v) { + t.Error("ReadUint16() == false, want true") + } + if v != 65534 { + t.Errorf("v = %d, want 65534", v) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUint24(t *testing.T) { + var b Builder + b.AddUint24(0xfffefd) + if err := builderBytesEq(&b, 255, 254, 253); err != nil { + t.Error(err) + } + + var s String = b.BytesOrPanic() + var v uint32 + if !s.ReadUint24(&v) { + t.Error("ReadUint8() = false, want true") + } + if v != 0xfffefd { + t.Errorf("v = %d, want fffefd", v) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUint24Truncation(t *testing.T) { + var b Builder + b.AddUint24(0x10111213) + if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil { + t.Error(err) + } +} + +func TestUint32(t *testing.T) { + var b Builder + b.AddUint32(0xfffefdfc) + if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil { + t.Error(err) + } + + var s String = b.BytesOrPanic() + var v uint32 + if !s.ReadUint32(&v) { + t.Error("ReadUint8() = false, want true") + } + if v != 0xfffefdfc { + t.Errorf("v = %x, want fffefdfc", v) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUMultiple(t *testing.T) { + var b Builder + b.AddUint8(23) + b.AddUint32(0xfffefdfc) + b.AddUint16(42) + if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil { + t.Error(err) + } + + var s String = b.BytesOrPanic() + var ( + x uint8 + y uint32 + z uint16 + ) + if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) { + t.Error("ReadUint8() = false, want true") + } + if x != 23 || y != 0xfffefdfc || z != 42 { + t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } +} + +func TestUint8LengthPrefixedSimple(t *testing.T) { + var b Builder + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8(23) + c.AddUint8(42) + }) + if err := builderBytesEq(&b, 2, 23, 42); err != nil { + t.Error(err) + } + + var base, child String = b.BytesOrPanic(), nil + var x, y uint8 + if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || + !child.ReadUint8(&y) { + t.Error("parsing failed") + } + if x != 23 || y != 42 { + t.Errorf("want x, y == 23, 42; got %d, %d", x, y) + } + if len(base) != 0 { + t.Errorf("len(base) = %d, want 0", len(base)) + } + if len(child) != 0 { + t.Errorf("len(child) = %d, want 0", len(child)) + } +} + +func TestUint8LengthPrefixedMulti(t *testing.T) { + var b Builder + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8(23) + c.AddUint8(42) + }) + b.AddUint8(5) + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8(123) + c.AddUint8(234) + }) + if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil { + t.Error(err) + } + + var s, child String = b.BytesOrPanic(), nil + var u, v, w, x, y uint8 + if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) || + !s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) { + t.Error("parsing failed") + } + if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 { + t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234", + u, v, w, x, y) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } + if len(child) != 0 { + t.Errorf("len(child) = %d, want 0", len(child)) + } +} + +func TestUint8LengthPrefixedNested(t *testing.T) { + var b Builder + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8(5) + c.AddUint8LengthPrefixed(func(d *Builder) { + d.AddUint8(23) + d.AddUint8(42) + }) + c.AddUint8(123) + }) + if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil { + t.Error(err) + } + + var base, child1, child2 String = b.BytesOrPanic(), nil, nil + var u, v, w, x uint8 + if !base.ReadUint8LengthPrefixed(&child1) { + t.Error("parsing base failed") + } + if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) { + t.Error("parsing child1 failed") + } + if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) { + t.Error("parsing child2 failed") + } + if u != 5 || v != 23 || w != 42 || x != 123 { + t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123", + u, v, w, x) + } + if len(base) != 0 { + t.Errorf("len(base) = %d, want 0", len(base)) + } + if len(child1) != 0 { + t.Errorf("len(child1) = %d, want 0", len(child1)) + } + if len(base) != 0 { + t.Errorf("len(child2) = %d, want 0", len(child2)) + } +} + +func TestPreallocatedBuffer(t *testing.T) { + var buf [5]byte + b := NewBuilder(buf[0:0]) + b.AddUint8(1) + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8(3) + c.AddUint8(4) + }) + b.AddUint16(1286) // Outgrow buf by one byte. + want := []byte{1, 2, 3, 4, 0} + if !bytes.Equal(buf[:], want) { + t.Errorf("buf = %v want %v", buf, want) + } + if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil { + t.Error(err) + } +} + +func TestWriteWithPendingChild(t *testing.T) { + var b Builder + b.AddUint8LengthPrefixed(func(c *Builder) { + c.AddUint8LengthPrefixed(func(d *Builder) { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") + } + }() + c.AddUint8(2) // panics + + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.AddUint8() did not panic") + } + }() + b.AddUint8(2) // panics + }) + + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.AddUint8() did not panic") + } + }() + b.AddUint8(2) // panics + }) +} + +// ASN.1 + +func TestASN1Int64(t *testing.T) { + tests := []struct { + in int64 + want []byte + }{ + {-0x800000, []byte{2, 3, 128, 0, 0}}, + {-256, []byte{2, 2, 255, 0}}, + {-129, []byte{2, 2, 255, 127}}, + {-128, []byte{2, 1, 128}}, + {-1, []byte{2, 1, 255}}, + {0, []byte{2, 1, 0}}, + {1, []byte{2, 1, 1}}, + {2, []byte{2, 1, 2}}, + {127, []byte{2, 1, 127}}, + {128, []byte{2, 2, 0, 128}}, + {256, []byte{2, 2, 1, 0}}, + {0x800000, []byte{2, 4, 0, 128, 0, 0}}, + } + for i, tt := range tests { + var b Builder + b.AddASN1Int64(tt.in) + if err := builderBytesEq(&b, tt.want...); err != nil { + t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in) + } + + var n int64 + s := String(b.BytesOrPanic()) + ok := s.ReadASN1Integer(&n) + if !ok || n != tt.in { + t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)", + ok, n, tt.in, i) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } + } +} + +func TestASN1Uint64(t *testing.T) { + tests := []struct { + in uint64 + want []byte + }{ + {0, []byte{2, 1, 0}}, + {1, []byte{2, 1, 1}}, + {2, []byte{2, 1, 2}}, + {127, []byte{2, 1, 127}}, + {128, []byte{2, 2, 0, 128}}, + {256, []byte{2, 2, 1, 0}}, + {0x800000, []byte{2, 4, 0, 128, 0, 0}}, + {0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}}, + {0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}}, + {0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}}, + } + for i, tt := range tests { + var b Builder + b.AddASN1Uint64(tt.in) + if err := builderBytesEq(&b, tt.want...); err != nil { + t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in) + } + + var n uint64 + s := String(b.BytesOrPanic()) + ok := s.ReadASN1Integer(&n) + if !ok || n != tt.in { + t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)", + ok, n, tt.in, i) + } + if len(s) != 0 { + t.Errorf("len(s) = %d, want 0", len(s)) + } + } +} diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/example_test.go b/libgo/go/golang_org/x/crypto/cryptobyte/example_test.go new file mode 100644 index 00000000000..f4c5f182b43 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/example_test.go @@ -0,0 +1,156 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package cryptobyte_test + +import ( + "errors" + "fmt" + + "golang_org/x/crypto/cryptobyte" + "golang_org/x/crypto/cryptobyte/asn1" +) + +func ExampleString_lengthPrefixed() { + // This is an example of parsing length-prefixed data (as found in, for + // example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed + // strings. + + input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'}) + var result []string + + var values cryptobyte.String + if !input.ReadUint16LengthPrefixed(&values) || + !input.Empty() { + panic("bad format") + } + + for !values.Empty() { + var value cryptobyte.String + if !values.ReadUint8LengthPrefixed(&value) { + panic("bad format") + } + + result = append(result, string(value)) + } + + // Output: []string{"hello", "world"} + fmt.Printf("%#v\n", result) +} + +func ExampleString_aSN1() { + // This is an example of parsing ASN.1 data that looks like: + // Foo ::= SEQUENCE { + // version [6] INTEGER DEFAULT 0 + // data OCTET STRING + // } + + input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'}) + + var ( + version int64 + data, inner, versionBytes cryptobyte.String + haveVersion bool + ) + if !input.ReadASN1(&inner, asn1.SEQUENCE) || + !input.Empty() || + !inner.ReadOptionalASN1(&versionBytes, &haveVersion, asn1.Tag(6).Constructed().ContextSpecific()) || + (haveVersion && !versionBytes.ReadASN1Integer(&version)) || + (haveVersion && !versionBytes.Empty()) || + !inner.ReadASN1(&data, asn1.OCTET_STRING) || + !inner.Empty() { + panic("bad format") + } + + // Output: haveVersion: true, version: 2, data: hello + fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data)) +} + +func ExampleBuilder_aSN1() { + // This is an example of building ASN.1 data that looks like: + // Foo ::= SEQUENCE { + // version [6] INTEGER DEFAULT 0 + // data OCTET STRING + // } + + version := int64(2) + data := []byte("hello") + const defaultVersion = 0 + + var b cryptobyte.Builder + b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { + if version != defaultVersion { + b.AddASN1(asn1.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) { + b.AddASN1Int64(version) + }) + } + b.AddASN1OctetString(data) + }) + + result, err := b.Bytes() + if err != nil { + panic(err) + } + + // Output: 300ca603020102040568656c6c6f + fmt.Printf("%x\n", result) +} + +func ExampleBuilder_lengthPrefixed() { + // This is an example of building length-prefixed data (as found in, + // for example, TLS). Imagine a 16-bit prefixed series of 8-bit + // prefixed strings. + input := []string{"hello", "world"} + + var b cryptobyte.Builder + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, value := range input { + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes([]byte(value)) + }) + } + }) + + result, err := b.Bytes() + if err != nil { + panic(err) + } + + // Output: 000c0568656c6c6f05776f726c64 + fmt.Printf("%x\n", result) +} + +func ExampleBuilder_lengthPrefixOverflow() { + // Writing more data that can be expressed by the length prefix results + // in an error from Bytes(). + + tooLarge := make([]byte, 256) + + var b cryptobyte.Builder + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(tooLarge) + }) + + result, err := b.Bytes() + fmt.Printf("len=%d err=%s\n", len(result), err) + + // Output: len=0 err=cryptobyte: pending child length 256 exceeds 1-byte length prefix +} + +func ExampleBuilderContinuation_errorHandling() { + var b cryptobyte.Builder + // Continuations that panic with a BuildError will cause Bytes to + // return the inner error. + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint32(0) + panic(cryptobyte.BuildError{Err: errors.New("example error")}) + }) + + result, err := b.Bytes() + fmt.Printf("len=%d err=%s\n", len(result), err) + + // Output: len=0 err=example error +} diff --git a/libgo/go/golang_org/x/crypto/cryptobyte/string.go b/libgo/go/golang_org/x/crypto/cryptobyte/string.go new file mode 100644 index 00000000000..7636fb9c8a8 --- /dev/null +++ b/libgo/go/golang_org/x/crypto/cryptobyte/string.go @@ -0,0 +1,167 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cryptobyte contains types that help with parsing and constructing +// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage +// contains useful ASN.1 constants.) +// +// The String type is for parsing. It wraps a []byte slice and provides helper +// functions for consuming structures, value by value. +// +// The Builder type is for constructing messages. It providers helper functions +// for appending values and also for appending length-prefixed submessages – +// without having to worry about calculating the length prefix ahead of time. +// +// See the documentation and examples for the Builder and String types to get +// started. +package cryptobyte // import "golang.org/x/crypto/cryptobyte" + +// String represents a string of bytes. It provides methods for parsing +// fixed-length and length-prefixed values from it. +type String []byte + +// read advances a String by n bytes and returns them. If less than n bytes +// remain, it returns nil. +func (s *String) read(n int) []byte { + if len(*s) < n { + return nil + } + v := (*s)[:n] + *s = (*s)[n:] + return v +} + +// Skip advances the String by n byte and reports whether it was successful. +func (s *String) Skip(n int) bool { + return s.read(n) != nil +} + +// ReadUint8 decodes an 8-bit value into out and advances over it. It +// returns true on success and false on error. +func (s *String) ReadUint8(out *uint8) bool { + v := s.read(1) + if v == nil { + return false + } + *out = uint8(v[0]) + return true +} + +// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. +// It returns true on success and false on error. +func (s *String) ReadUint16(out *uint16) bool { + v := s.read(2) + if v == nil { + return false + } + *out = uint16(v[0])<<8 | uint16(v[1]) + return true +} + +// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. +// It returns true on success and false on error. +func (s *String) ReadUint24(out *uint32) bool { + v := s.read(3) + if v == nil { + return false + } + *out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2]) + return true +} + +// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. +// It returns true on success and false on error. +func (s *String) ReadUint32(out *uint32) bool { + v := s.read(4) + if v == nil { + return false + } + *out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3]) + return true +} + +func (s *String) readUnsigned(out *uint32, length int) bool { + v := s.read(length) + if v == nil { + return false + } + var result uint32 + for i := 0; i < length; i++ { + result <<= 8 + result |= uint32(v[i]) + } + *out = result + return true +} + +func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool { + lenBytes := s.read(lenLen) + if lenBytes == nil { + return false + } + var length uint32 + for _, b := range lenBytes { + length = length << 8 + length = length | uint32(b) + } + if int(length) < 0 { + // This currently cannot overflow because we read uint24 at most, but check + // anyway in case that changes in the future. + return false + } + v := s.read(int(length)) + if v == nil { + return false + } + *outChild = v + return true +} + +// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value +// into out and advances over it. It returns true on success and false on +// error. +func (s *String) ReadUint8LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(1, out) +} + +// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit +// length-prefixed value into out and advances over it. It returns true on +// success and false on error. +func (s *String) ReadUint16LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(2, out) +} + +// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit +// length-prefixed value into out and advances over it. It returns true on +// success and false on error. +func (s *String) ReadUint24LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(3, out) +} + +// ReadBytes reads n bytes into out and advances over them. It returns true on +// success and false and error. +func (s *String) ReadBytes(out *[]byte, n int) bool { + v := s.read(n) + if v == nil { + return false + } + *out = v + return true +} + +// CopyBytes copies len(out) bytes into out and advances over them. It returns +// true on success and false on error. +func (s *String) CopyBytes(out []byte) bool { + n := len(out) + v := s.read(n) + if v == nil { + return false + } + return copy(out, v) == n +} + +// Empty reports whether the string does not contain any bytes. +func (s String) Empty() bool { + return len(s) == 0 +} diff --git a/libgo/go/golang_org/x/net/idna/idna.go b/libgo/go/golang_org/x/net/idna/idna.go index e8307f92c52..9fd0334cd9d 100644 --- a/libgo/go/golang_org/x/net/idna/idna.go +++ b/libgo/go/golang_org/x/net/idna/idna.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -21,6 +21,7 @@ import ( "unicode/utf8" "golang_org/x/text/secure/bidirule" + "golang_org/x/text/unicode/bidi" "golang_org/x/text/unicode/norm" ) @@ -67,6 +68,15 @@ func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } +// RemoveLeadingDots removes leading label separators. Leading runes that map to +// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. +// +// This is the behavior suggested by the UTS #46 and is adopted by some +// browsers. +func RemoveLeadingDots(remove bool) Option { + return func(o *options) { o.removeLeadingDots = remove } +} + // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. @@ -83,7 +93,7 @@ func ValidateLabels(enable bool) Option { } } -// StrictDomainName limits the set of permissable ASCII characters to those +// StrictDomainName limits the set of permissible ASCII characters to those // allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the // hyphen). This is set by default for MapForLookup and ValidateForRegistration. // @@ -137,10 +147,11 @@ func MapForLookup() Option { } type options struct { - transitional bool - useSTD3Rules bool - validateLabels bool - verifyDNSLength bool + transitional bool + useSTD3Rules bool + validateLabels bool + verifyDNSLength bool + removeLeadingDots bool trie *idnaTrie @@ -149,14 +160,14 @@ type options struct { // mapping implements a validation and mapping step as defined in RFC 5895 // or UTS 46, tailored to, for example, domain registration or lookup. - mapping func(p *Profile, s string) (string, error) + mapping func(p *Profile, s string) (mapped string, isBidi bool, err error) // bidirule, if specified, checks whether s conforms to the Bidi Rule // defined in RFC 5893. bidirule func(s string) bool } -// A Profile defines the configuration of a IDNA mapper. +// A Profile defines the configuration of an IDNA mapper. type Profile struct { options } @@ -289,12 +300,16 @@ func (e runeError) Error() string { // see http://www.unicode.org/reports/tr46. func (p *Profile) process(s string, toASCII bool) (string, error) { var err error + var isBidi bool if p.mapping != nil { - s, err = p.mapping(p, s) + s, isBidi, err = p.mapping(p, s) } // Remove leading empty labels. - for ; len(s) > 0 && s[0] == '.'; s = s[1:] { + if p.removeLeadingDots { + for ; len(s) > 0 && s[0] == '.'; s = s[1:] { + } } + // TODO: allow for a quick check of the tables data. // It seems like we should only create this error on ToASCII, but the // UTS 46 conformance tests suggests we should always check this. if err == nil && p.verifyDNSLength && s == "" { @@ -320,6 +335,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { // Spec says keep the old label. continue } + isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight labels.set(u) if err == nil && p.validateLabels { err = p.fromPuny(p, u) @@ -334,6 +350,14 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { err = p.validateLabel(label) } } + if isBidi && p.bidirule != nil && err == nil { + for labels.reset(); !labels.done(); labels.next() { + if !p.bidirule(labels.label()) { + err = &labelError{s, "B"} + break + } + } + } if toASCII { for labels.reset(); !labels.done(); labels.next() { label := labels.label() @@ -365,41 +389,77 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { return s, err } -func normalize(p *Profile, s string) (string, error) { - return norm.NFC.String(s), nil +func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) { + // TODO: consider first doing a quick check to see if any of these checks + // need to be done. This will make it slower in the general case, but + // faster in the common case. + mapped = norm.NFC.String(s) + isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft + return mapped, isBidi, nil } -func validateRegistration(p *Profile, s string) (string, error) { +func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) { + // TODO: filter need for normalization in loop below. if !norm.NFC.IsNormalString(s) { - return s, &labelError{s, "V1"} + return s, false, &labelError{s, "V1"} } - var err error for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) - i += sz + if sz == 0 { + return s, bidi, runeError(utf8.RuneError) + } + bidi = bidi || info(v).isBidi(s[i:]) // Copy bytes not copied so far. switch p.simplify(info(v).category()) { // TODO: handle the NV8 defined in the Unicode idna data set to allow // for strict conformance to IDNA2008. case valid, deviation: case disallowed, mapped, unknown, ignored: - if err == nil { - r, _ := utf8.DecodeRuneInString(s[i:]) - err = runeError(r) - } + r, _ := utf8.DecodeRuneInString(s[i:]) + return s, bidi, runeError(r) } + i += sz } - return s, err + return s, bidi, nil } -func validateAndMap(p *Profile, s string) (string, error) { +func (c info) isBidi(s string) bool { + if !c.isMapped() { + return c&attributesMask == rtl + } + // TODO: also store bidi info for mapped data. This is possible, but a bit + // cumbersome and not for the common case. + p, _ := bidi.LookupString(s) + switch p.Class() { + case bidi.R, bidi.AL, bidi.AN: + return true + } + return false +} + +func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) { var ( - err error - b []byte - k int + b []byte + k int ) + // combinedInfoBits contains the or-ed bits of all runes. We use this + // to derive the mayNeedNorm bit later. This may trigger normalization + // overeagerly, but it will not do so in the common case. The end result + // is another 10% saving on BenchmarkProfile for the common case. + var combinedInfoBits info for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) + if sz == 0 { + b = append(b, s[k:i]...) + b = append(b, "\ufffd"...) + k = len(s) + if err == nil { + err = runeError(utf8.RuneError) + } + break + } + combinedInfoBits |= info(v) + bidi = bidi || info(v).isBidi(s[i:]) start := i i += sz // Copy bytes not copied so far. @@ -408,7 +468,7 @@ func validateAndMap(p *Profile, s string) (string, error) { continue case disallowed: if err == nil { - r, _ := utf8.DecodeRuneInString(s[i:]) + r, _ := utf8.DecodeRuneInString(s[start:]) err = runeError(r) } continue @@ -426,7 +486,9 @@ func validateAndMap(p *Profile, s string) (string, error) { } if k == 0 { // No changes so far. - s = norm.NFC.String(s) + if combinedInfoBits&mayNeedNorm != 0 { + s = norm.NFC.String(s) + } } else { b = append(b, s[k:]...) if norm.NFC.QuickSpan(b) != len(b) { @@ -435,7 +497,7 @@ func validateAndMap(p *Profile, s string) (string, error) { // TODO: the punycode converters require strings as input. s = string(b) } - return s, err + return s, bidi, err } // A labelIter allows iterating over domain name labels. @@ -530,8 +592,13 @@ func validateFromPunycode(p *Profile, s string) error { if !norm.NFC.IsNormalString(s) { return &labelError{s, "V1"} } + // TODO: detect whether string may have to be normalized in the following + // loop. for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) + if sz == 0 { + return runeError(utf8.RuneError) + } if c := p.simplify(info(v).category()); c != valid && c != deviation { return &labelError{s, "V6"} } @@ -604,16 +671,13 @@ var joinStates = [][numJoinTypes]joinState{ // validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are // already implicitly satisfied by the overall implementation. -func (p *Profile) validateLabel(s string) error { +func (p *Profile) validateLabel(s string) (err error) { if s == "" { if p.verifyDNSLength { return &labelError{s, "A4"} } return nil } - if p.bidirule != nil && !p.bidirule(s) { - return &labelError{s, "B"} - } if !p.validateLabels { return nil } diff --git a/libgo/go/golang_org/x/net/idna/punycode.go b/libgo/go/golang_org/x/net/idna/punycode.go index fab9229881a..02c7d59af3b 100644 --- a/libgo/go/golang_org/x/net/idna/punycode.go +++ b/libgo/go/golang_org/x/net/idna/punycode.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/net/idna/tables.go b/libgo/go/golang_org/x/net/idna/tables.go index d57a3e25a9d..a470c5a3e25 100644 --- a/libgo/go/golang_org/x/net/idna/tables.go +++ b/libgo/go/golang_org/x/net/idna/tables.go @@ -1,11 +1,11 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT. package idna // UnicodeVersion is the Unicode version from which the tables in this package are derived. -const UnicodeVersion = "9.0.0" +const UnicodeVersion = "10.0.0" var mappings string = "" + // Size: 8176 bytes "\x00\x01 \x03 ̈\x01a\x03 ̄\x012\x013\x03 ́\x03 ̧\x011\x01o\x051⁄4\x051⁄2" + @@ -546,7 +546,7 @@ func (t *idnaTrie) lookupStringUnsafe(s string) uint16 { return 0 } -// idnaTrie. Total size: 28496 bytes (27.83 KiB). Checksum: 43288b883596640e. +// idnaTrie. Total size: 29052 bytes (28.37 KiB). Checksum: ef06e7ecc26f36dd. type idnaTrie struct{} func newIdnaTrie(i int) *idnaTrie { @@ -556,17 +556,17 @@ func newIdnaTrie(i int) *idnaTrie { // lookupValue determines the type of block n and looks up the value for b. func (t *idnaTrie) lookupValue(n uint32, b byte) uint16 { switch { - case n < 123: + case n < 125: return uint16(idnaValues[n<<6+uint32(b)]) default: - n -= 123 + n -= 125 return uint16(idnaSparse.lookup(n, b)) } } -// idnaValues: 125 blocks, 8000 entries, 16000 bytes +// idnaValues: 127 blocks, 8128 entries, 16256 bytes // The third block is the zero block. -var idnaValues = [8000]uint16{ +var idnaValues = [8128]uint16{ // Block 0x0, offset 0x0 0x00: 0x0080, 0x01: 0x0080, 0x02: 0x0080, 0x03: 0x0080, 0x04: 0x0080, 0x05: 0x0080, 0x06: 0x0080, 0x07: 0x0080, 0x08: 0x0080, 0x09: 0x0080, 0x0a: 0x0080, 0x0b: 0x0080, @@ -677,14 +677,14 @@ var idnaValues = [8000]uint16{ 0x276: 0x0018, 0x277: 0x0018, 0x278: 0x0018, 0x279: 0x0018, 0x27a: 0x0018, 0x27b: 0x0018, 0x27c: 0x0018, 0x27d: 0x0018, 0x27e: 0x0018, 0x27f: 0x0018, // Block 0xa, offset 0x280 - 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x1308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, - 0x286: 0x1308, 0x287: 0x1308, 0x288: 0x1308, 0x289: 0x1308, 0x28a: 0x1308, 0x28b: 0x1308, - 0x28c: 0x1308, 0x28d: 0x1308, 0x28e: 0x1308, 0x28f: 0x13c0, 0x290: 0x1308, 0x291: 0x1308, - 0x292: 0x1308, 0x293: 0x1308, 0x294: 0x1308, 0x295: 0x1308, 0x296: 0x1308, 0x297: 0x1308, - 0x298: 0x1308, 0x299: 0x1308, 0x29a: 0x1308, 0x29b: 0x1308, 0x29c: 0x1308, 0x29d: 0x1308, - 0x29e: 0x1308, 0x29f: 0x1308, 0x2a0: 0x1308, 0x2a1: 0x1308, 0x2a2: 0x1308, 0x2a3: 0x1308, - 0x2a4: 0x1308, 0x2a5: 0x1308, 0x2a6: 0x1308, 0x2a7: 0x1308, 0x2a8: 0x1308, 0x2a9: 0x1308, - 0x2aa: 0x1308, 0x2ab: 0x1308, 0x2ac: 0x1308, 0x2ad: 0x1308, 0x2ae: 0x1308, 0x2af: 0x1308, + 0x280: 0x03dd, 0x281: 0x03dd, 0x282: 0x3308, 0x283: 0x03f5, 0x284: 0x0379, 0x285: 0x040d, + 0x286: 0x3308, 0x287: 0x3308, 0x288: 0x3308, 0x289: 0x3308, 0x28a: 0x3308, 0x28b: 0x3308, + 0x28c: 0x3308, 0x28d: 0x3308, 0x28e: 0x3308, 0x28f: 0x33c0, 0x290: 0x3308, 0x291: 0x3308, + 0x292: 0x3308, 0x293: 0x3308, 0x294: 0x3308, 0x295: 0x3308, 0x296: 0x3308, 0x297: 0x3308, + 0x298: 0x3308, 0x299: 0x3308, 0x29a: 0x3308, 0x29b: 0x3308, 0x29c: 0x3308, 0x29d: 0x3308, + 0x29e: 0x3308, 0x29f: 0x3308, 0x2a0: 0x3308, 0x2a1: 0x3308, 0x2a2: 0x3308, 0x2a3: 0x3308, + 0x2a4: 0x3308, 0x2a5: 0x3308, 0x2a6: 0x3308, 0x2a7: 0x3308, 0x2a8: 0x3308, 0x2a9: 0x3308, + 0x2aa: 0x3308, 0x2ab: 0x3308, 0x2ac: 0x3308, 0x2ad: 0x3308, 0x2ae: 0x3308, 0x2af: 0x3308, 0x2b0: 0xe00d, 0x2b1: 0x0008, 0x2b2: 0xe00d, 0x2b3: 0x0008, 0x2b4: 0x0425, 0x2b5: 0x0008, 0x2b6: 0xe00d, 0x2b7: 0x0008, 0x2b8: 0x0040, 0x2b9: 0x0040, 0x2ba: 0x03a2, 0x2bb: 0x0008, 0x2bc: 0x0008, 0x2bd: 0x0008, 0x2be: 0x03c2, 0x2bf: 0x043d, @@ -725,8 +725,8 @@ var idnaValues = [8000]uint16{ 0x376: 0xe00d, 0x377: 0x0008, 0x378: 0xe00d, 0x379: 0x0008, 0x37a: 0xe00d, 0x37b: 0x0008, 0x37c: 0xe00d, 0x37d: 0x0008, 0x37e: 0xe00d, 0x37f: 0x0008, // Block 0xe, offset 0x380 - 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x1308, 0x384: 0x1308, 0x385: 0x1308, - 0x386: 0x1308, 0x387: 0x1308, 0x388: 0x1318, 0x389: 0x1318, 0x38a: 0xe00d, 0x38b: 0x0008, + 0x380: 0xe00d, 0x381: 0x0008, 0x382: 0x0018, 0x383: 0x3308, 0x384: 0x3308, 0x385: 0x3308, + 0x386: 0x3308, 0x387: 0x3308, 0x388: 0x3318, 0x389: 0x3318, 0x38a: 0xe00d, 0x38b: 0x0008, 0x38c: 0xe00d, 0x38d: 0x0008, 0x38e: 0xe00d, 0x38f: 0x0008, 0x390: 0xe00d, 0x391: 0x0008, 0x392: 0xe00d, 0x393: 0x0008, 0x394: 0xe00d, 0x395: 0x0008, 0x396: 0xe00d, 0x397: 0x0008, 0x398: 0xe00d, 0x399: 0x0008, 0x39a: 0xe00d, 0x39b: 0x0008, 0x39c: 0xe00d, 0x39d: 0x0008, @@ -761,129 +761,129 @@ var idnaValues = [8000]uint16{ 0x436: 0x03f5, 0x437: 0x03f5, 0x438: 0x03f5, 0x439: 0x03f5, 0x43a: 0x03f5, 0x43b: 0x03f5, 0x43c: 0x03f5, 0x43d: 0x03f5, 0x43e: 0x03f5, 0x43f: 0x03f5, // Block 0x11, offset 0x440 - 0x440: 0x0040, 0x441: 0x0040, 0x442: 0x0040, 0x443: 0x0040, 0x444: 0x0040, 0x445: 0x0040, - 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0018, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0018, - 0x44c: 0x0018, 0x44d: 0x0018, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x1308, 0x451: 0x1308, - 0x452: 0x1308, 0x453: 0x1308, 0x454: 0x1308, 0x455: 0x1308, 0x456: 0x1308, 0x457: 0x1308, - 0x458: 0x1308, 0x459: 0x1308, 0x45a: 0x1308, 0x45b: 0x0018, 0x45c: 0x0340, 0x45d: 0x0040, - 0x45e: 0x0018, 0x45f: 0x0018, 0x460: 0x0208, 0x461: 0x0008, 0x462: 0x0408, 0x463: 0x0408, - 0x464: 0x0408, 0x465: 0x0408, 0x466: 0x0208, 0x467: 0x0408, 0x468: 0x0208, 0x469: 0x0408, - 0x46a: 0x0208, 0x46b: 0x0208, 0x46c: 0x0208, 0x46d: 0x0208, 0x46e: 0x0208, 0x46f: 0x0408, - 0x470: 0x0408, 0x471: 0x0408, 0x472: 0x0408, 0x473: 0x0208, 0x474: 0x0208, 0x475: 0x0208, - 0x476: 0x0208, 0x477: 0x0208, 0x478: 0x0208, 0x479: 0x0208, 0x47a: 0x0208, 0x47b: 0x0208, - 0x47c: 0x0208, 0x47d: 0x0208, 0x47e: 0x0208, 0x47f: 0x0208, + 0x440: 0x0840, 0x441: 0x0840, 0x442: 0x0840, 0x443: 0x0840, 0x444: 0x0840, 0x445: 0x0840, + 0x446: 0x0018, 0x447: 0x0018, 0x448: 0x0818, 0x449: 0x0018, 0x44a: 0x0018, 0x44b: 0x0818, + 0x44c: 0x0018, 0x44d: 0x0818, 0x44e: 0x0018, 0x44f: 0x0018, 0x450: 0x3308, 0x451: 0x3308, + 0x452: 0x3308, 0x453: 0x3308, 0x454: 0x3308, 0x455: 0x3308, 0x456: 0x3308, 0x457: 0x3308, + 0x458: 0x3308, 0x459: 0x3308, 0x45a: 0x3308, 0x45b: 0x0818, 0x45c: 0x0b40, 0x45d: 0x0040, + 0x45e: 0x0818, 0x45f: 0x0818, 0x460: 0x0a08, 0x461: 0x0808, 0x462: 0x0c08, 0x463: 0x0c08, + 0x464: 0x0c08, 0x465: 0x0c08, 0x466: 0x0a08, 0x467: 0x0c08, 0x468: 0x0a08, 0x469: 0x0c08, + 0x46a: 0x0a08, 0x46b: 0x0a08, 0x46c: 0x0a08, 0x46d: 0x0a08, 0x46e: 0x0a08, 0x46f: 0x0c08, + 0x470: 0x0c08, 0x471: 0x0c08, 0x472: 0x0c08, 0x473: 0x0a08, 0x474: 0x0a08, 0x475: 0x0a08, + 0x476: 0x0a08, 0x477: 0x0a08, 0x478: 0x0a08, 0x479: 0x0a08, 0x47a: 0x0a08, 0x47b: 0x0a08, + 0x47c: 0x0a08, 0x47d: 0x0a08, 0x47e: 0x0a08, 0x47f: 0x0a08, // Block 0x12, offset 0x480 - 0x480: 0x0408, 0x481: 0x0208, 0x482: 0x0208, 0x483: 0x0408, 0x484: 0x0408, 0x485: 0x0408, - 0x486: 0x0408, 0x487: 0x0408, 0x488: 0x0408, 0x489: 0x0408, 0x48a: 0x0408, 0x48b: 0x0408, - 0x48c: 0x0208, 0x48d: 0x0408, 0x48e: 0x0208, 0x48f: 0x0408, 0x490: 0x0208, 0x491: 0x0208, - 0x492: 0x0408, 0x493: 0x0408, 0x494: 0x0018, 0x495: 0x0408, 0x496: 0x1308, 0x497: 0x1308, - 0x498: 0x1308, 0x499: 0x1308, 0x49a: 0x1308, 0x49b: 0x1308, 0x49c: 0x1308, 0x49d: 0x0040, - 0x49e: 0x0018, 0x49f: 0x1308, 0x4a0: 0x1308, 0x4a1: 0x1308, 0x4a2: 0x1308, 0x4a3: 0x1308, - 0x4a4: 0x1308, 0x4a5: 0x0008, 0x4a6: 0x0008, 0x4a7: 0x1308, 0x4a8: 0x1308, 0x4a9: 0x0018, - 0x4aa: 0x1308, 0x4ab: 0x1308, 0x4ac: 0x1308, 0x4ad: 0x1308, 0x4ae: 0x0408, 0x4af: 0x0408, - 0x4b0: 0x0008, 0x4b1: 0x0008, 0x4b2: 0x0008, 0x4b3: 0x0008, 0x4b4: 0x0008, 0x4b5: 0x0008, - 0x4b6: 0x0008, 0x4b7: 0x0008, 0x4b8: 0x0008, 0x4b9: 0x0008, 0x4ba: 0x0208, 0x4bb: 0x0208, - 0x4bc: 0x0208, 0x4bd: 0x0008, 0x4be: 0x0008, 0x4bf: 0x0208, + 0x480: 0x0818, 0x481: 0x0a08, 0x482: 0x0a08, 0x483: 0x0a08, 0x484: 0x0a08, 0x485: 0x0a08, + 0x486: 0x0a08, 0x487: 0x0a08, 0x488: 0x0c08, 0x489: 0x0a08, 0x48a: 0x0a08, 0x48b: 0x3308, + 0x48c: 0x3308, 0x48d: 0x3308, 0x48e: 0x3308, 0x48f: 0x3308, 0x490: 0x3308, 0x491: 0x3308, + 0x492: 0x3308, 0x493: 0x3308, 0x494: 0x3308, 0x495: 0x3308, 0x496: 0x3308, 0x497: 0x3308, + 0x498: 0x3308, 0x499: 0x3308, 0x49a: 0x3308, 0x49b: 0x3308, 0x49c: 0x3308, 0x49d: 0x3308, + 0x49e: 0x3308, 0x49f: 0x3308, 0x4a0: 0x0808, 0x4a1: 0x0808, 0x4a2: 0x0808, 0x4a3: 0x0808, + 0x4a4: 0x0808, 0x4a5: 0x0808, 0x4a6: 0x0808, 0x4a7: 0x0808, 0x4a8: 0x0808, 0x4a9: 0x0808, + 0x4aa: 0x0018, 0x4ab: 0x0818, 0x4ac: 0x0818, 0x4ad: 0x0818, 0x4ae: 0x0a08, 0x4af: 0x0a08, + 0x4b0: 0x3308, 0x4b1: 0x0c08, 0x4b2: 0x0c08, 0x4b3: 0x0c08, 0x4b4: 0x0808, 0x4b5: 0x0429, + 0x4b6: 0x0451, 0x4b7: 0x0479, 0x4b8: 0x04a1, 0x4b9: 0x0a08, 0x4ba: 0x0a08, 0x4bb: 0x0a08, + 0x4bc: 0x0a08, 0x4bd: 0x0a08, 0x4be: 0x0a08, 0x4bf: 0x0a08, // Block 0x13, offset 0x4c0 - 0x4c0: 0x0018, 0x4c1: 0x0018, 0x4c2: 0x0018, 0x4c3: 0x0018, 0x4c4: 0x0018, 0x4c5: 0x0018, - 0x4c6: 0x0018, 0x4c7: 0x0018, 0x4c8: 0x0018, 0x4c9: 0x0018, 0x4ca: 0x0018, 0x4cb: 0x0018, - 0x4cc: 0x0018, 0x4cd: 0x0018, 0x4ce: 0x0040, 0x4cf: 0x0340, 0x4d0: 0x0408, 0x4d1: 0x1308, - 0x4d2: 0x0208, 0x4d3: 0x0208, 0x4d4: 0x0208, 0x4d5: 0x0408, 0x4d6: 0x0408, 0x4d7: 0x0408, - 0x4d8: 0x0408, 0x4d9: 0x0408, 0x4da: 0x0208, 0x4db: 0x0208, 0x4dc: 0x0208, 0x4dd: 0x0208, - 0x4de: 0x0408, 0x4df: 0x0208, 0x4e0: 0x0208, 0x4e1: 0x0208, 0x4e2: 0x0208, 0x4e3: 0x0208, - 0x4e4: 0x0208, 0x4e5: 0x0208, 0x4e6: 0x0208, 0x4e7: 0x0208, 0x4e8: 0x0408, 0x4e9: 0x0208, - 0x4ea: 0x0408, 0x4eb: 0x0208, 0x4ec: 0x0408, 0x4ed: 0x0208, 0x4ee: 0x0208, 0x4ef: 0x0408, - 0x4f0: 0x1308, 0x4f1: 0x1308, 0x4f2: 0x1308, 0x4f3: 0x1308, 0x4f4: 0x1308, 0x4f5: 0x1308, - 0x4f6: 0x1308, 0x4f7: 0x1308, 0x4f8: 0x1308, 0x4f9: 0x1308, 0x4fa: 0x1308, 0x4fb: 0x1308, - 0x4fc: 0x1308, 0x4fd: 0x1308, 0x4fe: 0x1308, 0x4ff: 0x1308, + 0x4c0: 0x0c08, 0x4c1: 0x0a08, 0x4c2: 0x0a08, 0x4c3: 0x0c08, 0x4c4: 0x0c08, 0x4c5: 0x0c08, + 0x4c6: 0x0c08, 0x4c7: 0x0c08, 0x4c8: 0x0c08, 0x4c9: 0x0c08, 0x4ca: 0x0c08, 0x4cb: 0x0c08, + 0x4cc: 0x0a08, 0x4cd: 0x0c08, 0x4ce: 0x0a08, 0x4cf: 0x0c08, 0x4d0: 0x0a08, 0x4d1: 0x0a08, + 0x4d2: 0x0c08, 0x4d3: 0x0c08, 0x4d4: 0x0818, 0x4d5: 0x0c08, 0x4d6: 0x3308, 0x4d7: 0x3308, + 0x4d8: 0x3308, 0x4d9: 0x3308, 0x4da: 0x3308, 0x4db: 0x3308, 0x4dc: 0x3308, 0x4dd: 0x0840, + 0x4de: 0x0018, 0x4df: 0x3308, 0x4e0: 0x3308, 0x4e1: 0x3308, 0x4e2: 0x3308, 0x4e3: 0x3308, + 0x4e4: 0x3308, 0x4e5: 0x0808, 0x4e6: 0x0808, 0x4e7: 0x3308, 0x4e8: 0x3308, 0x4e9: 0x0018, + 0x4ea: 0x3308, 0x4eb: 0x3308, 0x4ec: 0x3308, 0x4ed: 0x3308, 0x4ee: 0x0c08, 0x4ef: 0x0c08, + 0x4f0: 0x0008, 0x4f1: 0x0008, 0x4f2: 0x0008, 0x4f3: 0x0008, 0x4f4: 0x0008, 0x4f5: 0x0008, + 0x4f6: 0x0008, 0x4f7: 0x0008, 0x4f8: 0x0008, 0x4f9: 0x0008, 0x4fa: 0x0a08, 0x4fb: 0x0a08, + 0x4fc: 0x0a08, 0x4fd: 0x0808, 0x4fe: 0x0808, 0x4ff: 0x0a08, // Block 0x14, offset 0x500 - 0x500: 0x1008, 0x501: 0x1308, 0x502: 0x1308, 0x503: 0x1308, 0x504: 0x1308, 0x505: 0x1308, - 0x506: 0x1308, 0x507: 0x1308, 0x508: 0x1308, 0x509: 0x1008, 0x50a: 0x1008, 0x50b: 0x1008, - 0x50c: 0x1008, 0x50d: 0x1b08, 0x50e: 0x1008, 0x50f: 0x1008, 0x510: 0x0008, 0x511: 0x1308, - 0x512: 0x1308, 0x513: 0x1308, 0x514: 0x1308, 0x515: 0x1308, 0x516: 0x1308, 0x517: 0x1308, - 0x518: 0x04c9, 0x519: 0x0501, 0x51a: 0x0539, 0x51b: 0x0571, 0x51c: 0x05a9, 0x51d: 0x05e1, - 0x51e: 0x0619, 0x51f: 0x0651, 0x520: 0x0008, 0x521: 0x0008, 0x522: 0x1308, 0x523: 0x1308, - 0x524: 0x0018, 0x525: 0x0018, 0x526: 0x0008, 0x527: 0x0008, 0x528: 0x0008, 0x529: 0x0008, - 0x52a: 0x0008, 0x52b: 0x0008, 0x52c: 0x0008, 0x52d: 0x0008, 0x52e: 0x0008, 0x52f: 0x0008, - 0x530: 0x0018, 0x531: 0x0008, 0x532: 0x0008, 0x533: 0x0008, 0x534: 0x0008, 0x535: 0x0008, - 0x536: 0x0008, 0x537: 0x0008, 0x538: 0x0008, 0x539: 0x0008, 0x53a: 0x0008, 0x53b: 0x0008, - 0x53c: 0x0008, 0x53d: 0x0008, 0x53e: 0x0008, 0x53f: 0x0008, + 0x500: 0x0818, 0x501: 0x0818, 0x502: 0x0818, 0x503: 0x0818, 0x504: 0x0818, 0x505: 0x0818, + 0x506: 0x0818, 0x507: 0x0818, 0x508: 0x0818, 0x509: 0x0818, 0x50a: 0x0818, 0x50b: 0x0818, + 0x50c: 0x0818, 0x50d: 0x0818, 0x50e: 0x0040, 0x50f: 0x0b40, 0x510: 0x0c08, 0x511: 0x3308, + 0x512: 0x0a08, 0x513: 0x0a08, 0x514: 0x0a08, 0x515: 0x0c08, 0x516: 0x0c08, 0x517: 0x0c08, + 0x518: 0x0c08, 0x519: 0x0c08, 0x51a: 0x0a08, 0x51b: 0x0a08, 0x51c: 0x0a08, 0x51d: 0x0a08, + 0x51e: 0x0c08, 0x51f: 0x0a08, 0x520: 0x0a08, 0x521: 0x0a08, 0x522: 0x0a08, 0x523: 0x0a08, + 0x524: 0x0a08, 0x525: 0x0a08, 0x526: 0x0a08, 0x527: 0x0a08, 0x528: 0x0c08, 0x529: 0x0a08, + 0x52a: 0x0c08, 0x52b: 0x0a08, 0x52c: 0x0c08, 0x52d: 0x0a08, 0x52e: 0x0a08, 0x52f: 0x0c08, + 0x530: 0x3308, 0x531: 0x3308, 0x532: 0x3308, 0x533: 0x3308, 0x534: 0x3308, 0x535: 0x3308, + 0x536: 0x3308, 0x537: 0x3308, 0x538: 0x3308, 0x539: 0x3308, 0x53a: 0x3308, 0x53b: 0x3308, + 0x53c: 0x3308, 0x53d: 0x3308, 0x53e: 0x3308, 0x53f: 0x3308, // Block 0x15, offset 0x540 - 0x540: 0x0008, 0x541: 0x1308, 0x542: 0x1008, 0x543: 0x1008, 0x544: 0x0040, 0x545: 0x0008, - 0x546: 0x0008, 0x547: 0x0008, 0x548: 0x0008, 0x549: 0x0008, 0x54a: 0x0008, 0x54b: 0x0008, - 0x54c: 0x0008, 0x54d: 0x0040, 0x54e: 0x0040, 0x54f: 0x0008, 0x550: 0x0008, 0x551: 0x0040, - 0x552: 0x0040, 0x553: 0x0008, 0x554: 0x0008, 0x555: 0x0008, 0x556: 0x0008, 0x557: 0x0008, - 0x558: 0x0008, 0x559: 0x0008, 0x55a: 0x0008, 0x55b: 0x0008, 0x55c: 0x0008, 0x55d: 0x0008, - 0x55e: 0x0008, 0x55f: 0x0008, 0x560: 0x0008, 0x561: 0x0008, 0x562: 0x0008, 0x563: 0x0008, - 0x564: 0x0008, 0x565: 0x0008, 0x566: 0x0008, 0x567: 0x0008, 0x568: 0x0008, 0x569: 0x0040, - 0x56a: 0x0008, 0x56b: 0x0008, 0x56c: 0x0008, 0x56d: 0x0008, 0x56e: 0x0008, 0x56f: 0x0008, - 0x570: 0x0008, 0x571: 0x0040, 0x572: 0x0008, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040, - 0x576: 0x0008, 0x577: 0x0008, 0x578: 0x0008, 0x579: 0x0008, 0x57a: 0x0040, 0x57b: 0x0040, - 0x57c: 0x1308, 0x57d: 0x0008, 0x57e: 0x1008, 0x57f: 0x1008, + 0x540: 0x0c08, 0x541: 0x0a08, 0x542: 0x0a08, 0x543: 0x0a08, 0x544: 0x0a08, 0x545: 0x0a08, + 0x546: 0x0c08, 0x547: 0x0c08, 0x548: 0x0a08, 0x549: 0x0c08, 0x54a: 0x0a08, 0x54b: 0x0a08, + 0x54c: 0x0a08, 0x54d: 0x0a08, 0x54e: 0x0a08, 0x54f: 0x0a08, 0x550: 0x0a08, 0x551: 0x0a08, + 0x552: 0x0a08, 0x553: 0x0a08, 0x554: 0x0c08, 0x555: 0x0a08, 0x556: 0x0808, 0x557: 0x0808, + 0x558: 0x0808, 0x559: 0x3308, 0x55a: 0x3308, 0x55b: 0x3308, 0x55c: 0x0040, 0x55d: 0x0040, + 0x55e: 0x0818, 0x55f: 0x0040, 0x560: 0x0a08, 0x561: 0x0808, 0x562: 0x0a08, 0x563: 0x0a08, + 0x564: 0x0a08, 0x565: 0x0a08, 0x566: 0x0808, 0x567: 0x0c08, 0x568: 0x0a08, 0x569: 0x0c08, + 0x56a: 0x0c08, 0x56b: 0x0040, 0x56c: 0x0040, 0x56d: 0x0040, 0x56e: 0x0040, 0x56f: 0x0040, + 0x570: 0x0040, 0x571: 0x0040, 0x572: 0x0040, 0x573: 0x0040, 0x574: 0x0040, 0x575: 0x0040, + 0x576: 0x0040, 0x577: 0x0040, 0x578: 0x0040, 0x579: 0x0040, 0x57a: 0x0040, 0x57b: 0x0040, + 0x57c: 0x0040, 0x57d: 0x0040, 0x57e: 0x0040, 0x57f: 0x0040, // Block 0x16, offset 0x580 - 0x580: 0x1008, 0x581: 0x1308, 0x582: 0x1308, 0x583: 0x1308, 0x584: 0x1308, 0x585: 0x0040, - 0x586: 0x0040, 0x587: 0x1008, 0x588: 0x1008, 0x589: 0x0040, 0x58a: 0x0040, 0x58b: 0x1008, - 0x58c: 0x1008, 0x58d: 0x1b08, 0x58e: 0x0008, 0x58f: 0x0040, 0x590: 0x0040, 0x591: 0x0040, - 0x592: 0x0040, 0x593: 0x0040, 0x594: 0x0040, 0x595: 0x0040, 0x596: 0x0040, 0x597: 0x1008, - 0x598: 0x0040, 0x599: 0x0040, 0x59a: 0x0040, 0x59b: 0x0040, 0x59c: 0x0689, 0x59d: 0x06c1, - 0x59e: 0x0040, 0x59f: 0x06f9, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x1308, 0x5a3: 0x1308, - 0x5a4: 0x0040, 0x5a5: 0x0040, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008, + 0x580: 0x3008, 0x581: 0x3308, 0x582: 0x3308, 0x583: 0x3308, 0x584: 0x3308, 0x585: 0x3308, + 0x586: 0x3308, 0x587: 0x3308, 0x588: 0x3308, 0x589: 0x3008, 0x58a: 0x3008, 0x58b: 0x3008, + 0x58c: 0x3008, 0x58d: 0x3b08, 0x58e: 0x3008, 0x58f: 0x3008, 0x590: 0x0008, 0x591: 0x3308, + 0x592: 0x3308, 0x593: 0x3308, 0x594: 0x3308, 0x595: 0x3308, 0x596: 0x3308, 0x597: 0x3308, + 0x598: 0x04c9, 0x599: 0x0501, 0x59a: 0x0539, 0x59b: 0x0571, 0x59c: 0x05a9, 0x59d: 0x05e1, + 0x59e: 0x0619, 0x59f: 0x0651, 0x5a0: 0x0008, 0x5a1: 0x0008, 0x5a2: 0x3308, 0x5a3: 0x3308, + 0x5a4: 0x0018, 0x5a5: 0x0018, 0x5a6: 0x0008, 0x5a7: 0x0008, 0x5a8: 0x0008, 0x5a9: 0x0008, 0x5aa: 0x0008, 0x5ab: 0x0008, 0x5ac: 0x0008, 0x5ad: 0x0008, 0x5ae: 0x0008, 0x5af: 0x0008, - 0x5b0: 0x0008, 0x5b1: 0x0008, 0x5b2: 0x0018, 0x5b3: 0x0018, 0x5b4: 0x0018, 0x5b5: 0x0018, - 0x5b6: 0x0018, 0x5b7: 0x0018, 0x5b8: 0x0018, 0x5b9: 0x0018, 0x5ba: 0x0018, 0x5bb: 0x0018, - 0x5bc: 0x0040, 0x5bd: 0x0040, 0x5be: 0x0040, 0x5bf: 0x0040, + 0x5b0: 0x0018, 0x5b1: 0x0008, 0x5b2: 0x0008, 0x5b3: 0x0008, 0x5b4: 0x0008, 0x5b5: 0x0008, + 0x5b6: 0x0008, 0x5b7: 0x0008, 0x5b8: 0x0008, 0x5b9: 0x0008, 0x5ba: 0x0008, 0x5bb: 0x0008, + 0x5bc: 0x0008, 0x5bd: 0x0008, 0x5be: 0x0008, 0x5bf: 0x0008, // Block 0x17, offset 0x5c0 - 0x5c0: 0x0040, 0x5c1: 0x1308, 0x5c2: 0x1308, 0x5c3: 0x1008, 0x5c4: 0x0040, 0x5c5: 0x0008, - 0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0040, - 0x5cc: 0x0040, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040, + 0x5c0: 0x0008, 0x5c1: 0x3308, 0x5c2: 0x3008, 0x5c3: 0x3008, 0x5c4: 0x0040, 0x5c5: 0x0008, + 0x5c6: 0x0008, 0x5c7: 0x0008, 0x5c8: 0x0008, 0x5c9: 0x0008, 0x5ca: 0x0008, 0x5cb: 0x0008, + 0x5cc: 0x0008, 0x5cd: 0x0040, 0x5ce: 0x0040, 0x5cf: 0x0008, 0x5d0: 0x0008, 0x5d1: 0x0040, 0x5d2: 0x0040, 0x5d3: 0x0008, 0x5d4: 0x0008, 0x5d5: 0x0008, 0x5d6: 0x0008, 0x5d7: 0x0008, 0x5d8: 0x0008, 0x5d9: 0x0008, 0x5da: 0x0008, 0x5db: 0x0008, 0x5dc: 0x0008, 0x5dd: 0x0008, 0x5de: 0x0008, 0x5df: 0x0008, 0x5e0: 0x0008, 0x5e1: 0x0008, 0x5e2: 0x0008, 0x5e3: 0x0008, 0x5e4: 0x0008, 0x5e5: 0x0008, 0x5e6: 0x0008, 0x5e7: 0x0008, 0x5e8: 0x0008, 0x5e9: 0x0040, 0x5ea: 0x0008, 0x5eb: 0x0008, 0x5ec: 0x0008, 0x5ed: 0x0008, 0x5ee: 0x0008, 0x5ef: 0x0008, - 0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0731, 0x5f4: 0x0040, 0x5f5: 0x0008, - 0x5f6: 0x0769, 0x5f7: 0x0040, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040, - 0x5fc: 0x1308, 0x5fd: 0x0040, 0x5fe: 0x1008, 0x5ff: 0x1008, + 0x5f0: 0x0008, 0x5f1: 0x0040, 0x5f2: 0x0008, 0x5f3: 0x0040, 0x5f4: 0x0040, 0x5f5: 0x0040, + 0x5f6: 0x0008, 0x5f7: 0x0008, 0x5f8: 0x0008, 0x5f9: 0x0008, 0x5fa: 0x0040, 0x5fb: 0x0040, + 0x5fc: 0x3308, 0x5fd: 0x0008, 0x5fe: 0x3008, 0x5ff: 0x3008, // Block 0x18, offset 0x600 - 0x600: 0x1008, 0x601: 0x1308, 0x602: 0x1308, 0x603: 0x0040, 0x604: 0x0040, 0x605: 0x0040, - 0x606: 0x0040, 0x607: 0x1308, 0x608: 0x1308, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x1308, - 0x60c: 0x1308, 0x60d: 0x1b08, 0x60e: 0x0040, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x1308, - 0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x0040, - 0x618: 0x0040, 0x619: 0x07a1, 0x61a: 0x07d9, 0x61b: 0x0811, 0x61c: 0x0008, 0x61d: 0x0040, - 0x61e: 0x0849, 0x61f: 0x0040, 0x620: 0x0040, 0x621: 0x0040, 0x622: 0x0040, 0x623: 0x0040, + 0x600: 0x3008, 0x601: 0x3308, 0x602: 0x3308, 0x603: 0x3308, 0x604: 0x3308, 0x605: 0x0040, + 0x606: 0x0040, 0x607: 0x3008, 0x608: 0x3008, 0x609: 0x0040, 0x60a: 0x0040, 0x60b: 0x3008, + 0x60c: 0x3008, 0x60d: 0x3b08, 0x60e: 0x0008, 0x60f: 0x0040, 0x610: 0x0040, 0x611: 0x0040, + 0x612: 0x0040, 0x613: 0x0040, 0x614: 0x0040, 0x615: 0x0040, 0x616: 0x0040, 0x617: 0x3008, + 0x618: 0x0040, 0x619: 0x0040, 0x61a: 0x0040, 0x61b: 0x0040, 0x61c: 0x0689, 0x61d: 0x06c1, + 0x61e: 0x0040, 0x61f: 0x06f9, 0x620: 0x0008, 0x621: 0x0008, 0x622: 0x3308, 0x623: 0x3308, 0x624: 0x0040, 0x625: 0x0040, 0x626: 0x0008, 0x627: 0x0008, 0x628: 0x0008, 0x629: 0x0008, 0x62a: 0x0008, 0x62b: 0x0008, 0x62c: 0x0008, 0x62d: 0x0008, 0x62e: 0x0008, 0x62f: 0x0008, - 0x630: 0x1308, 0x631: 0x1308, 0x632: 0x0008, 0x633: 0x0008, 0x634: 0x0008, 0x635: 0x1308, - 0x636: 0x0040, 0x637: 0x0040, 0x638: 0x0040, 0x639: 0x0040, 0x63a: 0x0040, 0x63b: 0x0040, - 0x63c: 0x0040, 0x63d: 0x0040, 0x63e: 0x0040, 0x63f: 0x0040, + 0x630: 0x0008, 0x631: 0x0008, 0x632: 0x0018, 0x633: 0x0018, 0x634: 0x0018, 0x635: 0x0018, + 0x636: 0x0018, 0x637: 0x0018, 0x638: 0x0018, 0x639: 0x0018, 0x63a: 0x0018, 0x63b: 0x0018, + 0x63c: 0x0008, 0x63d: 0x0018, 0x63e: 0x0040, 0x63f: 0x0040, // Block 0x19, offset 0x640 - 0x640: 0x0040, 0x641: 0x1308, 0x642: 0x1308, 0x643: 0x1008, 0x644: 0x0040, 0x645: 0x0008, - 0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0008, - 0x64c: 0x0008, 0x64d: 0x0008, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0008, + 0x640: 0x0040, 0x641: 0x3308, 0x642: 0x3308, 0x643: 0x3008, 0x644: 0x0040, 0x645: 0x0008, + 0x646: 0x0008, 0x647: 0x0008, 0x648: 0x0008, 0x649: 0x0008, 0x64a: 0x0008, 0x64b: 0x0040, + 0x64c: 0x0040, 0x64d: 0x0040, 0x64e: 0x0040, 0x64f: 0x0008, 0x650: 0x0008, 0x651: 0x0040, 0x652: 0x0040, 0x653: 0x0008, 0x654: 0x0008, 0x655: 0x0008, 0x656: 0x0008, 0x657: 0x0008, 0x658: 0x0008, 0x659: 0x0008, 0x65a: 0x0008, 0x65b: 0x0008, 0x65c: 0x0008, 0x65d: 0x0008, 0x65e: 0x0008, 0x65f: 0x0008, 0x660: 0x0008, 0x661: 0x0008, 0x662: 0x0008, 0x663: 0x0008, 0x664: 0x0008, 0x665: 0x0008, 0x666: 0x0008, 0x667: 0x0008, 0x668: 0x0008, 0x669: 0x0040, 0x66a: 0x0008, 0x66b: 0x0008, 0x66c: 0x0008, 0x66d: 0x0008, 0x66e: 0x0008, 0x66f: 0x0008, - 0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0008, 0x674: 0x0040, 0x675: 0x0008, - 0x676: 0x0008, 0x677: 0x0008, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040, - 0x67c: 0x1308, 0x67d: 0x0008, 0x67e: 0x1008, 0x67f: 0x1008, + 0x670: 0x0008, 0x671: 0x0040, 0x672: 0x0008, 0x673: 0x0731, 0x674: 0x0040, 0x675: 0x0008, + 0x676: 0x0769, 0x677: 0x0040, 0x678: 0x0008, 0x679: 0x0008, 0x67a: 0x0040, 0x67b: 0x0040, + 0x67c: 0x3308, 0x67d: 0x0040, 0x67e: 0x3008, 0x67f: 0x3008, // Block 0x1a, offset 0x680 - 0x680: 0x1008, 0x681: 0x1308, 0x682: 0x1308, 0x683: 0x1308, 0x684: 0x1308, 0x685: 0x1308, - 0x686: 0x0040, 0x687: 0x1308, 0x688: 0x1308, 0x689: 0x1008, 0x68a: 0x0040, 0x68b: 0x1008, - 0x68c: 0x1008, 0x68d: 0x1b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0008, 0x691: 0x0040, + 0x680: 0x3008, 0x681: 0x3308, 0x682: 0x3308, 0x683: 0x0040, 0x684: 0x0040, 0x685: 0x0040, + 0x686: 0x0040, 0x687: 0x3308, 0x688: 0x3308, 0x689: 0x0040, 0x68a: 0x0040, 0x68b: 0x3308, + 0x68c: 0x3308, 0x68d: 0x3b08, 0x68e: 0x0040, 0x68f: 0x0040, 0x690: 0x0040, 0x691: 0x3308, 0x692: 0x0040, 0x693: 0x0040, 0x694: 0x0040, 0x695: 0x0040, 0x696: 0x0040, 0x697: 0x0040, - 0x698: 0x0040, 0x699: 0x0040, 0x69a: 0x0040, 0x69b: 0x0040, 0x69c: 0x0040, 0x69d: 0x0040, - 0x69e: 0x0040, 0x69f: 0x0040, 0x6a0: 0x0008, 0x6a1: 0x0008, 0x6a2: 0x1308, 0x6a3: 0x1308, + 0x698: 0x0040, 0x699: 0x07a1, 0x69a: 0x07d9, 0x69b: 0x0811, 0x69c: 0x0008, 0x69d: 0x0040, + 0x69e: 0x0849, 0x69f: 0x0040, 0x6a0: 0x0040, 0x6a1: 0x0040, 0x6a2: 0x0040, 0x6a3: 0x0040, 0x6a4: 0x0040, 0x6a5: 0x0040, 0x6a6: 0x0008, 0x6a7: 0x0008, 0x6a8: 0x0008, 0x6a9: 0x0008, 0x6aa: 0x0008, 0x6ab: 0x0008, 0x6ac: 0x0008, 0x6ad: 0x0008, 0x6ae: 0x0008, 0x6af: 0x0008, - 0x6b0: 0x0018, 0x6b1: 0x0018, 0x6b2: 0x0040, 0x6b3: 0x0040, 0x6b4: 0x0040, 0x6b5: 0x0040, - 0x6b6: 0x0040, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0008, 0x6ba: 0x0040, 0x6bb: 0x0040, + 0x6b0: 0x3308, 0x6b1: 0x3308, 0x6b2: 0x0008, 0x6b3: 0x0008, 0x6b4: 0x0008, 0x6b5: 0x3308, + 0x6b6: 0x0040, 0x6b7: 0x0040, 0x6b8: 0x0040, 0x6b9: 0x0040, 0x6ba: 0x0040, 0x6bb: 0x0040, 0x6bc: 0x0040, 0x6bd: 0x0040, 0x6be: 0x0040, 0x6bf: 0x0040, // Block 0x1b, offset 0x6c0 - 0x6c0: 0x0040, 0x6c1: 0x1308, 0x6c2: 0x1008, 0x6c3: 0x1008, 0x6c4: 0x0040, 0x6c5: 0x0008, + 0x6c0: 0x0040, 0x6c1: 0x3308, 0x6c2: 0x3308, 0x6c3: 0x3008, 0x6c4: 0x0040, 0x6c5: 0x0008, 0x6c6: 0x0008, 0x6c7: 0x0008, 0x6c8: 0x0008, 0x6c9: 0x0008, 0x6ca: 0x0008, 0x6cb: 0x0008, - 0x6cc: 0x0008, 0x6cd: 0x0040, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0040, + 0x6cc: 0x0008, 0x6cd: 0x0008, 0x6ce: 0x0040, 0x6cf: 0x0008, 0x6d0: 0x0008, 0x6d1: 0x0008, 0x6d2: 0x0040, 0x6d3: 0x0008, 0x6d4: 0x0008, 0x6d5: 0x0008, 0x6d6: 0x0008, 0x6d7: 0x0008, 0x6d8: 0x0008, 0x6d9: 0x0008, 0x6da: 0x0008, 0x6db: 0x0008, 0x6dc: 0x0008, 0x6dd: 0x0008, 0x6de: 0x0008, 0x6df: 0x0008, 0x6e0: 0x0008, 0x6e1: 0x0008, 0x6e2: 0x0008, 0x6e3: 0x0008, @@ -891,1457 +891,1490 @@ var idnaValues = [8000]uint16{ 0x6ea: 0x0008, 0x6eb: 0x0008, 0x6ec: 0x0008, 0x6ed: 0x0008, 0x6ee: 0x0008, 0x6ef: 0x0008, 0x6f0: 0x0008, 0x6f1: 0x0040, 0x6f2: 0x0008, 0x6f3: 0x0008, 0x6f4: 0x0040, 0x6f5: 0x0008, 0x6f6: 0x0008, 0x6f7: 0x0008, 0x6f8: 0x0008, 0x6f9: 0x0008, 0x6fa: 0x0040, 0x6fb: 0x0040, - 0x6fc: 0x1308, 0x6fd: 0x0008, 0x6fe: 0x1008, 0x6ff: 0x1308, + 0x6fc: 0x3308, 0x6fd: 0x0008, 0x6fe: 0x3008, 0x6ff: 0x3008, // Block 0x1c, offset 0x700 - 0x700: 0x1008, 0x701: 0x1308, 0x702: 0x1308, 0x703: 0x1308, 0x704: 0x1308, 0x705: 0x0040, - 0x706: 0x0040, 0x707: 0x1008, 0x708: 0x1008, 0x709: 0x0040, 0x70a: 0x0040, 0x70b: 0x1008, - 0x70c: 0x1008, 0x70d: 0x1b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0040, 0x711: 0x0040, - 0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x1308, 0x717: 0x1008, - 0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0881, 0x71d: 0x08b9, - 0x71e: 0x0040, 0x71f: 0x0008, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x1308, 0x723: 0x1308, + 0x700: 0x3008, 0x701: 0x3308, 0x702: 0x3308, 0x703: 0x3308, 0x704: 0x3308, 0x705: 0x3308, + 0x706: 0x0040, 0x707: 0x3308, 0x708: 0x3308, 0x709: 0x3008, 0x70a: 0x0040, 0x70b: 0x3008, + 0x70c: 0x3008, 0x70d: 0x3b08, 0x70e: 0x0040, 0x70f: 0x0040, 0x710: 0x0008, 0x711: 0x0040, + 0x712: 0x0040, 0x713: 0x0040, 0x714: 0x0040, 0x715: 0x0040, 0x716: 0x0040, 0x717: 0x0040, + 0x718: 0x0040, 0x719: 0x0040, 0x71a: 0x0040, 0x71b: 0x0040, 0x71c: 0x0040, 0x71d: 0x0040, + 0x71e: 0x0040, 0x71f: 0x0040, 0x720: 0x0008, 0x721: 0x0008, 0x722: 0x3308, 0x723: 0x3308, 0x724: 0x0040, 0x725: 0x0040, 0x726: 0x0008, 0x727: 0x0008, 0x728: 0x0008, 0x729: 0x0008, 0x72a: 0x0008, 0x72b: 0x0008, 0x72c: 0x0008, 0x72d: 0x0008, 0x72e: 0x0008, 0x72f: 0x0008, - 0x730: 0x0018, 0x731: 0x0008, 0x732: 0x0018, 0x733: 0x0018, 0x734: 0x0018, 0x735: 0x0018, - 0x736: 0x0018, 0x737: 0x0018, 0x738: 0x0040, 0x739: 0x0040, 0x73a: 0x0040, 0x73b: 0x0040, - 0x73c: 0x0040, 0x73d: 0x0040, 0x73e: 0x0040, 0x73f: 0x0040, + 0x730: 0x0018, 0x731: 0x0018, 0x732: 0x0040, 0x733: 0x0040, 0x734: 0x0040, 0x735: 0x0040, + 0x736: 0x0040, 0x737: 0x0040, 0x738: 0x0040, 0x739: 0x0008, 0x73a: 0x3308, 0x73b: 0x3308, + 0x73c: 0x3308, 0x73d: 0x3308, 0x73e: 0x3308, 0x73f: 0x3308, // Block 0x1d, offset 0x740 - 0x740: 0x0040, 0x741: 0x0040, 0x742: 0x1308, 0x743: 0x0008, 0x744: 0x0040, 0x745: 0x0008, - 0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0040, - 0x74c: 0x0040, 0x74d: 0x0040, 0x74e: 0x0008, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040, - 0x752: 0x0008, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0040, 0x757: 0x0040, - 0x758: 0x0040, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0040, 0x75c: 0x0008, 0x75d: 0x0040, - 0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0040, 0x761: 0x0040, 0x762: 0x0040, 0x763: 0x0008, - 0x764: 0x0008, 0x765: 0x0040, 0x766: 0x0040, 0x767: 0x0040, 0x768: 0x0008, 0x769: 0x0008, - 0x76a: 0x0008, 0x76b: 0x0040, 0x76c: 0x0040, 0x76d: 0x0040, 0x76e: 0x0008, 0x76f: 0x0008, - 0x770: 0x0008, 0x771: 0x0008, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0008, 0x775: 0x0008, + 0x740: 0x0040, 0x741: 0x3308, 0x742: 0x3008, 0x743: 0x3008, 0x744: 0x0040, 0x745: 0x0008, + 0x746: 0x0008, 0x747: 0x0008, 0x748: 0x0008, 0x749: 0x0008, 0x74a: 0x0008, 0x74b: 0x0008, + 0x74c: 0x0008, 0x74d: 0x0040, 0x74e: 0x0040, 0x74f: 0x0008, 0x750: 0x0008, 0x751: 0x0040, + 0x752: 0x0040, 0x753: 0x0008, 0x754: 0x0008, 0x755: 0x0008, 0x756: 0x0008, 0x757: 0x0008, + 0x758: 0x0008, 0x759: 0x0008, 0x75a: 0x0008, 0x75b: 0x0008, 0x75c: 0x0008, 0x75d: 0x0008, + 0x75e: 0x0008, 0x75f: 0x0008, 0x760: 0x0008, 0x761: 0x0008, 0x762: 0x0008, 0x763: 0x0008, + 0x764: 0x0008, 0x765: 0x0008, 0x766: 0x0008, 0x767: 0x0008, 0x768: 0x0008, 0x769: 0x0040, + 0x76a: 0x0008, 0x76b: 0x0008, 0x76c: 0x0008, 0x76d: 0x0008, 0x76e: 0x0008, 0x76f: 0x0008, + 0x770: 0x0008, 0x771: 0x0040, 0x772: 0x0008, 0x773: 0x0008, 0x774: 0x0040, 0x775: 0x0008, 0x776: 0x0008, 0x777: 0x0008, 0x778: 0x0008, 0x779: 0x0008, 0x77a: 0x0040, 0x77b: 0x0040, - 0x77c: 0x0040, 0x77d: 0x0040, 0x77e: 0x1008, 0x77f: 0x1008, + 0x77c: 0x3308, 0x77d: 0x0008, 0x77e: 0x3008, 0x77f: 0x3308, // Block 0x1e, offset 0x780 - 0x780: 0x1308, 0x781: 0x1008, 0x782: 0x1008, 0x783: 0x1008, 0x784: 0x1008, 0x785: 0x0040, - 0x786: 0x1308, 0x787: 0x1308, 0x788: 0x1308, 0x789: 0x0040, 0x78a: 0x1308, 0x78b: 0x1308, - 0x78c: 0x1308, 0x78d: 0x1b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040, - 0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x1308, 0x796: 0x1308, 0x797: 0x0040, - 0x798: 0x0008, 0x799: 0x0008, 0x79a: 0x0008, 0x79b: 0x0040, 0x79c: 0x0040, 0x79d: 0x0040, - 0x79e: 0x0040, 0x79f: 0x0040, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x1308, 0x7a3: 0x1308, + 0x780: 0x3008, 0x781: 0x3308, 0x782: 0x3308, 0x783: 0x3308, 0x784: 0x3308, 0x785: 0x0040, + 0x786: 0x0040, 0x787: 0x3008, 0x788: 0x3008, 0x789: 0x0040, 0x78a: 0x0040, 0x78b: 0x3008, + 0x78c: 0x3008, 0x78d: 0x3b08, 0x78e: 0x0040, 0x78f: 0x0040, 0x790: 0x0040, 0x791: 0x0040, + 0x792: 0x0040, 0x793: 0x0040, 0x794: 0x0040, 0x795: 0x0040, 0x796: 0x3308, 0x797: 0x3008, + 0x798: 0x0040, 0x799: 0x0040, 0x79a: 0x0040, 0x79b: 0x0040, 0x79c: 0x0881, 0x79d: 0x08b9, + 0x79e: 0x0040, 0x79f: 0x0008, 0x7a0: 0x0008, 0x7a1: 0x0008, 0x7a2: 0x3308, 0x7a3: 0x3308, 0x7a4: 0x0040, 0x7a5: 0x0040, 0x7a6: 0x0008, 0x7a7: 0x0008, 0x7a8: 0x0008, 0x7a9: 0x0008, 0x7aa: 0x0008, 0x7ab: 0x0008, 0x7ac: 0x0008, 0x7ad: 0x0008, 0x7ae: 0x0008, 0x7af: 0x0008, - 0x7b0: 0x0040, 0x7b1: 0x0040, 0x7b2: 0x0040, 0x7b3: 0x0040, 0x7b4: 0x0040, 0x7b5: 0x0040, - 0x7b6: 0x0040, 0x7b7: 0x0040, 0x7b8: 0x0018, 0x7b9: 0x0018, 0x7ba: 0x0018, 0x7bb: 0x0018, - 0x7bc: 0x0018, 0x7bd: 0x0018, 0x7be: 0x0018, 0x7bf: 0x0018, + 0x7b0: 0x0018, 0x7b1: 0x0008, 0x7b2: 0x0018, 0x7b3: 0x0018, 0x7b4: 0x0018, 0x7b5: 0x0018, + 0x7b6: 0x0018, 0x7b7: 0x0018, 0x7b8: 0x0040, 0x7b9: 0x0040, 0x7ba: 0x0040, 0x7bb: 0x0040, + 0x7bc: 0x0040, 0x7bd: 0x0040, 0x7be: 0x0040, 0x7bf: 0x0040, // Block 0x1f, offset 0x7c0 - 0x7c0: 0x0008, 0x7c1: 0x1308, 0x7c2: 0x1008, 0x7c3: 0x1008, 0x7c4: 0x0040, 0x7c5: 0x0008, - 0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0008, - 0x7cc: 0x0008, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040, - 0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0008, 0x7d7: 0x0008, - 0x7d8: 0x0008, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0008, 0x7dc: 0x0008, 0x7dd: 0x0008, - 0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0008, 0x7e1: 0x0008, 0x7e2: 0x0008, 0x7e3: 0x0008, - 0x7e4: 0x0008, 0x7e5: 0x0008, 0x7e6: 0x0008, 0x7e7: 0x0008, 0x7e8: 0x0008, 0x7e9: 0x0040, - 0x7ea: 0x0008, 0x7eb: 0x0008, 0x7ec: 0x0008, 0x7ed: 0x0008, 0x7ee: 0x0008, 0x7ef: 0x0008, - 0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0040, 0x7f5: 0x0008, + 0x7c0: 0x0040, 0x7c1: 0x0040, 0x7c2: 0x3308, 0x7c3: 0x0008, 0x7c4: 0x0040, 0x7c5: 0x0008, + 0x7c6: 0x0008, 0x7c7: 0x0008, 0x7c8: 0x0008, 0x7c9: 0x0008, 0x7ca: 0x0008, 0x7cb: 0x0040, + 0x7cc: 0x0040, 0x7cd: 0x0040, 0x7ce: 0x0008, 0x7cf: 0x0008, 0x7d0: 0x0008, 0x7d1: 0x0040, + 0x7d2: 0x0008, 0x7d3: 0x0008, 0x7d4: 0x0008, 0x7d5: 0x0008, 0x7d6: 0x0040, 0x7d7: 0x0040, + 0x7d8: 0x0040, 0x7d9: 0x0008, 0x7da: 0x0008, 0x7db: 0x0040, 0x7dc: 0x0008, 0x7dd: 0x0040, + 0x7de: 0x0008, 0x7df: 0x0008, 0x7e0: 0x0040, 0x7e1: 0x0040, 0x7e2: 0x0040, 0x7e3: 0x0008, + 0x7e4: 0x0008, 0x7e5: 0x0040, 0x7e6: 0x0040, 0x7e7: 0x0040, 0x7e8: 0x0008, 0x7e9: 0x0008, + 0x7ea: 0x0008, 0x7eb: 0x0040, 0x7ec: 0x0040, 0x7ed: 0x0040, 0x7ee: 0x0008, 0x7ef: 0x0008, + 0x7f0: 0x0008, 0x7f1: 0x0008, 0x7f2: 0x0008, 0x7f3: 0x0008, 0x7f4: 0x0008, 0x7f5: 0x0008, 0x7f6: 0x0008, 0x7f7: 0x0008, 0x7f8: 0x0008, 0x7f9: 0x0008, 0x7fa: 0x0040, 0x7fb: 0x0040, - 0x7fc: 0x1308, 0x7fd: 0x0008, 0x7fe: 0x1008, 0x7ff: 0x1308, + 0x7fc: 0x0040, 0x7fd: 0x0040, 0x7fe: 0x3008, 0x7ff: 0x3008, // Block 0x20, offset 0x800 - 0x800: 0x1008, 0x801: 0x1008, 0x802: 0x1008, 0x803: 0x1008, 0x804: 0x1008, 0x805: 0x0040, - 0x806: 0x1308, 0x807: 0x1008, 0x808: 0x1008, 0x809: 0x0040, 0x80a: 0x1008, 0x80b: 0x1008, - 0x80c: 0x1308, 0x80d: 0x1b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040, - 0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x1008, 0x816: 0x1008, 0x817: 0x0040, - 0x818: 0x0040, 0x819: 0x0040, 0x81a: 0x0040, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040, - 0x81e: 0x0008, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x1308, 0x823: 0x1308, + 0x800: 0x3308, 0x801: 0x3008, 0x802: 0x3008, 0x803: 0x3008, 0x804: 0x3008, 0x805: 0x0040, + 0x806: 0x3308, 0x807: 0x3308, 0x808: 0x3308, 0x809: 0x0040, 0x80a: 0x3308, 0x80b: 0x3308, + 0x80c: 0x3308, 0x80d: 0x3b08, 0x80e: 0x0040, 0x80f: 0x0040, 0x810: 0x0040, 0x811: 0x0040, + 0x812: 0x0040, 0x813: 0x0040, 0x814: 0x0040, 0x815: 0x3308, 0x816: 0x3308, 0x817: 0x0040, + 0x818: 0x0008, 0x819: 0x0008, 0x81a: 0x0008, 0x81b: 0x0040, 0x81c: 0x0040, 0x81d: 0x0040, + 0x81e: 0x0040, 0x81f: 0x0040, 0x820: 0x0008, 0x821: 0x0008, 0x822: 0x3308, 0x823: 0x3308, 0x824: 0x0040, 0x825: 0x0040, 0x826: 0x0008, 0x827: 0x0008, 0x828: 0x0008, 0x829: 0x0008, 0x82a: 0x0008, 0x82b: 0x0008, 0x82c: 0x0008, 0x82d: 0x0008, 0x82e: 0x0008, 0x82f: 0x0008, - 0x830: 0x0040, 0x831: 0x0008, 0x832: 0x0008, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040, - 0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0040, 0x839: 0x0040, 0x83a: 0x0040, 0x83b: 0x0040, - 0x83c: 0x0040, 0x83d: 0x0040, 0x83e: 0x0040, 0x83f: 0x0040, + 0x830: 0x0040, 0x831: 0x0040, 0x832: 0x0040, 0x833: 0x0040, 0x834: 0x0040, 0x835: 0x0040, + 0x836: 0x0040, 0x837: 0x0040, 0x838: 0x0018, 0x839: 0x0018, 0x83a: 0x0018, 0x83b: 0x0018, + 0x83c: 0x0018, 0x83d: 0x0018, 0x83e: 0x0018, 0x83f: 0x0018, // Block 0x21, offset 0x840 - 0x840: 0x1008, 0x841: 0x1308, 0x842: 0x1308, 0x843: 0x1308, 0x844: 0x1308, 0x845: 0x0040, - 0x846: 0x1008, 0x847: 0x1008, 0x848: 0x1008, 0x849: 0x0040, 0x84a: 0x1008, 0x84b: 0x1008, - 0x84c: 0x1008, 0x84d: 0x1b08, 0x84e: 0x0008, 0x84f: 0x0018, 0x850: 0x0040, 0x851: 0x0040, - 0x852: 0x0040, 0x853: 0x0040, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x1008, - 0x858: 0x0018, 0x859: 0x0018, 0x85a: 0x0018, 0x85b: 0x0018, 0x85c: 0x0018, 0x85d: 0x0018, - 0x85e: 0x0018, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x1308, 0x863: 0x1308, - 0x864: 0x0040, 0x865: 0x0040, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0008, + 0x840: 0x0008, 0x841: 0x3308, 0x842: 0x3008, 0x843: 0x3008, 0x844: 0x0040, 0x845: 0x0008, + 0x846: 0x0008, 0x847: 0x0008, 0x848: 0x0008, 0x849: 0x0008, 0x84a: 0x0008, 0x84b: 0x0008, + 0x84c: 0x0008, 0x84d: 0x0040, 0x84e: 0x0008, 0x84f: 0x0008, 0x850: 0x0008, 0x851: 0x0040, + 0x852: 0x0008, 0x853: 0x0008, 0x854: 0x0008, 0x855: 0x0008, 0x856: 0x0008, 0x857: 0x0008, + 0x858: 0x0008, 0x859: 0x0008, 0x85a: 0x0008, 0x85b: 0x0008, 0x85c: 0x0008, 0x85d: 0x0008, + 0x85e: 0x0008, 0x85f: 0x0008, 0x860: 0x0008, 0x861: 0x0008, 0x862: 0x0008, 0x863: 0x0008, + 0x864: 0x0008, 0x865: 0x0008, 0x866: 0x0008, 0x867: 0x0008, 0x868: 0x0008, 0x869: 0x0040, 0x86a: 0x0008, 0x86b: 0x0008, 0x86c: 0x0008, 0x86d: 0x0008, 0x86e: 0x0008, 0x86f: 0x0008, - 0x870: 0x0018, 0x871: 0x0018, 0x872: 0x0018, 0x873: 0x0018, 0x874: 0x0018, 0x875: 0x0018, - 0x876: 0x0018, 0x877: 0x0018, 0x878: 0x0018, 0x879: 0x0018, 0x87a: 0x0008, 0x87b: 0x0008, - 0x87c: 0x0008, 0x87d: 0x0008, 0x87e: 0x0008, 0x87f: 0x0008, + 0x870: 0x0008, 0x871: 0x0008, 0x872: 0x0008, 0x873: 0x0008, 0x874: 0x0040, 0x875: 0x0008, + 0x876: 0x0008, 0x877: 0x0008, 0x878: 0x0008, 0x879: 0x0008, 0x87a: 0x0040, 0x87b: 0x0040, + 0x87c: 0x3308, 0x87d: 0x0008, 0x87e: 0x3008, 0x87f: 0x3308, // Block 0x22, offset 0x880 - 0x880: 0x0040, 0x881: 0x0008, 0x882: 0x0008, 0x883: 0x0040, 0x884: 0x0008, 0x885: 0x0040, - 0x886: 0x0040, 0x887: 0x0008, 0x888: 0x0008, 0x889: 0x0040, 0x88a: 0x0008, 0x88b: 0x0040, - 0x88c: 0x0040, 0x88d: 0x0008, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040, - 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0008, 0x895: 0x0008, 0x896: 0x0008, 0x897: 0x0008, - 0x898: 0x0040, 0x899: 0x0008, 0x89a: 0x0008, 0x89b: 0x0008, 0x89c: 0x0008, 0x89d: 0x0008, - 0x89e: 0x0008, 0x89f: 0x0008, 0x8a0: 0x0040, 0x8a1: 0x0008, 0x8a2: 0x0008, 0x8a3: 0x0008, - 0x8a4: 0x0040, 0x8a5: 0x0008, 0x8a6: 0x0040, 0x8a7: 0x0008, 0x8a8: 0x0040, 0x8a9: 0x0040, - 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0040, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, - 0x8b0: 0x0008, 0x8b1: 0x1308, 0x8b2: 0x0008, 0x8b3: 0x0929, 0x8b4: 0x1308, 0x8b5: 0x1308, - 0x8b6: 0x1308, 0x8b7: 0x1308, 0x8b8: 0x1308, 0x8b9: 0x1308, 0x8ba: 0x0040, 0x8bb: 0x1308, - 0x8bc: 0x1308, 0x8bd: 0x0008, 0x8be: 0x0040, 0x8bf: 0x0040, + 0x880: 0x3008, 0x881: 0x3008, 0x882: 0x3008, 0x883: 0x3008, 0x884: 0x3008, 0x885: 0x0040, + 0x886: 0x3308, 0x887: 0x3008, 0x888: 0x3008, 0x889: 0x0040, 0x88a: 0x3008, 0x88b: 0x3008, + 0x88c: 0x3308, 0x88d: 0x3b08, 0x88e: 0x0040, 0x88f: 0x0040, 0x890: 0x0040, 0x891: 0x0040, + 0x892: 0x0040, 0x893: 0x0040, 0x894: 0x0040, 0x895: 0x3008, 0x896: 0x3008, 0x897: 0x0040, + 0x898: 0x0040, 0x899: 0x0040, 0x89a: 0x0040, 0x89b: 0x0040, 0x89c: 0x0040, 0x89d: 0x0040, + 0x89e: 0x0008, 0x89f: 0x0040, 0x8a0: 0x0008, 0x8a1: 0x0008, 0x8a2: 0x3308, 0x8a3: 0x3308, + 0x8a4: 0x0040, 0x8a5: 0x0040, 0x8a6: 0x0008, 0x8a7: 0x0008, 0x8a8: 0x0008, 0x8a9: 0x0008, + 0x8aa: 0x0008, 0x8ab: 0x0008, 0x8ac: 0x0008, 0x8ad: 0x0008, 0x8ae: 0x0008, 0x8af: 0x0008, + 0x8b0: 0x0040, 0x8b1: 0x0008, 0x8b2: 0x0008, 0x8b3: 0x0040, 0x8b4: 0x0040, 0x8b5: 0x0040, + 0x8b6: 0x0040, 0x8b7: 0x0040, 0x8b8: 0x0040, 0x8b9: 0x0040, 0x8ba: 0x0040, 0x8bb: 0x0040, + 0x8bc: 0x0040, 0x8bd: 0x0040, 0x8be: 0x0040, 0x8bf: 0x0040, // Block 0x23, offset 0x8c0 - 0x8c0: 0x0008, 0x8c1: 0x0008, 0x8c2: 0x0008, 0x8c3: 0x09d1, 0x8c4: 0x0008, 0x8c5: 0x0008, - 0x8c6: 0x0008, 0x8c7: 0x0008, 0x8c8: 0x0040, 0x8c9: 0x0008, 0x8ca: 0x0008, 0x8cb: 0x0008, - 0x8cc: 0x0008, 0x8cd: 0x0a09, 0x8ce: 0x0008, 0x8cf: 0x0008, 0x8d0: 0x0008, 0x8d1: 0x0008, - 0x8d2: 0x0a41, 0x8d3: 0x0008, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x0a79, - 0x8d8: 0x0008, 0x8d9: 0x0008, 0x8da: 0x0008, 0x8db: 0x0008, 0x8dc: 0x0ab1, 0x8dd: 0x0008, - 0x8de: 0x0008, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x0008, 0x8e3: 0x0008, - 0x8e4: 0x0008, 0x8e5: 0x0008, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0ae9, - 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0040, 0x8ee: 0x0040, 0x8ef: 0x0040, - 0x8f0: 0x0040, 0x8f1: 0x1308, 0x8f2: 0x1308, 0x8f3: 0x0b21, 0x8f4: 0x1308, 0x8f5: 0x0b59, - 0x8f6: 0x0b91, 0x8f7: 0x0bc9, 0x8f8: 0x0c19, 0x8f9: 0x0c51, 0x8fa: 0x1308, 0x8fb: 0x1308, - 0x8fc: 0x1308, 0x8fd: 0x1308, 0x8fe: 0x1308, 0x8ff: 0x1008, + 0x8c0: 0x3008, 0x8c1: 0x3308, 0x8c2: 0x3308, 0x8c3: 0x3308, 0x8c4: 0x3308, 0x8c5: 0x0040, + 0x8c6: 0x3008, 0x8c7: 0x3008, 0x8c8: 0x3008, 0x8c9: 0x0040, 0x8ca: 0x3008, 0x8cb: 0x3008, + 0x8cc: 0x3008, 0x8cd: 0x3b08, 0x8ce: 0x0008, 0x8cf: 0x0018, 0x8d0: 0x0040, 0x8d1: 0x0040, + 0x8d2: 0x0040, 0x8d3: 0x0040, 0x8d4: 0x0008, 0x8d5: 0x0008, 0x8d6: 0x0008, 0x8d7: 0x3008, + 0x8d8: 0x0018, 0x8d9: 0x0018, 0x8da: 0x0018, 0x8db: 0x0018, 0x8dc: 0x0018, 0x8dd: 0x0018, + 0x8de: 0x0018, 0x8df: 0x0008, 0x8e0: 0x0008, 0x8e1: 0x0008, 0x8e2: 0x3308, 0x8e3: 0x3308, + 0x8e4: 0x0040, 0x8e5: 0x0040, 0x8e6: 0x0008, 0x8e7: 0x0008, 0x8e8: 0x0008, 0x8e9: 0x0008, + 0x8ea: 0x0008, 0x8eb: 0x0008, 0x8ec: 0x0008, 0x8ed: 0x0008, 0x8ee: 0x0008, 0x8ef: 0x0008, + 0x8f0: 0x0018, 0x8f1: 0x0018, 0x8f2: 0x0018, 0x8f3: 0x0018, 0x8f4: 0x0018, 0x8f5: 0x0018, + 0x8f6: 0x0018, 0x8f7: 0x0018, 0x8f8: 0x0018, 0x8f9: 0x0018, 0x8fa: 0x0008, 0x8fb: 0x0008, + 0x8fc: 0x0008, 0x8fd: 0x0008, 0x8fe: 0x0008, 0x8ff: 0x0008, // Block 0x24, offset 0x900 - 0x900: 0x1308, 0x901: 0x0ca1, 0x902: 0x1308, 0x903: 0x1308, 0x904: 0x1b08, 0x905: 0x0018, - 0x906: 0x1308, 0x907: 0x1308, 0x908: 0x0008, 0x909: 0x0008, 0x90a: 0x0008, 0x90b: 0x0008, - 0x90c: 0x0008, 0x90d: 0x1308, 0x90e: 0x1308, 0x90f: 0x1308, 0x910: 0x1308, 0x911: 0x1308, - 0x912: 0x1308, 0x913: 0x0cd9, 0x914: 0x1308, 0x915: 0x1308, 0x916: 0x1308, 0x917: 0x1308, - 0x918: 0x0040, 0x919: 0x1308, 0x91a: 0x1308, 0x91b: 0x1308, 0x91c: 0x1308, 0x91d: 0x0d11, - 0x91e: 0x1308, 0x91f: 0x1308, 0x920: 0x1308, 0x921: 0x1308, 0x922: 0x0d49, 0x923: 0x1308, - 0x924: 0x1308, 0x925: 0x1308, 0x926: 0x1308, 0x927: 0x0d81, 0x928: 0x1308, 0x929: 0x1308, - 0x92a: 0x1308, 0x92b: 0x1308, 0x92c: 0x0db9, 0x92d: 0x1308, 0x92e: 0x1308, 0x92f: 0x1308, - 0x930: 0x1308, 0x931: 0x1308, 0x932: 0x1308, 0x933: 0x1308, 0x934: 0x1308, 0x935: 0x1308, - 0x936: 0x1308, 0x937: 0x1308, 0x938: 0x1308, 0x939: 0x0df1, 0x93a: 0x1308, 0x93b: 0x1308, - 0x93c: 0x1308, 0x93d: 0x0040, 0x93e: 0x0018, 0x93f: 0x0018, + 0x900: 0x0040, 0x901: 0x0008, 0x902: 0x0008, 0x903: 0x0040, 0x904: 0x0008, 0x905: 0x0040, + 0x906: 0x0040, 0x907: 0x0008, 0x908: 0x0008, 0x909: 0x0040, 0x90a: 0x0008, 0x90b: 0x0040, + 0x90c: 0x0040, 0x90d: 0x0008, 0x90e: 0x0040, 0x90f: 0x0040, 0x910: 0x0040, 0x911: 0x0040, + 0x912: 0x0040, 0x913: 0x0040, 0x914: 0x0008, 0x915: 0x0008, 0x916: 0x0008, 0x917: 0x0008, + 0x918: 0x0040, 0x919: 0x0008, 0x91a: 0x0008, 0x91b: 0x0008, 0x91c: 0x0008, 0x91d: 0x0008, + 0x91e: 0x0008, 0x91f: 0x0008, 0x920: 0x0040, 0x921: 0x0008, 0x922: 0x0008, 0x923: 0x0008, + 0x924: 0x0040, 0x925: 0x0008, 0x926: 0x0040, 0x927: 0x0008, 0x928: 0x0040, 0x929: 0x0040, + 0x92a: 0x0008, 0x92b: 0x0008, 0x92c: 0x0040, 0x92d: 0x0008, 0x92e: 0x0008, 0x92f: 0x0008, + 0x930: 0x0008, 0x931: 0x3308, 0x932: 0x0008, 0x933: 0x0929, 0x934: 0x3308, 0x935: 0x3308, + 0x936: 0x3308, 0x937: 0x3308, 0x938: 0x3308, 0x939: 0x3308, 0x93a: 0x0040, 0x93b: 0x3308, + 0x93c: 0x3308, 0x93d: 0x0008, 0x93e: 0x0040, 0x93f: 0x0040, // Block 0x25, offset 0x940 - 0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x0008, 0x944: 0x0008, 0x945: 0x0008, - 0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0008, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, - 0x94c: 0x0008, 0x94d: 0x0008, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008, - 0x952: 0x0008, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0008, - 0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0008, 0x95d: 0x0008, + 0x940: 0x0008, 0x941: 0x0008, 0x942: 0x0008, 0x943: 0x09d1, 0x944: 0x0008, 0x945: 0x0008, + 0x946: 0x0008, 0x947: 0x0008, 0x948: 0x0040, 0x949: 0x0008, 0x94a: 0x0008, 0x94b: 0x0008, + 0x94c: 0x0008, 0x94d: 0x0a09, 0x94e: 0x0008, 0x94f: 0x0008, 0x950: 0x0008, 0x951: 0x0008, + 0x952: 0x0a41, 0x953: 0x0008, 0x954: 0x0008, 0x955: 0x0008, 0x956: 0x0008, 0x957: 0x0a79, + 0x958: 0x0008, 0x959: 0x0008, 0x95a: 0x0008, 0x95b: 0x0008, 0x95c: 0x0ab1, 0x95d: 0x0008, 0x95e: 0x0008, 0x95f: 0x0008, 0x960: 0x0008, 0x961: 0x0008, 0x962: 0x0008, 0x963: 0x0008, - 0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0008, - 0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0039, 0x96d: 0x0ed1, 0x96e: 0x0ee9, 0x96f: 0x0008, - 0x970: 0x0ef9, 0x971: 0x0f09, 0x972: 0x0f19, 0x973: 0x0f31, 0x974: 0x0249, 0x975: 0x0f41, - 0x976: 0x0259, 0x977: 0x0f51, 0x978: 0x0359, 0x979: 0x0f61, 0x97a: 0x0f71, 0x97b: 0x0008, - 0x97c: 0x00d9, 0x97d: 0x0f81, 0x97e: 0x0f99, 0x97f: 0x0269, + 0x964: 0x0008, 0x965: 0x0008, 0x966: 0x0008, 0x967: 0x0008, 0x968: 0x0008, 0x969: 0x0ae9, + 0x96a: 0x0008, 0x96b: 0x0008, 0x96c: 0x0008, 0x96d: 0x0040, 0x96e: 0x0040, 0x96f: 0x0040, + 0x970: 0x0040, 0x971: 0x3308, 0x972: 0x3308, 0x973: 0x0b21, 0x974: 0x3308, 0x975: 0x0b59, + 0x976: 0x0b91, 0x977: 0x0bc9, 0x978: 0x0c19, 0x979: 0x0c51, 0x97a: 0x3308, 0x97b: 0x3308, + 0x97c: 0x3308, 0x97d: 0x3308, 0x97e: 0x3308, 0x97f: 0x3008, // Block 0x26, offset 0x980 - 0x980: 0x0fa9, 0x981: 0x0fb9, 0x982: 0x0279, 0x983: 0x0039, 0x984: 0x0fc9, 0x985: 0x0fe1, - 0x986: 0x059d, 0x987: 0x0ee9, 0x988: 0x0ef9, 0x989: 0x0f09, 0x98a: 0x0ff9, 0x98b: 0x1011, - 0x98c: 0x1029, 0x98d: 0x0f31, 0x98e: 0x0008, 0x98f: 0x0f51, 0x990: 0x0f61, 0x991: 0x1041, - 0x992: 0x00d9, 0x993: 0x1059, 0x994: 0x05b5, 0x995: 0x05b5, 0x996: 0x0f99, 0x997: 0x0fa9, - 0x998: 0x0fb9, 0x999: 0x059d, 0x99a: 0x1071, 0x99b: 0x1089, 0x99c: 0x05cd, 0x99d: 0x1099, - 0x99e: 0x10b1, 0x99f: 0x10c9, 0x9a0: 0x10e1, 0x9a1: 0x10f9, 0x9a2: 0x0f41, 0x9a3: 0x0269, - 0x9a4: 0x0fb9, 0x9a5: 0x1089, 0x9a6: 0x1099, 0x9a7: 0x10b1, 0x9a8: 0x1111, 0x9a9: 0x10e1, - 0x9aa: 0x10f9, 0x9ab: 0x0008, 0x9ac: 0x0008, 0x9ad: 0x0008, 0x9ae: 0x0008, 0x9af: 0x0008, - 0x9b0: 0x0008, 0x9b1: 0x0008, 0x9b2: 0x0008, 0x9b3: 0x0008, 0x9b4: 0x0008, 0x9b5: 0x0008, - 0x9b6: 0x0008, 0x9b7: 0x0008, 0x9b8: 0x1129, 0x9b9: 0x0008, 0x9ba: 0x0008, 0x9bb: 0x0008, - 0x9bc: 0x0008, 0x9bd: 0x0008, 0x9be: 0x0008, 0x9bf: 0x0008, + 0x980: 0x3308, 0x981: 0x0ca1, 0x982: 0x3308, 0x983: 0x3308, 0x984: 0x3b08, 0x985: 0x0018, + 0x986: 0x3308, 0x987: 0x3308, 0x988: 0x0008, 0x989: 0x0008, 0x98a: 0x0008, 0x98b: 0x0008, + 0x98c: 0x0008, 0x98d: 0x3308, 0x98e: 0x3308, 0x98f: 0x3308, 0x990: 0x3308, 0x991: 0x3308, + 0x992: 0x3308, 0x993: 0x0cd9, 0x994: 0x3308, 0x995: 0x3308, 0x996: 0x3308, 0x997: 0x3308, + 0x998: 0x0040, 0x999: 0x3308, 0x99a: 0x3308, 0x99b: 0x3308, 0x99c: 0x3308, 0x99d: 0x0d11, + 0x99e: 0x3308, 0x99f: 0x3308, 0x9a0: 0x3308, 0x9a1: 0x3308, 0x9a2: 0x0d49, 0x9a3: 0x3308, + 0x9a4: 0x3308, 0x9a5: 0x3308, 0x9a6: 0x3308, 0x9a7: 0x0d81, 0x9a8: 0x3308, 0x9a9: 0x3308, + 0x9aa: 0x3308, 0x9ab: 0x3308, 0x9ac: 0x0db9, 0x9ad: 0x3308, 0x9ae: 0x3308, 0x9af: 0x3308, + 0x9b0: 0x3308, 0x9b1: 0x3308, 0x9b2: 0x3308, 0x9b3: 0x3308, 0x9b4: 0x3308, 0x9b5: 0x3308, + 0x9b6: 0x3308, 0x9b7: 0x3308, 0x9b8: 0x3308, 0x9b9: 0x0df1, 0x9ba: 0x3308, 0x9bb: 0x3308, + 0x9bc: 0x3308, 0x9bd: 0x0040, 0x9be: 0x0018, 0x9bf: 0x0018, // Block 0x27, offset 0x9c0 0x9c0: 0x0008, 0x9c1: 0x0008, 0x9c2: 0x0008, 0x9c3: 0x0008, 0x9c4: 0x0008, 0x9c5: 0x0008, 0x9c6: 0x0008, 0x9c7: 0x0008, 0x9c8: 0x0008, 0x9c9: 0x0008, 0x9ca: 0x0008, 0x9cb: 0x0008, 0x9cc: 0x0008, 0x9cd: 0x0008, 0x9ce: 0x0008, 0x9cf: 0x0008, 0x9d0: 0x0008, 0x9d1: 0x0008, 0x9d2: 0x0008, 0x9d3: 0x0008, 0x9d4: 0x0008, 0x9d5: 0x0008, 0x9d6: 0x0008, 0x9d7: 0x0008, - 0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x1141, 0x9dc: 0x1159, 0x9dd: 0x1169, - 0x9de: 0x1181, 0x9df: 0x1029, 0x9e0: 0x1199, 0x9e1: 0x11a9, 0x9e2: 0x11c1, 0x9e3: 0x11d9, - 0x9e4: 0x11f1, 0x9e5: 0x1209, 0x9e6: 0x1221, 0x9e7: 0x05e5, 0x9e8: 0x1239, 0x9e9: 0x1251, - 0x9ea: 0xe17d, 0x9eb: 0x1269, 0x9ec: 0x1281, 0x9ed: 0x1299, 0x9ee: 0x12b1, 0x9ef: 0x12c9, - 0x9f0: 0x12e1, 0x9f1: 0x12f9, 0x9f2: 0x1311, 0x9f3: 0x1329, 0x9f4: 0x1341, 0x9f5: 0x1359, - 0x9f6: 0x1371, 0x9f7: 0x1389, 0x9f8: 0x05fd, 0x9f9: 0x13a1, 0x9fa: 0x13b9, 0x9fb: 0x13d1, - 0x9fc: 0x13e1, 0x9fd: 0x13f9, 0x9fe: 0x1411, 0x9ff: 0x1429, + 0x9d8: 0x0008, 0x9d9: 0x0008, 0x9da: 0x0008, 0x9db: 0x0008, 0x9dc: 0x0008, 0x9dd: 0x0008, + 0x9de: 0x0008, 0x9df: 0x0008, 0x9e0: 0x0008, 0x9e1: 0x0008, 0x9e2: 0x0008, 0x9e3: 0x0008, + 0x9e4: 0x0008, 0x9e5: 0x0008, 0x9e6: 0x0008, 0x9e7: 0x0008, 0x9e8: 0x0008, 0x9e9: 0x0008, + 0x9ea: 0x0008, 0x9eb: 0x0008, 0x9ec: 0x0039, 0x9ed: 0x0ed1, 0x9ee: 0x0ee9, 0x9ef: 0x0008, + 0x9f0: 0x0ef9, 0x9f1: 0x0f09, 0x9f2: 0x0f19, 0x9f3: 0x0f31, 0x9f4: 0x0249, 0x9f5: 0x0f41, + 0x9f6: 0x0259, 0x9f7: 0x0f51, 0x9f8: 0x0359, 0x9f9: 0x0f61, 0x9fa: 0x0f71, 0x9fb: 0x0008, + 0x9fc: 0x00d9, 0x9fd: 0x0f81, 0x9fe: 0x0f99, 0x9ff: 0x0269, // Block 0x28, offset 0xa00 - 0xa00: 0xe00d, 0xa01: 0x0008, 0xa02: 0xe00d, 0xa03: 0x0008, 0xa04: 0xe00d, 0xa05: 0x0008, - 0xa06: 0xe00d, 0xa07: 0x0008, 0xa08: 0xe00d, 0xa09: 0x0008, 0xa0a: 0xe00d, 0xa0b: 0x0008, - 0xa0c: 0xe00d, 0xa0d: 0x0008, 0xa0e: 0xe00d, 0xa0f: 0x0008, 0xa10: 0xe00d, 0xa11: 0x0008, - 0xa12: 0xe00d, 0xa13: 0x0008, 0xa14: 0xe00d, 0xa15: 0x0008, 0xa16: 0xe00d, 0xa17: 0x0008, - 0xa18: 0xe00d, 0xa19: 0x0008, 0xa1a: 0xe00d, 0xa1b: 0x0008, 0xa1c: 0xe00d, 0xa1d: 0x0008, - 0xa1e: 0xe00d, 0xa1f: 0x0008, 0xa20: 0xe00d, 0xa21: 0x0008, 0xa22: 0xe00d, 0xa23: 0x0008, - 0xa24: 0xe00d, 0xa25: 0x0008, 0xa26: 0xe00d, 0xa27: 0x0008, 0xa28: 0xe00d, 0xa29: 0x0008, - 0xa2a: 0xe00d, 0xa2b: 0x0008, 0xa2c: 0xe00d, 0xa2d: 0x0008, 0xa2e: 0xe00d, 0xa2f: 0x0008, - 0xa30: 0xe00d, 0xa31: 0x0008, 0xa32: 0xe00d, 0xa33: 0x0008, 0xa34: 0xe00d, 0xa35: 0x0008, - 0xa36: 0xe00d, 0xa37: 0x0008, 0xa38: 0xe00d, 0xa39: 0x0008, 0xa3a: 0xe00d, 0xa3b: 0x0008, - 0xa3c: 0xe00d, 0xa3d: 0x0008, 0xa3e: 0xe00d, 0xa3f: 0x0008, + 0xa00: 0x0fa9, 0xa01: 0x0fb9, 0xa02: 0x0279, 0xa03: 0x0039, 0xa04: 0x0fc9, 0xa05: 0x0fe1, + 0xa06: 0x059d, 0xa07: 0x0ee9, 0xa08: 0x0ef9, 0xa09: 0x0f09, 0xa0a: 0x0ff9, 0xa0b: 0x1011, + 0xa0c: 0x1029, 0xa0d: 0x0f31, 0xa0e: 0x0008, 0xa0f: 0x0f51, 0xa10: 0x0f61, 0xa11: 0x1041, + 0xa12: 0x00d9, 0xa13: 0x1059, 0xa14: 0x05b5, 0xa15: 0x05b5, 0xa16: 0x0f99, 0xa17: 0x0fa9, + 0xa18: 0x0fb9, 0xa19: 0x059d, 0xa1a: 0x1071, 0xa1b: 0x1089, 0xa1c: 0x05cd, 0xa1d: 0x1099, + 0xa1e: 0x10b1, 0xa1f: 0x10c9, 0xa20: 0x10e1, 0xa21: 0x10f9, 0xa22: 0x0f41, 0xa23: 0x0269, + 0xa24: 0x0fb9, 0xa25: 0x1089, 0xa26: 0x1099, 0xa27: 0x10b1, 0xa28: 0x1111, 0xa29: 0x10e1, + 0xa2a: 0x10f9, 0xa2b: 0x0008, 0xa2c: 0x0008, 0xa2d: 0x0008, 0xa2e: 0x0008, 0xa2f: 0x0008, + 0xa30: 0x0008, 0xa31: 0x0008, 0xa32: 0x0008, 0xa33: 0x0008, 0xa34: 0x0008, 0xa35: 0x0008, + 0xa36: 0x0008, 0xa37: 0x0008, 0xa38: 0x1129, 0xa39: 0x0008, 0xa3a: 0x0008, 0xa3b: 0x0008, + 0xa3c: 0x0008, 0xa3d: 0x0008, 0xa3e: 0x0008, 0xa3f: 0x0008, // Block 0x29, offset 0xa40 - 0xa40: 0xe00d, 0xa41: 0x0008, 0xa42: 0xe00d, 0xa43: 0x0008, 0xa44: 0xe00d, 0xa45: 0x0008, - 0xa46: 0xe00d, 0xa47: 0x0008, 0xa48: 0xe00d, 0xa49: 0x0008, 0xa4a: 0xe00d, 0xa4b: 0x0008, - 0xa4c: 0xe00d, 0xa4d: 0x0008, 0xa4e: 0xe00d, 0xa4f: 0x0008, 0xa50: 0xe00d, 0xa51: 0x0008, - 0xa52: 0xe00d, 0xa53: 0x0008, 0xa54: 0xe00d, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008, - 0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0615, 0xa5b: 0x0635, 0xa5c: 0x0008, 0xa5d: 0x0008, - 0xa5e: 0x1441, 0xa5f: 0x0008, 0xa60: 0xe00d, 0xa61: 0x0008, 0xa62: 0xe00d, 0xa63: 0x0008, - 0xa64: 0xe00d, 0xa65: 0x0008, 0xa66: 0xe00d, 0xa67: 0x0008, 0xa68: 0xe00d, 0xa69: 0x0008, - 0xa6a: 0xe00d, 0xa6b: 0x0008, 0xa6c: 0xe00d, 0xa6d: 0x0008, 0xa6e: 0xe00d, 0xa6f: 0x0008, - 0xa70: 0xe00d, 0xa71: 0x0008, 0xa72: 0xe00d, 0xa73: 0x0008, 0xa74: 0xe00d, 0xa75: 0x0008, - 0xa76: 0xe00d, 0xa77: 0x0008, 0xa78: 0xe00d, 0xa79: 0x0008, 0xa7a: 0xe00d, 0xa7b: 0x0008, - 0xa7c: 0xe00d, 0xa7d: 0x0008, 0xa7e: 0xe00d, 0xa7f: 0x0008, + 0xa40: 0x0008, 0xa41: 0x0008, 0xa42: 0x0008, 0xa43: 0x0008, 0xa44: 0x0008, 0xa45: 0x0008, + 0xa46: 0x0008, 0xa47: 0x0008, 0xa48: 0x0008, 0xa49: 0x0008, 0xa4a: 0x0008, 0xa4b: 0x0008, + 0xa4c: 0x0008, 0xa4d: 0x0008, 0xa4e: 0x0008, 0xa4f: 0x0008, 0xa50: 0x0008, 0xa51: 0x0008, + 0xa52: 0x0008, 0xa53: 0x0008, 0xa54: 0x0008, 0xa55: 0x0008, 0xa56: 0x0008, 0xa57: 0x0008, + 0xa58: 0x0008, 0xa59: 0x0008, 0xa5a: 0x0008, 0xa5b: 0x1141, 0xa5c: 0x1159, 0xa5d: 0x1169, + 0xa5e: 0x1181, 0xa5f: 0x1029, 0xa60: 0x1199, 0xa61: 0x11a9, 0xa62: 0x11c1, 0xa63: 0x11d9, + 0xa64: 0x11f1, 0xa65: 0x1209, 0xa66: 0x1221, 0xa67: 0x05e5, 0xa68: 0x1239, 0xa69: 0x1251, + 0xa6a: 0xe17d, 0xa6b: 0x1269, 0xa6c: 0x1281, 0xa6d: 0x1299, 0xa6e: 0x12b1, 0xa6f: 0x12c9, + 0xa70: 0x12e1, 0xa71: 0x12f9, 0xa72: 0x1311, 0xa73: 0x1329, 0xa74: 0x1341, 0xa75: 0x1359, + 0xa76: 0x1371, 0xa77: 0x1389, 0xa78: 0x05fd, 0xa79: 0x13a1, 0xa7a: 0x13b9, 0xa7b: 0x13d1, + 0xa7c: 0x13e1, 0xa7d: 0x13f9, 0xa7e: 0x1411, 0xa7f: 0x1429, // Block 0x2a, offset 0xa80 - 0xa80: 0x0008, 0xa81: 0x0008, 0xa82: 0x0008, 0xa83: 0x0008, 0xa84: 0x0008, 0xa85: 0x0008, - 0xa86: 0x0040, 0xa87: 0x0040, 0xa88: 0xe045, 0xa89: 0xe045, 0xa8a: 0xe045, 0xa8b: 0xe045, - 0xa8c: 0xe045, 0xa8d: 0xe045, 0xa8e: 0x0040, 0xa8f: 0x0040, 0xa90: 0x0008, 0xa91: 0x0008, - 0xa92: 0x0008, 0xa93: 0x0008, 0xa94: 0x0008, 0xa95: 0x0008, 0xa96: 0x0008, 0xa97: 0x0008, - 0xa98: 0x0040, 0xa99: 0xe045, 0xa9a: 0x0040, 0xa9b: 0xe045, 0xa9c: 0x0040, 0xa9d: 0xe045, - 0xa9e: 0x0040, 0xa9f: 0xe045, 0xaa0: 0x0008, 0xaa1: 0x0008, 0xaa2: 0x0008, 0xaa3: 0x0008, - 0xaa4: 0x0008, 0xaa5: 0x0008, 0xaa6: 0x0008, 0xaa7: 0x0008, 0xaa8: 0xe045, 0xaa9: 0xe045, - 0xaaa: 0xe045, 0xaab: 0xe045, 0xaac: 0xe045, 0xaad: 0xe045, 0xaae: 0xe045, 0xaaf: 0xe045, - 0xab0: 0x0008, 0xab1: 0x1459, 0xab2: 0x0008, 0xab3: 0x1471, 0xab4: 0x0008, 0xab5: 0x1489, - 0xab6: 0x0008, 0xab7: 0x14a1, 0xab8: 0x0008, 0xab9: 0x14b9, 0xaba: 0x0008, 0xabb: 0x14d1, - 0xabc: 0x0008, 0xabd: 0x14e9, 0xabe: 0x0040, 0xabf: 0x0040, + 0xa80: 0xe00d, 0xa81: 0x0008, 0xa82: 0xe00d, 0xa83: 0x0008, 0xa84: 0xe00d, 0xa85: 0x0008, + 0xa86: 0xe00d, 0xa87: 0x0008, 0xa88: 0xe00d, 0xa89: 0x0008, 0xa8a: 0xe00d, 0xa8b: 0x0008, + 0xa8c: 0xe00d, 0xa8d: 0x0008, 0xa8e: 0xe00d, 0xa8f: 0x0008, 0xa90: 0xe00d, 0xa91: 0x0008, + 0xa92: 0xe00d, 0xa93: 0x0008, 0xa94: 0xe00d, 0xa95: 0x0008, 0xa96: 0xe00d, 0xa97: 0x0008, + 0xa98: 0xe00d, 0xa99: 0x0008, 0xa9a: 0xe00d, 0xa9b: 0x0008, 0xa9c: 0xe00d, 0xa9d: 0x0008, + 0xa9e: 0xe00d, 0xa9f: 0x0008, 0xaa0: 0xe00d, 0xaa1: 0x0008, 0xaa2: 0xe00d, 0xaa3: 0x0008, + 0xaa4: 0xe00d, 0xaa5: 0x0008, 0xaa6: 0xe00d, 0xaa7: 0x0008, 0xaa8: 0xe00d, 0xaa9: 0x0008, + 0xaaa: 0xe00d, 0xaab: 0x0008, 0xaac: 0xe00d, 0xaad: 0x0008, 0xaae: 0xe00d, 0xaaf: 0x0008, + 0xab0: 0xe00d, 0xab1: 0x0008, 0xab2: 0xe00d, 0xab3: 0x0008, 0xab4: 0xe00d, 0xab5: 0x0008, + 0xab6: 0xe00d, 0xab7: 0x0008, 0xab8: 0xe00d, 0xab9: 0x0008, 0xaba: 0xe00d, 0xabb: 0x0008, + 0xabc: 0xe00d, 0xabd: 0x0008, 0xabe: 0xe00d, 0xabf: 0x0008, // Block 0x2b, offset 0xac0 - 0xac0: 0x1501, 0xac1: 0x1531, 0xac2: 0x1561, 0xac3: 0x1591, 0xac4: 0x15c1, 0xac5: 0x15f1, - 0xac6: 0x1621, 0xac7: 0x1651, 0xac8: 0x1501, 0xac9: 0x1531, 0xaca: 0x1561, 0xacb: 0x1591, - 0xacc: 0x15c1, 0xacd: 0x15f1, 0xace: 0x1621, 0xacf: 0x1651, 0xad0: 0x1681, 0xad1: 0x16b1, - 0xad2: 0x16e1, 0xad3: 0x1711, 0xad4: 0x1741, 0xad5: 0x1771, 0xad6: 0x17a1, 0xad7: 0x17d1, - 0xad8: 0x1681, 0xad9: 0x16b1, 0xada: 0x16e1, 0xadb: 0x1711, 0xadc: 0x1741, 0xadd: 0x1771, - 0xade: 0x17a1, 0xadf: 0x17d1, 0xae0: 0x1801, 0xae1: 0x1831, 0xae2: 0x1861, 0xae3: 0x1891, - 0xae4: 0x18c1, 0xae5: 0x18f1, 0xae6: 0x1921, 0xae7: 0x1951, 0xae8: 0x1801, 0xae9: 0x1831, - 0xaea: 0x1861, 0xaeb: 0x1891, 0xaec: 0x18c1, 0xaed: 0x18f1, 0xaee: 0x1921, 0xaef: 0x1951, - 0xaf0: 0x0008, 0xaf1: 0x0008, 0xaf2: 0x1981, 0xaf3: 0x19b1, 0xaf4: 0x19d9, 0xaf5: 0x0040, - 0xaf6: 0x0008, 0xaf7: 0x1a01, 0xaf8: 0xe045, 0xaf9: 0xe045, 0xafa: 0x064d, 0xafb: 0x1459, - 0xafc: 0x19b1, 0xafd: 0x0666, 0xafe: 0x1a31, 0xaff: 0x0686, + 0xac0: 0xe00d, 0xac1: 0x0008, 0xac2: 0xe00d, 0xac3: 0x0008, 0xac4: 0xe00d, 0xac5: 0x0008, + 0xac6: 0xe00d, 0xac7: 0x0008, 0xac8: 0xe00d, 0xac9: 0x0008, 0xaca: 0xe00d, 0xacb: 0x0008, + 0xacc: 0xe00d, 0xacd: 0x0008, 0xace: 0xe00d, 0xacf: 0x0008, 0xad0: 0xe00d, 0xad1: 0x0008, + 0xad2: 0xe00d, 0xad3: 0x0008, 0xad4: 0xe00d, 0xad5: 0x0008, 0xad6: 0x0008, 0xad7: 0x0008, + 0xad8: 0x0008, 0xad9: 0x0008, 0xada: 0x0615, 0xadb: 0x0635, 0xadc: 0x0008, 0xadd: 0x0008, + 0xade: 0x1441, 0xadf: 0x0008, 0xae0: 0xe00d, 0xae1: 0x0008, 0xae2: 0xe00d, 0xae3: 0x0008, + 0xae4: 0xe00d, 0xae5: 0x0008, 0xae6: 0xe00d, 0xae7: 0x0008, 0xae8: 0xe00d, 0xae9: 0x0008, + 0xaea: 0xe00d, 0xaeb: 0x0008, 0xaec: 0xe00d, 0xaed: 0x0008, 0xaee: 0xe00d, 0xaef: 0x0008, + 0xaf0: 0xe00d, 0xaf1: 0x0008, 0xaf2: 0xe00d, 0xaf3: 0x0008, 0xaf4: 0xe00d, 0xaf5: 0x0008, + 0xaf6: 0xe00d, 0xaf7: 0x0008, 0xaf8: 0xe00d, 0xaf9: 0x0008, 0xafa: 0xe00d, 0xafb: 0x0008, + 0xafc: 0xe00d, 0xafd: 0x0008, 0xafe: 0xe00d, 0xaff: 0x0008, // Block 0x2c, offset 0xb00 - 0xb00: 0x06a6, 0xb01: 0x1a4a, 0xb02: 0x1a79, 0xb03: 0x1aa9, 0xb04: 0x1ad1, 0xb05: 0x0040, - 0xb06: 0x0008, 0xb07: 0x1af9, 0xb08: 0x06c5, 0xb09: 0x1471, 0xb0a: 0x06dd, 0xb0b: 0x1489, - 0xb0c: 0x1aa9, 0xb0d: 0x1b2a, 0xb0e: 0x1b5a, 0xb0f: 0x1b8a, 0xb10: 0x0008, 0xb11: 0x0008, - 0xb12: 0x0008, 0xb13: 0x1bb9, 0xb14: 0x0040, 0xb15: 0x0040, 0xb16: 0x0008, 0xb17: 0x0008, - 0xb18: 0xe045, 0xb19: 0xe045, 0xb1a: 0x06f5, 0xb1b: 0x14a1, 0xb1c: 0x0040, 0xb1d: 0x1bd2, - 0xb1e: 0x1c02, 0xb1f: 0x1c32, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x1c61, + 0xb00: 0x0008, 0xb01: 0x0008, 0xb02: 0x0008, 0xb03: 0x0008, 0xb04: 0x0008, 0xb05: 0x0008, + 0xb06: 0x0040, 0xb07: 0x0040, 0xb08: 0xe045, 0xb09: 0xe045, 0xb0a: 0xe045, 0xb0b: 0xe045, + 0xb0c: 0xe045, 0xb0d: 0xe045, 0xb0e: 0x0040, 0xb0f: 0x0040, 0xb10: 0x0008, 0xb11: 0x0008, + 0xb12: 0x0008, 0xb13: 0x0008, 0xb14: 0x0008, 0xb15: 0x0008, 0xb16: 0x0008, 0xb17: 0x0008, + 0xb18: 0x0040, 0xb19: 0xe045, 0xb1a: 0x0040, 0xb1b: 0xe045, 0xb1c: 0x0040, 0xb1d: 0xe045, + 0xb1e: 0x0040, 0xb1f: 0xe045, 0xb20: 0x0008, 0xb21: 0x0008, 0xb22: 0x0008, 0xb23: 0x0008, 0xb24: 0x0008, 0xb25: 0x0008, 0xb26: 0x0008, 0xb27: 0x0008, 0xb28: 0xe045, 0xb29: 0xe045, - 0xb2a: 0x070d, 0xb2b: 0x14d1, 0xb2c: 0xe04d, 0xb2d: 0x1c7a, 0xb2e: 0x03d2, 0xb2f: 0x1caa, - 0xb30: 0x0040, 0xb31: 0x0040, 0xb32: 0x1cb9, 0xb33: 0x1ce9, 0xb34: 0x1d11, 0xb35: 0x0040, - 0xb36: 0x0008, 0xb37: 0x1d39, 0xb38: 0x0725, 0xb39: 0x14b9, 0xb3a: 0x0515, 0xb3b: 0x14e9, - 0xb3c: 0x1ce9, 0xb3d: 0x073e, 0xb3e: 0x075e, 0xb3f: 0x0040, + 0xb2a: 0xe045, 0xb2b: 0xe045, 0xb2c: 0xe045, 0xb2d: 0xe045, 0xb2e: 0xe045, 0xb2f: 0xe045, + 0xb30: 0x0008, 0xb31: 0x1459, 0xb32: 0x0008, 0xb33: 0x1471, 0xb34: 0x0008, 0xb35: 0x1489, + 0xb36: 0x0008, 0xb37: 0x14a1, 0xb38: 0x0008, 0xb39: 0x14b9, 0xb3a: 0x0008, 0xb3b: 0x14d1, + 0xb3c: 0x0008, 0xb3d: 0x14e9, 0xb3e: 0x0040, 0xb3f: 0x0040, // Block 0x2d, offset 0xb40 - 0xb40: 0x000a, 0xb41: 0x000a, 0xb42: 0x000a, 0xb43: 0x000a, 0xb44: 0x000a, 0xb45: 0x000a, - 0xb46: 0x000a, 0xb47: 0x000a, 0xb48: 0x000a, 0xb49: 0x000a, 0xb4a: 0x000a, 0xb4b: 0x03c0, - 0xb4c: 0x0003, 0xb4d: 0x0003, 0xb4e: 0x0340, 0xb4f: 0x0340, 0xb50: 0x0018, 0xb51: 0xe00d, - 0xb52: 0x0018, 0xb53: 0x0018, 0xb54: 0x0018, 0xb55: 0x0018, 0xb56: 0x0018, 0xb57: 0x077e, - 0xb58: 0x0018, 0xb59: 0x0018, 0xb5a: 0x0018, 0xb5b: 0x0018, 0xb5c: 0x0018, 0xb5d: 0x0018, - 0xb5e: 0x0018, 0xb5f: 0x0018, 0xb60: 0x0018, 0xb61: 0x0018, 0xb62: 0x0018, 0xb63: 0x0018, - 0xb64: 0x0040, 0xb65: 0x0040, 0xb66: 0x0040, 0xb67: 0x0018, 0xb68: 0x0040, 0xb69: 0x0040, - 0xb6a: 0x0340, 0xb6b: 0x0340, 0xb6c: 0x0340, 0xb6d: 0x0340, 0xb6e: 0x0340, 0xb6f: 0x000a, - 0xb70: 0x0018, 0xb71: 0x0018, 0xb72: 0x0018, 0xb73: 0x1d69, 0xb74: 0x1da1, 0xb75: 0x0018, - 0xb76: 0x1df1, 0xb77: 0x1e29, 0xb78: 0x0018, 0xb79: 0x0018, 0xb7a: 0x0018, 0xb7b: 0x0018, - 0xb7c: 0x1e7a, 0xb7d: 0x0018, 0xb7e: 0x079e, 0xb7f: 0x0018, + 0xb40: 0x1501, 0xb41: 0x1531, 0xb42: 0x1561, 0xb43: 0x1591, 0xb44: 0x15c1, 0xb45: 0x15f1, + 0xb46: 0x1621, 0xb47: 0x1651, 0xb48: 0x1501, 0xb49: 0x1531, 0xb4a: 0x1561, 0xb4b: 0x1591, + 0xb4c: 0x15c1, 0xb4d: 0x15f1, 0xb4e: 0x1621, 0xb4f: 0x1651, 0xb50: 0x1681, 0xb51: 0x16b1, + 0xb52: 0x16e1, 0xb53: 0x1711, 0xb54: 0x1741, 0xb55: 0x1771, 0xb56: 0x17a1, 0xb57: 0x17d1, + 0xb58: 0x1681, 0xb59: 0x16b1, 0xb5a: 0x16e1, 0xb5b: 0x1711, 0xb5c: 0x1741, 0xb5d: 0x1771, + 0xb5e: 0x17a1, 0xb5f: 0x17d1, 0xb60: 0x1801, 0xb61: 0x1831, 0xb62: 0x1861, 0xb63: 0x1891, + 0xb64: 0x18c1, 0xb65: 0x18f1, 0xb66: 0x1921, 0xb67: 0x1951, 0xb68: 0x1801, 0xb69: 0x1831, + 0xb6a: 0x1861, 0xb6b: 0x1891, 0xb6c: 0x18c1, 0xb6d: 0x18f1, 0xb6e: 0x1921, 0xb6f: 0x1951, + 0xb70: 0x0008, 0xb71: 0x0008, 0xb72: 0x1981, 0xb73: 0x19b1, 0xb74: 0x19d9, 0xb75: 0x0040, + 0xb76: 0x0008, 0xb77: 0x1a01, 0xb78: 0xe045, 0xb79: 0xe045, 0xb7a: 0x064d, 0xb7b: 0x1459, + 0xb7c: 0x19b1, 0xb7d: 0x0666, 0xb7e: 0x1a31, 0xb7f: 0x0686, // Block 0x2e, offset 0xb80 - 0xb80: 0x0018, 0xb81: 0x0018, 0xb82: 0x0018, 0xb83: 0x0018, 0xb84: 0x0018, 0xb85: 0x0018, - 0xb86: 0x0018, 0xb87: 0x1e92, 0xb88: 0x1eaa, 0xb89: 0x1ec2, 0xb8a: 0x0018, 0xb8b: 0x0018, - 0xb8c: 0x0018, 0xb8d: 0x0018, 0xb8e: 0x0018, 0xb8f: 0x0018, 0xb90: 0x0018, 0xb91: 0x0018, - 0xb92: 0x0018, 0xb93: 0x0018, 0xb94: 0x0018, 0xb95: 0x0018, 0xb96: 0x0018, 0xb97: 0x1ed9, - 0xb98: 0x0018, 0xb99: 0x0018, 0xb9a: 0x0018, 0xb9b: 0x0018, 0xb9c: 0x0018, 0xb9d: 0x0018, - 0xb9e: 0x0018, 0xb9f: 0x000a, 0xba0: 0x03c0, 0xba1: 0x0340, 0xba2: 0x0340, 0xba3: 0x0340, - 0xba4: 0x03c0, 0xba5: 0x0040, 0xba6: 0x0040, 0xba7: 0x0040, 0xba8: 0x0040, 0xba9: 0x0040, - 0xbaa: 0x0340, 0xbab: 0x0340, 0xbac: 0x0340, 0xbad: 0x0340, 0xbae: 0x0340, 0xbaf: 0x0340, - 0xbb0: 0x1f41, 0xbb1: 0x0f41, 0xbb2: 0x0040, 0xbb3: 0x0040, 0xbb4: 0x1f51, 0xbb5: 0x1f61, - 0xbb6: 0x1f71, 0xbb7: 0x1f81, 0xbb8: 0x1f91, 0xbb9: 0x1fa1, 0xbba: 0x1fb2, 0xbbb: 0x07bd, - 0xbbc: 0x1fc2, 0xbbd: 0x1fd2, 0xbbe: 0x1fe2, 0xbbf: 0x0f71, + 0xb80: 0x06a6, 0xb81: 0x1a4a, 0xb82: 0x1a79, 0xb83: 0x1aa9, 0xb84: 0x1ad1, 0xb85: 0x0040, + 0xb86: 0x0008, 0xb87: 0x1af9, 0xb88: 0x06c5, 0xb89: 0x1471, 0xb8a: 0x06dd, 0xb8b: 0x1489, + 0xb8c: 0x1aa9, 0xb8d: 0x1b2a, 0xb8e: 0x1b5a, 0xb8f: 0x1b8a, 0xb90: 0x0008, 0xb91: 0x0008, + 0xb92: 0x0008, 0xb93: 0x1bb9, 0xb94: 0x0040, 0xb95: 0x0040, 0xb96: 0x0008, 0xb97: 0x0008, + 0xb98: 0xe045, 0xb99: 0xe045, 0xb9a: 0x06f5, 0xb9b: 0x14a1, 0xb9c: 0x0040, 0xb9d: 0x1bd2, + 0xb9e: 0x1c02, 0xb9f: 0x1c32, 0xba0: 0x0008, 0xba1: 0x0008, 0xba2: 0x0008, 0xba3: 0x1c61, + 0xba4: 0x0008, 0xba5: 0x0008, 0xba6: 0x0008, 0xba7: 0x0008, 0xba8: 0xe045, 0xba9: 0xe045, + 0xbaa: 0x070d, 0xbab: 0x14d1, 0xbac: 0xe04d, 0xbad: 0x1c7a, 0xbae: 0x03d2, 0xbaf: 0x1caa, + 0xbb0: 0x0040, 0xbb1: 0x0040, 0xbb2: 0x1cb9, 0xbb3: 0x1ce9, 0xbb4: 0x1d11, 0xbb5: 0x0040, + 0xbb6: 0x0008, 0xbb7: 0x1d39, 0xbb8: 0x0725, 0xbb9: 0x14b9, 0xbba: 0x0515, 0xbbb: 0x14e9, + 0xbbc: 0x1ce9, 0xbbd: 0x073e, 0xbbe: 0x075e, 0xbbf: 0x0040, // Block 0x2f, offset 0xbc0 - 0xbc0: 0x1f41, 0xbc1: 0x00c9, 0xbc2: 0x0069, 0xbc3: 0x0079, 0xbc4: 0x1f51, 0xbc5: 0x1f61, - 0xbc6: 0x1f71, 0xbc7: 0x1f81, 0xbc8: 0x1f91, 0xbc9: 0x1fa1, 0xbca: 0x1fb2, 0xbcb: 0x07d5, - 0xbcc: 0x1fc2, 0xbcd: 0x1fd2, 0xbce: 0x1fe2, 0xbcf: 0x0040, 0xbd0: 0x0039, 0xbd1: 0x0f09, - 0xbd2: 0x00d9, 0xbd3: 0x0369, 0xbd4: 0x0ff9, 0xbd5: 0x0249, 0xbd6: 0x0f51, 0xbd7: 0x0359, - 0xbd8: 0x0f61, 0xbd9: 0x0f71, 0xbda: 0x0f99, 0xbdb: 0x01d9, 0xbdc: 0x0fa9, 0xbdd: 0x0040, - 0xbde: 0x0040, 0xbdf: 0x0040, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018, - 0xbe4: 0x0018, 0xbe5: 0x0018, 0xbe6: 0x0018, 0xbe7: 0x0018, 0xbe8: 0x1ff1, 0xbe9: 0x0018, - 0xbea: 0x0018, 0xbeb: 0x0018, 0xbec: 0x0018, 0xbed: 0x0018, 0xbee: 0x0018, 0xbef: 0x0018, - 0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x0018, 0xbf4: 0x0018, 0xbf5: 0x0018, - 0xbf6: 0x0018, 0xbf7: 0x0018, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018, - 0xbfc: 0x0018, 0xbfd: 0x0018, 0xbfe: 0x0018, 0xbff: 0x0040, + 0xbc0: 0x000a, 0xbc1: 0x000a, 0xbc2: 0x000a, 0xbc3: 0x000a, 0xbc4: 0x000a, 0xbc5: 0x000a, + 0xbc6: 0x000a, 0xbc7: 0x000a, 0xbc8: 0x000a, 0xbc9: 0x000a, 0xbca: 0x000a, 0xbcb: 0x03c0, + 0xbcc: 0x0003, 0xbcd: 0x0003, 0xbce: 0x0340, 0xbcf: 0x0b40, 0xbd0: 0x0018, 0xbd1: 0xe00d, + 0xbd2: 0x0018, 0xbd3: 0x0018, 0xbd4: 0x0018, 0xbd5: 0x0018, 0xbd6: 0x0018, 0xbd7: 0x077e, + 0xbd8: 0x0018, 0xbd9: 0x0018, 0xbda: 0x0018, 0xbdb: 0x0018, 0xbdc: 0x0018, 0xbdd: 0x0018, + 0xbde: 0x0018, 0xbdf: 0x0018, 0xbe0: 0x0018, 0xbe1: 0x0018, 0xbe2: 0x0018, 0xbe3: 0x0018, + 0xbe4: 0x0040, 0xbe5: 0x0040, 0xbe6: 0x0040, 0xbe7: 0x0018, 0xbe8: 0x0040, 0xbe9: 0x0040, + 0xbea: 0x0340, 0xbeb: 0x0340, 0xbec: 0x0340, 0xbed: 0x0340, 0xbee: 0x0340, 0xbef: 0x000a, + 0xbf0: 0x0018, 0xbf1: 0x0018, 0xbf2: 0x0018, 0xbf3: 0x1d69, 0xbf4: 0x1da1, 0xbf5: 0x0018, + 0xbf6: 0x1df1, 0xbf7: 0x1e29, 0xbf8: 0x0018, 0xbf9: 0x0018, 0xbfa: 0x0018, 0xbfb: 0x0018, + 0xbfc: 0x1e7a, 0xbfd: 0x0018, 0xbfe: 0x079e, 0xbff: 0x0018, // Block 0x30, offset 0xc00 - 0xc00: 0x07ee, 0xc01: 0x080e, 0xc02: 0x1159, 0xc03: 0x082d, 0xc04: 0x0018, 0xc05: 0x084e, - 0xc06: 0x086e, 0xc07: 0x1011, 0xc08: 0x0018, 0xc09: 0x088d, 0xc0a: 0x0f31, 0xc0b: 0x0249, - 0xc0c: 0x0249, 0xc0d: 0x0249, 0xc0e: 0x0249, 0xc0f: 0x2009, 0xc10: 0x0f41, 0xc11: 0x0f41, - 0xc12: 0x0359, 0xc13: 0x0359, 0xc14: 0x0018, 0xc15: 0x0f71, 0xc16: 0x2021, 0xc17: 0x0018, - 0xc18: 0x0018, 0xc19: 0x0f99, 0xc1a: 0x2039, 0xc1b: 0x0269, 0xc1c: 0x0269, 0xc1d: 0x0269, - 0xc1e: 0x0018, 0xc1f: 0x0018, 0xc20: 0x2049, 0xc21: 0x08ad, 0xc22: 0x2061, 0xc23: 0x0018, - 0xc24: 0x13d1, 0xc25: 0x0018, 0xc26: 0x2079, 0xc27: 0x0018, 0xc28: 0x13d1, 0xc29: 0x0018, - 0xc2a: 0x0f51, 0xc2b: 0x2091, 0xc2c: 0x0ee9, 0xc2d: 0x1159, 0xc2e: 0x0018, 0xc2f: 0x0f09, - 0xc30: 0x0f09, 0xc31: 0x1199, 0xc32: 0x0040, 0xc33: 0x0f61, 0xc34: 0x00d9, 0xc35: 0x20a9, - 0xc36: 0x20c1, 0xc37: 0x20d9, 0xc38: 0x20f1, 0xc39: 0x0f41, 0xc3a: 0x0018, 0xc3b: 0x08cd, - 0xc3c: 0x2109, 0xc3d: 0x10b1, 0xc3e: 0x10b1, 0xc3f: 0x2109, + 0xc00: 0x0018, 0xc01: 0x0018, 0xc02: 0x0018, 0xc03: 0x0018, 0xc04: 0x0018, 0xc05: 0x0018, + 0xc06: 0x0018, 0xc07: 0x1e92, 0xc08: 0x1eaa, 0xc09: 0x1ec2, 0xc0a: 0x0018, 0xc0b: 0x0018, + 0xc0c: 0x0018, 0xc0d: 0x0018, 0xc0e: 0x0018, 0xc0f: 0x0018, 0xc10: 0x0018, 0xc11: 0x0018, + 0xc12: 0x0018, 0xc13: 0x0018, 0xc14: 0x0018, 0xc15: 0x0018, 0xc16: 0x0018, 0xc17: 0x1ed9, + 0xc18: 0x0018, 0xc19: 0x0018, 0xc1a: 0x0018, 0xc1b: 0x0018, 0xc1c: 0x0018, 0xc1d: 0x0018, + 0xc1e: 0x0018, 0xc1f: 0x000a, 0xc20: 0x03c0, 0xc21: 0x0340, 0xc22: 0x0340, 0xc23: 0x0340, + 0xc24: 0x03c0, 0xc25: 0x0040, 0xc26: 0x0040, 0xc27: 0x0040, 0xc28: 0x0040, 0xc29: 0x0040, + 0xc2a: 0x0340, 0xc2b: 0x0340, 0xc2c: 0x0340, 0xc2d: 0x0340, 0xc2e: 0x0340, 0xc2f: 0x0340, + 0xc30: 0x1f41, 0xc31: 0x0f41, 0xc32: 0x0040, 0xc33: 0x0040, 0xc34: 0x1f51, 0xc35: 0x1f61, + 0xc36: 0x1f71, 0xc37: 0x1f81, 0xc38: 0x1f91, 0xc39: 0x1fa1, 0xc3a: 0x1fb2, 0xc3b: 0x07bd, + 0xc3c: 0x1fc2, 0xc3d: 0x1fd2, 0xc3e: 0x1fe2, 0xc3f: 0x0f71, // Block 0x31, offset 0xc40 - 0xc40: 0x08ed, 0xc41: 0x0018, 0xc42: 0x0018, 0xc43: 0x0018, 0xc44: 0x0018, 0xc45: 0x0ef9, - 0xc46: 0x0ef9, 0xc47: 0x0f09, 0xc48: 0x0f41, 0xc49: 0x0259, 0xc4a: 0x0018, 0xc4b: 0x0018, - 0xc4c: 0x0018, 0xc4d: 0x0018, 0xc4e: 0x0008, 0xc4f: 0x0018, 0xc50: 0x2121, 0xc51: 0x2151, - 0xc52: 0x2181, 0xc53: 0x21b9, 0xc54: 0x21e9, 0xc55: 0x2219, 0xc56: 0x2249, 0xc57: 0x2279, - 0xc58: 0x22a9, 0xc59: 0x22d9, 0xc5a: 0x2309, 0xc5b: 0x2339, 0xc5c: 0x2369, 0xc5d: 0x2399, - 0xc5e: 0x23c9, 0xc5f: 0x23f9, 0xc60: 0x0f41, 0xc61: 0x2421, 0xc62: 0x0905, 0xc63: 0x2439, - 0xc64: 0x1089, 0xc65: 0x2451, 0xc66: 0x0925, 0xc67: 0x2469, 0xc68: 0x2491, 0xc69: 0x0369, - 0xc6a: 0x24a9, 0xc6b: 0x0945, 0xc6c: 0x0359, 0xc6d: 0x1159, 0xc6e: 0x0ef9, 0xc6f: 0x0f61, - 0xc70: 0x0f41, 0xc71: 0x2421, 0xc72: 0x0965, 0xc73: 0x2439, 0xc74: 0x1089, 0xc75: 0x2451, - 0xc76: 0x0985, 0xc77: 0x2469, 0xc78: 0x2491, 0xc79: 0x0369, 0xc7a: 0x24a9, 0xc7b: 0x09a5, - 0xc7c: 0x0359, 0xc7d: 0x1159, 0xc7e: 0x0ef9, 0xc7f: 0x0f61, + 0xc40: 0x1f41, 0xc41: 0x00c9, 0xc42: 0x0069, 0xc43: 0x0079, 0xc44: 0x1f51, 0xc45: 0x1f61, + 0xc46: 0x1f71, 0xc47: 0x1f81, 0xc48: 0x1f91, 0xc49: 0x1fa1, 0xc4a: 0x1fb2, 0xc4b: 0x07d5, + 0xc4c: 0x1fc2, 0xc4d: 0x1fd2, 0xc4e: 0x1fe2, 0xc4f: 0x0040, 0xc50: 0x0039, 0xc51: 0x0f09, + 0xc52: 0x00d9, 0xc53: 0x0369, 0xc54: 0x0ff9, 0xc55: 0x0249, 0xc56: 0x0f51, 0xc57: 0x0359, + 0xc58: 0x0f61, 0xc59: 0x0f71, 0xc5a: 0x0f99, 0xc5b: 0x01d9, 0xc5c: 0x0fa9, 0xc5d: 0x0040, + 0xc5e: 0x0040, 0xc5f: 0x0040, 0xc60: 0x0018, 0xc61: 0x0018, 0xc62: 0x0018, 0xc63: 0x0018, + 0xc64: 0x0018, 0xc65: 0x0018, 0xc66: 0x0018, 0xc67: 0x0018, 0xc68: 0x1ff1, 0xc69: 0x0018, + 0xc6a: 0x0018, 0xc6b: 0x0018, 0xc6c: 0x0018, 0xc6d: 0x0018, 0xc6e: 0x0018, 0xc6f: 0x0018, + 0xc70: 0x0018, 0xc71: 0x0018, 0xc72: 0x0018, 0xc73: 0x0018, 0xc74: 0x0018, 0xc75: 0x0018, + 0xc76: 0x0018, 0xc77: 0x0018, 0xc78: 0x0018, 0xc79: 0x0018, 0xc7a: 0x0018, 0xc7b: 0x0018, + 0xc7c: 0x0018, 0xc7d: 0x0018, 0xc7e: 0x0018, 0xc7f: 0x0018, // Block 0x32, offset 0xc80 - 0xc80: 0x0018, 0xc81: 0x0018, 0xc82: 0x0018, 0xc83: 0x0018, 0xc84: 0x0018, 0xc85: 0x0018, - 0xc86: 0x0018, 0xc87: 0x0018, 0xc88: 0x0018, 0xc89: 0x0018, 0xc8a: 0x0018, 0xc8b: 0x0040, - 0xc8c: 0x0040, 0xc8d: 0x0040, 0xc8e: 0x0040, 0xc8f: 0x0040, 0xc90: 0x0040, 0xc91: 0x0040, - 0xc92: 0x0040, 0xc93: 0x0040, 0xc94: 0x0040, 0xc95: 0x0040, 0xc96: 0x0040, 0xc97: 0x0040, - 0xc98: 0x0040, 0xc99: 0x0040, 0xc9a: 0x0040, 0xc9b: 0x0040, 0xc9c: 0x0040, 0xc9d: 0x0040, - 0xc9e: 0x0040, 0xc9f: 0x0040, 0xca0: 0x00c9, 0xca1: 0x0069, 0xca2: 0x0079, 0xca3: 0x1f51, - 0xca4: 0x1f61, 0xca5: 0x1f71, 0xca6: 0x1f81, 0xca7: 0x1f91, 0xca8: 0x1fa1, 0xca9: 0x2601, - 0xcaa: 0x2619, 0xcab: 0x2631, 0xcac: 0x2649, 0xcad: 0x2661, 0xcae: 0x2679, 0xcaf: 0x2691, - 0xcb0: 0x26a9, 0xcb1: 0x26c1, 0xcb2: 0x26d9, 0xcb3: 0x26f1, 0xcb4: 0x0a06, 0xcb5: 0x0a26, - 0xcb6: 0x0a46, 0xcb7: 0x0a66, 0xcb8: 0x0a86, 0xcb9: 0x0aa6, 0xcba: 0x0ac6, 0xcbb: 0x0ae6, - 0xcbc: 0x0b06, 0xcbd: 0x270a, 0xcbe: 0x2732, 0xcbf: 0x275a, + 0xc80: 0x07ee, 0xc81: 0x080e, 0xc82: 0x1159, 0xc83: 0x082d, 0xc84: 0x0018, 0xc85: 0x084e, + 0xc86: 0x086e, 0xc87: 0x1011, 0xc88: 0x0018, 0xc89: 0x088d, 0xc8a: 0x0f31, 0xc8b: 0x0249, + 0xc8c: 0x0249, 0xc8d: 0x0249, 0xc8e: 0x0249, 0xc8f: 0x2009, 0xc90: 0x0f41, 0xc91: 0x0f41, + 0xc92: 0x0359, 0xc93: 0x0359, 0xc94: 0x0018, 0xc95: 0x0f71, 0xc96: 0x2021, 0xc97: 0x0018, + 0xc98: 0x0018, 0xc99: 0x0f99, 0xc9a: 0x2039, 0xc9b: 0x0269, 0xc9c: 0x0269, 0xc9d: 0x0269, + 0xc9e: 0x0018, 0xc9f: 0x0018, 0xca0: 0x2049, 0xca1: 0x08ad, 0xca2: 0x2061, 0xca3: 0x0018, + 0xca4: 0x13d1, 0xca5: 0x0018, 0xca6: 0x2079, 0xca7: 0x0018, 0xca8: 0x13d1, 0xca9: 0x0018, + 0xcaa: 0x0f51, 0xcab: 0x2091, 0xcac: 0x0ee9, 0xcad: 0x1159, 0xcae: 0x0018, 0xcaf: 0x0f09, + 0xcb0: 0x0f09, 0xcb1: 0x1199, 0xcb2: 0x0040, 0xcb3: 0x0f61, 0xcb4: 0x00d9, 0xcb5: 0x20a9, + 0xcb6: 0x20c1, 0xcb7: 0x20d9, 0xcb8: 0x20f1, 0xcb9: 0x0f41, 0xcba: 0x0018, 0xcbb: 0x08cd, + 0xcbc: 0x2109, 0xcbd: 0x10b1, 0xcbe: 0x10b1, 0xcbf: 0x2109, // Block 0x33, offset 0xcc0 - 0xcc0: 0x2782, 0xcc1: 0x27aa, 0xcc2: 0x27d2, 0xcc3: 0x27fa, 0xcc4: 0x2822, 0xcc5: 0x284a, - 0xcc6: 0x2872, 0xcc7: 0x289a, 0xcc8: 0x0040, 0xcc9: 0x0040, 0xcca: 0x0040, 0xccb: 0x0040, - 0xccc: 0x0040, 0xccd: 0x0040, 0xcce: 0x0040, 0xccf: 0x0040, 0xcd0: 0x0040, 0xcd1: 0x0040, - 0xcd2: 0x0040, 0xcd3: 0x0040, 0xcd4: 0x0040, 0xcd5: 0x0040, 0xcd6: 0x0040, 0xcd7: 0x0040, - 0xcd8: 0x0040, 0xcd9: 0x0040, 0xcda: 0x0040, 0xcdb: 0x0040, 0xcdc: 0x0b26, 0xcdd: 0x0b46, - 0xcde: 0x0b66, 0xcdf: 0x0b86, 0xce0: 0x0ba6, 0xce1: 0x0bc6, 0xce2: 0x0be6, 0xce3: 0x0c06, - 0xce4: 0x0c26, 0xce5: 0x0c46, 0xce6: 0x0c66, 0xce7: 0x0c86, 0xce8: 0x0ca6, 0xce9: 0x0cc6, - 0xcea: 0x0ce6, 0xceb: 0x0d06, 0xcec: 0x0d26, 0xced: 0x0d46, 0xcee: 0x0d66, 0xcef: 0x0d86, - 0xcf0: 0x0da6, 0xcf1: 0x0dc6, 0xcf2: 0x0de6, 0xcf3: 0x0e06, 0xcf4: 0x0e26, 0xcf5: 0x0e46, - 0xcf6: 0x0039, 0xcf7: 0x0ee9, 0xcf8: 0x1159, 0xcf9: 0x0ef9, 0xcfa: 0x0f09, 0xcfb: 0x1199, - 0xcfc: 0x0f31, 0xcfd: 0x0249, 0xcfe: 0x0f41, 0xcff: 0x0259, + 0xcc0: 0x08ed, 0xcc1: 0x0018, 0xcc2: 0x0018, 0xcc3: 0x0018, 0xcc4: 0x0018, 0xcc5: 0x0ef9, + 0xcc6: 0x0ef9, 0xcc7: 0x0f09, 0xcc8: 0x0f41, 0xcc9: 0x0259, 0xcca: 0x0018, 0xccb: 0x0018, + 0xccc: 0x0018, 0xccd: 0x0018, 0xcce: 0x0008, 0xccf: 0x0018, 0xcd0: 0x2121, 0xcd1: 0x2151, + 0xcd2: 0x2181, 0xcd3: 0x21b9, 0xcd4: 0x21e9, 0xcd5: 0x2219, 0xcd6: 0x2249, 0xcd7: 0x2279, + 0xcd8: 0x22a9, 0xcd9: 0x22d9, 0xcda: 0x2309, 0xcdb: 0x2339, 0xcdc: 0x2369, 0xcdd: 0x2399, + 0xcde: 0x23c9, 0xcdf: 0x23f9, 0xce0: 0x0f41, 0xce1: 0x2421, 0xce2: 0x0905, 0xce3: 0x2439, + 0xce4: 0x1089, 0xce5: 0x2451, 0xce6: 0x0925, 0xce7: 0x2469, 0xce8: 0x2491, 0xce9: 0x0369, + 0xcea: 0x24a9, 0xceb: 0x0945, 0xcec: 0x0359, 0xced: 0x1159, 0xcee: 0x0ef9, 0xcef: 0x0f61, + 0xcf0: 0x0f41, 0xcf1: 0x2421, 0xcf2: 0x0965, 0xcf3: 0x2439, 0xcf4: 0x1089, 0xcf5: 0x2451, + 0xcf6: 0x0985, 0xcf7: 0x2469, 0xcf8: 0x2491, 0xcf9: 0x0369, 0xcfa: 0x24a9, 0xcfb: 0x09a5, + 0xcfc: 0x0359, 0xcfd: 0x1159, 0xcfe: 0x0ef9, 0xcff: 0x0f61, // Block 0x34, offset 0xd00 - 0xd00: 0x0f51, 0xd01: 0x0359, 0xd02: 0x0f61, 0xd03: 0x0f71, 0xd04: 0x00d9, 0xd05: 0x0f99, - 0xd06: 0x2039, 0xd07: 0x0269, 0xd08: 0x01d9, 0xd09: 0x0fa9, 0xd0a: 0x0fb9, 0xd0b: 0x1089, - 0xd0c: 0x0279, 0xd0d: 0x0369, 0xd0e: 0x0289, 0xd0f: 0x13d1, 0xd10: 0x0039, 0xd11: 0x0ee9, - 0xd12: 0x1159, 0xd13: 0x0ef9, 0xd14: 0x0f09, 0xd15: 0x1199, 0xd16: 0x0f31, 0xd17: 0x0249, - 0xd18: 0x0f41, 0xd19: 0x0259, 0xd1a: 0x0f51, 0xd1b: 0x0359, 0xd1c: 0x0f61, 0xd1d: 0x0f71, - 0xd1e: 0x00d9, 0xd1f: 0x0f99, 0xd20: 0x2039, 0xd21: 0x0269, 0xd22: 0x01d9, 0xd23: 0x0fa9, - 0xd24: 0x0fb9, 0xd25: 0x1089, 0xd26: 0x0279, 0xd27: 0x0369, 0xd28: 0x0289, 0xd29: 0x13d1, - 0xd2a: 0x1f41, 0xd2b: 0x0018, 0xd2c: 0x0018, 0xd2d: 0x0018, 0xd2e: 0x0018, 0xd2f: 0x0018, - 0xd30: 0x0018, 0xd31: 0x0018, 0xd32: 0x0018, 0xd33: 0x0018, 0xd34: 0x0018, 0xd35: 0x0018, - 0xd36: 0x0018, 0xd37: 0x0018, 0xd38: 0x0018, 0xd39: 0x0018, 0xd3a: 0x0018, 0xd3b: 0x0018, - 0xd3c: 0x0018, 0xd3d: 0x0018, 0xd3e: 0x0018, 0xd3f: 0x0018, + 0xd00: 0x0018, 0xd01: 0x0018, 0xd02: 0x0018, 0xd03: 0x0018, 0xd04: 0x0018, 0xd05: 0x0018, + 0xd06: 0x0018, 0xd07: 0x0018, 0xd08: 0x0018, 0xd09: 0x0018, 0xd0a: 0x0018, 0xd0b: 0x0040, + 0xd0c: 0x0040, 0xd0d: 0x0040, 0xd0e: 0x0040, 0xd0f: 0x0040, 0xd10: 0x0040, 0xd11: 0x0040, + 0xd12: 0x0040, 0xd13: 0x0040, 0xd14: 0x0040, 0xd15: 0x0040, 0xd16: 0x0040, 0xd17: 0x0040, + 0xd18: 0x0040, 0xd19: 0x0040, 0xd1a: 0x0040, 0xd1b: 0x0040, 0xd1c: 0x0040, 0xd1d: 0x0040, + 0xd1e: 0x0040, 0xd1f: 0x0040, 0xd20: 0x00c9, 0xd21: 0x0069, 0xd22: 0x0079, 0xd23: 0x1f51, + 0xd24: 0x1f61, 0xd25: 0x1f71, 0xd26: 0x1f81, 0xd27: 0x1f91, 0xd28: 0x1fa1, 0xd29: 0x2601, + 0xd2a: 0x2619, 0xd2b: 0x2631, 0xd2c: 0x2649, 0xd2d: 0x2661, 0xd2e: 0x2679, 0xd2f: 0x2691, + 0xd30: 0x26a9, 0xd31: 0x26c1, 0xd32: 0x26d9, 0xd33: 0x26f1, 0xd34: 0x0a06, 0xd35: 0x0a26, + 0xd36: 0x0a46, 0xd37: 0x0a66, 0xd38: 0x0a86, 0xd39: 0x0aa6, 0xd3a: 0x0ac6, 0xd3b: 0x0ae6, + 0xd3c: 0x0b06, 0xd3d: 0x270a, 0xd3e: 0x2732, 0xd3f: 0x275a, // Block 0x35, offset 0xd40 - 0xd40: 0x0008, 0xd41: 0x0008, 0xd42: 0x0008, 0xd43: 0x0008, 0xd44: 0x0008, 0xd45: 0x0008, - 0xd46: 0x0008, 0xd47: 0x0008, 0xd48: 0x0008, 0xd49: 0x0008, 0xd4a: 0x0008, 0xd4b: 0x0008, - 0xd4c: 0x0008, 0xd4d: 0x0008, 0xd4e: 0x0008, 0xd4f: 0x0008, 0xd50: 0x0008, 0xd51: 0x0008, - 0xd52: 0x0008, 0xd53: 0x0008, 0xd54: 0x0008, 0xd55: 0x0008, 0xd56: 0x0008, 0xd57: 0x0008, - 0xd58: 0x0008, 0xd59: 0x0008, 0xd5a: 0x0008, 0xd5b: 0x0008, 0xd5c: 0x0008, 0xd5d: 0x0008, - 0xd5e: 0x0008, 0xd5f: 0x0040, 0xd60: 0xe00d, 0xd61: 0x0008, 0xd62: 0x2971, 0xd63: 0x0ebd, - 0xd64: 0x2989, 0xd65: 0x0008, 0xd66: 0x0008, 0xd67: 0xe07d, 0xd68: 0x0008, 0xd69: 0xe01d, - 0xd6a: 0x0008, 0xd6b: 0xe03d, 0xd6c: 0x0008, 0xd6d: 0x0fe1, 0xd6e: 0x1281, 0xd6f: 0x0fc9, - 0xd70: 0x1141, 0xd71: 0x0008, 0xd72: 0xe00d, 0xd73: 0x0008, 0xd74: 0x0008, 0xd75: 0xe01d, - 0xd76: 0x0008, 0xd77: 0x0008, 0xd78: 0x0008, 0xd79: 0x0008, 0xd7a: 0x0008, 0xd7b: 0x0008, - 0xd7c: 0x0259, 0xd7d: 0x1089, 0xd7e: 0x29a1, 0xd7f: 0x29b9, + 0xd40: 0x2782, 0xd41: 0x27aa, 0xd42: 0x27d2, 0xd43: 0x27fa, 0xd44: 0x2822, 0xd45: 0x284a, + 0xd46: 0x2872, 0xd47: 0x289a, 0xd48: 0x0040, 0xd49: 0x0040, 0xd4a: 0x0040, 0xd4b: 0x0040, + 0xd4c: 0x0040, 0xd4d: 0x0040, 0xd4e: 0x0040, 0xd4f: 0x0040, 0xd50: 0x0040, 0xd51: 0x0040, + 0xd52: 0x0040, 0xd53: 0x0040, 0xd54: 0x0040, 0xd55: 0x0040, 0xd56: 0x0040, 0xd57: 0x0040, + 0xd58: 0x0040, 0xd59: 0x0040, 0xd5a: 0x0040, 0xd5b: 0x0040, 0xd5c: 0x0b26, 0xd5d: 0x0b46, + 0xd5e: 0x0b66, 0xd5f: 0x0b86, 0xd60: 0x0ba6, 0xd61: 0x0bc6, 0xd62: 0x0be6, 0xd63: 0x0c06, + 0xd64: 0x0c26, 0xd65: 0x0c46, 0xd66: 0x0c66, 0xd67: 0x0c86, 0xd68: 0x0ca6, 0xd69: 0x0cc6, + 0xd6a: 0x0ce6, 0xd6b: 0x0d06, 0xd6c: 0x0d26, 0xd6d: 0x0d46, 0xd6e: 0x0d66, 0xd6f: 0x0d86, + 0xd70: 0x0da6, 0xd71: 0x0dc6, 0xd72: 0x0de6, 0xd73: 0x0e06, 0xd74: 0x0e26, 0xd75: 0x0e46, + 0xd76: 0x0039, 0xd77: 0x0ee9, 0xd78: 0x1159, 0xd79: 0x0ef9, 0xd7a: 0x0f09, 0xd7b: 0x1199, + 0xd7c: 0x0f31, 0xd7d: 0x0249, 0xd7e: 0x0f41, 0xd7f: 0x0259, // Block 0x36, offset 0xd80 - 0xd80: 0xe00d, 0xd81: 0x0008, 0xd82: 0xe00d, 0xd83: 0x0008, 0xd84: 0xe00d, 0xd85: 0x0008, - 0xd86: 0xe00d, 0xd87: 0x0008, 0xd88: 0xe00d, 0xd89: 0x0008, 0xd8a: 0xe00d, 0xd8b: 0x0008, - 0xd8c: 0xe00d, 0xd8d: 0x0008, 0xd8e: 0xe00d, 0xd8f: 0x0008, 0xd90: 0xe00d, 0xd91: 0x0008, - 0xd92: 0xe00d, 0xd93: 0x0008, 0xd94: 0xe00d, 0xd95: 0x0008, 0xd96: 0xe00d, 0xd97: 0x0008, - 0xd98: 0xe00d, 0xd99: 0x0008, 0xd9a: 0xe00d, 0xd9b: 0x0008, 0xd9c: 0xe00d, 0xd9d: 0x0008, - 0xd9e: 0xe00d, 0xd9f: 0x0008, 0xda0: 0xe00d, 0xda1: 0x0008, 0xda2: 0xe00d, 0xda3: 0x0008, - 0xda4: 0x0008, 0xda5: 0x0018, 0xda6: 0x0018, 0xda7: 0x0018, 0xda8: 0x0018, 0xda9: 0x0018, - 0xdaa: 0x0018, 0xdab: 0xe03d, 0xdac: 0x0008, 0xdad: 0xe01d, 0xdae: 0x0008, 0xdaf: 0x1308, - 0xdb0: 0x1308, 0xdb1: 0x1308, 0xdb2: 0xe00d, 0xdb3: 0x0008, 0xdb4: 0x0040, 0xdb5: 0x0040, - 0xdb6: 0x0040, 0xdb7: 0x0040, 0xdb8: 0x0040, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018, + 0xd80: 0x0f51, 0xd81: 0x0359, 0xd82: 0x0f61, 0xd83: 0x0f71, 0xd84: 0x00d9, 0xd85: 0x0f99, + 0xd86: 0x2039, 0xd87: 0x0269, 0xd88: 0x01d9, 0xd89: 0x0fa9, 0xd8a: 0x0fb9, 0xd8b: 0x1089, + 0xd8c: 0x0279, 0xd8d: 0x0369, 0xd8e: 0x0289, 0xd8f: 0x13d1, 0xd90: 0x0039, 0xd91: 0x0ee9, + 0xd92: 0x1159, 0xd93: 0x0ef9, 0xd94: 0x0f09, 0xd95: 0x1199, 0xd96: 0x0f31, 0xd97: 0x0249, + 0xd98: 0x0f41, 0xd99: 0x0259, 0xd9a: 0x0f51, 0xd9b: 0x0359, 0xd9c: 0x0f61, 0xd9d: 0x0f71, + 0xd9e: 0x00d9, 0xd9f: 0x0f99, 0xda0: 0x2039, 0xda1: 0x0269, 0xda2: 0x01d9, 0xda3: 0x0fa9, + 0xda4: 0x0fb9, 0xda5: 0x1089, 0xda6: 0x0279, 0xda7: 0x0369, 0xda8: 0x0289, 0xda9: 0x13d1, + 0xdaa: 0x1f41, 0xdab: 0x0018, 0xdac: 0x0018, 0xdad: 0x0018, 0xdae: 0x0018, 0xdaf: 0x0018, + 0xdb0: 0x0018, 0xdb1: 0x0018, 0xdb2: 0x0018, 0xdb3: 0x0018, 0xdb4: 0x0018, 0xdb5: 0x0018, + 0xdb6: 0x0018, 0xdb7: 0x0018, 0xdb8: 0x0018, 0xdb9: 0x0018, 0xdba: 0x0018, 0xdbb: 0x0018, 0xdbc: 0x0018, 0xdbd: 0x0018, 0xdbe: 0x0018, 0xdbf: 0x0018, // Block 0x37, offset 0xdc0 - 0xdc0: 0x26fd, 0xdc1: 0x271d, 0xdc2: 0x273d, 0xdc3: 0x275d, 0xdc4: 0x277d, 0xdc5: 0x279d, - 0xdc6: 0x27bd, 0xdc7: 0x27dd, 0xdc8: 0x27fd, 0xdc9: 0x281d, 0xdca: 0x283d, 0xdcb: 0x285d, - 0xdcc: 0x287d, 0xdcd: 0x289d, 0xdce: 0x28bd, 0xdcf: 0x28dd, 0xdd0: 0x28fd, 0xdd1: 0x291d, - 0xdd2: 0x293d, 0xdd3: 0x295d, 0xdd4: 0x297d, 0xdd5: 0x299d, 0xdd6: 0x0040, 0xdd7: 0x0040, - 0xdd8: 0x0040, 0xdd9: 0x0040, 0xdda: 0x0040, 0xddb: 0x0040, 0xddc: 0x0040, 0xddd: 0x0040, - 0xdde: 0x0040, 0xddf: 0x0040, 0xde0: 0x0040, 0xde1: 0x0040, 0xde2: 0x0040, 0xde3: 0x0040, - 0xde4: 0x0040, 0xde5: 0x0040, 0xde6: 0x0040, 0xde7: 0x0040, 0xde8: 0x0040, 0xde9: 0x0040, - 0xdea: 0x0040, 0xdeb: 0x0040, 0xdec: 0x0040, 0xded: 0x0040, 0xdee: 0x0040, 0xdef: 0x0040, - 0xdf0: 0x0040, 0xdf1: 0x0040, 0xdf2: 0x0040, 0xdf3: 0x0040, 0xdf4: 0x0040, 0xdf5: 0x0040, - 0xdf6: 0x0040, 0xdf7: 0x0040, 0xdf8: 0x0040, 0xdf9: 0x0040, 0xdfa: 0x0040, 0xdfb: 0x0040, - 0xdfc: 0x0040, 0xdfd: 0x0040, 0xdfe: 0x0040, 0xdff: 0x0040, + 0xdc0: 0x0008, 0xdc1: 0x0008, 0xdc2: 0x0008, 0xdc3: 0x0008, 0xdc4: 0x0008, 0xdc5: 0x0008, + 0xdc6: 0x0008, 0xdc7: 0x0008, 0xdc8: 0x0008, 0xdc9: 0x0008, 0xdca: 0x0008, 0xdcb: 0x0008, + 0xdcc: 0x0008, 0xdcd: 0x0008, 0xdce: 0x0008, 0xdcf: 0x0008, 0xdd0: 0x0008, 0xdd1: 0x0008, + 0xdd2: 0x0008, 0xdd3: 0x0008, 0xdd4: 0x0008, 0xdd5: 0x0008, 0xdd6: 0x0008, 0xdd7: 0x0008, + 0xdd8: 0x0008, 0xdd9: 0x0008, 0xdda: 0x0008, 0xddb: 0x0008, 0xddc: 0x0008, 0xddd: 0x0008, + 0xdde: 0x0008, 0xddf: 0x0040, 0xde0: 0xe00d, 0xde1: 0x0008, 0xde2: 0x2971, 0xde3: 0x0ebd, + 0xde4: 0x2989, 0xde5: 0x0008, 0xde6: 0x0008, 0xde7: 0xe07d, 0xde8: 0x0008, 0xde9: 0xe01d, + 0xdea: 0x0008, 0xdeb: 0xe03d, 0xdec: 0x0008, 0xded: 0x0fe1, 0xdee: 0x1281, 0xdef: 0x0fc9, + 0xdf0: 0x1141, 0xdf1: 0x0008, 0xdf2: 0xe00d, 0xdf3: 0x0008, 0xdf4: 0x0008, 0xdf5: 0xe01d, + 0xdf6: 0x0008, 0xdf7: 0x0008, 0xdf8: 0x0008, 0xdf9: 0x0008, 0xdfa: 0x0008, 0xdfb: 0x0008, + 0xdfc: 0x0259, 0xdfd: 0x1089, 0xdfe: 0x29a1, 0xdff: 0x29b9, // Block 0x38, offset 0xe00 - 0xe00: 0x000a, 0xe01: 0x0018, 0xe02: 0x29d1, 0xe03: 0x0018, 0xe04: 0x0018, 0xe05: 0x0008, - 0xe06: 0x0008, 0xe07: 0x0008, 0xe08: 0x0018, 0xe09: 0x0018, 0xe0a: 0x0018, 0xe0b: 0x0018, - 0xe0c: 0x0018, 0xe0d: 0x0018, 0xe0e: 0x0018, 0xe0f: 0x0018, 0xe10: 0x0018, 0xe11: 0x0018, - 0xe12: 0x0018, 0xe13: 0x0018, 0xe14: 0x0018, 0xe15: 0x0018, 0xe16: 0x0018, 0xe17: 0x0018, - 0xe18: 0x0018, 0xe19: 0x0018, 0xe1a: 0x0018, 0xe1b: 0x0018, 0xe1c: 0x0018, 0xe1d: 0x0018, - 0xe1e: 0x0018, 0xe1f: 0x0018, 0xe20: 0x0018, 0xe21: 0x0018, 0xe22: 0x0018, 0xe23: 0x0018, - 0xe24: 0x0018, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018, - 0xe2a: 0x1308, 0xe2b: 0x1308, 0xe2c: 0x1308, 0xe2d: 0x1308, 0xe2e: 0x1018, 0xe2f: 0x1018, - 0xe30: 0x0018, 0xe31: 0x0018, 0xe32: 0x0018, 0xe33: 0x0018, 0xe34: 0x0018, 0xe35: 0x0018, - 0xe36: 0xe125, 0xe37: 0x0018, 0xe38: 0x29bd, 0xe39: 0x29dd, 0xe3a: 0x29fd, 0xe3b: 0x0018, - 0xe3c: 0x0008, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018, + 0xe00: 0xe00d, 0xe01: 0x0008, 0xe02: 0xe00d, 0xe03: 0x0008, 0xe04: 0xe00d, 0xe05: 0x0008, + 0xe06: 0xe00d, 0xe07: 0x0008, 0xe08: 0xe00d, 0xe09: 0x0008, 0xe0a: 0xe00d, 0xe0b: 0x0008, + 0xe0c: 0xe00d, 0xe0d: 0x0008, 0xe0e: 0xe00d, 0xe0f: 0x0008, 0xe10: 0xe00d, 0xe11: 0x0008, + 0xe12: 0xe00d, 0xe13: 0x0008, 0xe14: 0xe00d, 0xe15: 0x0008, 0xe16: 0xe00d, 0xe17: 0x0008, + 0xe18: 0xe00d, 0xe19: 0x0008, 0xe1a: 0xe00d, 0xe1b: 0x0008, 0xe1c: 0xe00d, 0xe1d: 0x0008, + 0xe1e: 0xe00d, 0xe1f: 0x0008, 0xe20: 0xe00d, 0xe21: 0x0008, 0xe22: 0xe00d, 0xe23: 0x0008, + 0xe24: 0x0008, 0xe25: 0x0018, 0xe26: 0x0018, 0xe27: 0x0018, 0xe28: 0x0018, 0xe29: 0x0018, + 0xe2a: 0x0018, 0xe2b: 0xe03d, 0xe2c: 0x0008, 0xe2d: 0xe01d, 0xe2e: 0x0008, 0xe2f: 0x3308, + 0xe30: 0x3308, 0xe31: 0x3308, 0xe32: 0xe00d, 0xe33: 0x0008, 0xe34: 0x0040, 0xe35: 0x0040, + 0xe36: 0x0040, 0xe37: 0x0040, 0xe38: 0x0040, 0xe39: 0x0018, 0xe3a: 0x0018, 0xe3b: 0x0018, + 0xe3c: 0x0018, 0xe3d: 0x0018, 0xe3e: 0x0018, 0xe3f: 0x0018, // Block 0x39, offset 0xe40 - 0xe40: 0x2b3d, 0xe41: 0x2b5d, 0xe42: 0x2b7d, 0xe43: 0x2b9d, 0xe44: 0x2bbd, 0xe45: 0x2bdd, - 0xe46: 0x2bdd, 0xe47: 0x2bdd, 0xe48: 0x2bfd, 0xe49: 0x2bfd, 0xe4a: 0x2bfd, 0xe4b: 0x2bfd, - 0xe4c: 0x2c1d, 0xe4d: 0x2c1d, 0xe4e: 0x2c1d, 0xe4f: 0x2c3d, 0xe50: 0x2c5d, 0xe51: 0x2c5d, - 0xe52: 0x2a7d, 0xe53: 0x2a7d, 0xe54: 0x2c5d, 0xe55: 0x2c5d, 0xe56: 0x2c7d, 0xe57: 0x2c7d, - 0xe58: 0x2c5d, 0xe59: 0x2c5d, 0xe5a: 0x2a7d, 0xe5b: 0x2a7d, 0xe5c: 0x2c5d, 0xe5d: 0x2c5d, - 0xe5e: 0x2c3d, 0xe5f: 0x2c3d, 0xe60: 0x2c9d, 0xe61: 0x2c9d, 0xe62: 0x2cbd, 0xe63: 0x2cbd, - 0xe64: 0x0040, 0xe65: 0x2cdd, 0xe66: 0x2cfd, 0xe67: 0x2d1d, 0xe68: 0x2d1d, 0xe69: 0x2d3d, - 0xe6a: 0x2d5d, 0xe6b: 0x2d7d, 0xe6c: 0x2d9d, 0xe6d: 0x2dbd, 0xe6e: 0x2ddd, 0xe6f: 0x2dfd, - 0xe70: 0x2e1d, 0xe71: 0x2e3d, 0xe72: 0x2e3d, 0xe73: 0x2e5d, 0xe74: 0x2e7d, 0xe75: 0x2e7d, - 0xe76: 0x2e9d, 0xe77: 0x2ebd, 0xe78: 0x2e5d, 0xe79: 0x2edd, 0xe7a: 0x2efd, 0xe7b: 0x2edd, - 0xe7c: 0x2e5d, 0xe7d: 0x2f1d, 0xe7e: 0x2f3d, 0xe7f: 0x2f5d, + 0xe40: 0x26fd, 0xe41: 0x271d, 0xe42: 0x273d, 0xe43: 0x275d, 0xe44: 0x277d, 0xe45: 0x279d, + 0xe46: 0x27bd, 0xe47: 0x27dd, 0xe48: 0x27fd, 0xe49: 0x281d, 0xe4a: 0x283d, 0xe4b: 0x285d, + 0xe4c: 0x287d, 0xe4d: 0x289d, 0xe4e: 0x28bd, 0xe4f: 0x28dd, 0xe50: 0x28fd, 0xe51: 0x291d, + 0xe52: 0x293d, 0xe53: 0x295d, 0xe54: 0x297d, 0xe55: 0x299d, 0xe56: 0x0040, 0xe57: 0x0040, + 0xe58: 0x0040, 0xe59: 0x0040, 0xe5a: 0x0040, 0xe5b: 0x0040, 0xe5c: 0x0040, 0xe5d: 0x0040, + 0xe5e: 0x0040, 0xe5f: 0x0040, 0xe60: 0x0040, 0xe61: 0x0040, 0xe62: 0x0040, 0xe63: 0x0040, + 0xe64: 0x0040, 0xe65: 0x0040, 0xe66: 0x0040, 0xe67: 0x0040, 0xe68: 0x0040, 0xe69: 0x0040, + 0xe6a: 0x0040, 0xe6b: 0x0040, 0xe6c: 0x0040, 0xe6d: 0x0040, 0xe6e: 0x0040, 0xe6f: 0x0040, + 0xe70: 0x0040, 0xe71: 0x0040, 0xe72: 0x0040, 0xe73: 0x0040, 0xe74: 0x0040, 0xe75: 0x0040, + 0xe76: 0x0040, 0xe77: 0x0040, 0xe78: 0x0040, 0xe79: 0x0040, 0xe7a: 0x0040, 0xe7b: 0x0040, + 0xe7c: 0x0040, 0xe7d: 0x0040, 0xe7e: 0x0040, 0xe7f: 0x0040, // Block 0x3a, offset 0xe80 - 0xe80: 0x2f7d, 0xe81: 0x2f9d, 0xe82: 0x2cfd, 0xe83: 0x2cdd, 0xe84: 0x2fbd, 0xe85: 0x2fdd, - 0xe86: 0x2ffd, 0xe87: 0x301d, 0xe88: 0x303d, 0xe89: 0x305d, 0xe8a: 0x307d, 0xe8b: 0x309d, - 0xe8c: 0x30bd, 0xe8d: 0x30dd, 0xe8e: 0x30fd, 0xe8f: 0x0040, 0xe90: 0x0018, 0xe91: 0x0018, - 0xe92: 0x311d, 0xe93: 0x313d, 0xe94: 0x315d, 0xe95: 0x317d, 0xe96: 0x319d, 0xe97: 0x31bd, - 0xe98: 0x31dd, 0xe99: 0x31fd, 0xe9a: 0x321d, 0xe9b: 0x323d, 0xe9c: 0x315d, 0xe9d: 0x325d, - 0xe9e: 0x327d, 0xe9f: 0x329d, 0xea0: 0x0008, 0xea1: 0x0008, 0xea2: 0x0008, 0xea3: 0x0008, - 0xea4: 0x0008, 0xea5: 0x0008, 0xea6: 0x0008, 0xea7: 0x0008, 0xea8: 0x0008, 0xea9: 0x0008, - 0xeaa: 0x0008, 0xeab: 0x0008, 0xeac: 0x0008, 0xead: 0x0008, 0xeae: 0x0008, 0xeaf: 0x0008, - 0xeb0: 0x0008, 0xeb1: 0x0008, 0xeb2: 0x0008, 0xeb3: 0x0008, 0xeb4: 0x0008, 0xeb5: 0x0008, - 0xeb6: 0x0008, 0xeb7: 0x0008, 0xeb8: 0x0008, 0xeb9: 0x0008, 0xeba: 0x0008, 0xebb: 0x0040, - 0xebc: 0x0040, 0xebd: 0x0040, 0xebe: 0x0040, 0xebf: 0x0040, + 0xe80: 0x000a, 0xe81: 0x0018, 0xe82: 0x29d1, 0xe83: 0x0018, 0xe84: 0x0018, 0xe85: 0x0008, + 0xe86: 0x0008, 0xe87: 0x0008, 0xe88: 0x0018, 0xe89: 0x0018, 0xe8a: 0x0018, 0xe8b: 0x0018, + 0xe8c: 0x0018, 0xe8d: 0x0018, 0xe8e: 0x0018, 0xe8f: 0x0018, 0xe90: 0x0018, 0xe91: 0x0018, + 0xe92: 0x0018, 0xe93: 0x0018, 0xe94: 0x0018, 0xe95: 0x0018, 0xe96: 0x0018, 0xe97: 0x0018, + 0xe98: 0x0018, 0xe99: 0x0018, 0xe9a: 0x0018, 0xe9b: 0x0018, 0xe9c: 0x0018, 0xe9d: 0x0018, + 0xe9e: 0x0018, 0xe9f: 0x0018, 0xea0: 0x0018, 0xea1: 0x0018, 0xea2: 0x0018, 0xea3: 0x0018, + 0xea4: 0x0018, 0xea5: 0x0018, 0xea6: 0x0018, 0xea7: 0x0018, 0xea8: 0x0018, 0xea9: 0x0018, + 0xeaa: 0x3308, 0xeab: 0x3308, 0xeac: 0x3308, 0xead: 0x3308, 0xeae: 0x3018, 0xeaf: 0x3018, + 0xeb0: 0x0018, 0xeb1: 0x0018, 0xeb2: 0x0018, 0xeb3: 0x0018, 0xeb4: 0x0018, 0xeb5: 0x0018, + 0xeb6: 0xe125, 0xeb7: 0x0018, 0xeb8: 0x29bd, 0xeb9: 0x29dd, 0xeba: 0x29fd, 0xebb: 0x0018, + 0xebc: 0x0008, 0xebd: 0x0018, 0xebe: 0x0018, 0xebf: 0x0018, // Block 0x3b, offset 0xec0 - 0xec0: 0x36a2, 0xec1: 0x36d2, 0xec2: 0x3702, 0xec3: 0x3732, 0xec4: 0x32bd, 0xec5: 0x32dd, - 0xec6: 0x32fd, 0xec7: 0x331d, 0xec8: 0x0018, 0xec9: 0x0018, 0xeca: 0x0018, 0xecb: 0x0018, - 0xecc: 0x0018, 0xecd: 0x0018, 0xece: 0x0018, 0xecf: 0x0018, 0xed0: 0x333d, 0xed1: 0x3761, - 0xed2: 0x3779, 0xed3: 0x3791, 0xed4: 0x37a9, 0xed5: 0x37c1, 0xed6: 0x37d9, 0xed7: 0x37f1, - 0xed8: 0x3809, 0xed9: 0x3821, 0xeda: 0x3839, 0xedb: 0x3851, 0xedc: 0x3869, 0xedd: 0x3881, - 0xede: 0x3899, 0xedf: 0x38b1, 0xee0: 0x335d, 0xee1: 0x337d, 0xee2: 0x339d, 0xee3: 0x33bd, - 0xee4: 0x33dd, 0xee5: 0x33dd, 0xee6: 0x33fd, 0xee7: 0x341d, 0xee8: 0x343d, 0xee9: 0x345d, - 0xeea: 0x347d, 0xeeb: 0x349d, 0xeec: 0x34bd, 0xeed: 0x34dd, 0xeee: 0x34fd, 0xeef: 0x351d, - 0xef0: 0x353d, 0xef1: 0x355d, 0xef2: 0x357d, 0xef3: 0x359d, 0xef4: 0x35bd, 0xef5: 0x35dd, - 0xef6: 0x35fd, 0xef7: 0x361d, 0xef8: 0x363d, 0xef9: 0x365d, 0xefa: 0x367d, 0xefb: 0x369d, - 0xefc: 0x38c9, 0xefd: 0x3901, 0xefe: 0x36bd, 0xeff: 0x0018, + 0xec0: 0x2b3d, 0xec1: 0x2b5d, 0xec2: 0x2b7d, 0xec3: 0x2b9d, 0xec4: 0x2bbd, 0xec5: 0x2bdd, + 0xec6: 0x2bdd, 0xec7: 0x2bdd, 0xec8: 0x2bfd, 0xec9: 0x2bfd, 0xeca: 0x2bfd, 0xecb: 0x2bfd, + 0xecc: 0x2c1d, 0xecd: 0x2c1d, 0xece: 0x2c1d, 0xecf: 0x2c3d, 0xed0: 0x2c5d, 0xed1: 0x2c5d, + 0xed2: 0x2a7d, 0xed3: 0x2a7d, 0xed4: 0x2c5d, 0xed5: 0x2c5d, 0xed6: 0x2c7d, 0xed7: 0x2c7d, + 0xed8: 0x2c5d, 0xed9: 0x2c5d, 0xeda: 0x2a7d, 0xedb: 0x2a7d, 0xedc: 0x2c5d, 0xedd: 0x2c5d, + 0xede: 0x2c3d, 0xedf: 0x2c3d, 0xee0: 0x2c9d, 0xee1: 0x2c9d, 0xee2: 0x2cbd, 0xee3: 0x2cbd, + 0xee4: 0x0040, 0xee5: 0x2cdd, 0xee6: 0x2cfd, 0xee7: 0x2d1d, 0xee8: 0x2d1d, 0xee9: 0x2d3d, + 0xeea: 0x2d5d, 0xeeb: 0x2d7d, 0xeec: 0x2d9d, 0xeed: 0x2dbd, 0xeee: 0x2ddd, 0xeef: 0x2dfd, + 0xef0: 0x2e1d, 0xef1: 0x2e3d, 0xef2: 0x2e3d, 0xef3: 0x2e5d, 0xef4: 0x2e7d, 0xef5: 0x2e7d, + 0xef6: 0x2e9d, 0xef7: 0x2ebd, 0xef8: 0x2e5d, 0xef9: 0x2edd, 0xefa: 0x2efd, 0xefb: 0x2edd, + 0xefc: 0x2e5d, 0xefd: 0x2f1d, 0xefe: 0x2f3d, 0xeff: 0x2f5d, // Block 0x3c, offset 0xf00 - 0xf00: 0x36dd, 0xf01: 0x36fd, 0xf02: 0x371d, 0xf03: 0x373d, 0xf04: 0x375d, 0xf05: 0x377d, - 0xf06: 0x379d, 0xf07: 0x37bd, 0xf08: 0x37dd, 0xf09: 0x37fd, 0xf0a: 0x381d, 0xf0b: 0x383d, - 0xf0c: 0x385d, 0xf0d: 0x387d, 0xf0e: 0x389d, 0xf0f: 0x38bd, 0xf10: 0x38dd, 0xf11: 0x38fd, - 0xf12: 0x391d, 0xf13: 0x393d, 0xf14: 0x395d, 0xf15: 0x397d, 0xf16: 0x399d, 0xf17: 0x39bd, - 0xf18: 0x39dd, 0xf19: 0x39fd, 0xf1a: 0x3a1d, 0xf1b: 0x3a3d, 0xf1c: 0x3a5d, 0xf1d: 0x3a7d, - 0xf1e: 0x3a9d, 0xf1f: 0x3abd, 0xf20: 0x3add, 0xf21: 0x3afd, 0xf22: 0x3b1d, 0xf23: 0x3b3d, - 0xf24: 0x3b5d, 0xf25: 0x3b7d, 0xf26: 0x127d, 0xf27: 0x3b9d, 0xf28: 0x3bbd, 0xf29: 0x3bdd, - 0xf2a: 0x3bfd, 0xf2b: 0x3c1d, 0xf2c: 0x3c3d, 0xf2d: 0x3c5d, 0xf2e: 0x239d, 0xf2f: 0x3c7d, - 0xf30: 0x3c9d, 0xf31: 0x3939, 0xf32: 0x3951, 0xf33: 0x3969, 0xf34: 0x3981, 0xf35: 0x3999, - 0xf36: 0x39b1, 0xf37: 0x39c9, 0xf38: 0x39e1, 0xf39: 0x39f9, 0xf3a: 0x3a11, 0xf3b: 0x3a29, - 0xf3c: 0x3a41, 0xf3d: 0x3a59, 0xf3e: 0x3a71, 0xf3f: 0x3a89, + 0xf00: 0x2f7d, 0xf01: 0x2f9d, 0xf02: 0x2cfd, 0xf03: 0x2cdd, 0xf04: 0x2fbd, 0xf05: 0x2fdd, + 0xf06: 0x2ffd, 0xf07: 0x301d, 0xf08: 0x303d, 0xf09: 0x305d, 0xf0a: 0x307d, 0xf0b: 0x309d, + 0xf0c: 0x30bd, 0xf0d: 0x30dd, 0xf0e: 0x30fd, 0xf0f: 0x0040, 0xf10: 0x0018, 0xf11: 0x0018, + 0xf12: 0x311d, 0xf13: 0x313d, 0xf14: 0x315d, 0xf15: 0x317d, 0xf16: 0x319d, 0xf17: 0x31bd, + 0xf18: 0x31dd, 0xf19: 0x31fd, 0xf1a: 0x321d, 0xf1b: 0x323d, 0xf1c: 0x315d, 0xf1d: 0x325d, + 0xf1e: 0x327d, 0xf1f: 0x329d, 0xf20: 0x0008, 0xf21: 0x0008, 0xf22: 0x0008, 0xf23: 0x0008, + 0xf24: 0x0008, 0xf25: 0x0008, 0xf26: 0x0008, 0xf27: 0x0008, 0xf28: 0x0008, 0xf29: 0x0008, + 0xf2a: 0x0008, 0xf2b: 0x0008, 0xf2c: 0x0008, 0xf2d: 0x0008, 0xf2e: 0x0008, 0xf2f: 0x0008, + 0xf30: 0x0008, 0xf31: 0x0008, 0xf32: 0x0008, 0xf33: 0x0008, 0xf34: 0x0008, 0xf35: 0x0008, + 0xf36: 0x0008, 0xf37: 0x0008, 0xf38: 0x0008, 0xf39: 0x0008, 0xf3a: 0x0008, 0xf3b: 0x0040, + 0xf3c: 0x0040, 0xf3d: 0x0040, 0xf3e: 0x0040, 0xf3f: 0x0040, // Block 0x3d, offset 0xf40 - 0xf40: 0x3aa1, 0xf41: 0x3ac9, 0xf42: 0x3af1, 0xf43: 0x3b19, 0xf44: 0x3b41, 0xf45: 0x3b69, - 0xf46: 0x3b91, 0xf47: 0x3bb9, 0xf48: 0x3be1, 0xf49: 0x3c09, 0xf4a: 0x3c39, 0xf4b: 0x3c69, - 0xf4c: 0x3c99, 0xf4d: 0x3cbd, 0xf4e: 0x3cb1, 0xf4f: 0x3cdd, 0xf50: 0x3cfd, 0xf51: 0x3d15, - 0xf52: 0x3d2d, 0xf53: 0x3d45, 0xf54: 0x3d5d, 0xf55: 0x3d5d, 0xf56: 0x3d45, 0xf57: 0x3d75, - 0xf58: 0x07bd, 0xf59: 0x3d8d, 0xf5a: 0x3da5, 0xf5b: 0x3dbd, 0xf5c: 0x3dd5, 0xf5d: 0x3ded, - 0xf5e: 0x3e05, 0xf5f: 0x3e1d, 0xf60: 0x3e35, 0xf61: 0x3e4d, 0xf62: 0x3e65, 0xf63: 0x3e7d, - 0xf64: 0x3e95, 0xf65: 0x3e95, 0xf66: 0x3ead, 0xf67: 0x3ead, 0xf68: 0x3ec5, 0xf69: 0x3ec5, - 0xf6a: 0x3edd, 0xf6b: 0x3ef5, 0xf6c: 0x3f0d, 0xf6d: 0x3f25, 0xf6e: 0x3f3d, 0xf6f: 0x3f3d, - 0xf70: 0x3f55, 0xf71: 0x3f55, 0xf72: 0x3f55, 0xf73: 0x3f6d, 0xf74: 0x3f85, 0xf75: 0x3f9d, - 0xf76: 0x3fb5, 0xf77: 0x3f9d, 0xf78: 0x3fcd, 0xf79: 0x3fe5, 0xf7a: 0x3f6d, 0xf7b: 0x3ffd, - 0xf7c: 0x4015, 0xf7d: 0x4015, 0xf7e: 0x4015, 0xf7f: 0x0040, + 0xf40: 0x36a2, 0xf41: 0x36d2, 0xf42: 0x3702, 0xf43: 0x3732, 0xf44: 0x32bd, 0xf45: 0x32dd, + 0xf46: 0x32fd, 0xf47: 0x331d, 0xf48: 0x0018, 0xf49: 0x0018, 0xf4a: 0x0018, 0xf4b: 0x0018, + 0xf4c: 0x0018, 0xf4d: 0x0018, 0xf4e: 0x0018, 0xf4f: 0x0018, 0xf50: 0x333d, 0xf51: 0x3761, + 0xf52: 0x3779, 0xf53: 0x3791, 0xf54: 0x37a9, 0xf55: 0x37c1, 0xf56: 0x37d9, 0xf57: 0x37f1, + 0xf58: 0x3809, 0xf59: 0x3821, 0xf5a: 0x3839, 0xf5b: 0x3851, 0xf5c: 0x3869, 0xf5d: 0x3881, + 0xf5e: 0x3899, 0xf5f: 0x38b1, 0xf60: 0x335d, 0xf61: 0x337d, 0xf62: 0x339d, 0xf63: 0x33bd, + 0xf64: 0x33dd, 0xf65: 0x33dd, 0xf66: 0x33fd, 0xf67: 0x341d, 0xf68: 0x343d, 0xf69: 0x345d, + 0xf6a: 0x347d, 0xf6b: 0x349d, 0xf6c: 0x34bd, 0xf6d: 0x34dd, 0xf6e: 0x34fd, 0xf6f: 0x351d, + 0xf70: 0x353d, 0xf71: 0x355d, 0xf72: 0x357d, 0xf73: 0x359d, 0xf74: 0x35bd, 0xf75: 0x35dd, + 0xf76: 0x35fd, 0xf77: 0x361d, 0xf78: 0x363d, 0xf79: 0x365d, 0xf7a: 0x367d, 0xf7b: 0x369d, + 0xf7c: 0x38c9, 0xf7d: 0x3901, 0xf7e: 0x36bd, 0xf7f: 0x0018, // Block 0x3e, offset 0xf80 - 0xf80: 0x3cc9, 0xf81: 0x3d31, 0xf82: 0x3d99, 0xf83: 0x3e01, 0xf84: 0x3e51, 0xf85: 0x3eb9, - 0xf86: 0x3f09, 0xf87: 0x3f59, 0xf88: 0x3fd9, 0xf89: 0x4041, 0xf8a: 0x4091, 0xf8b: 0x40e1, - 0xf8c: 0x4131, 0xf8d: 0x4199, 0xf8e: 0x4201, 0xf8f: 0x4251, 0xf90: 0x42a1, 0xf91: 0x42d9, - 0xf92: 0x4329, 0xf93: 0x4391, 0xf94: 0x43f9, 0xf95: 0x4431, 0xf96: 0x44b1, 0xf97: 0x4549, - 0xf98: 0x45c9, 0xf99: 0x4619, 0xf9a: 0x4699, 0xf9b: 0x4719, 0xf9c: 0x4781, 0xf9d: 0x47d1, - 0xf9e: 0x4821, 0xf9f: 0x4871, 0xfa0: 0x48d9, 0xfa1: 0x4959, 0xfa2: 0x49c1, 0xfa3: 0x4a11, - 0xfa4: 0x4a61, 0xfa5: 0x4ab1, 0xfa6: 0x4ae9, 0xfa7: 0x4b21, 0xfa8: 0x4b59, 0xfa9: 0x4b91, - 0xfaa: 0x4be1, 0xfab: 0x4c31, 0xfac: 0x4cb1, 0xfad: 0x4d01, 0xfae: 0x4d69, 0xfaf: 0x4de9, - 0xfb0: 0x4e39, 0xfb1: 0x4e71, 0xfb2: 0x4ea9, 0xfb3: 0x4f29, 0xfb4: 0x4f91, 0xfb5: 0x5011, - 0xfb6: 0x5061, 0xfb7: 0x50e1, 0xfb8: 0x5119, 0xfb9: 0x5169, 0xfba: 0x51b9, 0xfbb: 0x5209, - 0xfbc: 0x5259, 0xfbd: 0x52a9, 0xfbe: 0x5311, 0xfbf: 0x5361, + 0xf80: 0x36dd, 0xf81: 0x36fd, 0xf82: 0x371d, 0xf83: 0x373d, 0xf84: 0x375d, 0xf85: 0x377d, + 0xf86: 0x379d, 0xf87: 0x37bd, 0xf88: 0x37dd, 0xf89: 0x37fd, 0xf8a: 0x381d, 0xf8b: 0x383d, + 0xf8c: 0x385d, 0xf8d: 0x387d, 0xf8e: 0x389d, 0xf8f: 0x38bd, 0xf90: 0x38dd, 0xf91: 0x38fd, + 0xf92: 0x391d, 0xf93: 0x393d, 0xf94: 0x395d, 0xf95: 0x397d, 0xf96: 0x399d, 0xf97: 0x39bd, + 0xf98: 0x39dd, 0xf99: 0x39fd, 0xf9a: 0x3a1d, 0xf9b: 0x3a3d, 0xf9c: 0x3a5d, 0xf9d: 0x3a7d, + 0xf9e: 0x3a9d, 0xf9f: 0x3abd, 0xfa0: 0x3add, 0xfa1: 0x3afd, 0xfa2: 0x3b1d, 0xfa3: 0x3b3d, + 0xfa4: 0x3b5d, 0xfa5: 0x3b7d, 0xfa6: 0x127d, 0xfa7: 0x3b9d, 0xfa8: 0x3bbd, 0xfa9: 0x3bdd, + 0xfaa: 0x3bfd, 0xfab: 0x3c1d, 0xfac: 0x3c3d, 0xfad: 0x3c5d, 0xfae: 0x239d, 0xfaf: 0x3c7d, + 0xfb0: 0x3c9d, 0xfb1: 0x3939, 0xfb2: 0x3951, 0xfb3: 0x3969, 0xfb4: 0x3981, 0xfb5: 0x3999, + 0xfb6: 0x39b1, 0xfb7: 0x39c9, 0xfb8: 0x39e1, 0xfb9: 0x39f9, 0xfba: 0x3a11, 0xfbb: 0x3a29, + 0xfbc: 0x3a41, 0xfbd: 0x3a59, 0xfbe: 0x3a71, 0xfbf: 0x3a89, // Block 0x3f, offset 0xfc0 - 0xfc0: 0x5399, 0xfc1: 0x53e9, 0xfc2: 0x5439, 0xfc3: 0x5489, 0xfc4: 0x54f1, 0xfc5: 0x5541, - 0xfc6: 0x5591, 0xfc7: 0x55e1, 0xfc8: 0x5661, 0xfc9: 0x56c9, 0xfca: 0x5701, 0xfcb: 0x5781, - 0xfcc: 0x57b9, 0xfcd: 0x5821, 0xfce: 0x5889, 0xfcf: 0x58d9, 0xfd0: 0x5929, 0xfd1: 0x5979, - 0xfd2: 0x59e1, 0xfd3: 0x5a19, 0xfd4: 0x5a69, 0xfd5: 0x5ad1, 0xfd6: 0x5b09, 0xfd7: 0x5b89, - 0xfd8: 0x5bd9, 0xfd9: 0x5c01, 0xfda: 0x5c29, 0xfdb: 0x5c51, 0xfdc: 0x5c79, 0xfdd: 0x5ca1, - 0xfde: 0x5cc9, 0xfdf: 0x5cf1, 0xfe0: 0x5d19, 0xfe1: 0x5d41, 0xfe2: 0x5d69, 0xfe3: 0x5d99, - 0xfe4: 0x5dc9, 0xfe5: 0x5df9, 0xfe6: 0x5e29, 0xfe7: 0x5e59, 0xfe8: 0x5e89, 0xfe9: 0x5eb9, - 0xfea: 0x5ee9, 0xfeb: 0x5f19, 0xfec: 0x5f49, 0xfed: 0x5f79, 0xfee: 0x5fa9, 0xfef: 0x5fd9, - 0xff0: 0x6009, 0xff1: 0x402d, 0xff2: 0x6039, 0xff3: 0x6051, 0xff4: 0x404d, 0xff5: 0x6069, - 0xff6: 0x6081, 0xff7: 0x6099, 0xff8: 0x406d, 0xff9: 0x406d, 0xffa: 0x60b1, 0xffb: 0x60c9, - 0xffc: 0x6101, 0xffd: 0x6139, 0xffe: 0x6171, 0xfff: 0x61a9, + 0xfc0: 0x3aa1, 0xfc1: 0x3ac9, 0xfc2: 0x3af1, 0xfc3: 0x3b19, 0xfc4: 0x3b41, 0xfc5: 0x3b69, + 0xfc6: 0x3b91, 0xfc7: 0x3bb9, 0xfc8: 0x3be1, 0xfc9: 0x3c09, 0xfca: 0x3c39, 0xfcb: 0x3c69, + 0xfcc: 0x3c99, 0xfcd: 0x3cbd, 0xfce: 0x3cb1, 0xfcf: 0x3cdd, 0xfd0: 0x3cfd, 0xfd1: 0x3d15, + 0xfd2: 0x3d2d, 0xfd3: 0x3d45, 0xfd4: 0x3d5d, 0xfd5: 0x3d5d, 0xfd6: 0x3d45, 0xfd7: 0x3d75, + 0xfd8: 0x07bd, 0xfd9: 0x3d8d, 0xfda: 0x3da5, 0xfdb: 0x3dbd, 0xfdc: 0x3dd5, 0xfdd: 0x3ded, + 0xfde: 0x3e05, 0xfdf: 0x3e1d, 0xfe0: 0x3e35, 0xfe1: 0x3e4d, 0xfe2: 0x3e65, 0xfe3: 0x3e7d, + 0xfe4: 0x3e95, 0xfe5: 0x3e95, 0xfe6: 0x3ead, 0xfe7: 0x3ead, 0xfe8: 0x3ec5, 0xfe9: 0x3ec5, + 0xfea: 0x3edd, 0xfeb: 0x3ef5, 0xfec: 0x3f0d, 0xfed: 0x3f25, 0xfee: 0x3f3d, 0xfef: 0x3f3d, + 0xff0: 0x3f55, 0xff1: 0x3f55, 0xff2: 0x3f55, 0xff3: 0x3f6d, 0xff4: 0x3f85, 0xff5: 0x3f9d, + 0xff6: 0x3fb5, 0xff7: 0x3f9d, 0xff8: 0x3fcd, 0xff9: 0x3fe5, 0xffa: 0x3f6d, 0xffb: 0x3ffd, + 0xffc: 0x4015, 0xffd: 0x4015, 0xffe: 0x4015, 0xfff: 0x0040, // Block 0x40, offset 0x1000 - 0x1000: 0x6211, 0x1001: 0x6229, 0x1002: 0x408d, 0x1003: 0x6241, 0x1004: 0x6259, 0x1005: 0x6271, - 0x1006: 0x6289, 0x1007: 0x62a1, 0x1008: 0x40ad, 0x1009: 0x62b9, 0x100a: 0x62e1, 0x100b: 0x62f9, - 0x100c: 0x40cd, 0x100d: 0x40cd, 0x100e: 0x6311, 0x100f: 0x6329, 0x1010: 0x6341, 0x1011: 0x40ed, - 0x1012: 0x410d, 0x1013: 0x412d, 0x1014: 0x414d, 0x1015: 0x416d, 0x1016: 0x6359, 0x1017: 0x6371, - 0x1018: 0x6389, 0x1019: 0x63a1, 0x101a: 0x63b9, 0x101b: 0x418d, 0x101c: 0x63d1, 0x101d: 0x63e9, - 0x101e: 0x6401, 0x101f: 0x41ad, 0x1020: 0x41cd, 0x1021: 0x6419, 0x1022: 0x41ed, 0x1023: 0x420d, - 0x1024: 0x422d, 0x1025: 0x6431, 0x1026: 0x424d, 0x1027: 0x6449, 0x1028: 0x6479, 0x1029: 0x6211, - 0x102a: 0x426d, 0x102b: 0x428d, 0x102c: 0x42ad, 0x102d: 0x42cd, 0x102e: 0x64b1, 0x102f: 0x64f1, - 0x1030: 0x6539, 0x1031: 0x6551, 0x1032: 0x42ed, 0x1033: 0x6569, 0x1034: 0x6581, 0x1035: 0x6599, - 0x1036: 0x430d, 0x1037: 0x65b1, 0x1038: 0x65c9, 0x1039: 0x65b1, 0x103a: 0x65e1, 0x103b: 0x65f9, - 0x103c: 0x432d, 0x103d: 0x6611, 0x103e: 0x6629, 0x103f: 0x6611, + 0x1000: 0x3cc9, 0x1001: 0x3d31, 0x1002: 0x3d99, 0x1003: 0x3e01, 0x1004: 0x3e51, 0x1005: 0x3eb9, + 0x1006: 0x3f09, 0x1007: 0x3f59, 0x1008: 0x3fd9, 0x1009: 0x4041, 0x100a: 0x4091, 0x100b: 0x40e1, + 0x100c: 0x4131, 0x100d: 0x4199, 0x100e: 0x4201, 0x100f: 0x4251, 0x1010: 0x42a1, 0x1011: 0x42d9, + 0x1012: 0x4329, 0x1013: 0x4391, 0x1014: 0x43f9, 0x1015: 0x4431, 0x1016: 0x44b1, 0x1017: 0x4549, + 0x1018: 0x45c9, 0x1019: 0x4619, 0x101a: 0x4699, 0x101b: 0x4719, 0x101c: 0x4781, 0x101d: 0x47d1, + 0x101e: 0x4821, 0x101f: 0x4871, 0x1020: 0x48d9, 0x1021: 0x4959, 0x1022: 0x49c1, 0x1023: 0x4a11, + 0x1024: 0x4a61, 0x1025: 0x4ab1, 0x1026: 0x4ae9, 0x1027: 0x4b21, 0x1028: 0x4b59, 0x1029: 0x4b91, + 0x102a: 0x4be1, 0x102b: 0x4c31, 0x102c: 0x4cb1, 0x102d: 0x4d01, 0x102e: 0x4d69, 0x102f: 0x4de9, + 0x1030: 0x4e39, 0x1031: 0x4e71, 0x1032: 0x4ea9, 0x1033: 0x4f29, 0x1034: 0x4f91, 0x1035: 0x5011, + 0x1036: 0x5061, 0x1037: 0x50e1, 0x1038: 0x5119, 0x1039: 0x5169, 0x103a: 0x51b9, 0x103b: 0x5209, + 0x103c: 0x5259, 0x103d: 0x52a9, 0x103e: 0x5311, 0x103f: 0x5361, // Block 0x41, offset 0x1040 - 0x1040: 0x434d, 0x1041: 0x436d, 0x1042: 0x0040, 0x1043: 0x6641, 0x1044: 0x6659, 0x1045: 0x6671, - 0x1046: 0x6689, 0x1047: 0x0040, 0x1048: 0x66c1, 0x1049: 0x66d9, 0x104a: 0x66f1, 0x104b: 0x6709, - 0x104c: 0x6721, 0x104d: 0x6739, 0x104e: 0x6401, 0x104f: 0x6751, 0x1050: 0x6769, 0x1051: 0x6781, - 0x1052: 0x438d, 0x1053: 0x6799, 0x1054: 0x6289, 0x1055: 0x43ad, 0x1056: 0x43cd, 0x1057: 0x67b1, - 0x1058: 0x0040, 0x1059: 0x43ed, 0x105a: 0x67c9, 0x105b: 0x67e1, 0x105c: 0x67f9, 0x105d: 0x6811, - 0x105e: 0x6829, 0x105f: 0x6859, 0x1060: 0x6889, 0x1061: 0x68b1, 0x1062: 0x68d9, 0x1063: 0x6901, - 0x1064: 0x6929, 0x1065: 0x6951, 0x1066: 0x6979, 0x1067: 0x69a1, 0x1068: 0x69c9, 0x1069: 0x69f1, - 0x106a: 0x6a21, 0x106b: 0x6a51, 0x106c: 0x6a81, 0x106d: 0x6ab1, 0x106e: 0x6ae1, 0x106f: 0x6b11, - 0x1070: 0x6b41, 0x1071: 0x6b71, 0x1072: 0x6ba1, 0x1073: 0x6bd1, 0x1074: 0x6c01, 0x1075: 0x6c31, - 0x1076: 0x6c61, 0x1077: 0x6c91, 0x1078: 0x6cc1, 0x1079: 0x6cf1, 0x107a: 0x6d21, 0x107b: 0x6d51, - 0x107c: 0x6d81, 0x107d: 0x6db1, 0x107e: 0x6de1, 0x107f: 0x440d, + 0x1040: 0x5399, 0x1041: 0x53e9, 0x1042: 0x5439, 0x1043: 0x5489, 0x1044: 0x54f1, 0x1045: 0x5541, + 0x1046: 0x5591, 0x1047: 0x55e1, 0x1048: 0x5661, 0x1049: 0x56c9, 0x104a: 0x5701, 0x104b: 0x5781, + 0x104c: 0x57b9, 0x104d: 0x5821, 0x104e: 0x5889, 0x104f: 0x58d9, 0x1050: 0x5929, 0x1051: 0x5979, + 0x1052: 0x59e1, 0x1053: 0x5a19, 0x1054: 0x5a69, 0x1055: 0x5ad1, 0x1056: 0x5b09, 0x1057: 0x5b89, + 0x1058: 0x5bd9, 0x1059: 0x5c01, 0x105a: 0x5c29, 0x105b: 0x5c51, 0x105c: 0x5c79, 0x105d: 0x5ca1, + 0x105e: 0x5cc9, 0x105f: 0x5cf1, 0x1060: 0x5d19, 0x1061: 0x5d41, 0x1062: 0x5d69, 0x1063: 0x5d99, + 0x1064: 0x5dc9, 0x1065: 0x5df9, 0x1066: 0x5e29, 0x1067: 0x5e59, 0x1068: 0x5e89, 0x1069: 0x5eb9, + 0x106a: 0x5ee9, 0x106b: 0x5f19, 0x106c: 0x5f49, 0x106d: 0x5f79, 0x106e: 0x5fa9, 0x106f: 0x5fd9, + 0x1070: 0x6009, 0x1071: 0x402d, 0x1072: 0x6039, 0x1073: 0x6051, 0x1074: 0x404d, 0x1075: 0x6069, + 0x1076: 0x6081, 0x1077: 0x6099, 0x1078: 0x406d, 0x1079: 0x406d, 0x107a: 0x60b1, 0x107b: 0x60c9, + 0x107c: 0x6101, 0x107d: 0x6139, 0x107e: 0x6171, 0x107f: 0x61a9, // Block 0x42, offset 0x1080 - 0x1080: 0xe00d, 0x1081: 0x0008, 0x1082: 0xe00d, 0x1083: 0x0008, 0x1084: 0xe00d, 0x1085: 0x0008, - 0x1086: 0xe00d, 0x1087: 0x0008, 0x1088: 0xe00d, 0x1089: 0x0008, 0x108a: 0xe00d, 0x108b: 0x0008, - 0x108c: 0xe00d, 0x108d: 0x0008, 0x108e: 0xe00d, 0x108f: 0x0008, 0x1090: 0xe00d, 0x1091: 0x0008, - 0x1092: 0xe00d, 0x1093: 0x0008, 0x1094: 0xe00d, 0x1095: 0x0008, 0x1096: 0xe00d, 0x1097: 0x0008, - 0x1098: 0xe00d, 0x1099: 0x0008, 0x109a: 0xe00d, 0x109b: 0x0008, 0x109c: 0xe00d, 0x109d: 0x0008, - 0x109e: 0xe00d, 0x109f: 0x0008, 0x10a0: 0xe00d, 0x10a1: 0x0008, 0x10a2: 0xe00d, 0x10a3: 0x0008, - 0x10a4: 0xe00d, 0x10a5: 0x0008, 0x10a6: 0xe00d, 0x10a7: 0x0008, 0x10a8: 0xe00d, 0x10a9: 0x0008, - 0x10aa: 0xe00d, 0x10ab: 0x0008, 0x10ac: 0xe00d, 0x10ad: 0x0008, 0x10ae: 0x0008, 0x10af: 0x1308, - 0x10b0: 0x1318, 0x10b1: 0x1318, 0x10b2: 0x1318, 0x10b3: 0x0018, 0x10b4: 0x1308, 0x10b5: 0x1308, - 0x10b6: 0x1308, 0x10b7: 0x1308, 0x10b8: 0x1308, 0x10b9: 0x1308, 0x10ba: 0x1308, 0x10bb: 0x1308, - 0x10bc: 0x1308, 0x10bd: 0x1308, 0x10be: 0x0018, 0x10bf: 0x0008, + 0x1080: 0x6211, 0x1081: 0x6229, 0x1082: 0x408d, 0x1083: 0x6241, 0x1084: 0x6259, 0x1085: 0x6271, + 0x1086: 0x6289, 0x1087: 0x62a1, 0x1088: 0x40ad, 0x1089: 0x62b9, 0x108a: 0x62e1, 0x108b: 0x62f9, + 0x108c: 0x40cd, 0x108d: 0x40cd, 0x108e: 0x6311, 0x108f: 0x6329, 0x1090: 0x6341, 0x1091: 0x40ed, + 0x1092: 0x410d, 0x1093: 0x412d, 0x1094: 0x414d, 0x1095: 0x416d, 0x1096: 0x6359, 0x1097: 0x6371, + 0x1098: 0x6389, 0x1099: 0x63a1, 0x109a: 0x63b9, 0x109b: 0x418d, 0x109c: 0x63d1, 0x109d: 0x63e9, + 0x109e: 0x6401, 0x109f: 0x41ad, 0x10a0: 0x41cd, 0x10a1: 0x6419, 0x10a2: 0x41ed, 0x10a3: 0x420d, + 0x10a4: 0x422d, 0x10a5: 0x6431, 0x10a6: 0x424d, 0x10a7: 0x6449, 0x10a8: 0x6479, 0x10a9: 0x6211, + 0x10aa: 0x426d, 0x10ab: 0x428d, 0x10ac: 0x42ad, 0x10ad: 0x42cd, 0x10ae: 0x64b1, 0x10af: 0x64f1, + 0x10b0: 0x6539, 0x10b1: 0x6551, 0x10b2: 0x42ed, 0x10b3: 0x6569, 0x10b4: 0x6581, 0x10b5: 0x6599, + 0x10b6: 0x430d, 0x10b7: 0x65b1, 0x10b8: 0x65c9, 0x10b9: 0x65b1, 0x10ba: 0x65e1, 0x10bb: 0x65f9, + 0x10bc: 0x432d, 0x10bd: 0x6611, 0x10be: 0x6629, 0x10bf: 0x6611, // Block 0x43, offset 0x10c0 - 0x10c0: 0xe00d, 0x10c1: 0x0008, 0x10c2: 0xe00d, 0x10c3: 0x0008, 0x10c4: 0xe00d, 0x10c5: 0x0008, - 0x10c6: 0xe00d, 0x10c7: 0x0008, 0x10c8: 0xe00d, 0x10c9: 0x0008, 0x10ca: 0xe00d, 0x10cb: 0x0008, - 0x10cc: 0xe00d, 0x10cd: 0x0008, 0x10ce: 0xe00d, 0x10cf: 0x0008, 0x10d0: 0xe00d, 0x10d1: 0x0008, - 0x10d2: 0xe00d, 0x10d3: 0x0008, 0x10d4: 0xe00d, 0x10d5: 0x0008, 0x10d6: 0xe00d, 0x10d7: 0x0008, - 0x10d8: 0xe00d, 0x10d9: 0x0008, 0x10da: 0xe00d, 0x10db: 0x0008, 0x10dc: 0x0ea1, 0x10dd: 0x6e11, - 0x10de: 0x1308, 0x10df: 0x1308, 0x10e0: 0x0008, 0x10e1: 0x0008, 0x10e2: 0x0008, 0x10e3: 0x0008, - 0x10e4: 0x0008, 0x10e5: 0x0008, 0x10e6: 0x0008, 0x10e7: 0x0008, 0x10e8: 0x0008, 0x10e9: 0x0008, - 0x10ea: 0x0008, 0x10eb: 0x0008, 0x10ec: 0x0008, 0x10ed: 0x0008, 0x10ee: 0x0008, 0x10ef: 0x0008, - 0x10f0: 0x0008, 0x10f1: 0x0008, 0x10f2: 0x0008, 0x10f3: 0x0008, 0x10f4: 0x0008, 0x10f5: 0x0008, - 0x10f6: 0x0008, 0x10f7: 0x0008, 0x10f8: 0x0008, 0x10f9: 0x0008, 0x10fa: 0x0008, 0x10fb: 0x0008, - 0x10fc: 0x0008, 0x10fd: 0x0008, 0x10fe: 0x0008, 0x10ff: 0x0008, + 0x10c0: 0x434d, 0x10c1: 0x436d, 0x10c2: 0x0040, 0x10c3: 0x6641, 0x10c4: 0x6659, 0x10c5: 0x6671, + 0x10c6: 0x6689, 0x10c7: 0x0040, 0x10c8: 0x66c1, 0x10c9: 0x66d9, 0x10ca: 0x66f1, 0x10cb: 0x6709, + 0x10cc: 0x6721, 0x10cd: 0x6739, 0x10ce: 0x6401, 0x10cf: 0x6751, 0x10d0: 0x6769, 0x10d1: 0x6781, + 0x10d2: 0x438d, 0x10d3: 0x6799, 0x10d4: 0x6289, 0x10d5: 0x43ad, 0x10d6: 0x43cd, 0x10d7: 0x67b1, + 0x10d8: 0x0040, 0x10d9: 0x43ed, 0x10da: 0x67c9, 0x10db: 0x67e1, 0x10dc: 0x67f9, 0x10dd: 0x6811, + 0x10de: 0x6829, 0x10df: 0x6859, 0x10e0: 0x6889, 0x10e1: 0x68b1, 0x10e2: 0x68d9, 0x10e3: 0x6901, + 0x10e4: 0x6929, 0x10e5: 0x6951, 0x10e6: 0x6979, 0x10e7: 0x69a1, 0x10e8: 0x69c9, 0x10e9: 0x69f1, + 0x10ea: 0x6a21, 0x10eb: 0x6a51, 0x10ec: 0x6a81, 0x10ed: 0x6ab1, 0x10ee: 0x6ae1, 0x10ef: 0x6b11, + 0x10f0: 0x6b41, 0x10f1: 0x6b71, 0x10f2: 0x6ba1, 0x10f3: 0x6bd1, 0x10f4: 0x6c01, 0x10f5: 0x6c31, + 0x10f6: 0x6c61, 0x10f7: 0x6c91, 0x10f8: 0x6cc1, 0x10f9: 0x6cf1, 0x10fa: 0x6d21, 0x10fb: 0x6d51, + 0x10fc: 0x6d81, 0x10fd: 0x6db1, 0x10fe: 0x6de1, 0x10ff: 0x440d, // Block 0x44, offset 0x1100 - 0x1100: 0x0018, 0x1101: 0x0018, 0x1102: 0x0018, 0x1103: 0x0018, 0x1104: 0x0018, 0x1105: 0x0018, - 0x1106: 0x0018, 0x1107: 0x0018, 0x1108: 0x0018, 0x1109: 0x0018, 0x110a: 0x0018, 0x110b: 0x0018, - 0x110c: 0x0018, 0x110d: 0x0018, 0x110e: 0x0018, 0x110f: 0x0018, 0x1110: 0x0018, 0x1111: 0x0018, - 0x1112: 0x0018, 0x1113: 0x0018, 0x1114: 0x0018, 0x1115: 0x0018, 0x1116: 0x0018, 0x1117: 0x0008, - 0x1118: 0x0008, 0x1119: 0x0008, 0x111a: 0x0008, 0x111b: 0x0008, 0x111c: 0x0008, 0x111d: 0x0008, - 0x111e: 0x0008, 0x111f: 0x0008, 0x1120: 0x0018, 0x1121: 0x0018, 0x1122: 0xe00d, 0x1123: 0x0008, + 0x1100: 0xe00d, 0x1101: 0x0008, 0x1102: 0xe00d, 0x1103: 0x0008, 0x1104: 0xe00d, 0x1105: 0x0008, + 0x1106: 0xe00d, 0x1107: 0x0008, 0x1108: 0xe00d, 0x1109: 0x0008, 0x110a: 0xe00d, 0x110b: 0x0008, + 0x110c: 0xe00d, 0x110d: 0x0008, 0x110e: 0xe00d, 0x110f: 0x0008, 0x1110: 0xe00d, 0x1111: 0x0008, + 0x1112: 0xe00d, 0x1113: 0x0008, 0x1114: 0xe00d, 0x1115: 0x0008, 0x1116: 0xe00d, 0x1117: 0x0008, + 0x1118: 0xe00d, 0x1119: 0x0008, 0x111a: 0xe00d, 0x111b: 0x0008, 0x111c: 0xe00d, 0x111d: 0x0008, + 0x111e: 0xe00d, 0x111f: 0x0008, 0x1120: 0xe00d, 0x1121: 0x0008, 0x1122: 0xe00d, 0x1123: 0x0008, 0x1124: 0xe00d, 0x1125: 0x0008, 0x1126: 0xe00d, 0x1127: 0x0008, 0x1128: 0xe00d, 0x1129: 0x0008, - 0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0xe00d, 0x112f: 0x0008, - 0x1130: 0x0008, 0x1131: 0x0008, 0x1132: 0xe00d, 0x1133: 0x0008, 0x1134: 0xe00d, 0x1135: 0x0008, - 0x1136: 0xe00d, 0x1137: 0x0008, 0x1138: 0xe00d, 0x1139: 0x0008, 0x113a: 0xe00d, 0x113b: 0x0008, - 0x113c: 0xe00d, 0x113d: 0x0008, 0x113e: 0xe00d, 0x113f: 0x0008, + 0x112a: 0xe00d, 0x112b: 0x0008, 0x112c: 0xe00d, 0x112d: 0x0008, 0x112e: 0x0008, 0x112f: 0x3308, + 0x1130: 0x3318, 0x1131: 0x3318, 0x1132: 0x3318, 0x1133: 0x0018, 0x1134: 0x3308, 0x1135: 0x3308, + 0x1136: 0x3308, 0x1137: 0x3308, 0x1138: 0x3308, 0x1139: 0x3308, 0x113a: 0x3308, 0x113b: 0x3308, + 0x113c: 0x3308, 0x113d: 0x3308, 0x113e: 0x0018, 0x113f: 0x0008, // Block 0x45, offset 0x1140 0x1140: 0xe00d, 0x1141: 0x0008, 0x1142: 0xe00d, 0x1143: 0x0008, 0x1144: 0xe00d, 0x1145: 0x0008, 0x1146: 0xe00d, 0x1147: 0x0008, 0x1148: 0xe00d, 0x1149: 0x0008, 0x114a: 0xe00d, 0x114b: 0x0008, 0x114c: 0xe00d, 0x114d: 0x0008, 0x114e: 0xe00d, 0x114f: 0x0008, 0x1150: 0xe00d, 0x1151: 0x0008, 0x1152: 0xe00d, 0x1153: 0x0008, 0x1154: 0xe00d, 0x1155: 0x0008, 0x1156: 0xe00d, 0x1157: 0x0008, - 0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0xe00d, 0x115d: 0x0008, - 0x115e: 0xe00d, 0x115f: 0x0008, 0x1160: 0xe00d, 0x1161: 0x0008, 0x1162: 0xe00d, 0x1163: 0x0008, - 0x1164: 0xe00d, 0x1165: 0x0008, 0x1166: 0xe00d, 0x1167: 0x0008, 0x1168: 0xe00d, 0x1169: 0x0008, - 0x116a: 0xe00d, 0x116b: 0x0008, 0x116c: 0xe00d, 0x116d: 0x0008, 0x116e: 0xe00d, 0x116f: 0x0008, - 0x1170: 0xe0fd, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008, - 0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0xe01d, 0x117a: 0x0008, 0x117b: 0xe03d, - 0x117c: 0x0008, 0x117d: 0x442d, 0x117e: 0xe00d, 0x117f: 0x0008, + 0x1158: 0xe00d, 0x1159: 0x0008, 0x115a: 0xe00d, 0x115b: 0x0008, 0x115c: 0x0ea1, 0x115d: 0x6e11, + 0x115e: 0x3308, 0x115f: 0x3308, 0x1160: 0x0008, 0x1161: 0x0008, 0x1162: 0x0008, 0x1163: 0x0008, + 0x1164: 0x0008, 0x1165: 0x0008, 0x1166: 0x0008, 0x1167: 0x0008, 0x1168: 0x0008, 0x1169: 0x0008, + 0x116a: 0x0008, 0x116b: 0x0008, 0x116c: 0x0008, 0x116d: 0x0008, 0x116e: 0x0008, 0x116f: 0x0008, + 0x1170: 0x0008, 0x1171: 0x0008, 0x1172: 0x0008, 0x1173: 0x0008, 0x1174: 0x0008, 0x1175: 0x0008, + 0x1176: 0x0008, 0x1177: 0x0008, 0x1178: 0x0008, 0x1179: 0x0008, 0x117a: 0x0008, 0x117b: 0x0008, + 0x117c: 0x0008, 0x117d: 0x0008, 0x117e: 0x0008, 0x117f: 0x0008, // Block 0x46, offset 0x1180 - 0x1180: 0xe00d, 0x1181: 0x0008, 0x1182: 0xe00d, 0x1183: 0x0008, 0x1184: 0xe00d, 0x1185: 0x0008, - 0x1186: 0xe00d, 0x1187: 0x0008, 0x1188: 0x0008, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0xe03d, - 0x118c: 0x0008, 0x118d: 0x11d9, 0x118e: 0x0008, 0x118f: 0x0008, 0x1190: 0xe00d, 0x1191: 0x0008, - 0x1192: 0xe00d, 0x1193: 0x0008, 0x1194: 0x0008, 0x1195: 0x0008, 0x1196: 0xe00d, 0x1197: 0x0008, - 0x1198: 0xe00d, 0x1199: 0x0008, 0x119a: 0xe00d, 0x119b: 0x0008, 0x119c: 0xe00d, 0x119d: 0x0008, - 0x119e: 0xe00d, 0x119f: 0x0008, 0x11a0: 0xe00d, 0x11a1: 0x0008, 0x11a2: 0xe00d, 0x11a3: 0x0008, + 0x1180: 0x0018, 0x1181: 0x0018, 0x1182: 0x0018, 0x1183: 0x0018, 0x1184: 0x0018, 0x1185: 0x0018, + 0x1186: 0x0018, 0x1187: 0x0018, 0x1188: 0x0018, 0x1189: 0x0018, 0x118a: 0x0018, 0x118b: 0x0018, + 0x118c: 0x0018, 0x118d: 0x0018, 0x118e: 0x0018, 0x118f: 0x0018, 0x1190: 0x0018, 0x1191: 0x0018, + 0x1192: 0x0018, 0x1193: 0x0018, 0x1194: 0x0018, 0x1195: 0x0018, 0x1196: 0x0018, 0x1197: 0x0008, + 0x1198: 0x0008, 0x1199: 0x0008, 0x119a: 0x0008, 0x119b: 0x0008, 0x119c: 0x0008, 0x119d: 0x0008, + 0x119e: 0x0008, 0x119f: 0x0008, 0x11a0: 0x0018, 0x11a1: 0x0018, 0x11a2: 0xe00d, 0x11a3: 0x0008, 0x11a4: 0xe00d, 0x11a5: 0x0008, 0x11a6: 0xe00d, 0x11a7: 0x0008, 0x11a8: 0xe00d, 0x11a9: 0x0008, - 0x11aa: 0x6e29, 0x11ab: 0x1029, 0x11ac: 0x11c1, 0x11ad: 0x6e41, 0x11ae: 0x1221, 0x11af: 0x0040, - 0x11b0: 0x6e59, 0x11b1: 0x6e71, 0x11b2: 0x1239, 0x11b3: 0x444d, 0x11b4: 0xe00d, 0x11b5: 0x0008, - 0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0x0040, 0x11b9: 0x0040, 0x11ba: 0x0040, 0x11bb: 0x0040, - 0x11bc: 0x0040, 0x11bd: 0x0040, 0x11be: 0x0040, 0x11bf: 0x0040, + 0x11aa: 0xe00d, 0x11ab: 0x0008, 0x11ac: 0xe00d, 0x11ad: 0x0008, 0x11ae: 0xe00d, 0x11af: 0x0008, + 0x11b0: 0x0008, 0x11b1: 0x0008, 0x11b2: 0xe00d, 0x11b3: 0x0008, 0x11b4: 0xe00d, 0x11b5: 0x0008, + 0x11b6: 0xe00d, 0x11b7: 0x0008, 0x11b8: 0xe00d, 0x11b9: 0x0008, 0x11ba: 0xe00d, 0x11bb: 0x0008, + 0x11bc: 0xe00d, 0x11bd: 0x0008, 0x11be: 0xe00d, 0x11bf: 0x0008, // Block 0x47, offset 0x11c0 - 0x11c0: 0x64d5, 0x11c1: 0x64f5, 0x11c2: 0x6515, 0x11c3: 0x6535, 0x11c4: 0x6555, 0x11c5: 0x6575, - 0x11c6: 0x6595, 0x11c7: 0x65b5, 0x11c8: 0x65d5, 0x11c9: 0x65f5, 0x11ca: 0x6615, 0x11cb: 0x6635, - 0x11cc: 0x6655, 0x11cd: 0x6675, 0x11ce: 0x0008, 0x11cf: 0x0008, 0x11d0: 0x6695, 0x11d1: 0x0008, - 0x11d2: 0x66b5, 0x11d3: 0x0008, 0x11d4: 0x0008, 0x11d5: 0x66d5, 0x11d6: 0x66f5, 0x11d7: 0x6715, - 0x11d8: 0x6735, 0x11d9: 0x6755, 0x11da: 0x6775, 0x11db: 0x6795, 0x11dc: 0x67b5, 0x11dd: 0x67d5, - 0x11de: 0x67f5, 0x11df: 0x0008, 0x11e0: 0x6815, 0x11e1: 0x0008, 0x11e2: 0x6835, 0x11e3: 0x0008, - 0x11e4: 0x0008, 0x11e5: 0x6855, 0x11e6: 0x6875, 0x11e7: 0x0008, 0x11e8: 0x0008, 0x11e9: 0x0008, - 0x11ea: 0x6895, 0x11eb: 0x68b5, 0x11ec: 0x68d5, 0x11ed: 0x68f5, 0x11ee: 0x6915, 0x11ef: 0x6935, - 0x11f0: 0x6955, 0x11f1: 0x6975, 0x11f2: 0x6995, 0x11f3: 0x69b5, 0x11f4: 0x69d5, 0x11f5: 0x69f5, - 0x11f6: 0x6a15, 0x11f7: 0x6a35, 0x11f8: 0x6a55, 0x11f9: 0x6a75, 0x11fa: 0x6a95, 0x11fb: 0x6ab5, - 0x11fc: 0x6ad5, 0x11fd: 0x6af5, 0x11fe: 0x6b15, 0x11ff: 0x6b35, + 0x11c0: 0xe00d, 0x11c1: 0x0008, 0x11c2: 0xe00d, 0x11c3: 0x0008, 0x11c4: 0xe00d, 0x11c5: 0x0008, + 0x11c6: 0xe00d, 0x11c7: 0x0008, 0x11c8: 0xe00d, 0x11c9: 0x0008, 0x11ca: 0xe00d, 0x11cb: 0x0008, + 0x11cc: 0xe00d, 0x11cd: 0x0008, 0x11ce: 0xe00d, 0x11cf: 0x0008, 0x11d0: 0xe00d, 0x11d1: 0x0008, + 0x11d2: 0xe00d, 0x11d3: 0x0008, 0x11d4: 0xe00d, 0x11d5: 0x0008, 0x11d6: 0xe00d, 0x11d7: 0x0008, + 0x11d8: 0xe00d, 0x11d9: 0x0008, 0x11da: 0xe00d, 0x11db: 0x0008, 0x11dc: 0xe00d, 0x11dd: 0x0008, + 0x11de: 0xe00d, 0x11df: 0x0008, 0x11e0: 0xe00d, 0x11e1: 0x0008, 0x11e2: 0xe00d, 0x11e3: 0x0008, + 0x11e4: 0xe00d, 0x11e5: 0x0008, 0x11e6: 0xe00d, 0x11e7: 0x0008, 0x11e8: 0xe00d, 0x11e9: 0x0008, + 0x11ea: 0xe00d, 0x11eb: 0x0008, 0x11ec: 0xe00d, 0x11ed: 0x0008, 0x11ee: 0xe00d, 0x11ef: 0x0008, + 0x11f0: 0xe0fd, 0x11f1: 0x0008, 0x11f2: 0x0008, 0x11f3: 0x0008, 0x11f4: 0x0008, 0x11f5: 0x0008, + 0x11f6: 0x0008, 0x11f7: 0x0008, 0x11f8: 0x0008, 0x11f9: 0xe01d, 0x11fa: 0x0008, 0x11fb: 0xe03d, + 0x11fc: 0x0008, 0x11fd: 0x442d, 0x11fe: 0xe00d, 0x11ff: 0x0008, // Block 0x48, offset 0x1200 - 0x1200: 0x7a95, 0x1201: 0x7ab5, 0x1202: 0x7ad5, 0x1203: 0x7af5, 0x1204: 0x7b15, 0x1205: 0x7b35, - 0x1206: 0x7b55, 0x1207: 0x7b75, 0x1208: 0x7b95, 0x1209: 0x7bb5, 0x120a: 0x7bd5, 0x120b: 0x7bf5, - 0x120c: 0x7c15, 0x120d: 0x7c35, 0x120e: 0x7c55, 0x120f: 0x6ec9, 0x1210: 0x6ef1, 0x1211: 0x6f19, - 0x1212: 0x7c75, 0x1213: 0x7c95, 0x1214: 0x7cb5, 0x1215: 0x6f41, 0x1216: 0x6f69, 0x1217: 0x6f91, - 0x1218: 0x7cd5, 0x1219: 0x7cf5, 0x121a: 0x0040, 0x121b: 0x0040, 0x121c: 0x0040, 0x121d: 0x0040, - 0x121e: 0x0040, 0x121f: 0x0040, 0x1220: 0x0040, 0x1221: 0x0040, 0x1222: 0x0040, 0x1223: 0x0040, - 0x1224: 0x0040, 0x1225: 0x0040, 0x1226: 0x0040, 0x1227: 0x0040, 0x1228: 0x0040, 0x1229: 0x0040, - 0x122a: 0x0040, 0x122b: 0x0040, 0x122c: 0x0040, 0x122d: 0x0040, 0x122e: 0x0040, 0x122f: 0x0040, - 0x1230: 0x0040, 0x1231: 0x0040, 0x1232: 0x0040, 0x1233: 0x0040, 0x1234: 0x0040, 0x1235: 0x0040, - 0x1236: 0x0040, 0x1237: 0x0040, 0x1238: 0x0040, 0x1239: 0x0040, 0x123a: 0x0040, 0x123b: 0x0040, + 0x1200: 0xe00d, 0x1201: 0x0008, 0x1202: 0xe00d, 0x1203: 0x0008, 0x1204: 0xe00d, 0x1205: 0x0008, + 0x1206: 0xe00d, 0x1207: 0x0008, 0x1208: 0x0008, 0x1209: 0x0018, 0x120a: 0x0018, 0x120b: 0xe03d, + 0x120c: 0x0008, 0x120d: 0x11d9, 0x120e: 0x0008, 0x120f: 0x0008, 0x1210: 0xe00d, 0x1211: 0x0008, + 0x1212: 0xe00d, 0x1213: 0x0008, 0x1214: 0x0008, 0x1215: 0x0008, 0x1216: 0xe00d, 0x1217: 0x0008, + 0x1218: 0xe00d, 0x1219: 0x0008, 0x121a: 0xe00d, 0x121b: 0x0008, 0x121c: 0xe00d, 0x121d: 0x0008, + 0x121e: 0xe00d, 0x121f: 0x0008, 0x1220: 0xe00d, 0x1221: 0x0008, 0x1222: 0xe00d, 0x1223: 0x0008, + 0x1224: 0xe00d, 0x1225: 0x0008, 0x1226: 0xe00d, 0x1227: 0x0008, 0x1228: 0xe00d, 0x1229: 0x0008, + 0x122a: 0x6e29, 0x122b: 0x1029, 0x122c: 0x11c1, 0x122d: 0x6e41, 0x122e: 0x1221, 0x122f: 0x0040, + 0x1230: 0x6e59, 0x1231: 0x6e71, 0x1232: 0x1239, 0x1233: 0x444d, 0x1234: 0xe00d, 0x1235: 0x0008, + 0x1236: 0xe00d, 0x1237: 0x0008, 0x1238: 0x0040, 0x1239: 0x0040, 0x123a: 0x0040, 0x123b: 0x0040, 0x123c: 0x0040, 0x123d: 0x0040, 0x123e: 0x0040, 0x123f: 0x0040, // Block 0x49, offset 0x1240 - 0x1240: 0x6fb9, 0x1241: 0x6fd1, 0x1242: 0x6fe9, 0x1243: 0x7d15, 0x1244: 0x7d35, 0x1245: 0x7001, - 0x1246: 0x7001, 0x1247: 0x0040, 0x1248: 0x0040, 0x1249: 0x0040, 0x124a: 0x0040, 0x124b: 0x0040, - 0x124c: 0x0040, 0x124d: 0x0040, 0x124e: 0x0040, 0x124f: 0x0040, 0x1250: 0x0040, 0x1251: 0x0040, - 0x1252: 0x0040, 0x1253: 0x7019, 0x1254: 0x7041, 0x1255: 0x7069, 0x1256: 0x7091, 0x1257: 0x70b9, - 0x1258: 0x0040, 0x1259: 0x0040, 0x125a: 0x0040, 0x125b: 0x0040, 0x125c: 0x0040, 0x125d: 0x70e1, - 0x125e: 0x1308, 0x125f: 0x7109, 0x1260: 0x7131, 0x1261: 0x20a9, 0x1262: 0x20f1, 0x1263: 0x7149, - 0x1264: 0x7161, 0x1265: 0x7179, 0x1266: 0x7191, 0x1267: 0x71a9, 0x1268: 0x71c1, 0x1269: 0x1fb2, - 0x126a: 0x71d9, 0x126b: 0x7201, 0x126c: 0x7229, 0x126d: 0x7261, 0x126e: 0x7299, 0x126f: 0x72c1, - 0x1270: 0x72e9, 0x1271: 0x7311, 0x1272: 0x7339, 0x1273: 0x7361, 0x1274: 0x7389, 0x1275: 0x73b1, - 0x1276: 0x73d9, 0x1277: 0x0040, 0x1278: 0x7401, 0x1279: 0x7429, 0x127a: 0x7451, 0x127b: 0x7479, - 0x127c: 0x74a1, 0x127d: 0x0040, 0x127e: 0x74c9, 0x127f: 0x0040, + 0x1240: 0x64d5, 0x1241: 0x64f5, 0x1242: 0x6515, 0x1243: 0x6535, 0x1244: 0x6555, 0x1245: 0x6575, + 0x1246: 0x6595, 0x1247: 0x65b5, 0x1248: 0x65d5, 0x1249: 0x65f5, 0x124a: 0x6615, 0x124b: 0x6635, + 0x124c: 0x6655, 0x124d: 0x6675, 0x124e: 0x0008, 0x124f: 0x0008, 0x1250: 0x6695, 0x1251: 0x0008, + 0x1252: 0x66b5, 0x1253: 0x0008, 0x1254: 0x0008, 0x1255: 0x66d5, 0x1256: 0x66f5, 0x1257: 0x6715, + 0x1258: 0x6735, 0x1259: 0x6755, 0x125a: 0x6775, 0x125b: 0x6795, 0x125c: 0x67b5, 0x125d: 0x67d5, + 0x125e: 0x67f5, 0x125f: 0x0008, 0x1260: 0x6815, 0x1261: 0x0008, 0x1262: 0x6835, 0x1263: 0x0008, + 0x1264: 0x0008, 0x1265: 0x6855, 0x1266: 0x6875, 0x1267: 0x0008, 0x1268: 0x0008, 0x1269: 0x0008, + 0x126a: 0x6895, 0x126b: 0x68b5, 0x126c: 0x68d5, 0x126d: 0x68f5, 0x126e: 0x6915, 0x126f: 0x6935, + 0x1270: 0x6955, 0x1271: 0x6975, 0x1272: 0x6995, 0x1273: 0x69b5, 0x1274: 0x69d5, 0x1275: 0x69f5, + 0x1276: 0x6a15, 0x1277: 0x6a35, 0x1278: 0x6a55, 0x1279: 0x6a75, 0x127a: 0x6a95, 0x127b: 0x6ab5, + 0x127c: 0x6ad5, 0x127d: 0x6af5, 0x127e: 0x6b15, 0x127f: 0x6b35, // Block 0x4a, offset 0x1280 - 0x1280: 0x74f1, 0x1281: 0x7519, 0x1282: 0x0040, 0x1283: 0x7541, 0x1284: 0x7569, 0x1285: 0x0040, - 0x1286: 0x7591, 0x1287: 0x75b9, 0x1288: 0x75e1, 0x1289: 0x7609, 0x128a: 0x7631, 0x128b: 0x7659, - 0x128c: 0x7681, 0x128d: 0x76a9, 0x128e: 0x76d1, 0x128f: 0x76f9, 0x1290: 0x7721, 0x1291: 0x7721, - 0x1292: 0x7739, 0x1293: 0x7739, 0x1294: 0x7739, 0x1295: 0x7739, 0x1296: 0x7751, 0x1297: 0x7751, - 0x1298: 0x7751, 0x1299: 0x7751, 0x129a: 0x7769, 0x129b: 0x7769, 0x129c: 0x7769, 0x129d: 0x7769, - 0x129e: 0x7781, 0x129f: 0x7781, 0x12a0: 0x7781, 0x12a1: 0x7781, 0x12a2: 0x7799, 0x12a3: 0x7799, - 0x12a4: 0x7799, 0x12a5: 0x7799, 0x12a6: 0x77b1, 0x12a7: 0x77b1, 0x12a8: 0x77b1, 0x12a9: 0x77b1, - 0x12aa: 0x77c9, 0x12ab: 0x77c9, 0x12ac: 0x77c9, 0x12ad: 0x77c9, 0x12ae: 0x77e1, 0x12af: 0x77e1, - 0x12b0: 0x77e1, 0x12b1: 0x77e1, 0x12b2: 0x77f9, 0x12b3: 0x77f9, 0x12b4: 0x77f9, 0x12b5: 0x77f9, - 0x12b6: 0x7811, 0x12b7: 0x7811, 0x12b8: 0x7811, 0x12b9: 0x7811, 0x12ba: 0x7829, 0x12bb: 0x7829, - 0x12bc: 0x7829, 0x12bd: 0x7829, 0x12be: 0x7841, 0x12bf: 0x7841, + 0x1280: 0x7a95, 0x1281: 0x7ab5, 0x1282: 0x7ad5, 0x1283: 0x7af5, 0x1284: 0x7b15, 0x1285: 0x7b35, + 0x1286: 0x7b55, 0x1287: 0x7b75, 0x1288: 0x7b95, 0x1289: 0x7bb5, 0x128a: 0x7bd5, 0x128b: 0x7bf5, + 0x128c: 0x7c15, 0x128d: 0x7c35, 0x128e: 0x7c55, 0x128f: 0x6ec9, 0x1290: 0x6ef1, 0x1291: 0x6f19, + 0x1292: 0x7c75, 0x1293: 0x7c95, 0x1294: 0x7cb5, 0x1295: 0x6f41, 0x1296: 0x6f69, 0x1297: 0x6f91, + 0x1298: 0x7cd5, 0x1299: 0x7cf5, 0x129a: 0x0040, 0x129b: 0x0040, 0x129c: 0x0040, 0x129d: 0x0040, + 0x129e: 0x0040, 0x129f: 0x0040, 0x12a0: 0x0040, 0x12a1: 0x0040, 0x12a2: 0x0040, 0x12a3: 0x0040, + 0x12a4: 0x0040, 0x12a5: 0x0040, 0x12a6: 0x0040, 0x12a7: 0x0040, 0x12a8: 0x0040, 0x12a9: 0x0040, + 0x12aa: 0x0040, 0x12ab: 0x0040, 0x12ac: 0x0040, 0x12ad: 0x0040, 0x12ae: 0x0040, 0x12af: 0x0040, + 0x12b0: 0x0040, 0x12b1: 0x0040, 0x12b2: 0x0040, 0x12b3: 0x0040, 0x12b4: 0x0040, 0x12b5: 0x0040, + 0x12b6: 0x0040, 0x12b7: 0x0040, 0x12b8: 0x0040, 0x12b9: 0x0040, 0x12ba: 0x0040, 0x12bb: 0x0040, + 0x12bc: 0x0040, 0x12bd: 0x0040, 0x12be: 0x0040, 0x12bf: 0x0040, // Block 0x4b, offset 0x12c0 - 0x12c0: 0x7841, 0x12c1: 0x7841, 0x12c2: 0x7859, 0x12c3: 0x7859, 0x12c4: 0x7871, 0x12c5: 0x7871, - 0x12c6: 0x7889, 0x12c7: 0x7889, 0x12c8: 0x78a1, 0x12c9: 0x78a1, 0x12ca: 0x78b9, 0x12cb: 0x78b9, - 0x12cc: 0x78d1, 0x12cd: 0x78d1, 0x12ce: 0x78e9, 0x12cf: 0x78e9, 0x12d0: 0x78e9, 0x12d1: 0x78e9, - 0x12d2: 0x7901, 0x12d3: 0x7901, 0x12d4: 0x7901, 0x12d5: 0x7901, 0x12d6: 0x7919, 0x12d7: 0x7919, - 0x12d8: 0x7919, 0x12d9: 0x7919, 0x12da: 0x7931, 0x12db: 0x7931, 0x12dc: 0x7931, 0x12dd: 0x7931, - 0x12de: 0x7949, 0x12df: 0x7949, 0x12e0: 0x7961, 0x12e1: 0x7961, 0x12e2: 0x7961, 0x12e3: 0x7961, - 0x12e4: 0x7979, 0x12e5: 0x7979, 0x12e6: 0x7991, 0x12e7: 0x7991, 0x12e8: 0x7991, 0x12e9: 0x7991, - 0x12ea: 0x79a9, 0x12eb: 0x79a9, 0x12ec: 0x79a9, 0x12ed: 0x79a9, 0x12ee: 0x79c1, 0x12ef: 0x79c1, - 0x12f0: 0x79d9, 0x12f1: 0x79d9, 0x12f2: 0x0018, 0x12f3: 0x0018, 0x12f4: 0x0018, 0x12f5: 0x0018, - 0x12f6: 0x0018, 0x12f7: 0x0018, 0x12f8: 0x0018, 0x12f9: 0x0018, 0x12fa: 0x0018, 0x12fb: 0x0018, - 0x12fc: 0x0018, 0x12fd: 0x0018, 0x12fe: 0x0018, 0x12ff: 0x0018, + 0x12c0: 0x6fb9, 0x12c1: 0x6fd1, 0x12c2: 0x6fe9, 0x12c3: 0x7d15, 0x12c4: 0x7d35, 0x12c5: 0x7001, + 0x12c6: 0x7001, 0x12c7: 0x0040, 0x12c8: 0x0040, 0x12c9: 0x0040, 0x12ca: 0x0040, 0x12cb: 0x0040, + 0x12cc: 0x0040, 0x12cd: 0x0040, 0x12ce: 0x0040, 0x12cf: 0x0040, 0x12d0: 0x0040, 0x12d1: 0x0040, + 0x12d2: 0x0040, 0x12d3: 0x7019, 0x12d4: 0x7041, 0x12d5: 0x7069, 0x12d6: 0x7091, 0x12d7: 0x70b9, + 0x12d8: 0x0040, 0x12d9: 0x0040, 0x12da: 0x0040, 0x12db: 0x0040, 0x12dc: 0x0040, 0x12dd: 0x70e1, + 0x12de: 0x3308, 0x12df: 0x7109, 0x12e0: 0x7131, 0x12e1: 0x20a9, 0x12e2: 0x20f1, 0x12e3: 0x7149, + 0x12e4: 0x7161, 0x12e5: 0x7179, 0x12e6: 0x7191, 0x12e7: 0x71a9, 0x12e8: 0x71c1, 0x12e9: 0x1fb2, + 0x12ea: 0x71d9, 0x12eb: 0x7201, 0x12ec: 0x7229, 0x12ed: 0x7261, 0x12ee: 0x7299, 0x12ef: 0x72c1, + 0x12f0: 0x72e9, 0x12f1: 0x7311, 0x12f2: 0x7339, 0x12f3: 0x7361, 0x12f4: 0x7389, 0x12f5: 0x73b1, + 0x12f6: 0x73d9, 0x12f7: 0x0040, 0x12f8: 0x7401, 0x12f9: 0x7429, 0x12fa: 0x7451, 0x12fb: 0x7479, + 0x12fc: 0x74a1, 0x12fd: 0x0040, 0x12fe: 0x74c9, 0x12ff: 0x0040, // Block 0x4c, offset 0x1300 - 0x1300: 0x0018, 0x1301: 0x0018, 0x1302: 0x0040, 0x1303: 0x0040, 0x1304: 0x0040, 0x1305: 0x0040, - 0x1306: 0x0040, 0x1307: 0x0040, 0x1308: 0x0040, 0x1309: 0x0040, 0x130a: 0x0040, 0x130b: 0x0040, - 0x130c: 0x0040, 0x130d: 0x0040, 0x130e: 0x0040, 0x130f: 0x0040, 0x1310: 0x0040, 0x1311: 0x0040, - 0x1312: 0x0040, 0x1313: 0x79f1, 0x1314: 0x79f1, 0x1315: 0x79f1, 0x1316: 0x79f1, 0x1317: 0x7a09, - 0x1318: 0x7a09, 0x1319: 0x7a21, 0x131a: 0x7a21, 0x131b: 0x7a39, 0x131c: 0x7a39, 0x131d: 0x0479, - 0x131e: 0x7a51, 0x131f: 0x7a51, 0x1320: 0x7a69, 0x1321: 0x7a69, 0x1322: 0x7a81, 0x1323: 0x7a81, - 0x1324: 0x7a99, 0x1325: 0x7a99, 0x1326: 0x7a99, 0x1327: 0x7a99, 0x1328: 0x7ab1, 0x1329: 0x7ab1, - 0x132a: 0x7ac9, 0x132b: 0x7ac9, 0x132c: 0x7af1, 0x132d: 0x7af1, 0x132e: 0x7b19, 0x132f: 0x7b19, - 0x1330: 0x7b41, 0x1331: 0x7b41, 0x1332: 0x7b69, 0x1333: 0x7b69, 0x1334: 0x7b91, 0x1335: 0x7b91, - 0x1336: 0x7bb9, 0x1337: 0x7bb9, 0x1338: 0x7bb9, 0x1339: 0x7be1, 0x133a: 0x7be1, 0x133b: 0x7be1, - 0x133c: 0x7c09, 0x133d: 0x7c09, 0x133e: 0x7c09, 0x133f: 0x7c09, + 0x1300: 0x74f1, 0x1301: 0x7519, 0x1302: 0x0040, 0x1303: 0x7541, 0x1304: 0x7569, 0x1305: 0x0040, + 0x1306: 0x7591, 0x1307: 0x75b9, 0x1308: 0x75e1, 0x1309: 0x7609, 0x130a: 0x7631, 0x130b: 0x7659, + 0x130c: 0x7681, 0x130d: 0x76a9, 0x130e: 0x76d1, 0x130f: 0x76f9, 0x1310: 0x7721, 0x1311: 0x7721, + 0x1312: 0x7739, 0x1313: 0x7739, 0x1314: 0x7739, 0x1315: 0x7739, 0x1316: 0x7751, 0x1317: 0x7751, + 0x1318: 0x7751, 0x1319: 0x7751, 0x131a: 0x7769, 0x131b: 0x7769, 0x131c: 0x7769, 0x131d: 0x7769, + 0x131e: 0x7781, 0x131f: 0x7781, 0x1320: 0x7781, 0x1321: 0x7781, 0x1322: 0x7799, 0x1323: 0x7799, + 0x1324: 0x7799, 0x1325: 0x7799, 0x1326: 0x77b1, 0x1327: 0x77b1, 0x1328: 0x77b1, 0x1329: 0x77b1, + 0x132a: 0x77c9, 0x132b: 0x77c9, 0x132c: 0x77c9, 0x132d: 0x77c9, 0x132e: 0x77e1, 0x132f: 0x77e1, + 0x1330: 0x77e1, 0x1331: 0x77e1, 0x1332: 0x77f9, 0x1333: 0x77f9, 0x1334: 0x77f9, 0x1335: 0x77f9, + 0x1336: 0x7811, 0x1337: 0x7811, 0x1338: 0x7811, 0x1339: 0x7811, 0x133a: 0x7829, 0x133b: 0x7829, + 0x133c: 0x7829, 0x133d: 0x7829, 0x133e: 0x7841, 0x133f: 0x7841, // Block 0x4d, offset 0x1340 - 0x1340: 0x85f9, 0x1341: 0x8621, 0x1342: 0x8649, 0x1343: 0x8671, 0x1344: 0x8699, 0x1345: 0x86c1, - 0x1346: 0x86e9, 0x1347: 0x8711, 0x1348: 0x8739, 0x1349: 0x8761, 0x134a: 0x8789, 0x134b: 0x87b1, - 0x134c: 0x87d9, 0x134d: 0x8801, 0x134e: 0x8829, 0x134f: 0x8851, 0x1350: 0x8879, 0x1351: 0x88a1, - 0x1352: 0x88c9, 0x1353: 0x88f1, 0x1354: 0x8919, 0x1355: 0x8941, 0x1356: 0x8969, 0x1357: 0x8991, - 0x1358: 0x89b9, 0x1359: 0x89e1, 0x135a: 0x8a09, 0x135b: 0x8a31, 0x135c: 0x8a59, 0x135d: 0x8a81, - 0x135e: 0x8aaa, 0x135f: 0x8ada, 0x1360: 0x8b0a, 0x1361: 0x8b3a, 0x1362: 0x8b6a, 0x1363: 0x8b9a, - 0x1364: 0x8bc9, 0x1365: 0x8bf1, 0x1366: 0x7c71, 0x1367: 0x8c19, 0x1368: 0x7be1, 0x1369: 0x7c99, - 0x136a: 0x8c41, 0x136b: 0x8c69, 0x136c: 0x7d39, 0x136d: 0x8c91, 0x136e: 0x7d61, 0x136f: 0x7d89, - 0x1370: 0x8cb9, 0x1371: 0x8ce1, 0x1372: 0x7e29, 0x1373: 0x8d09, 0x1374: 0x7e51, 0x1375: 0x7e79, - 0x1376: 0x8d31, 0x1377: 0x8d59, 0x1378: 0x7ec9, 0x1379: 0x8d81, 0x137a: 0x7ef1, 0x137b: 0x7f19, - 0x137c: 0x83a1, 0x137d: 0x83c9, 0x137e: 0x8441, 0x137f: 0x8469, + 0x1340: 0x7841, 0x1341: 0x7841, 0x1342: 0x7859, 0x1343: 0x7859, 0x1344: 0x7871, 0x1345: 0x7871, + 0x1346: 0x7889, 0x1347: 0x7889, 0x1348: 0x78a1, 0x1349: 0x78a1, 0x134a: 0x78b9, 0x134b: 0x78b9, + 0x134c: 0x78d1, 0x134d: 0x78d1, 0x134e: 0x78e9, 0x134f: 0x78e9, 0x1350: 0x78e9, 0x1351: 0x78e9, + 0x1352: 0x7901, 0x1353: 0x7901, 0x1354: 0x7901, 0x1355: 0x7901, 0x1356: 0x7919, 0x1357: 0x7919, + 0x1358: 0x7919, 0x1359: 0x7919, 0x135a: 0x7931, 0x135b: 0x7931, 0x135c: 0x7931, 0x135d: 0x7931, + 0x135e: 0x7949, 0x135f: 0x7949, 0x1360: 0x7961, 0x1361: 0x7961, 0x1362: 0x7961, 0x1363: 0x7961, + 0x1364: 0x7979, 0x1365: 0x7979, 0x1366: 0x7991, 0x1367: 0x7991, 0x1368: 0x7991, 0x1369: 0x7991, + 0x136a: 0x79a9, 0x136b: 0x79a9, 0x136c: 0x79a9, 0x136d: 0x79a9, 0x136e: 0x79c1, 0x136f: 0x79c1, + 0x1370: 0x79d9, 0x1371: 0x79d9, 0x1372: 0x0818, 0x1373: 0x0818, 0x1374: 0x0818, 0x1375: 0x0818, + 0x1376: 0x0818, 0x1377: 0x0818, 0x1378: 0x0818, 0x1379: 0x0818, 0x137a: 0x0818, 0x137b: 0x0818, + 0x137c: 0x0818, 0x137d: 0x0818, 0x137e: 0x0818, 0x137f: 0x0818, // Block 0x4e, offset 0x1380 - 0x1380: 0x8491, 0x1381: 0x8531, 0x1382: 0x8559, 0x1383: 0x8581, 0x1384: 0x85a9, 0x1385: 0x8649, - 0x1386: 0x8671, 0x1387: 0x8699, 0x1388: 0x8da9, 0x1389: 0x8739, 0x138a: 0x8dd1, 0x138b: 0x8df9, - 0x138c: 0x8829, 0x138d: 0x8e21, 0x138e: 0x8851, 0x138f: 0x8879, 0x1390: 0x8a81, 0x1391: 0x8e49, - 0x1392: 0x8e71, 0x1393: 0x89b9, 0x1394: 0x8e99, 0x1395: 0x89e1, 0x1396: 0x8a09, 0x1397: 0x7c21, - 0x1398: 0x7c49, 0x1399: 0x8ec1, 0x139a: 0x7c71, 0x139b: 0x8ee9, 0x139c: 0x7cc1, 0x139d: 0x7ce9, - 0x139e: 0x7d11, 0x139f: 0x7d39, 0x13a0: 0x8f11, 0x13a1: 0x7db1, 0x13a2: 0x7dd9, 0x13a3: 0x7e01, - 0x13a4: 0x7e29, 0x13a5: 0x8f39, 0x13a6: 0x7ec9, 0x13a7: 0x7f41, 0x13a8: 0x7f69, 0x13a9: 0x7f91, - 0x13aa: 0x7fb9, 0x13ab: 0x7fe1, 0x13ac: 0x8031, 0x13ad: 0x8059, 0x13ae: 0x8081, 0x13af: 0x80a9, - 0x13b0: 0x80d1, 0x13b1: 0x80f9, 0x13b2: 0x8f61, 0x13b3: 0x8121, 0x13b4: 0x8149, 0x13b5: 0x8171, - 0x13b6: 0x8199, 0x13b7: 0x81c1, 0x13b8: 0x81e9, 0x13b9: 0x8239, 0x13ba: 0x8261, 0x13bb: 0x8289, - 0x13bc: 0x82b1, 0x13bd: 0x82d9, 0x13be: 0x8301, 0x13bf: 0x8329, + 0x1380: 0x0818, 0x1381: 0x0818, 0x1382: 0x0040, 0x1383: 0x0040, 0x1384: 0x0040, 0x1385: 0x0040, + 0x1386: 0x0040, 0x1387: 0x0040, 0x1388: 0x0040, 0x1389: 0x0040, 0x138a: 0x0040, 0x138b: 0x0040, + 0x138c: 0x0040, 0x138d: 0x0040, 0x138e: 0x0040, 0x138f: 0x0040, 0x1390: 0x0040, 0x1391: 0x0040, + 0x1392: 0x0040, 0x1393: 0x79f1, 0x1394: 0x79f1, 0x1395: 0x79f1, 0x1396: 0x79f1, 0x1397: 0x7a09, + 0x1398: 0x7a09, 0x1399: 0x7a21, 0x139a: 0x7a21, 0x139b: 0x7a39, 0x139c: 0x7a39, 0x139d: 0x0479, + 0x139e: 0x7a51, 0x139f: 0x7a51, 0x13a0: 0x7a69, 0x13a1: 0x7a69, 0x13a2: 0x7a81, 0x13a3: 0x7a81, + 0x13a4: 0x7a99, 0x13a5: 0x7a99, 0x13a6: 0x7a99, 0x13a7: 0x7a99, 0x13a8: 0x7ab1, 0x13a9: 0x7ab1, + 0x13aa: 0x7ac9, 0x13ab: 0x7ac9, 0x13ac: 0x7af1, 0x13ad: 0x7af1, 0x13ae: 0x7b19, 0x13af: 0x7b19, + 0x13b0: 0x7b41, 0x13b1: 0x7b41, 0x13b2: 0x7b69, 0x13b3: 0x7b69, 0x13b4: 0x7b91, 0x13b5: 0x7b91, + 0x13b6: 0x7bb9, 0x13b7: 0x7bb9, 0x13b8: 0x7bb9, 0x13b9: 0x7be1, 0x13ba: 0x7be1, 0x13bb: 0x7be1, + 0x13bc: 0x7c09, 0x13bd: 0x7c09, 0x13be: 0x7c09, 0x13bf: 0x7c09, // Block 0x4f, offset 0x13c0 - 0x13c0: 0x8351, 0x13c1: 0x8379, 0x13c2: 0x83f1, 0x13c3: 0x8419, 0x13c4: 0x84b9, 0x13c5: 0x84e1, - 0x13c6: 0x8509, 0x13c7: 0x8531, 0x13c8: 0x8559, 0x13c9: 0x85d1, 0x13ca: 0x85f9, 0x13cb: 0x8621, - 0x13cc: 0x8649, 0x13cd: 0x8f89, 0x13ce: 0x86c1, 0x13cf: 0x86e9, 0x13d0: 0x8711, 0x13d1: 0x8739, - 0x13d2: 0x87b1, 0x13d3: 0x87d9, 0x13d4: 0x8801, 0x13d5: 0x8829, 0x13d6: 0x8fb1, 0x13d7: 0x88a1, - 0x13d8: 0x88c9, 0x13d9: 0x8fd9, 0x13da: 0x8941, 0x13db: 0x8969, 0x13dc: 0x8991, 0x13dd: 0x89b9, - 0x13de: 0x9001, 0x13df: 0x7c71, 0x13e0: 0x8ee9, 0x13e1: 0x7d39, 0x13e2: 0x8f11, 0x13e3: 0x7e29, - 0x13e4: 0x8f39, 0x13e5: 0x7ec9, 0x13e6: 0x9029, 0x13e7: 0x80d1, 0x13e8: 0x9051, 0x13e9: 0x9079, - 0x13ea: 0x90a1, 0x13eb: 0x8531, 0x13ec: 0x8559, 0x13ed: 0x8649, 0x13ee: 0x8829, 0x13ef: 0x8fb1, - 0x13f0: 0x89b9, 0x13f1: 0x9001, 0x13f2: 0x90c9, 0x13f3: 0x9101, 0x13f4: 0x9139, 0x13f5: 0x9171, - 0x13f6: 0x9199, 0x13f7: 0x91c1, 0x13f8: 0x91e9, 0x13f9: 0x9211, 0x13fa: 0x9239, 0x13fb: 0x9261, - 0x13fc: 0x9289, 0x13fd: 0x92b1, 0x13fe: 0x92d9, 0x13ff: 0x9301, + 0x13c0: 0x85f9, 0x13c1: 0x8621, 0x13c2: 0x8649, 0x13c3: 0x8671, 0x13c4: 0x8699, 0x13c5: 0x86c1, + 0x13c6: 0x86e9, 0x13c7: 0x8711, 0x13c8: 0x8739, 0x13c9: 0x8761, 0x13ca: 0x8789, 0x13cb: 0x87b1, + 0x13cc: 0x87d9, 0x13cd: 0x8801, 0x13ce: 0x8829, 0x13cf: 0x8851, 0x13d0: 0x8879, 0x13d1: 0x88a1, + 0x13d2: 0x88c9, 0x13d3: 0x88f1, 0x13d4: 0x8919, 0x13d5: 0x8941, 0x13d6: 0x8969, 0x13d7: 0x8991, + 0x13d8: 0x89b9, 0x13d9: 0x89e1, 0x13da: 0x8a09, 0x13db: 0x8a31, 0x13dc: 0x8a59, 0x13dd: 0x8a81, + 0x13de: 0x8aaa, 0x13df: 0x8ada, 0x13e0: 0x8b0a, 0x13e1: 0x8b3a, 0x13e2: 0x8b6a, 0x13e3: 0x8b9a, + 0x13e4: 0x8bc9, 0x13e5: 0x8bf1, 0x13e6: 0x7c71, 0x13e7: 0x8c19, 0x13e8: 0x7be1, 0x13e9: 0x7c99, + 0x13ea: 0x8c41, 0x13eb: 0x8c69, 0x13ec: 0x7d39, 0x13ed: 0x8c91, 0x13ee: 0x7d61, 0x13ef: 0x7d89, + 0x13f0: 0x8cb9, 0x13f1: 0x8ce1, 0x13f2: 0x7e29, 0x13f3: 0x8d09, 0x13f4: 0x7e51, 0x13f5: 0x7e79, + 0x13f6: 0x8d31, 0x13f7: 0x8d59, 0x13f8: 0x7ec9, 0x13f9: 0x8d81, 0x13fa: 0x7ef1, 0x13fb: 0x7f19, + 0x13fc: 0x83a1, 0x13fd: 0x83c9, 0x13fe: 0x8441, 0x13ff: 0x8469, // Block 0x50, offset 0x1400 - 0x1400: 0x9329, 0x1401: 0x9351, 0x1402: 0x9379, 0x1403: 0x93a1, 0x1404: 0x93c9, 0x1405: 0x93f1, - 0x1406: 0x9419, 0x1407: 0x9441, 0x1408: 0x9469, 0x1409: 0x9491, 0x140a: 0x94b9, 0x140b: 0x94e1, - 0x140c: 0x9079, 0x140d: 0x9509, 0x140e: 0x9531, 0x140f: 0x9559, 0x1410: 0x9581, 0x1411: 0x9171, - 0x1412: 0x9199, 0x1413: 0x91c1, 0x1414: 0x91e9, 0x1415: 0x9211, 0x1416: 0x9239, 0x1417: 0x9261, - 0x1418: 0x9289, 0x1419: 0x92b1, 0x141a: 0x92d9, 0x141b: 0x9301, 0x141c: 0x9329, 0x141d: 0x9351, - 0x141e: 0x9379, 0x141f: 0x93a1, 0x1420: 0x93c9, 0x1421: 0x93f1, 0x1422: 0x9419, 0x1423: 0x9441, - 0x1424: 0x9469, 0x1425: 0x9491, 0x1426: 0x94b9, 0x1427: 0x94e1, 0x1428: 0x9079, 0x1429: 0x9509, - 0x142a: 0x9531, 0x142b: 0x9559, 0x142c: 0x9581, 0x142d: 0x9491, 0x142e: 0x94b9, 0x142f: 0x94e1, - 0x1430: 0x9079, 0x1431: 0x9051, 0x1432: 0x90a1, 0x1433: 0x8211, 0x1434: 0x8059, 0x1435: 0x8081, - 0x1436: 0x80a9, 0x1437: 0x9491, 0x1438: 0x94b9, 0x1439: 0x94e1, 0x143a: 0x8211, 0x143b: 0x8239, - 0x143c: 0x95a9, 0x143d: 0x95a9, 0x143e: 0x0018, 0x143f: 0x0018, + 0x1400: 0x8491, 0x1401: 0x8531, 0x1402: 0x8559, 0x1403: 0x8581, 0x1404: 0x85a9, 0x1405: 0x8649, + 0x1406: 0x8671, 0x1407: 0x8699, 0x1408: 0x8da9, 0x1409: 0x8739, 0x140a: 0x8dd1, 0x140b: 0x8df9, + 0x140c: 0x8829, 0x140d: 0x8e21, 0x140e: 0x8851, 0x140f: 0x8879, 0x1410: 0x8a81, 0x1411: 0x8e49, + 0x1412: 0x8e71, 0x1413: 0x89b9, 0x1414: 0x8e99, 0x1415: 0x89e1, 0x1416: 0x8a09, 0x1417: 0x7c21, + 0x1418: 0x7c49, 0x1419: 0x8ec1, 0x141a: 0x7c71, 0x141b: 0x8ee9, 0x141c: 0x7cc1, 0x141d: 0x7ce9, + 0x141e: 0x7d11, 0x141f: 0x7d39, 0x1420: 0x8f11, 0x1421: 0x7db1, 0x1422: 0x7dd9, 0x1423: 0x7e01, + 0x1424: 0x7e29, 0x1425: 0x8f39, 0x1426: 0x7ec9, 0x1427: 0x7f41, 0x1428: 0x7f69, 0x1429: 0x7f91, + 0x142a: 0x7fb9, 0x142b: 0x7fe1, 0x142c: 0x8031, 0x142d: 0x8059, 0x142e: 0x8081, 0x142f: 0x80a9, + 0x1430: 0x80d1, 0x1431: 0x80f9, 0x1432: 0x8f61, 0x1433: 0x8121, 0x1434: 0x8149, 0x1435: 0x8171, + 0x1436: 0x8199, 0x1437: 0x81c1, 0x1438: 0x81e9, 0x1439: 0x8239, 0x143a: 0x8261, 0x143b: 0x8289, + 0x143c: 0x82b1, 0x143d: 0x82d9, 0x143e: 0x8301, 0x143f: 0x8329, // Block 0x51, offset 0x1440 - 0x1440: 0x0040, 0x1441: 0x0040, 0x1442: 0x0040, 0x1443: 0x0040, 0x1444: 0x0040, 0x1445: 0x0040, - 0x1446: 0x0040, 0x1447: 0x0040, 0x1448: 0x0040, 0x1449: 0x0040, 0x144a: 0x0040, 0x144b: 0x0040, - 0x144c: 0x0040, 0x144d: 0x0040, 0x144e: 0x0040, 0x144f: 0x0040, 0x1450: 0x95d1, 0x1451: 0x9609, - 0x1452: 0x9609, 0x1453: 0x9641, 0x1454: 0x9679, 0x1455: 0x96b1, 0x1456: 0x96e9, 0x1457: 0x9721, - 0x1458: 0x9759, 0x1459: 0x9759, 0x145a: 0x9791, 0x145b: 0x97c9, 0x145c: 0x9801, 0x145d: 0x9839, - 0x145e: 0x9871, 0x145f: 0x98a9, 0x1460: 0x98a9, 0x1461: 0x98e1, 0x1462: 0x9919, 0x1463: 0x9919, - 0x1464: 0x9951, 0x1465: 0x9951, 0x1466: 0x9989, 0x1467: 0x99c1, 0x1468: 0x99c1, 0x1469: 0x99f9, - 0x146a: 0x9a31, 0x146b: 0x9a31, 0x146c: 0x9a69, 0x146d: 0x9a69, 0x146e: 0x9aa1, 0x146f: 0x9ad9, - 0x1470: 0x9ad9, 0x1471: 0x9b11, 0x1472: 0x9b11, 0x1473: 0x9b49, 0x1474: 0x9b81, 0x1475: 0x9bb9, - 0x1476: 0x9bf1, 0x1477: 0x9bf1, 0x1478: 0x9c29, 0x1479: 0x9c61, 0x147a: 0x9c99, 0x147b: 0x9cd1, - 0x147c: 0x9d09, 0x147d: 0x9d09, 0x147e: 0x9d41, 0x147f: 0x9d79, + 0x1440: 0x8351, 0x1441: 0x8379, 0x1442: 0x83f1, 0x1443: 0x8419, 0x1444: 0x84b9, 0x1445: 0x84e1, + 0x1446: 0x8509, 0x1447: 0x8531, 0x1448: 0x8559, 0x1449: 0x85d1, 0x144a: 0x85f9, 0x144b: 0x8621, + 0x144c: 0x8649, 0x144d: 0x8f89, 0x144e: 0x86c1, 0x144f: 0x86e9, 0x1450: 0x8711, 0x1451: 0x8739, + 0x1452: 0x87b1, 0x1453: 0x87d9, 0x1454: 0x8801, 0x1455: 0x8829, 0x1456: 0x8fb1, 0x1457: 0x88a1, + 0x1458: 0x88c9, 0x1459: 0x8fd9, 0x145a: 0x8941, 0x145b: 0x8969, 0x145c: 0x8991, 0x145d: 0x89b9, + 0x145e: 0x9001, 0x145f: 0x7c71, 0x1460: 0x8ee9, 0x1461: 0x7d39, 0x1462: 0x8f11, 0x1463: 0x7e29, + 0x1464: 0x8f39, 0x1465: 0x7ec9, 0x1466: 0x9029, 0x1467: 0x80d1, 0x1468: 0x9051, 0x1469: 0x9079, + 0x146a: 0x90a1, 0x146b: 0x8531, 0x146c: 0x8559, 0x146d: 0x8649, 0x146e: 0x8829, 0x146f: 0x8fb1, + 0x1470: 0x89b9, 0x1471: 0x9001, 0x1472: 0x90c9, 0x1473: 0x9101, 0x1474: 0x9139, 0x1475: 0x9171, + 0x1476: 0x9199, 0x1477: 0x91c1, 0x1478: 0x91e9, 0x1479: 0x9211, 0x147a: 0x9239, 0x147b: 0x9261, + 0x147c: 0x9289, 0x147d: 0x92b1, 0x147e: 0x92d9, 0x147f: 0x9301, // Block 0x52, offset 0x1480 - 0x1480: 0xa949, 0x1481: 0xa981, 0x1482: 0xa9b9, 0x1483: 0xa8a1, 0x1484: 0x9bb9, 0x1485: 0x9989, - 0x1486: 0xa9f1, 0x1487: 0xaa29, 0x1488: 0x0040, 0x1489: 0x0040, 0x148a: 0x0040, 0x148b: 0x0040, - 0x148c: 0x0040, 0x148d: 0x0040, 0x148e: 0x0040, 0x148f: 0x0040, 0x1490: 0x0040, 0x1491: 0x0040, - 0x1492: 0x0040, 0x1493: 0x0040, 0x1494: 0x0040, 0x1495: 0x0040, 0x1496: 0x0040, 0x1497: 0x0040, - 0x1498: 0x0040, 0x1499: 0x0040, 0x149a: 0x0040, 0x149b: 0x0040, 0x149c: 0x0040, 0x149d: 0x0040, - 0x149e: 0x0040, 0x149f: 0x0040, 0x14a0: 0x0040, 0x14a1: 0x0040, 0x14a2: 0x0040, 0x14a3: 0x0040, - 0x14a4: 0x0040, 0x14a5: 0x0040, 0x14a6: 0x0040, 0x14a7: 0x0040, 0x14a8: 0x0040, 0x14a9: 0x0040, - 0x14aa: 0x0040, 0x14ab: 0x0040, 0x14ac: 0x0040, 0x14ad: 0x0040, 0x14ae: 0x0040, 0x14af: 0x0040, - 0x14b0: 0xaa61, 0x14b1: 0xaa99, 0x14b2: 0xaad1, 0x14b3: 0xab19, 0x14b4: 0xab61, 0x14b5: 0xaba9, - 0x14b6: 0xabf1, 0x14b7: 0xac39, 0x14b8: 0xac81, 0x14b9: 0xacc9, 0x14ba: 0xad02, 0x14bb: 0xae12, - 0x14bc: 0xae91, 0x14bd: 0x0018, 0x14be: 0x0040, 0x14bf: 0x0040, + 0x1480: 0x9329, 0x1481: 0x9351, 0x1482: 0x9379, 0x1483: 0x93a1, 0x1484: 0x93c9, 0x1485: 0x93f1, + 0x1486: 0x9419, 0x1487: 0x9441, 0x1488: 0x9469, 0x1489: 0x9491, 0x148a: 0x94b9, 0x148b: 0x94e1, + 0x148c: 0x9079, 0x148d: 0x9509, 0x148e: 0x9531, 0x148f: 0x9559, 0x1490: 0x9581, 0x1491: 0x9171, + 0x1492: 0x9199, 0x1493: 0x91c1, 0x1494: 0x91e9, 0x1495: 0x9211, 0x1496: 0x9239, 0x1497: 0x9261, + 0x1498: 0x9289, 0x1499: 0x92b1, 0x149a: 0x92d9, 0x149b: 0x9301, 0x149c: 0x9329, 0x149d: 0x9351, + 0x149e: 0x9379, 0x149f: 0x93a1, 0x14a0: 0x93c9, 0x14a1: 0x93f1, 0x14a2: 0x9419, 0x14a3: 0x9441, + 0x14a4: 0x9469, 0x14a5: 0x9491, 0x14a6: 0x94b9, 0x14a7: 0x94e1, 0x14a8: 0x9079, 0x14a9: 0x9509, + 0x14aa: 0x9531, 0x14ab: 0x9559, 0x14ac: 0x9581, 0x14ad: 0x9491, 0x14ae: 0x94b9, 0x14af: 0x94e1, + 0x14b0: 0x9079, 0x14b1: 0x9051, 0x14b2: 0x90a1, 0x14b3: 0x8211, 0x14b4: 0x8059, 0x14b5: 0x8081, + 0x14b6: 0x80a9, 0x14b7: 0x9491, 0x14b8: 0x94b9, 0x14b9: 0x94e1, 0x14ba: 0x8211, 0x14bb: 0x8239, + 0x14bc: 0x95a9, 0x14bd: 0x95a9, 0x14be: 0x0018, 0x14bf: 0x0018, // Block 0x53, offset 0x14c0 - 0x14c0: 0x13c0, 0x14c1: 0x13c0, 0x14c2: 0x13c0, 0x14c3: 0x13c0, 0x14c4: 0x13c0, 0x14c5: 0x13c0, - 0x14c6: 0x13c0, 0x14c7: 0x13c0, 0x14c8: 0x13c0, 0x14c9: 0x13c0, 0x14ca: 0x13c0, 0x14cb: 0x13c0, - 0x14cc: 0x13c0, 0x14cd: 0x13c0, 0x14ce: 0x13c0, 0x14cf: 0x13c0, 0x14d0: 0xaeda, 0x14d1: 0x7d55, - 0x14d2: 0x0040, 0x14d3: 0xaeea, 0x14d4: 0x03c2, 0x14d5: 0xaefa, 0x14d6: 0xaf0a, 0x14d7: 0x7d75, - 0x14d8: 0x7d95, 0x14d9: 0x0040, 0x14da: 0x0040, 0x14db: 0x0040, 0x14dc: 0x0040, 0x14dd: 0x0040, - 0x14de: 0x0040, 0x14df: 0x0040, 0x14e0: 0x1308, 0x14e1: 0x1308, 0x14e2: 0x1308, 0x14e3: 0x1308, - 0x14e4: 0x1308, 0x14e5: 0x1308, 0x14e6: 0x1308, 0x14e7: 0x1308, 0x14e8: 0x1308, 0x14e9: 0x1308, - 0x14ea: 0x1308, 0x14eb: 0x1308, 0x14ec: 0x1308, 0x14ed: 0x1308, 0x14ee: 0x1308, 0x14ef: 0x1308, - 0x14f0: 0x0040, 0x14f1: 0x7db5, 0x14f2: 0x7dd5, 0x14f3: 0xaf1a, 0x14f4: 0xaf1a, 0x14f5: 0x1fd2, - 0x14f6: 0x1fe2, 0x14f7: 0xaf2a, 0x14f8: 0xaf3a, 0x14f9: 0x7df5, 0x14fa: 0x7e15, 0x14fb: 0x7e35, - 0x14fc: 0x7df5, 0x14fd: 0x7e55, 0x14fe: 0x7e75, 0x14ff: 0x7e55, + 0x14c0: 0x0040, 0x14c1: 0x0040, 0x14c2: 0x0040, 0x14c3: 0x0040, 0x14c4: 0x0040, 0x14c5: 0x0040, + 0x14c6: 0x0040, 0x14c7: 0x0040, 0x14c8: 0x0040, 0x14c9: 0x0040, 0x14ca: 0x0040, 0x14cb: 0x0040, + 0x14cc: 0x0040, 0x14cd: 0x0040, 0x14ce: 0x0040, 0x14cf: 0x0040, 0x14d0: 0x95d1, 0x14d1: 0x9609, + 0x14d2: 0x9609, 0x14d3: 0x9641, 0x14d4: 0x9679, 0x14d5: 0x96b1, 0x14d6: 0x96e9, 0x14d7: 0x9721, + 0x14d8: 0x9759, 0x14d9: 0x9759, 0x14da: 0x9791, 0x14db: 0x97c9, 0x14dc: 0x9801, 0x14dd: 0x9839, + 0x14de: 0x9871, 0x14df: 0x98a9, 0x14e0: 0x98a9, 0x14e1: 0x98e1, 0x14e2: 0x9919, 0x14e3: 0x9919, + 0x14e4: 0x9951, 0x14e5: 0x9951, 0x14e6: 0x9989, 0x14e7: 0x99c1, 0x14e8: 0x99c1, 0x14e9: 0x99f9, + 0x14ea: 0x9a31, 0x14eb: 0x9a31, 0x14ec: 0x9a69, 0x14ed: 0x9a69, 0x14ee: 0x9aa1, 0x14ef: 0x9ad9, + 0x14f0: 0x9ad9, 0x14f1: 0x9b11, 0x14f2: 0x9b11, 0x14f3: 0x9b49, 0x14f4: 0x9b81, 0x14f5: 0x9bb9, + 0x14f6: 0x9bf1, 0x14f7: 0x9bf1, 0x14f8: 0x9c29, 0x14f9: 0x9c61, 0x14fa: 0x9c99, 0x14fb: 0x9cd1, + 0x14fc: 0x9d09, 0x14fd: 0x9d09, 0x14fe: 0x9d41, 0x14ff: 0x9d79, // Block 0x54, offset 0x1500 - 0x1500: 0x7e95, 0x1501: 0x7eb5, 0x1502: 0x7ed5, 0x1503: 0x7eb5, 0x1504: 0x7ef5, 0x1505: 0x0018, - 0x1506: 0x0018, 0x1507: 0xaf4a, 0x1508: 0xaf5a, 0x1509: 0x7f16, 0x150a: 0x7f36, 0x150b: 0x7f56, - 0x150c: 0x7f76, 0x150d: 0xaf1a, 0x150e: 0xaf1a, 0x150f: 0xaf1a, 0x1510: 0xaeda, 0x1511: 0x7f95, - 0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x03c2, 0x1515: 0xaeea, 0x1516: 0xaf0a, 0x1517: 0xaefa, - 0x1518: 0x7fb5, 0x1519: 0x1fd2, 0x151a: 0x1fe2, 0x151b: 0xaf2a, 0x151c: 0xaf3a, 0x151d: 0x7e95, - 0x151e: 0x7ef5, 0x151f: 0xaf6a, 0x1520: 0xaf7a, 0x1521: 0xaf8a, 0x1522: 0x1fb2, 0x1523: 0xaf99, - 0x1524: 0xafaa, 0x1525: 0xafba, 0x1526: 0x1fc2, 0x1527: 0x0040, 0x1528: 0xafca, 0x1529: 0xafda, - 0x152a: 0xafea, 0x152b: 0xaffa, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040, - 0x1530: 0x7fd6, 0x1531: 0xb009, 0x1532: 0x7ff6, 0x1533: 0x0008, 0x1534: 0x8016, 0x1535: 0x0040, - 0x1536: 0x8036, 0x1537: 0xb031, 0x1538: 0x8056, 0x1539: 0xb059, 0x153a: 0x8076, 0x153b: 0xb081, - 0x153c: 0x8096, 0x153d: 0xb0a9, 0x153e: 0x80b6, 0x153f: 0xb0d1, + 0x1500: 0xa949, 0x1501: 0xa981, 0x1502: 0xa9b9, 0x1503: 0xa8a1, 0x1504: 0x9bb9, 0x1505: 0x9989, + 0x1506: 0xa9f1, 0x1507: 0xaa29, 0x1508: 0x0040, 0x1509: 0x0040, 0x150a: 0x0040, 0x150b: 0x0040, + 0x150c: 0x0040, 0x150d: 0x0040, 0x150e: 0x0040, 0x150f: 0x0040, 0x1510: 0x0040, 0x1511: 0x0040, + 0x1512: 0x0040, 0x1513: 0x0040, 0x1514: 0x0040, 0x1515: 0x0040, 0x1516: 0x0040, 0x1517: 0x0040, + 0x1518: 0x0040, 0x1519: 0x0040, 0x151a: 0x0040, 0x151b: 0x0040, 0x151c: 0x0040, 0x151d: 0x0040, + 0x151e: 0x0040, 0x151f: 0x0040, 0x1520: 0x0040, 0x1521: 0x0040, 0x1522: 0x0040, 0x1523: 0x0040, + 0x1524: 0x0040, 0x1525: 0x0040, 0x1526: 0x0040, 0x1527: 0x0040, 0x1528: 0x0040, 0x1529: 0x0040, + 0x152a: 0x0040, 0x152b: 0x0040, 0x152c: 0x0040, 0x152d: 0x0040, 0x152e: 0x0040, 0x152f: 0x0040, + 0x1530: 0xaa61, 0x1531: 0xaa99, 0x1532: 0xaad1, 0x1533: 0xab19, 0x1534: 0xab61, 0x1535: 0xaba9, + 0x1536: 0xabf1, 0x1537: 0xac39, 0x1538: 0xac81, 0x1539: 0xacc9, 0x153a: 0xad02, 0x153b: 0xae12, + 0x153c: 0xae91, 0x153d: 0x0018, 0x153e: 0x0040, 0x153f: 0x0040, // Block 0x55, offset 0x1540 - 0x1540: 0xb0f9, 0x1541: 0xb111, 0x1542: 0xb111, 0x1543: 0xb129, 0x1544: 0xb129, 0x1545: 0xb141, - 0x1546: 0xb141, 0x1547: 0xb159, 0x1548: 0xb159, 0x1549: 0xb171, 0x154a: 0xb171, 0x154b: 0xb171, - 0x154c: 0xb171, 0x154d: 0xb189, 0x154e: 0xb189, 0x154f: 0xb1a1, 0x1550: 0xb1a1, 0x1551: 0xb1a1, - 0x1552: 0xb1a1, 0x1553: 0xb1b9, 0x1554: 0xb1b9, 0x1555: 0xb1d1, 0x1556: 0xb1d1, 0x1557: 0xb1d1, - 0x1558: 0xb1d1, 0x1559: 0xb1e9, 0x155a: 0xb1e9, 0x155b: 0xb1e9, 0x155c: 0xb1e9, 0x155d: 0xb201, - 0x155e: 0xb201, 0x155f: 0xb201, 0x1560: 0xb201, 0x1561: 0xb219, 0x1562: 0xb219, 0x1563: 0xb219, - 0x1564: 0xb219, 0x1565: 0xb231, 0x1566: 0xb231, 0x1567: 0xb231, 0x1568: 0xb231, 0x1569: 0xb249, - 0x156a: 0xb249, 0x156b: 0xb261, 0x156c: 0xb261, 0x156d: 0xb279, 0x156e: 0xb279, 0x156f: 0xb291, - 0x1570: 0xb291, 0x1571: 0xb2a9, 0x1572: 0xb2a9, 0x1573: 0xb2a9, 0x1574: 0xb2a9, 0x1575: 0xb2c1, - 0x1576: 0xb2c1, 0x1577: 0xb2c1, 0x1578: 0xb2c1, 0x1579: 0xb2d9, 0x157a: 0xb2d9, 0x157b: 0xb2d9, - 0x157c: 0xb2d9, 0x157d: 0xb2f1, 0x157e: 0xb2f1, 0x157f: 0xb2f1, + 0x1540: 0x33c0, 0x1541: 0x33c0, 0x1542: 0x33c0, 0x1543: 0x33c0, 0x1544: 0x33c0, 0x1545: 0x33c0, + 0x1546: 0x33c0, 0x1547: 0x33c0, 0x1548: 0x33c0, 0x1549: 0x33c0, 0x154a: 0x33c0, 0x154b: 0x33c0, + 0x154c: 0x33c0, 0x154d: 0x33c0, 0x154e: 0x33c0, 0x154f: 0x33c0, 0x1550: 0xaeda, 0x1551: 0x7d55, + 0x1552: 0x0040, 0x1553: 0xaeea, 0x1554: 0x03c2, 0x1555: 0xaefa, 0x1556: 0xaf0a, 0x1557: 0x7d75, + 0x1558: 0x7d95, 0x1559: 0x0040, 0x155a: 0x0040, 0x155b: 0x0040, 0x155c: 0x0040, 0x155d: 0x0040, + 0x155e: 0x0040, 0x155f: 0x0040, 0x1560: 0x3308, 0x1561: 0x3308, 0x1562: 0x3308, 0x1563: 0x3308, + 0x1564: 0x3308, 0x1565: 0x3308, 0x1566: 0x3308, 0x1567: 0x3308, 0x1568: 0x3308, 0x1569: 0x3308, + 0x156a: 0x3308, 0x156b: 0x3308, 0x156c: 0x3308, 0x156d: 0x3308, 0x156e: 0x3308, 0x156f: 0x3308, + 0x1570: 0x0040, 0x1571: 0x7db5, 0x1572: 0x7dd5, 0x1573: 0xaf1a, 0x1574: 0xaf1a, 0x1575: 0x1fd2, + 0x1576: 0x1fe2, 0x1577: 0xaf2a, 0x1578: 0xaf3a, 0x1579: 0x7df5, 0x157a: 0x7e15, 0x157b: 0x7e35, + 0x157c: 0x7df5, 0x157d: 0x7e55, 0x157e: 0x7e75, 0x157f: 0x7e55, // Block 0x56, offset 0x1580 - 0x1580: 0xb2f1, 0x1581: 0xb309, 0x1582: 0xb309, 0x1583: 0xb309, 0x1584: 0xb309, 0x1585: 0xb321, - 0x1586: 0xb321, 0x1587: 0xb321, 0x1588: 0xb321, 0x1589: 0xb339, 0x158a: 0xb339, 0x158b: 0xb339, - 0x158c: 0xb339, 0x158d: 0xb351, 0x158e: 0xb351, 0x158f: 0xb351, 0x1590: 0xb351, 0x1591: 0xb369, - 0x1592: 0xb369, 0x1593: 0xb369, 0x1594: 0xb369, 0x1595: 0xb381, 0x1596: 0xb381, 0x1597: 0xb381, - 0x1598: 0xb381, 0x1599: 0xb399, 0x159a: 0xb399, 0x159b: 0xb399, 0x159c: 0xb399, 0x159d: 0xb3b1, - 0x159e: 0xb3b1, 0x159f: 0xb3b1, 0x15a0: 0xb3b1, 0x15a1: 0xb3c9, 0x15a2: 0xb3c9, 0x15a3: 0xb3c9, - 0x15a4: 0xb3c9, 0x15a5: 0xb3e1, 0x15a6: 0xb3e1, 0x15a7: 0xb3e1, 0x15a8: 0xb3e1, 0x15a9: 0xb3f9, - 0x15aa: 0xb3f9, 0x15ab: 0xb3f9, 0x15ac: 0xb3f9, 0x15ad: 0xb411, 0x15ae: 0xb411, 0x15af: 0x7ab1, - 0x15b0: 0x7ab1, 0x15b1: 0xb429, 0x15b2: 0xb429, 0x15b3: 0xb429, 0x15b4: 0xb429, 0x15b5: 0xb441, - 0x15b6: 0xb441, 0x15b7: 0xb469, 0x15b8: 0xb469, 0x15b9: 0xb491, 0x15ba: 0xb491, 0x15bb: 0xb4b9, - 0x15bc: 0xb4b9, 0x15bd: 0x0040, 0x15be: 0x0040, 0x15bf: 0x03c0, + 0x1580: 0x7e95, 0x1581: 0x7eb5, 0x1582: 0x7ed5, 0x1583: 0x7eb5, 0x1584: 0x7ef5, 0x1585: 0x0018, + 0x1586: 0x0018, 0x1587: 0xaf4a, 0x1588: 0xaf5a, 0x1589: 0x7f16, 0x158a: 0x7f36, 0x158b: 0x7f56, + 0x158c: 0x7f76, 0x158d: 0xaf1a, 0x158e: 0xaf1a, 0x158f: 0xaf1a, 0x1590: 0xaeda, 0x1591: 0x7f95, + 0x1592: 0x0040, 0x1593: 0x0040, 0x1594: 0x03c2, 0x1595: 0xaeea, 0x1596: 0xaf0a, 0x1597: 0xaefa, + 0x1598: 0x7fb5, 0x1599: 0x1fd2, 0x159a: 0x1fe2, 0x159b: 0xaf2a, 0x159c: 0xaf3a, 0x159d: 0x7e95, + 0x159e: 0x7ef5, 0x159f: 0xaf6a, 0x15a0: 0xaf7a, 0x15a1: 0xaf8a, 0x15a2: 0x1fb2, 0x15a3: 0xaf99, + 0x15a4: 0xafaa, 0x15a5: 0xafba, 0x15a6: 0x1fc2, 0x15a7: 0x0040, 0x15a8: 0xafca, 0x15a9: 0xafda, + 0x15aa: 0xafea, 0x15ab: 0xaffa, 0x15ac: 0x0040, 0x15ad: 0x0040, 0x15ae: 0x0040, 0x15af: 0x0040, + 0x15b0: 0x7fd6, 0x15b1: 0xb009, 0x15b2: 0x7ff6, 0x15b3: 0x0808, 0x15b4: 0x8016, 0x15b5: 0x0040, + 0x15b6: 0x8036, 0x15b7: 0xb031, 0x15b8: 0x8056, 0x15b9: 0xb059, 0x15ba: 0x8076, 0x15bb: 0xb081, + 0x15bc: 0x8096, 0x15bd: 0xb0a9, 0x15be: 0x80b6, 0x15bf: 0xb0d1, // Block 0x57, offset 0x15c0 - 0x15c0: 0x0040, 0x15c1: 0xaefa, 0x15c2: 0xb4e2, 0x15c3: 0xaf6a, 0x15c4: 0xafda, 0x15c5: 0xafea, - 0x15c6: 0xaf7a, 0x15c7: 0xb4f2, 0x15c8: 0x1fd2, 0x15c9: 0x1fe2, 0x15ca: 0xaf8a, 0x15cb: 0x1fb2, - 0x15cc: 0xaeda, 0x15cd: 0xaf99, 0x15ce: 0x29d1, 0x15cf: 0xb502, 0x15d0: 0x1f41, 0x15d1: 0x00c9, - 0x15d2: 0x0069, 0x15d3: 0x0079, 0x15d4: 0x1f51, 0x15d5: 0x1f61, 0x15d6: 0x1f71, 0x15d7: 0x1f81, - 0x15d8: 0x1f91, 0x15d9: 0x1fa1, 0x15da: 0xaeea, 0x15db: 0x03c2, 0x15dc: 0xafaa, 0x15dd: 0x1fc2, - 0x15de: 0xafba, 0x15df: 0xaf0a, 0x15e0: 0xaffa, 0x15e1: 0x0039, 0x15e2: 0x0ee9, 0x15e3: 0x1159, - 0x15e4: 0x0ef9, 0x15e5: 0x0f09, 0x15e6: 0x1199, 0x15e7: 0x0f31, 0x15e8: 0x0249, 0x15e9: 0x0f41, - 0x15ea: 0x0259, 0x15eb: 0x0f51, 0x15ec: 0x0359, 0x15ed: 0x0f61, 0x15ee: 0x0f71, 0x15ef: 0x00d9, - 0x15f0: 0x0f99, 0x15f1: 0x2039, 0x15f2: 0x0269, 0x15f3: 0x01d9, 0x15f4: 0x0fa9, 0x15f5: 0x0fb9, - 0x15f6: 0x1089, 0x15f7: 0x0279, 0x15f8: 0x0369, 0x15f9: 0x0289, 0x15fa: 0x13d1, 0x15fb: 0xaf4a, - 0x15fc: 0xafca, 0x15fd: 0xaf5a, 0x15fe: 0xb512, 0x15ff: 0xaf1a, + 0x15c0: 0xb0f9, 0x15c1: 0xb111, 0x15c2: 0xb111, 0x15c3: 0xb129, 0x15c4: 0xb129, 0x15c5: 0xb141, + 0x15c6: 0xb141, 0x15c7: 0xb159, 0x15c8: 0xb159, 0x15c9: 0xb171, 0x15ca: 0xb171, 0x15cb: 0xb171, + 0x15cc: 0xb171, 0x15cd: 0xb189, 0x15ce: 0xb189, 0x15cf: 0xb1a1, 0x15d0: 0xb1a1, 0x15d1: 0xb1a1, + 0x15d2: 0xb1a1, 0x15d3: 0xb1b9, 0x15d4: 0xb1b9, 0x15d5: 0xb1d1, 0x15d6: 0xb1d1, 0x15d7: 0xb1d1, + 0x15d8: 0xb1d1, 0x15d9: 0xb1e9, 0x15da: 0xb1e9, 0x15db: 0xb1e9, 0x15dc: 0xb1e9, 0x15dd: 0xb201, + 0x15de: 0xb201, 0x15df: 0xb201, 0x15e0: 0xb201, 0x15e1: 0xb219, 0x15e2: 0xb219, 0x15e3: 0xb219, + 0x15e4: 0xb219, 0x15e5: 0xb231, 0x15e6: 0xb231, 0x15e7: 0xb231, 0x15e8: 0xb231, 0x15e9: 0xb249, + 0x15ea: 0xb249, 0x15eb: 0xb261, 0x15ec: 0xb261, 0x15ed: 0xb279, 0x15ee: 0xb279, 0x15ef: 0xb291, + 0x15f0: 0xb291, 0x15f1: 0xb2a9, 0x15f2: 0xb2a9, 0x15f3: 0xb2a9, 0x15f4: 0xb2a9, 0x15f5: 0xb2c1, + 0x15f6: 0xb2c1, 0x15f7: 0xb2c1, 0x15f8: 0xb2c1, 0x15f9: 0xb2d9, 0x15fa: 0xb2d9, 0x15fb: 0xb2d9, + 0x15fc: 0xb2d9, 0x15fd: 0xb2f1, 0x15fe: 0xb2f1, 0x15ff: 0xb2f1, // Block 0x58, offset 0x1600 - 0x1600: 0x1caa, 0x1601: 0x0039, 0x1602: 0x0ee9, 0x1603: 0x1159, 0x1604: 0x0ef9, 0x1605: 0x0f09, - 0x1606: 0x1199, 0x1607: 0x0f31, 0x1608: 0x0249, 0x1609: 0x0f41, 0x160a: 0x0259, 0x160b: 0x0f51, - 0x160c: 0x0359, 0x160d: 0x0f61, 0x160e: 0x0f71, 0x160f: 0x00d9, 0x1610: 0x0f99, 0x1611: 0x2039, - 0x1612: 0x0269, 0x1613: 0x01d9, 0x1614: 0x0fa9, 0x1615: 0x0fb9, 0x1616: 0x1089, 0x1617: 0x0279, - 0x1618: 0x0369, 0x1619: 0x0289, 0x161a: 0x13d1, 0x161b: 0xaf2a, 0x161c: 0xb522, 0x161d: 0xaf3a, - 0x161e: 0xb532, 0x161f: 0x80d5, 0x1620: 0x80f5, 0x1621: 0x29d1, 0x1622: 0x8115, 0x1623: 0x8115, - 0x1624: 0x8135, 0x1625: 0x8155, 0x1626: 0x8175, 0x1627: 0x8195, 0x1628: 0x81b5, 0x1629: 0x81d5, - 0x162a: 0x81f5, 0x162b: 0x8215, 0x162c: 0x8235, 0x162d: 0x8255, 0x162e: 0x8275, 0x162f: 0x8295, - 0x1630: 0x82b5, 0x1631: 0x82d5, 0x1632: 0x82f5, 0x1633: 0x8315, 0x1634: 0x8335, 0x1635: 0x8355, - 0x1636: 0x8375, 0x1637: 0x8395, 0x1638: 0x83b5, 0x1639: 0x83d5, 0x163a: 0x83f5, 0x163b: 0x8415, - 0x163c: 0x81b5, 0x163d: 0x8435, 0x163e: 0x8455, 0x163f: 0x8215, + 0x1600: 0xb2f1, 0x1601: 0xb309, 0x1602: 0xb309, 0x1603: 0xb309, 0x1604: 0xb309, 0x1605: 0xb321, + 0x1606: 0xb321, 0x1607: 0xb321, 0x1608: 0xb321, 0x1609: 0xb339, 0x160a: 0xb339, 0x160b: 0xb339, + 0x160c: 0xb339, 0x160d: 0xb351, 0x160e: 0xb351, 0x160f: 0xb351, 0x1610: 0xb351, 0x1611: 0xb369, + 0x1612: 0xb369, 0x1613: 0xb369, 0x1614: 0xb369, 0x1615: 0xb381, 0x1616: 0xb381, 0x1617: 0xb381, + 0x1618: 0xb381, 0x1619: 0xb399, 0x161a: 0xb399, 0x161b: 0xb399, 0x161c: 0xb399, 0x161d: 0xb3b1, + 0x161e: 0xb3b1, 0x161f: 0xb3b1, 0x1620: 0xb3b1, 0x1621: 0xb3c9, 0x1622: 0xb3c9, 0x1623: 0xb3c9, + 0x1624: 0xb3c9, 0x1625: 0xb3e1, 0x1626: 0xb3e1, 0x1627: 0xb3e1, 0x1628: 0xb3e1, 0x1629: 0xb3f9, + 0x162a: 0xb3f9, 0x162b: 0xb3f9, 0x162c: 0xb3f9, 0x162d: 0xb411, 0x162e: 0xb411, 0x162f: 0x7ab1, + 0x1630: 0x7ab1, 0x1631: 0xb429, 0x1632: 0xb429, 0x1633: 0xb429, 0x1634: 0xb429, 0x1635: 0xb441, + 0x1636: 0xb441, 0x1637: 0xb469, 0x1638: 0xb469, 0x1639: 0xb491, 0x163a: 0xb491, 0x163b: 0xb4b9, + 0x163c: 0xb4b9, 0x163d: 0x0040, 0x163e: 0x0040, 0x163f: 0x03c0, // Block 0x59, offset 0x1640 - 0x1640: 0x8475, 0x1641: 0x8495, 0x1642: 0x84b5, 0x1643: 0x84d5, 0x1644: 0x84f5, 0x1645: 0x8515, - 0x1646: 0x8535, 0x1647: 0x8555, 0x1648: 0x84d5, 0x1649: 0x8575, 0x164a: 0x84d5, 0x164b: 0x8595, - 0x164c: 0x8595, 0x164d: 0x85b5, 0x164e: 0x85b5, 0x164f: 0x85d5, 0x1650: 0x8515, 0x1651: 0x85f5, - 0x1652: 0x8615, 0x1653: 0x85f5, 0x1654: 0x8635, 0x1655: 0x8615, 0x1656: 0x8655, 0x1657: 0x8655, - 0x1658: 0x8675, 0x1659: 0x8675, 0x165a: 0x8695, 0x165b: 0x8695, 0x165c: 0x8615, 0x165d: 0x8115, - 0x165e: 0x86b5, 0x165f: 0x86d5, 0x1660: 0x0040, 0x1661: 0x86f5, 0x1662: 0x8715, 0x1663: 0x8735, - 0x1664: 0x8755, 0x1665: 0x8735, 0x1666: 0x8775, 0x1667: 0x8795, 0x1668: 0x87b5, 0x1669: 0x87b5, - 0x166a: 0x87d5, 0x166b: 0x87d5, 0x166c: 0x87f5, 0x166d: 0x87f5, 0x166e: 0x87d5, 0x166f: 0x87d5, - 0x1670: 0x8815, 0x1671: 0x8835, 0x1672: 0x8855, 0x1673: 0x8875, 0x1674: 0x8895, 0x1675: 0x88b5, - 0x1676: 0x88b5, 0x1677: 0x88b5, 0x1678: 0x88d5, 0x1679: 0x88d5, 0x167a: 0x88d5, 0x167b: 0x88d5, - 0x167c: 0x87b5, 0x167d: 0x87b5, 0x167e: 0x87b5, 0x167f: 0x0040, + 0x1640: 0x0040, 0x1641: 0xaefa, 0x1642: 0xb4e2, 0x1643: 0xaf6a, 0x1644: 0xafda, 0x1645: 0xafea, + 0x1646: 0xaf7a, 0x1647: 0xb4f2, 0x1648: 0x1fd2, 0x1649: 0x1fe2, 0x164a: 0xaf8a, 0x164b: 0x1fb2, + 0x164c: 0xaeda, 0x164d: 0xaf99, 0x164e: 0x29d1, 0x164f: 0xb502, 0x1650: 0x1f41, 0x1651: 0x00c9, + 0x1652: 0x0069, 0x1653: 0x0079, 0x1654: 0x1f51, 0x1655: 0x1f61, 0x1656: 0x1f71, 0x1657: 0x1f81, + 0x1658: 0x1f91, 0x1659: 0x1fa1, 0x165a: 0xaeea, 0x165b: 0x03c2, 0x165c: 0xafaa, 0x165d: 0x1fc2, + 0x165e: 0xafba, 0x165f: 0xaf0a, 0x1660: 0xaffa, 0x1661: 0x0039, 0x1662: 0x0ee9, 0x1663: 0x1159, + 0x1664: 0x0ef9, 0x1665: 0x0f09, 0x1666: 0x1199, 0x1667: 0x0f31, 0x1668: 0x0249, 0x1669: 0x0f41, + 0x166a: 0x0259, 0x166b: 0x0f51, 0x166c: 0x0359, 0x166d: 0x0f61, 0x166e: 0x0f71, 0x166f: 0x00d9, + 0x1670: 0x0f99, 0x1671: 0x2039, 0x1672: 0x0269, 0x1673: 0x01d9, 0x1674: 0x0fa9, 0x1675: 0x0fb9, + 0x1676: 0x1089, 0x1677: 0x0279, 0x1678: 0x0369, 0x1679: 0x0289, 0x167a: 0x13d1, 0x167b: 0xaf4a, + 0x167c: 0xafca, 0x167d: 0xaf5a, 0x167e: 0xb512, 0x167f: 0xaf1a, // Block 0x5a, offset 0x1680 - 0x1680: 0x0040, 0x1681: 0x0040, 0x1682: 0x8715, 0x1683: 0x86f5, 0x1684: 0x88f5, 0x1685: 0x86f5, - 0x1686: 0x8715, 0x1687: 0x86f5, 0x1688: 0x0040, 0x1689: 0x0040, 0x168a: 0x8915, 0x168b: 0x8715, - 0x168c: 0x8935, 0x168d: 0x88f5, 0x168e: 0x8935, 0x168f: 0x8715, 0x1690: 0x0040, 0x1691: 0x0040, - 0x1692: 0x8955, 0x1693: 0x8975, 0x1694: 0x8875, 0x1695: 0x8935, 0x1696: 0x88f5, 0x1697: 0x8935, - 0x1698: 0x0040, 0x1699: 0x0040, 0x169a: 0x8995, 0x169b: 0x89b5, 0x169c: 0x8995, 0x169d: 0x0040, - 0x169e: 0x0040, 0x169f: 0x0040, 0x16a0: 0xb541, 0x16a1: 0xb559, 0x16a2: 0xb571, 0x16a3: 0x89d6, - 0x16a4: 0xb589, 0x16a5: 0xb5a1, 0x16a6: 0x89f5, 0x16a7: 0x0040, 0x16a8: 0x8a15, 0x16a9: 0x8a35, - 0x16aa: 0x8a55, 0x16ab: 0x8a35, 0x16ac: 0x8a75, 0x16ad: 0x8a95, 0x16ae: 0x8ab5, 0x16af: 0x0040, - 0x16b0: 0x0040, 0x16b1: 0x0040, 0x16b2: 0x0040, 0x16b3: 0x0040, 0x16b4: 0x0040, 0x16b5: 0x0040, - 0x16b6: 0x0040, 0x16b7: 0x0040, 0x16b8: 0x0040, 0x16b9: 0x0340, 0x16ba: 0x0340, 0x16bb: 0x0340, - 0x16bc: 0x0040, 0x16bd: 0x0040, 0x16be: 0x0040, 0x16bf: 0x0040, + 0x1680: 0x1caa, 0x1681: 0x0039, 0x1682: 0x0ee9, 0x1683: 0x1159, 0x1684: 0x0ef9, 0x1685: 0x0f09, + 0x1686: 0x1199, 0x1687: 0x0f31, 0x1688: 0x0249, 0x1689: 0x0f41, 0x168a: 0x0259, 0x168b: 0x0f51, + 0x168c: 0x0359, 0x168d: 0x0f61, 0x168e: 0x0f71, 0x168f: 0x00d9, 0x1690: 0x0f99, 0x1691: 0x2039, + 0x1692: 0x0269, 0x1693: 0x01d9, 0x1694: 0x0fa9, 0x1695: 0x0fb9, 0x1696: 0x1089, 0x1697: 0x0279, + 0x1698: 0x0369, 0x1699: 0x0289, 0x169a: 0x13d1, 0x169b: 0xaf2a, 0x169c: 0xb522, 0x169d: 0xaf3a, + 0x169e: 0xb532, 0x169f: 0x80d5, 0x16a0: 0x80f5, 0x16a1: 0x29d1, 0x16a2: 0x8115, 0x16a3: 0x8115, + 0x16a4: 0x8135, 0x16a5: 0x8155, 0x16a6: 0x8175, 0x16a7: 0x8195, 0x16a8: 0x81b5, 0x16a9: 0x81d5, + 0x16aa: 0x81f5, 0x16ab: 0x8215, 0x16ac: 0x8235, 0x16ad: 0x8255, 0x16ae: 0x8275, 0x16af: 0x8295, + 0x16b0: 0x82b5, 0x16b1: 0x82d5, 0x16b2: 0x82f5, 0x16b3: 0x8315, 0x16b4: 0x8335, 0x16b5: 0x8355, + 0x16b6: 0x8375, 0x16b7: 0x8395, 0x16b8: 0x83b5, 0x16b9: 0x83d5, 0x16ba: 0x83f5, 0x16bb: 0x8415, + 0x16bc: 0x81b5, 0x16bd: 0x8435, 0x16be: 0x8455, 0x16bf: 0x8215, // Block 0x5b, offset 0x16c0 - 0x16c0: 0x0208, 0x16c1: 0x0208, 0x16c2: 0x0208, 0x16c3: 0x0208, 0x16c4: 0x0208, 0x16c5: 0x0408, - 0x16c6: 0x0008, 0x16c7: 0x0408, 0x16c8: 0x0018, 0x16c9: 0x0408, 0x16ca: 0x0408, 0x16cb: 0x0008, - 0x16cc: 0x0008, 0x16cd: 0x0108, 0x16ce: 0x0408, 0x16cf: 0x0408, 0x16d0: 0x0408, 0x16d1: 0x0408, - 0x16d2: 0x0408, 0x16d3: 0x0208, 0x16d4: 0x0208, 0x16d5: 0x0208, 0x16d6: 0x0208, 0x16d7: 0x0108, - 0x16d8: 0x0208, 0x16d9: 0x0208, 0x16da: 0x0208, 0x16db: 0x0208, 0x16dc: 0x0208, 0x16dd: 0x0408, - 0x16de: 0x0208, 0x16df: 0x0208, 0x16e0: 0x0208, 0x16e1: 0x0408, 0x16e2: 0x0008, 0x16e3: 0x0008, - 0x16e4: 0x0408, 0x16e5: 0x1308, 0x16e6: 0x1308, 0x16e7: 0x0040, 0x16e8: 0x0040, 0x16e9: 0x0040, - 0x16ea: 0x0040, 0x16eb: 0x0218, 0x16ec: 0x0218, 0x16ed: 0x0218, 0x16ee: 0x0218, 0x16ef: 0x0418, - 0x16f0: 0x0018, 0x16f1: 0x0018, 0x16f2: 0x0018, 0x16f3: 0x0018, 0x16f4: 0x0018, 0x16f5: 0x0018, - 0x16f6: 0x0018, 0x16f7: 0x0040, 0x16f8: 0x0040, 0x16f9: 0x0040, 0x16fa: 0x0040, 0x16fb: 0x0040, - 0x16fc: 0x0040, 0x16fd: 0x0040, 0x16fe: 0x0040, 0x16ff: 0x0040, + 0x16c0: 0x8475, 0x16c1: 0x8495, 0x16c2: 0x84b5, 0x16c3: 0x84d5, 0x16c4: 0x84f5, 0x16c5: 0x8515, + 0x16c6: 0x8535, 0x16c7: 0x8555, 0x16c8: 0x84d5, 0x16c9: 0x8575, 0x16ca: 0x84d5, 0x16cb: 0x8595, + 0x16cc: 0x8595, 0x16cd: 0x85b5, 0x16ce: 0x85b5, 0x16cf: 0x85d5, 0x16d0: 0x8515, 0x16d1: 0x85f5, + 0x16d2: 0x8615, 0x16d3: 0x85f5, 0x16d4: 0x8635, 0x16d5: 0x8615, 0x16d6: 0x8655, 0x16d7: 0x8655, + 0x16d8: 0x8675, 0x16d9: 0x8675, 0x16da: 0x8695, 0x16db: 0x8695, 0x16dc: 0x8615, 0x16dd: 0x8115, + 0x16de: 0x86b5, 0x16df: 0x86d5, 0x16e0: 0x0040, 0x16e1: 0x86f5, 0x16e2: 0x8715, 0x16e3: 0x8735, + 0x16e4: 0x8755, 0x16e5: 0x8735, 0x16e6: 0x8775, 0x16e7: 0x8795, 0x16e8: 0x87b5, 0x16e9: 0x87b5, + 0x16ea: 0x87d5, 0x16eb: 0x87d5, 0x16ec: 0x87f5, 0x16ed: 0x87f5, 0x16ee: 0x87d5, 0x16ef: 0x87d5, + 0x16f0: 0x8815, 0x16f1: 0x8835, 0x16f2: 0x8855, 0x16f3: 0x8875, 0x16f4: 0x8895, 0x16f5: 0x88b5, + 0x16f6: 0x88b5, 0x16f7: 0x88b5, 0x16f8: 0x88d5, 0x16f9: 0x88d5, 0x16fa: 0x88d5, 0x16fb: 0x88d5, + 0x16fc: 0x87b5, 0x16fd: 0x87b5, 0x16fe: 0x87b5, 0x16ff: 0x0040, // Block 0x5c, offset 0x1700 - 0x1700: 0x0208, 0x1701: 0x0408, 0x1702: 0x0208, 0x1703: 0x0408, 0x1704: 0x0408, 0x1705: 0x0408, - 0x1706: 0x0208, 0x1707: 0x0208, 0x1708: 0x0208, 0x1709: 0x0408, 0x170a: 0x0208, 0x170b: 0x0208, - 0x170c: 0x0408, 0x170d: 0x0208, 0x170e: 0x0408, 0x170f: 0x0408, 0x1710: 0x0208, 0x1711: 0x0408, - 0x1712: 0x0040, 0x1713: 0x0040, 0x1714: 0x0040, 0x1715: 0x0040, 0x1716: 0x0040, 0x1717: 0x0040, - 0x1718: 0x0040, 0x1719: 0x0018, 0x171a: 0x0018, 0x171b: 0x0018, 0x171c: 0x0018, 0x171d: 0x0040, - 0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0x0040, 0x1721: 0x0040, 0x1722: 0x0040, 0x1723: 0x0040, - 0x1724: 0x0040, 0x1725: 0x0040, 0x1726: 0x0040, 0x1727: 0x0040, 0x1728: 0x0040, 0x1729: 0x0418, - 0x172a: 0x0418, 0x172b: 0x0418, 0x172c: 0x0418, 0x172d: 0x0218, 0x172e: 0x0218, 0x172f: 0x0018, + 0x1700: 0x0040, 0x1701: 0x0040, 0x1702: 0x8715, 0x1703: 0x86f5, 0x1704: 0x88f5, 0x1705: 0x86f5, + 0x1706: 0x8715, 0x1707: 0x86f5, 0x1708: 0x0040, 0x1709: 0x0040, 0x170a: 0x8915, 0x170b: 0x8715, + 0x170c: 0x8935, 0x170d: 0x88f5, 0x170e: 0x8935, 0x170f: 0x8715, 0x1710: 0x0040, 0x1711: 0x0040, + 0x1712: 0x8955, 0x1713: 0x8975, 0x1714: 0x8875, 0x1715: 0x8935, 0x1716: 0x88f5, 0x1717: 0x8935, + 0x1718: 0x0040, 0x1719: 0x0040, 0x171a: 0x8995, 0x171b: 0x89b5, 0x171c: 0x8995, 0x171d: 0x0040, + 0x171e: 0x0040, 0x171f: 0x0040, 0x1720: 0xb541, 0x1721: 0xb559, 0x1722: 0xb571, 0x1723: 0x89d6, + 0x1724: 0xb589, 0x1725: 0xb5a1, 0x1726: 0x89f5, 0x1727: 0x0040, 0x1728: 0x8a15, 0x1729: 0x8a35, + 0x172a: 0x8a55, 0x172b: 0x8a35, 0x172c: 0x8a75, 0x172d: 0x8a95, 0x172e: 0x8ab5, 0x172f: 0x0040, 0x1730: 0x0040, 0x1731: 0x0040, 0x1732: 0x0040, 0x1733: 0x0040, 0x1734: 0x0040, 0x1735: 0x0040, - 0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0040, 0x173a: 0x0040, 0x173b: 0x0040, + 0x1736: 0x0040, 0x1737: 0x0040, 0x1738: 0x0040, 0x1739: 0x0340, 0x173a: 0x0340, 0x173b: 0x0340, 0x173c: 0x0040, 0x173d: 0x0040, 0x173e: 0x0040, 0x173f: 0x0040, // Block 0x5d, offset 0x1740 - 0x1740: 0x1308, 0x1741: 0x1308, 0x1742: 0x1008, 0x1743: 0x1008, 0x1744: 0x0040, 0x1745: 0x0008, - 0x1746: 0x0008, 0x1747: 0x0008, 0x1748: 0x0008, 0x1749: 0x0008, 0x174a: 0x0008, 0x174b: 0x0008, - 0x174c: 0x0008, 0x174d: 0x0040, 0x174e: 0x0040, 0x174f: 0x0008, 0x1750: 0x0008, 0x1751: 0x0040, - 0x1752: 0x0040, 0x1753: 0x0008, 0x1754: 0x0008, 0x1755: 0x0008, 0x1756: 0x0008, 0x1757: 0x0008, - 0x1758: 0x0008, 0x1759: 0x0008, 0x175a: 0x0008, 0x175b: 0x0008, 0x175c: 0x0008, 0x175d: 0x0008, - 0x175e: 0x0008, 0x175f: 0x0008, 0x1760: 0x0008, 0x1761: 0x0008, 0x1762: 0x0008, 0x1763: 0x0008, - 0x1764: 0x0008, 0x1765: 0x0008, 0x1766: 0x0008, 0x1767: 0x0008, 0x1768: 0x0008, 0x1769: 0x0040, - 0x176a: 0x0008, 0x176b: 0x0008, 0x176c: 0x0008, 0x176d: 0x0008, 0x176e: 0x0008, 0x176f: 0x0008, - 0x1770: 0x0008, 0x1771: 0x0040, 0x1772: 0x0008, 0x1773: 0x0008, 0x1774: 0x0040, 0x1775: 0x0008, - 0x1776: 0x0008, 0x1777: 0x0008, 0x1778: 0x0008, 0x1779: 0x0008, 0x177a: 0x0040, 0x177b: 0x0040, - 0x177c: 0x1308, 0x177d: 0x0008, 0x177e: 0x1008, 0x177f: 0x1008, + 0x1740: 0x0a08, 0x1741: 0x0a08, 0x1742: 0x0a08, 0x1743: 0x0a08, 0x1744: 0x0a08, 0x1745: 0x0c08, + 0x1746: 0x0808, 0x1747: 0x0c08, 0x1748: 0x0818, 0x1749: 0x0c08, 0x174a: 0x0c08, 0x174b: 0x0808, + 0x174c: 0x0808, 0x174d: 0x0908, 0x174e: 0x0c08, 0x174f: 0x0c08, 0x1750: 0x0c08, 0x1751: 0x0c08, + 0x1752: 0x0c08, 0x1753: 0x0a08, 0x1754: 0x0a08, 0x1755: 0x0a08, 0x1756: 0x0a08, 0x1757: 0x0908, + 0x1758: 0x0a08, 0x1759: 0x0a08, 0x175a: 0x0a08, 0x175b: 0x0a08, 0x175c: 0x0a08, 0x175d: 0x0c08, + 0x175e: 0x0a08, 0x175f: 0x0a08, 0x1760: 0x0a08, 0x1761: 0x0c08, 0x1762: 0x0808, 0x1763: 0x0808, + 0x1764: 0x0c08, 0x1765: 0x3308, 0x1766: 0x3308, 0x1767: 0x0040, 0x1768: 0x0040, 0x1769: 0x0040, + 0x176a: 0x0040, 0x176b: 0x0a18, 0x176c: 0x0a18, 0x176d: 0x0a18, 0x176e: 0x0a18, 0x176f: 0x0c18, + 0x1770: 0x0818, 0x1771: 0x0818, 0x1772: 0x0818, 0x1773: 0x0818, 0x1774: 0x0818, 0x1775: 0x0818, + 0x1776: 0x0818, 0x1777: 0x0040, 0x1778: 0x0040, 0x1779: 0x0040, 0x177a: 0x0040, 0x177b: 0x0040, + 0x177c: 0x0040, 0x177d: 0x0040, 0x177e: 0x0040, 0x177f: 0x0040, // Block 0x5e, offset 0x1780 - 0x1780: 0x1308, 0x1781: 0x1008, 0x1782: 0x1008, 0x1783: 0x1008, 0x1784: 0x1008, 0x1785: 0x0040, - 0x1786: 0x0040, 0x1787: 0x1008, 0x1788: 0x1008, 0x1789: 0x0040, 0x178a: 0x0040, 0x178b: 0x1008, - 0x178c: 0x1008, 0x178d: 0x1808, 0x178e: 0x0040, 0x178f: 0x0040, 0x1790: 0x0008, 0x1791: 0x0040, - 0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x1008, - 0x1798: 0x0040, 0x1799: 0x0040, 0x179a: 0x0040, 0x179b: 0x0040, 0x179c: 0x0040, 0x179d: 0x0008, - 0x179e: 0x0008, 0x179f: 0x0008, 0x17a0: 0x0008, 0x17a1: 0x0008, 0x17a2: 0x1008, 0x17a3: 0x1008, - 0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x1308, 0x17a7: 0x1308, 0x17a8: 0x1308, 0x17a9: 0x1308, - 0x17aa: 0x1308, 0x17ab: 0x1308, 0x17ac: 0x1308, 0x17ad: 0x0040, 0x17ae: 0x0040, 0x17af: 0x0040, - 0x17b0: 0x1308, 0x17b1: 0x1308, 0x17b2: 0x1308, 0x17b3: 0x1308, 0x17b4: 0x1308, 0x17b5: 0x0040, + 0x1780: 0x0a08, 0x1781: 0x0c08, 0x1782: 0x0a08, 0x1783: 0x0c08, 0x1784: 0x0c08, 0x1785: 0x0c08, + 0x1786: 0x0a08, 0x1787: 0x0a08, 0x1788: 0x0a08, 0x1789: 0x0c08, 0x178a: 0x0a08, 0x178b: 0x0a08, + 0x178c: 0x0c08, 0x178d: 0x0a08, 0x178e: 0x0c08, 0x178f: 0x0c08, 0x1790: 0x0a08, 0x1791: 0x0c08, + 0x1792: 0x0040, 0x1793: 0x0040, 0x1794: 0x0040, 0x1795: 0x0040, 0x1796: 0x0040, 0x1797: 0x0040, + 0x1798: 0x0040, 0x1799: 0x0818, 0x179a: 0x0818, 0x179b: 0x0818, 0x179c: 0x0818, 0x179d: 0x0040, + 0x179e: 0x0040, 0x179f: 0x0040, 0x17a0: 0x0040, 0x17a1: 0x0040, 0x17a2: 0x0040, 0x17a3: 0x0040, + 0x17a4: 0x0040, 0x17a5: 0x0040, 0x17a6: 0x0040, 0x17a7: 0x0040, 0x17a8: 0x0040, 0x17a9: 0x0c18, + 0x17aa: 0x0c18, 0x17ab: 0x0c18, 0x17ac: 0x0c18, 0x17ad: 0x0a18, 0x17ae: 0x0a18, 0x17af: 0x0818, + 0x17b0: 0x0040, 0x17b1: 0x0040, 0x17b2: 0x0040, 0x17b3: 0x0040, 0x17b4: 0x0040, 0x17b5: 0x0040, 0x17b6: 0x0040, 0x17b7: 0x0040, 0x17b8: 0x0040, 0x17b9: 0x0040, 0x17ba: 0x0040, 0x17bb: 0x0040, 0x17bc: 0x0040, 0x17bd: 0x0040, 0x17be: 0x0040, 0x17bf: 0x0040, // Block 0x5f, offset 0x17c0 - 0x17c0: 0x0039, 0x17c1: 0x0ee9, 0x17c2: 0x1159, 0x17c3: 0x0ef9, 0x17c4: 0x0f09, 0x17c5: 0x1199, - 0x17c6: 0x0f31, 0x17c7: 0x0249, 0x17c8: 0x0f41, 0x17c9: 0x0259, 0x17ca: 0x0f51, 0x17cb: 0x0359, - 0x17cc: 0x0f61, 0x17cd: 0x0f71, 0x17ce: 0x00d9, 0x17cf: 0x0f99, 0x17d0: 0x2039, 0x17d1: 0x0269, - 0x17d2: 0x01d9, 0x17d3: 0x0fa9, 0x17d4: 0x0fb9, 0x17d5: 0x1089, 0x17d6: 0x0279, 0x17d7: 0x0369, - 0x17d8: 0x0289, 0x17d9: 0x13d1, 0x17da: 0x0039, 0x17db: 0x0ee9, 0x17dc: 0x1159, 0x17dd: 0x0ef9, - 0x17de: 0x0f09, 0x17df: 0x1199, 0x17e0: 0x0f31, 0x17e1: 0x0249, 0x17e2: 0x0f41, 0x17e3: 0x0259, - 0x17e4: 0x0f51, 0x17e5: 0x0359, 0x17e6: 0x0f61, 0x17e7: 0x0f71, 0x17e8: 0x00d9, 0x17e9: 0x0f99, - 0x17ea: 0x2039, 0x17eb: 0x0269, 0x17ec: 0x01d9, 0x17ed: 0x0fa9, 0x17ee: 0x0fb9, 0x17ef: 0x1089, - 0x17f0: 0x0279, 0x17f1: 0x0369, 0x17f2: 0x0289, 0x17f3: 0x13d1, 0x17f4: 0x0039, 0x17f5: 0x0ee9, - 0x17f6: 0x1159, 0x17f7: 0x0ef9, 0x17f8: 0x0f09, 0x17f9: 0x1199, 0x17fa: 0x0f31, 0x17fb: 0x0249, - 0x17fc: 0x0f41, 0x17fd: 0x0259, 0x17fe: 0x0f51, 0x17ff: 0x0359, + 0x17c0: 0x3308, 0x17c1: 0x3308, 0x17c2: 0x3008, 0x17c3: 0x3008, 0x17c4: 0x0040, 0x17c5: 0x0008, + 0x17c6: 0x0008, 0x17c7: 0x0008, 0x17c8: 0x0008, 0x17c9: 0x0008, 0x17ca: 0x0008, 0x17cb: 0x0008, + 0x17cc: 0x0008, 0x17cd: 0x0040, 0x17ce: 0x0040, 0x17cf: 0x0008, 0x17d0: 0x0008, 0x17d1: 0x0040, + 0x17d2: 0x0040, 0x17d3: 0x0008, 0x17d4: 0x0008, 0x17d5: 0x0008, 0x17d6: 0x0008, 0x17d7: 0x0008, + 0x17d8: 0x0008, 0x17d9: 0x0008, 0x17da: 0x0008, 0x17db: 0x0008, 0x17dc: 0x0008, 0x17dd: 0x0008, + 0x17de: 0x0008, 0x17df: 0x0008, 0x17e0: 0x0008, 0x17e1: 0x0008, 0x17e2: 0x0008, 0x17e3: 0x0008, + 0x17e4: 0x0008, 0x17e5: 0x0008, 0x17e6: 0x0008, 0x17e7: 0x0008, 0x17e8: 0x0008, 0x17e9: 0x0040, + 0x17ea: 0x0008, 0x17eb: 0x0008, 0x17ec: 0x0008, 0x17ed: 0x0008, 0x17ee: 0x0008, 0x17ef: 0x0008, + 0x17f0: 0x0008, 0x17f1: 0x0040, 0x17f2: 0x0008, 0x17f3: 0x0008, 0x17f4: 0x0040, 0x17f5: 0x0008, + 0x17f6: 0x0008, 0x17f7: 0x0008, 0x17f8: 0x0008, 0x17f9: 0x0008, 0x17fa: 0x0040, 0x17fb: 0x0040, + 0x17fc: 0x3308, 0x17fd: 0x0008, 0x17fe: 0x3008, 0x17ff: 0x3008, // Block 0x60, offset 0x1800 - 0x1800: 0x0f61, 0x1801: 0x0f71, 0x1802: 0x00d9, 0x1803: 0x0f99, 0x1804: 0x2039, 0x1805: 0x0269, - 0x1806: 0x01d9, 0x1807: 0x0fa9, 0x1808: 0x0fb9, 0x1809: 0x1089, 0x180a: 0x0279, 0x180b: 0x0369, - 0x180c: 0x0289, 0x180d: 0x13d1, 0x180e: 0x0039, 0x180f: 0x0ee9, 0x1810: 0x1159, 0x1811: 0x0ef9, - 0x1812: 0x0f09, 0x1813: 0x1199, 0x1814: 0x0f31, 0x1815: 0x0040, 0x1816: 0x0f41, 0x1817: 0x0259, - 0x1818: 0x0f51, 0x1819: 0x0359, 0x181a: 0x0f61, 0x181b: 0x0f71, 0x181c: 0x00d9, 0x181d: 0x0f99, - 0x181e: 0x2039, 0x181f: 0x0269, 0x1820: 0x01d9, 0x1821: 0x0fa9, 0x1822: 0x0fb9, 0x1823: 0x1089, - 0x1824: 0x0279, 0x1825: 0x0369, 0x1826: 0x0289, 0x1827: 0x13d1, 0x1828: 0x0039, 0x1829: 0x0ee9, - 0x182a: 0x1159, 0x182b: 0x0ef9, 0x182c: 0x0f09, 0x182d: 0x1199, 0x182e: 0x0f31, 0x182f: 0x0249, - 0x1830: 0x0f41, 0x1831: 0x0259, 0x1832: 0x0f51, 0x1833: 0x0359, 0x1834: 0x0f61, 0x1835: 0x0f71, - 0x1836: 0x00d9, 0x1837: 0x0f99, 0x1838: 0x2039, 0x1839: 0x0269, 0x183a: 0x01d9, 0x183b: 0x0fa9, - 0x183c: 0x0fb9, 0x183d: 0x1089, 0x183e: 0x0279, 0x183f: 0x0369, + 0x1800: 0x3308, 0x1801: 0x3008, 0x1802: 0x3008, 0x1803: 0x3008, 0x1804: 0x3008, 0x1805: 0x0040, + 0x1806: 0x0040, 0x1807: 0x3008, 0x1808: 0x3008, 0x1809: 0x0040, 0x180a: 0x0040, 0x180b: 0x3008, + 0x180c: 0x3008, 0x180d: 0x3808, 0x180e: 0x0040, 0x180f: 0x0040, 0x1810: 0x0008, 0x1811: 0x0040, + 0x1812: 0x0040, 0x1813: 0x0040, 0x1814: 0x0040, 0x1815: 0x0040, 0x1816: 0x0040, 0x1817: 0x3008, + 0x1818: 0x0040, 0x1819: 0x0040, 0x181a: 0x0040, 0x181b: 0x0040, 0x181c: 0x0040, 0x181d: 0x0008, + 0x181e: 0x0008, 0x181f: 0x0008, 0x1820: 0x0008, 0x1821: 0x0008, 0x1822: 0x3008, 0x1823: 0x3008, + 0x1824: 0x0040, 0x1825: 0x0040, 0x1826: 0x3308, 0x1827: 0x3308, 0x1828: 0x3308, 0x1829: 0x3308, + 0x182a: 0x3308, 0x182b: 0x3308, 0x182c: 0x3308, 0x182d: 0x0040, 0x182e: 0x0040, 0x182f: 0x0040, + 0x1830: 0x3308, 0x1831: 0x3308, 0x1832: 0x3308, 0x1833: 0x3308, 0x1834: 0x3308, 0x1835: 0x0040, + 0x1836: 0x0040, 0x1837: 0x0040, 0x1838: 0x0040, 0x1839: 0x0040, 0x183a: 0x0040, 0x183b: 0x0040, + 0x183c: 0x0040, 0x183d: 0x0040, 0x183e: 0x0040, 0x183f: 0x0040, // Block 0x61, offset 0x1840 - 0x1840: 0x0289, 0x1841: 0x13d1, 0x1842: 0x0039, 0x1843: 0x0ee9, 0x1844: 0x1159, 0x1845: 0x0ef9, - 0x1846: 0x0f09, 0x1847: 0x1199, 0x1848: 0x0f31, 0x1849: 0x0249, 0x184a: 0x0f41, 0x184b: 0x0259, - 0x184c: 0x0f51, 0x184d: 0x0359, 0x184e: 0x0f61, 0x184f: 0x0f71, 0x1850: 0x00d9, 0x1851: 0x0f99, - 0x1852: 0x2039, 0x1853: 0x0269, 0x1854: 0x01d9, 0x1855: 0x0fa9, 0x1856: 0x0fb9, 0x1857: 0x1089, - 0x1858: 0x0279, 0x1859: 0x0369, 0x185a: 0x0289, 0x185b: 0x13d1, 0x185c: 0x0039, 0x185d: 0x0040, - 0x185e: 0x1159, 0x185f: 0x0ef9, 0x1860: 0x0040, 0x1861: 0x0040, 0x1862: 0x0f31, 0x1863: 0x0040, - 0x1864: 0x0040, 0x1865: 0x0259, 0x1866: 0x0f51, 0x1867: 0x0040, 0x1868: 0x0040, 0x1869: 0x0f71, - 0x186a: 0x00d9, 0x186b: 0x0f99, 0x186c: 0x2039, 0x186d: 0x0040, 0x186e: 0x01d9, 0x186f: 0x0fa9, - 0x1870: 0x0fb9, 0x1871: 0x1089, 0x1872: 0x0279, 0x1873: 0x0369, 0x1874: 0x0289, 0x1875: 0x13d1, - 0x1876: 0x0039, 0x1877: 0x0ee9, 0x1878: 0x1159, 0x1879: 0x0ef9, 0x187a: 0x0040, 0x187b: 0x1199, - 0x187c: 0x0040, 0x187d: 0x0249, 0x187e: 0x0f41, 0x187f: 0x0259, + 0x1840: 0x0039, 0x1841: 0x0ee9, 0x1842: 0x1159, 0x1843: 0x0ef9, 0x1844: 0x0f09, 0x1845: 0x1199, + 0x1846: 0x0f31, 0x1847: 0x0249, 0x1848: 0x0f41, 0x1849: 0x0259, 0x184a: 0x0f51, 0x184b: 0x0359, + 0x184c: 0x0f61, 0x184d: 0x0f71, 0x184e: 0x00d9, 0x184f: 0x0f99, 0x1850: 0x2039, 0x1851: 0x0269, + 0x1852: 0x01d9, 0x1853: 0x0fa9, 0x1854: 0x0fb9, 0x1855: 0x1089, 0x1856: 0x0279, 0x1857: 0x0369, + 0x1858: 0x0289, 0x1859: 0x13d1, 0x185a: 0x0039, 0x185b: 0x0ee9, 0x185c: 0x1159, 0x185d: 0x0ef9, + 0x185e: 0x0f09, 0x185f: 0x1199, 0x1860: 0x0f31, 0x1861: 0x0249, 0x1862: 0x0f41, 0x1863: 0x0259, + 0x1864: 0x0f51, 0x1865: 0x0359, 0x1866: 0x0f61, 0x1867: 0x0f71, 0x1868: 0x00d9, 0x1869: 0x0f99, + 0x186a: 0x2039, 0x186b: 0x0269, 0x186c: 0x01d9, 0x186d: 0x0fa9, 0x186e: 0x0fb9, 0x186f: 0x1089, + 0x1870: 0x0279, 0x1871: 0x0369, 0x1872: 0x0289, 0x1873: 0x13d1, 0x1874: 0x0039, 0x1875: 0x0ee9, + 0x1876: 0x1159, 0x1877: 0x0ef9, 0x1878: 0x0f09, 0x1879: 0x1199, 0x187a: 0x0f31, 0x187b: 0x0249, + 0x187c: 0x0f41, 0x187d: 0x0259, 0x187e: 0x0f51, 0x187f: 0x0359, // Block 0x62, offset 0x1880 - 0x1880: 0x0f51, 0x1881: 0x0359, 0x1882: 0x0f61, 0x1883: 0x0f71, 0x1884: 0x0040, 0x1885: 0x0f99, - 0x1886: 0x2039, 0x1887: 0x0269, 0x1888: 0x01d9, 0x1889: 0x0fa9, 0x188a: 0x0fb9, 0x188b: 0x1089, - 0x188c: 0x0279, 0x188d: 0x0369, 0x188e: 0x0289, 0x188f: 0x13d1, 0x1890: 0x0039, 0x1891: 0x0ee9, - 0x1892: 0x1159, 0x1893: 0x0ef9, 0x1894: 0x0f09, 0x1895: 0x1199, 0x1896: 0x0f31, 0x1897: 0x0249, - 0x1898: 0x0f41, 0x1899: 0x0259, 0x189a: 0x0f51, 0x189b: 0x0359, 0x189c: 0x0f61, 0x189d: 0x0f71, - 0x189e: 0x00d9, 0x189f: 0x0f99, 0x18a0: 0x2039, 0x18a1: 0x0269, 0x18a2: 0x01d9, 0x18a3: 0x0fa9, - 0x18a4: 0x0fb9, 0x18a5: 0x1089, 0x18a6: 0x0279, 0x18a7: 0x0369, 0x18a8: 0x0289, 0x18a9: 0x13d1, - 0x18aa: 0x0039, 0x18ab: 0x0ee9, 0x18ac: 0x1159, 0x18ad: 0x0ef9, 0x18ae: 0x0f09, 0x18af: 0x1199, - 0x18b0: 0x0f31, 0x18b1: 0x0249, 0x18b2: 0x0f41, 0x18b3: 0x0259, 0x18b4: 0x0f51, 0x18b5: 0x0359, - 0x18b6: 0x0f61, 0x18b7: 0x0f71, 0x18b8: 0x00d9, 0x18b9: 0x0f99, 0x18ba: 0x2039, 0x18bb: 0x0269, - 0x18bc: 0x01d9, 0x18bd: 0x0fa9, 0x18be: 0x0fb9, 0x18bf: 0x1089, + 0x1880: 0x0f61, 0x1881: 0x0f71, 0x1882: 0x00d9, 0x1883: 0x0f99, 0x1884: 0x2039, 0x1885: 0x0269, + 0x1886: 0x01d9, 0x1887: 0x0fa9, 0x1888: 0x0fb9, 0x1889: 0x1089, 0x188a: 0x0279, 0x188b: 0x0369, + 0x188c: 0x0289, 0x188d: 0x13d1, 0x188e: 0x0039, 0x188f: 0x0ee9, 0x1890: 0x1159, 0x1891: 0x0ef9, + 0x1892: 0x0f09, 0x1893: 0x1199, 0x1894: 0x0f31, 0x1895: 0x0040, 0x1896: 0x0f41, 0x1897: 0x0259, + 0x1898: 0x0f51, 0x1899: 0x0359, 0x189a: 0x0f61, 0x189b: 0x0f71, 0x189c: 0x00d9, 0x189d: 0x0f99, + 0x189e: 0x2039, 0x189f: 0x0269, 0x18a0: 0x01d9, 0x18a1: 0x0fa9, 0x18a2: 0x0fb9, 0x18a3: 0x1089, + 0x18a4: 0x0279, 0x18a5: 0x0369, 0x18a6: 0x0289, 0x18a7: 0x13d1, 0x18a8: 0x0039, 0x18a9: 0x0ee9, + 0x18aa: 0x1159, 0x18ab: 0x0ef9, 0x18ac: 0x0f09, 0x18ad: 0x1199, 0x18ae: 0x0f31, 0x18af: 0x0249, + 0x18b0: 0x0f41, 0x18b1: 0x0259, 0x18b2: 0x0f51, 0x18b3: 0x0359, 0x18b4: 0x0f61, 0x18b5: 0x0f71, + 0x18b6: 0x00d9, 0x18b7: 0x0f99, 0x18b8: 0x2039, 0x18b9: 0x0269, 0x18ba: 0x01d9, 0x18bb: 0x0fa9, + 0x18bc: 0x0fb9, 0x18bd: 0x1089, 0x18be: 0x0279, 0x18bf: 0x0369, // Block 0x63, offset 0x18c0 - 0x18c0: 0x0279, 0x18c1: 0x0369, 0x18c2: 0x0289, 0x18c3: 0x13d1, 0x18c4: 0x0039, 0x18c5: 0x0ee9, - 0x18c6: 0x0040, 0x18c7: 0x0ef9, 0x18c8: 0x0f09, 0x18c9: 0x1199, 0x18ca: 0x0f31, 0x18cb: 0x0040, - 0x18cc: 0x0040, 0x18cd: 0x0259, 0x18ce: 0x0f51, 0x18cf: 0x0359, 0x18d0: 0x0f61, 0x18d1: 0x0f71, - 0x18d2: 0x00d9, 0x18d3: 0x0f99, 0x18d4: 0x2039, 0x18d5: 0x0040, 0x18d6: 0x01d9, 0x18d7: 0x0fa9, - 0x18d8: 0x0fb9, 0x18d9: 0x1089, 0x18da: 0x0279, 0x18db: 0x0369, 0x18dc: 0x0289, 0x18dd: 0x0040, - 0x18de: 0x0039, 0x18df: 0x0ee9, 0x18e0: 0x1159, 0x18e1: 0x0ef9, 0x18e2: 0x0f09, 0x18e3: 0x1199, - 0x18e4: 0x0f31, 0x18e5: 0x0249, 0x18e6: 0x0f41, 0x18e7: 0x0259, 0x18e8: 0x0f51, 0x18e9: 0x0359, - 0x18ea: 0x0f61, 0x18eb: 0x0f71, 0x18ec: 0x00d9, 0x18ed: 0x0f99, 0x18ee: 0x2039, 0x18ef: 0x0269, - 0x18f0: 0x01d9, 0x18f1: 0x0fa9, 0x18f2: 0x0fb9, 0x18f3: 0x1089, 0x18f4: 0x0279, 0x18f5: 0x0369, - 0x18f6: 0x0289, 0x18f7: 0x13d1, 0x18f8: 0x0039, 0x18f9: 0x0ee9, 0x18fa: 0x0040, 0x18fb: 0x0ef9, - 0x18fc: 0x0f09, 0x18fd: 0x1199, 0x18fe: 0x0f31, 0x18ff: 0x0040, + 0x18c0: 0x0289, 0x18c1: 0x13d1, 0x18c2: 0x0039, 0x18c3: 0x0ee9, 0x18c4: 0x1159, 0x18c5: 0x0ef9, + 0x18c6: 0x0f09, 0x18c7: 0x1199, 0x18c8: 0x0f31, 0x18c9: 0x0249, 0x18ca: 0x0f41, 0x18cb: 0x0259, + 0x18cc: 0x0f51, 0x18cd: 0x0359, 0x18ce: 0x0f61, 0x18cf: 0x0f71, 0x18d0: 0x00d9, 0x18d1: 0x0f99, + 0x18d2: 0x2039, 0x18d3: 0x0269, 0x18d4: 0x01d9, 0x18d5: 0x0fa9, 0x18d6: 0x0fb9, 0x18d7: 0x1089, + 0x18d8: 0x0279, 0x18d9: 0x0369, 0x18da: 0x0289, 0x18db: 0x13d1, 0x18dc: 0x0039, 0x18dd: 0x0040, + 0x18de: 0x1159, 0x18df: 0x0ef9, 0x18e0: 0x0040, 0x18e1: 0x0040, 0x18e2: 0x0f31, 0x18e3: 0x0040, + 0x18e4: 0x0040, 0x18e5: 0x0259, 0x18e6: 0x0f51, 0x18e7: 0x0040, 0x18e8: 0x0040, 0x18e9: 0x0f71, + 0x18ea: 0x00d9, 0x18eb: 0x0f99, 0x18ec: 0x2039, 0x18ed: 0x0040, 0x18ee: 0x01d9, 0x18ef: 0x0fa9, + 0x18f0: 0x0fb9, 0x18f1: 0x1089, 0x18f2: 0x0279, 0x18f3: 0x0369, 0x18f4: 0x0289, 0x18f5: 0x13d1, + 0x18f6: 0x0039, 0x18f7: 0x0ee9, 0x18f8: 0x1159, 0x18f9: 0x0ef9, 0x18fa: 0x0040, 0x18fb: 0x1199, + 0x18fc: 0x0040, 0x18fd: 0x0249, 0x18fe: 0x0f41, 0x18ff: 0x0259, // Block 0x64, offset 0x1900 - 0x1900: 0x0f41, 0x1901: 0x0259, 0x1902: 0x0f51, 0x1903: 0x0359, 0x1904: 0x0f61, 0x1905: 0x0040, - 0x1906: 0x00d9, 0x1907: 0x0040, 0x1908: 0x0040, 0x1909: 0x0040, 0x190a: 0x01d9, 0x190b: 0x0fa9, - 0x190c: 0x0fb9, 0x190d: 0x1089, 0x190e: 0x0279, 0x190f: 0x0369, 0x1910: 0x0289, 0x1911: 0x0040, - 0x1912: 0x0039, 0x1913: 0x0ee9, 0x1914: 0x1159, 0x1915: 0x0ef9, 0x1916: 0x0f09, 0x1917: 0x1199, - 0x1918: 0x0f31, 0x1919: 0x0249, 0x191a: 0x0f41, 0x191b: 0x0259, 0x191c: 0x0f51, 0x191d: 0x0359, - 0x191e: 0x0f61, 0x191f: 0x0f71, 0x1920: 0x00d9, 0x1921: 0x0f99, 0x1922: 0x2039, 0x1923: 0x0269, - 0x1924: 0x01d9, 0x1925: 0x0fa9, 0x1926: 0x0fb9, 0x1927: 0x1089, 0x1928: 0x0279, 0x1929: 0x0369, - 0x192a: 0x0289, 0x192b: 0x13d1, 0x192c: 0x0039, 0x192d: 0x0ee9, 0x192e: 0x1159, 0x192f: 0x0ef9, - 0x1930: 0x0f09, 0x1931: 0x1199, 0x1932: 0x0f31, 0x1933: 0x0249, 0x1934: 0x0f41, 0x1935: 0x0259, - 0x1936: 0x0f51, 0x1937: 0x0359, 0x1938: 0x0f61, 0x1939: 0x0f71, 0x193a: 0x00d9, 0x193b: 0x0f99, - 0x193c: 0x2039, 0x193d: 0x0269, 0x193e: 0x01d9, 0x193f: 0x0fa9, + 0x1900: 0x0f51, 0x1901: 0x0359, 0x1902: 0x0f61, 0x1903: 0x0f71, 0x1904: 0x0040, 0x1905: 0x0f99, + 0x1906: 0x2039, 0x1907: 0x0269, 0x1908: 0x01d9, 0x1909: 0x0fa9, 0x190a: 0x0fb9, 0x190b: 0x1089, + 0x190c: 0x0279, 0x190d: 0x0369, 0x190e: 0x0289, 0x190f: 0x13d1, 0x1910: 0x0039, 0x1911: 0x0ee9, + 0x1912: 0x1159, 0x1913: 0x0ef9, 0x1914: 0x0f09, 0x1915: 0x1199, 0x1916: 0x0f31, 0x1917: 0x0249, + 0x1918: 0x0f41, 0x1919: 0x0259, 0x191a: 0x0f51, 0x191b: 0x0359, 0x191c: 0x0f61, 0x191d: 0x0f71, + 0x191e: 0x00d9, 0x191f: 0x0f99, 0x1920: 0x2039, 0x1921: 0x0269, 0x1922: 0x01d9, 0x1923: 0x0fa9, + 0x1924: 0x0fb9, 0x1925: 0x1089, 0x1926: 0x0279, 0x1927: 0x0369, 0x1928: 0x0289, 0x1929: 0x13d1, + 0x192a: 0x0039, 0x192b: 0x0ee9, 0x192c: 0x1159, 0x192d: 0x0ef9, 0x192e: 0x0f09, 0x192f: 0x1199, + 0x1930: 0x0f31, 0x1931: 0x0249, 0x1932: 0x0f41, 0x1933: 0x0259, 0x1934: 0x0f51, 0x1935: 0x0359, + 0x1936: 0x0f61, 0x1937: 0x0f71, 0x1938: 0x00d9, 0x1939: 0x0f99, 0x193a: 0x2039, 0x193b: 0x0269, + 0x193c: 0x01d9, 0x193d: 0x0fa9, 0x193e: 0x0fb9, 0x193f: 0x1089, // Block 0x65, offset 0x1940 - 0x1940: 0x0fb9, 0x1941: 0x1089, 0x1942: 0x0279, 0x1943: 0x0369, 0x1944: 0x0289, 0x1945: 0x13d1, - 0x1946: 0x0039, 0x1947: 0x0ee9, 0x1948: 0x1159, 0x1949: 0x0ef9, 0x194a: 0x0f09, 0x194b: 0x1199, - 0x194c: 0x0f31, 0x194d: 0x0249, 0x194e: 0x0f41, 0x194f: 0x0259, 0x1950: 0x0f51, 0x1951: 0x0359, - 0x1952: 0x0f61, 0x1953: 0x0f71, 0x1954: 0x00d9, 0x1955: 0x0f99, 0x1956: 0x2039, 0x1957: 0x0269, - 0x1958: 0x01d9, 0x1959: 0x0fa9, 0x195a: 0x0fb9, 0x195b: 0x1089, 0x195c: 0x0279, 0x195d: 0x0369, - 0x195e: 0x0289, 0x195f: 0x13d1, 0x1960: 0x0039, 0x1961: 0x0ee9, 0x1962: 0x1159, 0x1963: 0x0ef9, - 0x1964: 0x0f09, 0x1965: 0x1199, 0x1966: 0x0f31, 0x1967: 0x0249, 0x1968: 0x0f41, 0x1969: 0x0259, - 0x196a: 0x0f51, 0x196b: 0x0359, 0x196c: 0x0f61, 0x196d: 0x0f71, 0x196e: 0x00d9, 0x196f: 0x0f99, - 0x1970: 0x2039, 0x1971: 0x0269, 0x1972: 0x01d9, 0x1973: 0x0fa9, 0x1974: 0x0fb9, 0x1975: 0x1089, - 0x1976: 0x0279, 0x1977: 0x0369, 0x1978: 0x0289, 0x1979: 0x13d1, 0x197a: 0x0039, 0x197b: 0x0ee9, - 0x197c: 0x1159, 0x197d: 0x0ef9, 0x197e: 0x0f09, 0x197f: 0x1199, + 0x1940: 0x0279, 0x1941: 0x0369, 0x1942: 0x0289, 0x1943: 0x13d1, 0x1944: 0x0039, 0x1945: 0x0ee9, + 0x1946: 0x0040, 0x1947: 0x0ef9, 0x1948: 0x0f09, 0x1949: 0x1199, 0x194a: 0x0f31, 0x194b: 0x0040, + 0x194c: 0x0040, 0x194d: 0x0259, 0x194e: 0x0f51, 0x194f: 0x0359, 0x1950: 0x0f61, 0x1951: 0x0f71, + 0x1952: 0x00d9, 0x1953: 0x0f99, 0x1954: 0x2039, 0x1955: 0x0040, 0x1956: 0x01d9, 0x1957: 0x0fa9, + 0x1958: 0x0fb9, 0x1959: 0x1089, 0x195a: 0x0279, 0x195b: 0x0369, 0x195c: 0x0289, 0x195d: 0x0040, + 0x195e: 0x0039, 0x195f: 0x0ee9, 0x1960: 0x1159, 0x1961: 0x0ef9, 0x1962: 0x0f09, 0x1963: 0x1199, + 0x1964: 0x0f31, 0x1965: 0x0249, 0x1966: 0x0f41, 0x1967: 0x0259, 0x1968: 0x0f51, 0x1969: 0x0359, + 0x196a: 0x0f61, 0x196b: 0x0f71, 0x196c: 0x00d9, 0x196d: 0x0f99, 0x196e: 0x2039, 0x196f: 0x0269, + 0x1970: 0x01d9, 0x1971: 0x0fa9, 0x1972: 0x0fb9, 0x1973: 0x1089, 0x1974: 0x0279, 0x1975: 0x0369, + 0x1976: 0x0289, 0x1977: 0x13d1, 0x1978: 0x0039, 0x1979: 0x0ee9, 0x197a: 0x0040, 0x197b: 0x0ef9, + 0x197c: 0x0f09, 0x197d: 0x1199, 0x197e: 0x0f31, 0x197f: 0x0040, // Block 0x66, offset 0x1980 - 0x1980: 0x0f31, 0x1981: 0x0249, 0x1982: 0x0f41, 0x1983: 0x0259, 0x1984: 0x0f51, 0x1985: 0x0359, - 0x1986: 0x0f61, 0x1987: 0x0f71, 0x1988: 0x00d9, 0x1989: 0x0f99, 0x198a: 0x2039, 0x198b: 0x0269, - 0x198c: 0x01d9, 0x198d: 0x0fa9, 0x198e: 0x0fb9, 0x198f: 0x1089, 0x1990: 0x0279, 0x1991: 0x0369, - 0x1992: 0x0289, 0x1993: 0x13d1, 0x1994: 0x0039, 0x1995: 0x0ee9, 0x1996: 0x1159, 0x1997: 0x0ef9, - 0x1998: 0x0f09, 0x1999: 0x1199, 0x199a: 0x0f31, 0x199b: 0x0249, 0x199c: 0x0f41, 0x199d: 0x0259, - 0x199e: 0x0f51, 0x199f: 0x0359, 0x19a0: 0x0f61, 0x19a1: 0x0f71, 0x19a2: 0x00d9, 0x19a3: 0x0f99, - 0x19a4: 0x2039, 0x19a5: 0x0269, 0x19a6: 0x01d9, 0x19a7: 0x0fa9, 0x19a8: 0x0fb9, 0x19a9: 0x1089, - 0x19aa: 0x0279, 0x19ab: 0x0369, 0x19ac: 0x0289, 0x19ad: 0x13d1, 0x19ae: 0x0039, 0x19af: 0x0ee9, - 0x19b0: 0x1159, 0x19b1: 0x0ef9, 0x19b2: 0x0f09, 0x19b3: 0x1199, 0x19b4: 0x0f31, 0x19b5: 0x0249, - 0x19b6: 0x0f41, 0x19b7: 0x0259, 0x19b8: 0x0f51, 0x19b9: 0x0359, 0x19ba: 0x0f61, 0x19bb: 0x0f71, - 0x19bc: 0x00d9, 0x19bd: 0x0f99, 0x19be: 0x2039, 0x19bf: 0x0269, + 0x1980: 0x0f41, 0x1981: 0x0259, 0x1982: 0x0f51, 0x1983: 0x0359, 0x1984: 0x0f61, 0x1985: 0x0040, + 0x1986: 0x00d9, 0x1987: 0x0040, 0x1988: 0x0040, 0x1989: 0x0040, 0x198a: 0x01d9, 0x198b: 0x0fa9, + 0x198c: 0x0fb9, 0x198d: 0x1089, 0x198e: 0x0279, 0x198f: 0x0369, 0x1990: 0x0289, 0x1991: 0x0040, + 0x1992: 0x0039, 0x1993: 0x0ee9, 0x1994: 0x1159, 0x1995: 0x0ef9, 0x1996: 0x0f09, 0x1997: 0x1199, + 0x1998: 0x0f31, 0x1999: 0x0249, 0x199a: 0x0f41, 0x199b: 0x0259, 0x199c: 0x0f51, 0x199d: 0x0359, + 0x199e: 0x0f61, 0x199f: 0x0f71, 0x19a0: 0x00d9, 0x19a1: 0x0f99, 0x19a2: 0x2039, 0x19a3: 0x0269, + 0x19a4: 0x01d9, 0x19a5: 0x0fa9, 0x19a6: 0x0fb9, 0x19a7: 0x1089, 0x19a8: 0x0279, 0x19a9: 0x0369, + 0x19aa: 0x0289, 0x19ab: 0x13d1, 0x19ac: 0x0039, 0x19ad: 0x0ee9, 0x19ae: 0x1159, 0x19af: 0x0ef9, + 0x19b0: 0x0f09, 0x19b1: 0x1199, 0x19b2: 0x0f31, 0x19b3: 0x0249, 0x19b4: 0x0f41, 0x19b5: 0x0259, + 0x19b6: 0x0f51, 0x19b7: 0x0359, 0x19b8: 0x0f61, 0x19b9: 0x0f71, 0x19ba: 0x00d9, 0x19bb: 0x0f99, + 0x19bc: 0x2039, 0x19bd: 0x0269, 0x19be: 0x01d9, 0x19bf: 0x0fa9, // Block 0x67, offset 0x19c0 - 0x19c0: 0x01d9, 0x19c1: 0x0fa9, 0x19c2: 0x0fb9, 0x19c3: 0x1089, 0x19c4: 0x0279, 0x19c5: 0x0369, - 0x19c6: 0x0289, 0x19c7: 0x13d1, 0x19c8: 0x0039, 0x19c9: 0x0ee9, 0x19ca: 0x1159, 0x19cb: 0x0ef9, - 0x19cc: 0x0f09, 0x19cd: 0x1199, 0x19ce: 0x0f31, 0x19cf: 0x0249, 0x19d0: 0x0f41, 0x19d1: 0x0259, - 0x19d2: 0x0f51, 0x19d3: 0x0359, 0x19d4: 0x0f61, 0x19d5: 0x0f71, 0x19d6: 0x00d9, 0x19d7: 0x0f99, - 0x19d8: 0x2039, 0x19d9: 0x0269, 0x19da: 0x01d9, 0x19db: 0x0fa9, 0x19dc: 0x0fb9, 0x19dd: 0x1089, - 0x19de: 0x0279, 0x19df: 0x0369, 0x19e0: 0x0289, 0x19e1: 0x13d1, 0x19e2: 0x0039, 0x19e3: 0x0ee9, - 0x19e4: 0x1159, 0x19e5: 0x0ef9, 0x19e6: 0x0f09, 0x19e7: 0x1199, 0x19e8: 0x0f31, 0x19e9: 0x0249, - 0x19ea: 0x0f41, 0x19eb: 0x0259, 0x19ec: 0x0f51, 0x19ed: 0x0359, 0x19ee: 0x0f61, 0x19ef: 0x0f71, - 0x19f0: 0x00d9, 0x19f1: 0x0f99, 0x19f2: 0x2039, 0x19f3: 0x0269, 0x19f4: 0x01d9, 0x19f5: 0x0fa9, - 0x19f6: 0x0fb9, 0x19f7: 0x1089, 0x19f8: 0x0279, 0x19f9: 0x0369, 0x19fa: 0x0289, 0x19fb: 0x13d1, - 0x19fc: 0x0039, 0x19fd: 0x0ee9, 0x19fe: 0x1159, 0x19ff: 0x0ef9, + 0x19c0: 0x0fb9, 0x19c1: 0x1089, 0x19c2: 0x0279, 0x19c3: 0x0369, 0x19c4: 0x0289, 0x19c5: 0x13d1, + 0x19c6: 0x0039, 0x19c7: 0x0ee9, 0x19c8: 0x1159, 0x19c9: 0x0ef9, 0x19ca: 0x0f09, 0x19cb: 0x1199, + 0x19cc: 0x0f31, 0x19cd: 0x0249, 0x19ce: 0x0f41, 0x19cf: 0x0259, 0x19d0: 0x0f51, 0x19d1: 0x0359, + 0x19d2: 0x0f61, 0x19d3: 0x0f71, 0x19d4: 0x00d9, 0x19d5: 0x0f99, 0x19d6: 0x2039, 0x19d7: 0x0269, + 0x19d8: 0x01d9, 0x19d9: 0x0fa9, 0x19da: 0x0fb9, 0x19db: 0x1089, 0x19dc: 0x0279, 0x19dd: 0x0369, + 0x19de: 0x0289, 0x19df: 0x13d1, 0x19e0: 0x0039, 0x19e1: 0x0ee9, 0x19e2: 0x1159, 0x19e3: 0x0ef9, + 0x19e4: 0x0f09, 0x19e5: 0x1199, 0x19e6: 0x0f31, 0x19e7: 0x0249, 0x19e8: 0x0f41, 0x19e9: 0x0259, + 0x19ea: 0x0f51, 0x19eb: 0x0359, 0x19ec: 0x0f61, 0x19ed: 0x0f71, 0x19ee: 0x00d9, 0x19ef: 0x0f99, + 0x19f0: 0x2039, 0x19f1: 0x0269, 0x19f2: 0x01d9, 0x19f3: 0x0fa9, 0x19f4: 0x0fb9, 0x19f5: 0x1089, + 0x19f6: 0x0279, 0x19f7: 0x0369, 0x19f8: 0x0289, 0x19f9: 0x13d1, 0x19fa: 0x0039, 0x19fb: 0x0ee9, + 0x19fc: 0x1159, 0x19fd: 0x0ef9, 0x19fe: 0x0f09, 0x19ff: 0x1199, // Block 0x68, offset 0x1a00 - 0x1a00: 0x0f09, 0x1a01: 0x1199, 0x1a02: 0x0f31, 0x1a03: 0x0249, 0x1a04: 0x0f41, 0x1a05: 0x0259, - 0x1a06: 0x0f51, 0x1a07: 0x0359, 0x1a08: 0x0f61, 0x1a09: 0x0f71, 0x1a0a: 0x00d9, 0x1a0b: 0x0f99, - 0x1a0c: 0x2039, 0x1a0d: 0x0269, 0x1a0e: 0x01d9, 0x1a0f: 0x0fa9, 0x1a10: 0x0fb9, 0x1a11: 0x1089, - 0x1a12: 0x0279, 0x1a13: 0x0369, 0x1a14: 0x0289, 0x1a15: 0x13d1, 0x1a16: 0x0039, 0x1a17: 0x0ee9, - 0x1a18: 0x1159, 0x1a19: 0x0ef9, 0x1a1a: 0x0f09, 0x1a1b: 0x1199, 0x1a1c: 0x0f31, 0x1a1d: 0x0249, - 0x1a1e: 0x0f41, 0x1a1f: 0x0259, 0x1a20: 0x0f51, 0x1a21: 0x0359, 0x1a22: 0x0f61, 0x1a23: 0x0f71, - 0x1a24: 0x00d9, 0x1a25: 0x0f99, 0x1a26: 0x2039, 0x1a27: 0x0269, 0x1a28: 0x01d9, 0x1a29: 0x0fa9, - 0x1a2a: 0x0fb9, 0x1a2b: 0x1089, 0x1a2c: 0x0279, 0x1a2d: 0x0369, 0x1a2e: 0x0289, 0x1a2f: 0x13d1, - 0x1a30: 0x0039, 0x1a31: 0x0ee9, 0x1a32: 0x1159, 0x1a33: 0x0ef9, 0x1a34: 0x0f09, 0x1a35: 0x1199, - 0x1a36: 0x0f31, 0x1a37: 0x0249, 0x1a38: 0x0f41, 0x1a39: 0x0259, 0x1a3a: 0x0f51, 0x1a3b: 0x0359, - 0x1a3c: 0x0f61, 0x1a3d: 0x0f71, 0x1a3e: 0x00d9, 0x1a3f: 0x0f99, + 0x1a00: 0x0f31, 0x1a01: 0x0249, 0x1a02: 0x0f41, 0x1a03: 0x0259, 0x1a04: 0x0f51, 0x1a05: 0x0359, + 0x1a06: 0x0f61, 0x1a07: 0x0f71, 0x1a08: 0x00d9, 0x1a09: 0x0f99, 0x1a0a: 0x2039, 0x1a0b: 0x0269, + 0x1a0c: 0x01d9, 0x1a0d: 0x0fa9, 0x1a0e: 0x0fb9, 0x1a0f: 0x1089, 0x1a10: 0x0279, 0x1a11: 0x0369, + 0x1a12: 0x0289, 0x1a13: 0x13d1, 0x1a14: 0x0039, 0x1a15: 0x0ee9, 0x1a16: 0x1159, 0x1a17: 0x0ef9, + 0x1a18: 0x0f09, 0x1a19: 0x1199, 0x1a1a: 0x0f31, 0x1a1b: 0x0249, 0x1a1c: 0x0f41, 0x1a1d: 0x0259, + 0x1a1e: 0x0f51, 0x1a1f: 0x0359, 0x1a20: 0x0f61, 0x1a21: 0x0f71, 0x1a22: 0x00d9, 0x1a23: 0x0f99, + 0x1a24: 0x2039, 0x1a25: 0x0269, 0x1a26: 0x01d9, 0x1a27: 0x0fa9, 0x1a28: 0x0fb9, 0x1a29: 0x1089, + 0x1a2a: 0x0279, 0x1a2b: 0x0369, 0x1a2c: 0x0289, 0x1a2d: 0x13d1, 0x1a2e: 0x0039, 0x1a2f: 0x0ee9, + 0x1a30: 0x1159, 0x1a31: 0x0ef9, 0x1a32: 0x0f09, 0x1a33: 0x1199, 0x1a34: 0x0f31, 0x1a35: 0x0249, + 0x1a36: 0x0f41, 0x1a37: 0x0259, 0x1a38: 0x0f51, 0x1a39: 0x0359, 0x1a3a: 0x0f61, 0x1a3b: 0x0f71, + 0x1a3c: 0x00d9, 0x1a3d: 0x0f99, 0x1a3e: 0x2039, 0x1a3f: 0x0269, // Block 0x69, offset 0x1a40 - 0x1a40: 0x2039, 0x1a41: 0x0269, 0x1a42: 0x01d9, 0x1a43: 0x0fa9, 0x1a44: 0x0fb9, 0x1a45: 0x1089, - 0x1a46: 0x0279, 0x1a47: 0x0369, 0x1a48: 0x0289, 0x1a49: 0x13d1, 0x1a4a: 0x0039, 0x1a4b: 0x0ee9, - 0x1a4c: 0x1159, 0x1a4d: 0x0ef9, 0x1a4e: 0x0f09, 0x1a4f: 0x1199, 0x1a50: 0x0f31, 0x1a51: 0x0249, - 0x1a52: 0x0f41, 0x1a53: 0x0259, 0x1a54: 0x0f51, 0x1a55: 0x0359, 0x1a56: 0x0f61, 0x1a57: 0x0f71, - 0x1a58: 0x00d9, 0x1a59: 0x0f99, 0x1a5a: 0x2039, 0x1a5b: 0x0269, 0x1a5c: 0x01d9, 0x1a5d: 0x0fa9, - 0x1a5e: 0x0fb9, 0x1a5f: 0x1089, 0x1a60: 0x0279, 0x1a61: 0x0369, 0x1a62: 0x0289, 0x1a63: 0x13d1, - 0x1a64: 0xba81, 0x1a65: 0xba99, 0x1a66: 0x0040, 0x1a67: 0x0040, 0x1a68: 0xbab1, 0x1a69: 0x1099, - 0x1a6a: 0x10b1, 0x1a6b: 0x10c9, 0x1a6c: 0xbac9, 0x1a6d: 0xbae1, 0x1a6e: 0xbaf9, 0x1a6f: 0x1429, - 0x1a70: 0x1a31, 0x1a71: 0xbb11, 0x1a72: 0xbb29, 0x1a73: 0xbb41, 0x1a74: 0xbb59, 0x1a75: 0xbb71, - 0x1a76: 0xbb89, 0x1a77: 0x2109, 0x1a78: 0x1111, 0x1a79: 0x1429, 0x1a7a: 0xbba1, 0x1a7b: 0xbbb9, - 0x1a7c: 0xbbd1, 0x1a7d: 0x10e1, 0x1a7e: 0x10f9, 0x1a7f: 0xbbe9, + 0x1a40: 0x01d9, 0x1a41: 0x0fa9, 0x1a42: 0x0fb9, 0x1a43: 0x1089, 0x1a44: 0x0279, 0x1a45: 0x0369, + 0x1a46: 0x0289, 0x1a47: 0x13d1, 0x1a48: 0x0039, 0x1a49: 0x0ee9, 0x1a4a: 0x1159, 0x1a4b: 0x0ef9, + 0x1a4c: 0x0f09, 0x1a4d: 0x1199, 0x1a4e: 0x0f31, 0x1a4f: 0x0249, 0x1a50: 0x0f41, 0x1a51: 0x0259, + 0x1a52: 0x0f51, 0x1a53: 0x0359, 0x1a54: 0x0f61, 0x1a55: 0x0f71, 0x1a56: 0x00d9, 0x1a57: 0x0f99, + 0x1a58: 0x2039, 0x1a59: 0x0269, 0x1a5a: 0x01d9, 0x1a5b: 0x0fa9, 0x1a5c: 0x0fb9, 0x1a5d: 0x1089, + 0x1a5e: 0x0279, 0x1a5f: 0x0369, 0x1a60: 0x0289, 0x1a61: 0x13d1, 0x1a62: 0x0039, 0x1a63: 0x0ee9, + 0x1a64: 0x1159, 0x1a65: 0x0ef9, 0x1a66: 0x0f09, 0x1a67: 0x1199, 0x1a68: 0x0f31, 0x1a69: 0x0249, + 0x1a6a: 0x0f41, 0x1a6b: 0x0259, 0x1a6c: 0x0f51, 0x1a6d: 0x0359, 0x1a6e: 0x0f61, 0x1a6f: 0x0f71, + 0x1a70: 0x00d9, 0x1a71: 0x0f99, 0x1a72: 0x2039, 0x1a73: 0x0269, 0x1a74: 0x01d9, 0x1a75: 0x0fa9, + 0x1a76: 0x0fb9, 0x1a77: 0x1089, 0x1a78: 0x0279, 0x1a79: 0x0369, 0x1a7a: 0x0289, 0x1a7b: 0x13d1, + 0x1a7c: 0x0039, 0x1a7d: 0x0ee9, 0x1a7e: 0x1159, 0x1a7f: 0x0ef9, // Block 0x6a, offset 0x1a80 - 0x1a80: 0x2079, 0x1a81: 0xbc01, 0x1a82: 0xbab1, 0x1a83: 0x1099, 0x1a84: 0x10b1, 0x1a85: 0x10c9, - 0x1a86: 0xbac9, 0x1a87: 0xbae1, 0x1a88: 0xbaf9, 0x1a89: 0x1429, 0x1a8a: 0x1a31, 0x1a8b: 0xbb11, - 0x1a8c: 0xbb29, 0x1a8d: 0xbb41, 0x1a8e: 0xbb59, 0x1a8f: 0xbb71, 0x1a90: 0xbb89, 0x1a91: 0x2109, - 0x1a92: 0x1111, 0x1a93: 0xbba1, 0x1a94: 0xbba1, 0x1a95: 0xbbb9, 0x1a96: 0xbbd1, 0x1a97: 0x10e1, - 0x1a98: 0x10f9, 0x1a99: 0xbbe9, 0x1a9a: 0x2079, 0x1a9b: 0xbc21, 0x1a9c: 0xbac9, 0x1a9d: 0x1429, - 0x1a9e: 0xbb11, 0x1a9f: 0x10e1, 0x1aa0: 0x1111, 0x1aa1: 0x2109, 0x1aa2: 0xbab1, 0x1aa3: 0x1099, - 0x1aa4: 0x10b1, 0x1aa5: 0x10c9, 0x1aa6: 0xbac9, 0x1aa7: 0xbae1, 0x1aa8: 0xbaf9, 0x1aa9: 0x1429, - 0x1aaa: 0x1a31, 0x1aab: 0xbb11, 0x1aac: 0xbb29, 0x1aad: 0xbb41, 0x1aae: 0xbb59, 0x1aaf: 0xbb71, - 0x1ab0: 0xbb89, 0x1ab1: 0x2109, 0x1ab2: 0x1111, 0x1ab3: 0x1429, 0x1ab4: 0xbba1, 0x1ab5: 0xbbb9, - 0x1ab6: 0xbbd1, 0x1ab7: 0x10e1, 0x1ab8: 0x10f9, 0x1ab9: 0xbbe9, 0x1aba: 0x2079, 0x1abb: 0xbc01, - 0x1abc: 0xbab1, 0x1abd: 0x1099, 0x1abe: 0x10b1, 0x1abf: 0x10c9, + 0x1a80: 0x0f09, 0x1a81: 0x1199, 0x1a82: 0x0f31, 0x1a83: 0x0249, 0x1a84: 0x0f41, 0x1a85: 0x0259, + 0x1a86: 0x0f51, 0x1a87: 0x0359, 0x1a88: 0x0f61, 0x1a89: 0x0f71, 0x1a8a: 0x00d9, 0x1a8b: 0x0f99, + 0x1a8c: 0x2039, 0x1a8d: 0x0269, 0x1a8e: 0x01d9, 0x1a8f: 0x0fa9, 0x1a90: 0x0fb9, 0x1a91: 0x1089, + 0x1a92: 0x0279, 0x1a93: 0x0369, 0x1a94: 0x0289, 0x1a95: 0x13d1, 0x1a96: 0x0039, 0x1a97: 0x0ee9, + 0x1a98: 0x1159, 0x1a99: 0x0ef9, 0x1a9a: 0x0f09, 0x1a9b: 0x1199, 0x1a9c: 0x0f31, 0x1a9d: 0x0249, + 0x1a9e: 0x0f41, 0x1a9f: 0x0259, 0x1aa0: 0x0f51, 0x1aa1: 0x0359, 0x1aa2: 0x0f61, 0x1aa3: 0x0f71, + 0x1aa4: 0x00d9, 0x1aa5: 0x0f99, 0x1aa6: 0x2039, 0x1aa7: 0x0269, 0x1aa8: 0x01d9, 0x1aa9: 0x0fa9, + 0x1aaa: 0x0fb9, 0x1aab: 0x1089, 0x1aac: 0x0279, 0x1aad: 0x0369, 0x1aae: 0x0289, 0x1aaf: 0x13d1, + 0x1ab0: 0x0039, 0x1ab1: 0x0ee9, 0x1ab2: 0x1159, 0x1ab3: 0x0ef9, 0x1ab4: 0x0f09, 0x1ab5: 0x1199, + 0x1ab6: 0x0f31, 0x1ab7: 0x0249, 0x1ab8: 0x0f41, 0x1ab9: 0x0259, 0x1aba: 0x0f51, 0x1abb: 0x0359, + 0x1abc: 0x0f61, 0x1abd: 0x0f71, 0x1abe: 0x00d9, 0x1abf: 0x0f99, // Block 0x6b, offset 0x1ac0 - 0x1ac0: 0xbac9, 0x1ac1: 0xbae1, 0x1ac2: 0xbaf9, 0x1ac3: 0x1429, 0x1ac4: 0x1a31, 0x1ac5: 0xbb11, - 0x1ac6: 0xbb29, 0x1ac7: 0xbb41, 0x1ac8: 0xbb59, 0x1ac9: 0xbb71, 0x1aca: 0xbb89, 0x1acb: 0x2109, - 0x1acc: 0x1111, 0x1acd: 0xbba1, 0x1ace: 0xbba1, 0x1acf: 0xbbb9, 0x1ad0: 0xbbd1, 0x1ad1: 0x10e1, - 0x1ad2: 0x10f9, 0x1ad3: 0xbbe9, 0x1ad4: 0x2079, 0x1ad5: 0xbc21, 0x1ad6: 0xbac9, 0x1ad7: 0x1429, - 0x1ad8: 0xbb11, 0x1ad9: 0x10e1, 0x1ada: 0x1111, 0x1adb: 0x2109, 0x1adc: 0xbab1, 0x1add: 0x1099, - 0x1ade: 0x10b1, 0x1adf: 0x10c9, 0x1ae0: 0xbac9, 0x1ae1: 0xbae1, 0x1ae2: 0xbaf9, 0x1ae3: 0x1429, - 0x1ae4: 0x1a31, 0x1ae5: 0xbb11, 0x1ae6: 0xbb29, 0x1ae7: 0xbb41, 0x1ae8: 0xbb59, 0x1ae9: 0xbb71, - 0x1aea: 0xbb89, 0x1aeb: 0x2109, 0x1aec: 0x1111, 0x1aed: 0x1429, 0x1aee: 0xbba1, 0x1aef: 0xbbb9, - 0x1af0: 0xbbd1, 0x1af1: 0x10e1, 0x1af2: 0x10f9, 0x1af3: 0xbbe9, 0x1af4: 0x2079, 0x1af5: 0xbc01, - 0x1af6: 0xbab1, 0x1af7: 0x1099, 0x1af8: 0x10b1, 0x1af9: 0x10c9, 0x1afa: 0xbac9, 0x1afb: 0xbae1, - 0x1afc: 0xbaf9, 0x1afd: 0x1429, 0x1afe: 0x1a31, 0x1aff: 0xbb11, + 0x1ac0: 0x2039, 0x1ac1: 0x0269, 0x1ac2: 0x01d9, 0x1ac3: 0x0fa9, 0x1ac4: 0x0fb9, 0x1ac5: 0x1089, + 0x1ac6: 0x0279, 0x1ac7: 0x0369, 0x1ac8: 0x0289, 0x1ac9: 0x13d1, 0x1aca: 0x0039, 0x1acb: 0x0ee9, + 0x1acc: 0x1159, 0x1acd: 0x0ef9, 0x1ace: 0x0f09, 0x1acf: 0x1199, 0x1ad0: 0x0f31, 0x1ad1: 0x0249, + 0x1ad2: 0x0f41, 0x1ad3: 0x0259, 0x1ad4: 0x0f51, 0x1ad5: 0x0359, 0x1ad6: 0x0f61, 0x1ad7: 0x0f71, + 0x1ad8: 0x00d9, 0x1ad9: 0x0f99, 0x1ada: 0x2039, 0x1adb: 0x0269, 0x1adc: 0x01d9, 0x1add: 0x0fa9, + 0x1ade: 0x0fb9, 0x1adf: 0x1089, 0x1ae0: 0x0279, 0x1ae1: 0x0369, 0x1ae2: 0x0289, 0x1ae3: 0x13d1, + 0x1ae4: 0xba81, 0x1ae5: 0xba99, 0x1ae6: 0x0040, 0x1ae7: 0x0040, 0x1ae8: 0xbab1, 0x1ae9: 0x1099, + 0x1aea: 0x10b1, 0x1aeb: 0x10c9, 0x1aec: 0xbac9, 0x1aed: 0xbae1, 0x1aee: 0xbaf9, 0x1aef: 0x1429, + 0x1af0: 0x1a31, 0x1af1: 0xbb11, 0x1af2: 0xbb29, 0x1af3: 0xbb41, 0x1af4: 0xbb59, 0x1af5: 0xbb71, + 0x1af6: 0xbb89, 0x1af7: 0x2109, 0x1af8: 0x1111, 0x1af9: 0x1429, 0x1afa: 0xbba1, 0x1afb: 0xbbb9, + 0x1afc: 0xbbd1, 0x1afd: 0x10e1, 0x1afe: 0x10f9, 0x1aff: 0xbbe9, // Block 0x6c, offset 0x1b00 - 0x1b00: 0xbb29, 0x1b01: 0xbb41, 0x1b02: 0xbb59, 0x1b03: 0xbb71, 0x1b04: 0xbb89, 0x1b05: 0x2109, - 0x1b06: 0x1111, 0x1b07: 0xbba1, 0x1b08: 0xbba1, 0x1b09: 0xbbb9, 0x1b0a: 0xbbd1, 0x1b0b: 0x10e1, - 0x1b0c: 0x10f9, 0x1b0d: 0xbbe9, 0x1b0e: 0x2079, 0x1b0f: 0xbc21, 0x1b10: 0xbac9, 0x1b11: 0x1429, - 0x1b12: 0xbb11, 0x1b13: 0x10e1, 0x1b14: 0x1111, 0x1b15: 0x2109, 0x1b16: 0xbab1, 0x1b17: 0x1099, - 0x1b18: 0x10b1, 0x1b19: 0x10c9, 0x1b1a: 0xbac9, 0x1b1b: 0xbae1, 0x1b1c: 0xbaf9, 0x1b1d: 0x1429, - 0x1b1e: 0x1a31, 0x1b1f: 0xbb11, 0x1b20: 0xbb29, 0x1b21: 0xbb41, 0x1b22: 0xbb59, 0x1b23: 0xbb71, - 0x1b24: 0xbb89, 0x1b25: 0x2109, 0x1b26: 0x1111, 0x1b27: 0x1429, 0x1b28: 0xbba1, 0x1b29: 0xbbb9, - 0x1b2a: 0xbbd1, 0x1b2b: 0x10e1, 0x1b2c: 0x10f9, 0x1b2d: 0xbbe9, 0x1b2e: 0x2079, 0x1b2f: 0xbc01, - 0x1b30: 0xbab1, 0x1b31: 0x1099, 0x1b32: 0x10b1, 0x1b33: 0x10c9, 0x1b34: 0xbac9, 0x1b35: 0xbae1, - 0x1b36: 0xbaf9, 0x1b37: 0x1429, 0x1b38: 0x1a31, 0x1b39: 0xbb11, 0x1b3a: 0xbb29, 0x1b3b: 0xbb41, - 0x1b3c: 0xbb59, 0x1b3d: 0xbb71, 0x1b3e: 0xbb89, 0x1b3f: 0x2109, + 0x1b00: 0x2079, 0x1b01: 0xbc01, 0x1b02: 0xbab1, 0x1b03: 0x1099, 0x1b04: 0x10b1, 0x1b05: 0x10c9, + 0x1b06: 0xbac9, 0x1b07: 0xbae1, 0x1b08: 0xbaf9, 0x1b09: 0x1429, 0x1b0a: 0x1a31, 0x1b0b: 0xbb11, + 0x1b0c: 0xbb29, 0x1b0d: 0xbb41, 0x1b0e: 0xbb59, 0x1b0f: 0xbb71, 0x1b10: 0xbb89, 0x1b11: 0x2109, + 0x1b12: 0x1111, 0x1b13: 0xbba1, 0x1b14: 0xbba1, 0x1b15: 0xbbb9, 0x1b16: 0xbbd1, 0x1b17: 0x10e1, + 0x1b18: 0x10f9, 0x1b19: 0xbbe9, 0x1b1a: 0x2079, 0x1b1b: 0xbc21, 0x1b1c: 0xbac9, 0x1b1d: 0x1429, + 0x1b1e: 0xbb11, 0x1b1f: 0x10e1, 0x1b20: 0x1111, 0x1b21: 0x2109, 0x1b22: 0xbab1, 0x1b23: 0x1099, + 0x1b24: 0x10b1, 0x1b25: 0x10c9, 0x1b26: 0xbac9, 0x1b27: 0xbae1, 0x1b28: 0xbaf9, 0x1b29: 0x1429, + 0x1b2a: 0x1a31, 0x1b2b: 0xbb11, 0x1b2c: 0xbb29, 0x1b2d: 0xbb41, 0x1b2e: 0xbb59, 0x1b2f: 0xbb71, + 0x1b30: 0xbb89, 0x1b31: 0x2109, 0x1b32: 0x1111, 0x1b33: 0x1429, 0x1b34: 0xbba1, 0x1b35: 0xbbb9, + 0x1b36: 0xbbd1, 0x1b37: 0x10e1, 0x1b38: 0x10f9, 0x1b39: 0xbbe9, 0x1b3a: 0x2079, 0x1b3b: 0xbc01, + 0x1b3c: 0xbab1, 0x1b3d: 0x1099, 0x1b3e: 0x10b1, 0x1b3f: 0x10c9, // Block 0x6d, offset 0x1b40 - 0x1b40: 0x1111, 0x1b41: 0xbba1, 0x1b42: 0xbba1, 0x1b43: 0xbbb9, 0x1b44: 0xbbd1, 0x1b45: 0x10e1, - 0x1b46: 0x10f9, 0x1b47: 0xbbe9, 0x1b48: 0x2079, 0x1b49: 0xbc21, 0x1b4a: 0xbac9, 0x1b4b: 0x1429, - 0x1b4c: 0xbb11, 0x1b4d: 0x10e1, 0x1b4e: 0x1111, 0x1b4f: 0x2109, 0x1b50: 0xbab1, 0x1b51: 0x1099, - 0x1b52: 0x10b1, 0x1b53: 0x10c9, 0x1b54: 0xbac9, 0x1b55: 0xbae1, 0x1b56: 0xbaf9, 0x1b57: 0x1429, - 0x1b58: 0x1a31, 0x1b59: 0xbb11, 0x1b5a: 0xbb29, 0x1b5b: 0xbb41, 0x1b5c: 0xbb59, 0x1b5d: 0xbb71, - 0x1b5e: 0xbb89, 0x1b5f: 0x2109, 0x1b60: 0x1111, 0x1b61: 0x1429, 0x1b62: 0xbba1, 0x1b63: 0xbbb9, - 0x1b64: 0xbbd1, 0x1b65: 0x10e1, 0x1b66: 0x10f9, 0x1b67: 0xbbe9, 0x1b68: 0x2079, 0x1b69: 0xbc01, - 0x1b6a: 0xbab1, 0x1b6b: 0x1099, 0x1b6c: 0x10b1, 0x1b6d: 0x10c9, 0x1b6e: 0xbac9, 0x1b6f: 0xbae1, - 0x1b70: 0xbaf9, 0x1b71: 0x1429, 0x1b72: 0x1a31, 0x1b73: 0xbb11, 0x1b74: 0xbb29, 0x1b75: 0xbb41, - 0x1b76: 0xbb59, 0x1b77: 0xbb71, 0x1b78: 0xbb89, 0x1b79: 0x2109, 0x1b7a: 0x1111, 0x1b7b: 0xbba1, - 0x1b7c: 0xbba1, 0x1b7d: 0xbbb9, 0x1b7e: 0xbbd1, 0x1b7f: 0x10e1, + 0x1b40: 0xbac9, 0x1b41: 0xbae1, 0x1b42: 0xbaf9, 0x1b43: 0x1429, 0x1b44: 0x1a31, 0x1b45: 0xbb11, + 0x1b46: 0xbb29, 0x1b47: 0xbb41, 0x1b48: 0xbb59, 0x1b49: 0xbb71, 0x1b4a: 0xbb89, 0x1b4b: 0x2109, + 0x1b4c: 0x1111, 0x1b4d: 0xbba1, 0x1b4e: 0xbba1, 0x1b4f: 0xbbb9, 0x1b50: 0xbbd1, 0x1b51: 0x10e1, + 0x1b52: 0x10f9, 0x1b53: 0xbbe9, 0x1b54: 0x2079, 0x1b55: 0xbc21, 0x1b56: 0xbac9, 0x1b57: 0x1429, + 0x1b58: 0xbb11, 0x1b59: 0x10e1, 0x1b5a: 0x1111, 0x1b5b: 0x2109, 0x1b5c: 0xbab1, 0x1b5d: 0x1099, + 0x1b5e: 0x10b1, 0x1b5f: 0x10c9, 0x1b60: 0xbac9, 0x1b61: 0xbae1, 0x1b62: 0xbaf9, 0x1b63: 0x1429, + 0x1b64: 0x1a31, 0x1b65: 0xbb11, 0x1b66: 0xbb29, 0x1b67: 0xbb41, 0x1b68: 0xbb59, 0x1b69: 0xbb71, + 0x1b6a: 0xbb89, 0x1b6b: 0x2109, 0x1b6c: 0x1111, 0x1b6d: 0x1429, 0x1b6e: 0xbba1, 0x1b6f: 0xbbb9, + 0x1b70: 0xbbd1, 0x1b71: 0x10e1, 0x1b72: 0x10f9, 0x1b73: 0xbbe9, 0x1b74: 0x2079, 0x1b75: 0xbc01, + 0x1b76: 0xbab1, 0x1b77: 0x1099, 0x1b78: 0x10b1, 0x1b79: 0x10c9, 0x1b7a: 0xbac9, 0x1b7b: 0xbae1, + 0x1b7c: 0xbaf9, 0x1b7d: 0x1429, 0x1b7e: 0x1a31, 0x1b7f: 0xbb11, // Block 0x6e, offset 0x1b80 - 0x1b80: 0x10f9, 0x1b81: 0xbbe9, 0x1b82: 0x2079, 0x1b83: 0xbc21, 0x1b84: 0xbac9, 0x1b85: 0x1429, - 0x1b86: 0xbb11, 0x1b87: 0x10e1, 0x1b88: 0x1111, 0x1b89: 0x2109, 0x1b8a: 0xbc41, 0x1b8b: 0xbc41, - 0x1b8c: 0x0040, 0x1b8d: 0x0040, 0x1b8e: 0x1f41, 0x1b8f: 0x00c9, 0x1b90: 0x0069, 0x1b91: 0x0079, - 0x1b92: 0x1f51, 0x1b93: 0x1f61, 0x1b94: 0x1f71, 0x1b95: 0x1f81, 0x1b96: 0x1f91, 0x1b97: 0x1fa1, - 0x1b98: 0x1f41, 0x1b99: 0x00c9, 0x1b9a: 0x0069, 0x1b9b: 0x0079, 0x1b9c: 0x1f51, 0x1b9d: 0x1f61, - 0x1b9e: 0x1f71, 0x1b9f: 0x1f81, 0x1ba0: 0x1f91, 0x1ba1: 0x1fa1, 0x1ba2: 0x1f41, 0x1ba3: 0x00c9, - 0x1ba4: 0x0069, 0x1ba5: 0x0079, 0x1ba6: 0x1f51, 0x1ba7: 0x1f61, 0x1ba8: 0x1f71, 0x1ba9: 0x1f81, - 0x1baa: 0x1f91, 0x1bab: 0x1fa1, 0x1bac: 0x1f41, 0x1bad: 0x00c9, 0x1bae: 0x0069, 0x1baf: 0x0079, - 0x1bb0: 0x1f51, 0x1bb1: 0x1f61, 0x1bb2: 0x1f71, 0x1bb3: 0x1f81, 0x1bb4: 0x1f91, 0x1bb5: 0x1fa1, - 0x1bb6: 0x1f41, 0x1bb7: 0x00c9, 0x1bb8: 0x0069, 0x1bb9: 0x0079, 0x1bba: 0x1f51, 0x1bbb: 0x1f61, - 0x1bbc: 0x1f71, 0x1bbd: 0x1f81, 0x1bbe: 0x1f91, 0x1bbf: 0x1fa1, + 0x1b80: 0xbb29, 0x1b81: 0xbb41, 0x1b82: 0xbb59, 0x1b83: 0xbb71, 0x1b84: 0xbb89, 0x1b85: 0x2109, + 0x1b86: 0x1111, 0x1b87: 0xbba1, 0x1b88: 0xbba1, 0x1b89: 0xbbb9, 0x1b8a: 0xbbd1, 0x1b8b: 0x10e1, + 0x1b8c: 0x10f9, 0x1b8d: 0xbbe9, 0x1b8e: 0x2079, 0x1b8f: 0xbc21, 0x1b90: 0xbac9, 0x1b91: 0x1429, + 0x1b92: 0xbb11, 0x1b93: 0x10e1, 0x1b94: 0x1111, 0x1b95: 0x2109, 0x1b96: 0xbab1, 0x1b97: 0x1099, + 0x1b98: 0x10b1, 0x1b99: 0x10c9, 0x1b9a: 0xbac9, 0x1b9b: 0xbae1, 0x1b9c: 0xbaf9, 0x1b9d: 0x1429, + 0x1b9e: 0x1a31, 0x1b9f: 0xbb11, 0x1ba0: 0xbb29, 0x1ba1: 0xbb41, 0x1ba2: 0xbb59, 0x1ba3: 0xbb71, + 0x1ba4: 0xbb89, 0x1ba5: 0x2109, 0x1ba6: 0x1111, 0x1ba7: 0x1429, 0x1ba8: 0xbba1, 0x1ba9: 0xbbb9, + 0x1baa: 0xbbd1, 0x1bab: 0x10e1, 0x1bac: 0x10f9, 0x1bad: 0xbbe9, 0x1bae: 0x2079, 0x1baf: 0xbc01, + 0x1bb0: 0xbab1, 0x1bb1: 0x1099, 0x1bb2: 0x10b1, 0x1bb3: 0x10c9, 0x1bb4: 0xbac9, 0x1bb5: 0xbae1, + 0x1bb6: 0xbaf9, 0x1bb7: 0x1429, 0x1bb8: 0x1a31, 0x1bb9: 0xbb11, 0x1bba: 0xbb29, 0x1bbb: 0xbb41, + 0x1bbc: 0xbb59, 0x1bbd: 0xbb71, 0x1bbe: 0xbb89, 0x1bbf: 0x2109, // Block 0x6f, offset 0x1bc0 - 0x1bc0: 0xe115, 0x1bc1: 0xe115, 0x1bc2: 0xe135, 0x1bc3: 0xe135, 0x1bc4: 0xe115, 0x1bc5: 0xe115, - 0x1bc6: 0xe175, 0x1bc7: 0xe175, 0x1bc8: 0xe115, 0x1bc9: 0xe115, 0x1bca: 0xe135, 0x1bcb: 0xe135, - 0x1bcc: 0xe115, 0x1bcd: 0xe115, 0x1bce: 0xe1f5, 0x1bcf: 0xe1f5, 0x1bd0: 0xe115, 0x1bd1: 0xe115, - 0x1bd2: 0xe135, 0x1bd3: 0xe135, 0x1bd4: 0xe115, 0x1bd5: 0xe115, 0x1bd6: 0xe175, 0x1bd7: 0xe175, - 0x1bd8: 0xe115, 0x1bd9: 0xe115, 0x1bda: 0xe135, 0x1bdb: 0xe135, 0x1bdc: 0xe115, 0x1bdd: 0xe115, - 0x1bde: 0x8b05, 0x1bdf: 0x8b05, 0x1be0: 0x04b5, 0x1be1: 0x04b5, 0x1be2: 0x0208, 0x1be3: 0x0208, - 0x1be4: 0x0208, 0x1be5: 0x0208, 0x1be6: 0x0208, 0x1be7: 0x0208, 0x1be8: 0x0208, 0x1be9: 0x0208, - 0x1bea: 0x0208, 0x1beb: 0x0208, 0x1bec: 0x0208, 0x1bed: 0x0208, 0x1bee: 0x0208, 0x1bef: 0x0208, - 0x1bf0: 0x0208, 0x1bf1: 0x0208, 0x1bf2: 0x0208, 0x1bf3: 0x0208, 0x1bf4: 0x0208, 0x1bf5: 0x0208, - 0x1bf6: 0x0208, 0x1bf7: 0x0208, 0x1bf8: 0x0208, 0x1bf9: 0x0208, 0x1bfa: 0x0208, 0x1bfb: 0x0208, - 0x1bfc: 0x0208, 0x1bfd: 0x0208, 0x1bfe: 0x0208, 0x1bff: 0x0208, + 0x1bc0: 0x1111, 0x1bc1: 0xbba1, 0x1bc2: 0xbba1, 0x1bc3: 0xbbb9, 0x1bc4: 0xbbd1, 0x1bc5: 0x10e1, + 0x1bc6: 0x10f9, 0x1bc7: 0xbbe9, 0x1bc8: 0x2079, 0x1bc9: 0xbc21, 0x1bca: 0xbac9, 0x1bcb: 0x1429, + 0x1bcc: 0xbb11, 0x1bcd: 0x10e1, 0x1bce: 0x1111, 0x1bcf: 0x2109, 0x1bd0: 0xbab1, 0x1bd1: 0x1099, + 0x1bd2: 0x10b1, 0x1bd3: 0x10c9, 0x1bd4: 0xbac9, 0x1bd5: 0xbae1, 0x1bd6: 0xbaf9, 0x1bd7: 0x1429, + 0x1bd8: 0x1a31, 0x1bd9: 0xbb11, 0x1bda: 0xbb29, 0x1bdb: 0xbb41, 0x1bdc: 0xbb59, 0x1bdd: 0xbb71, + 0x1bde: 0xbb89, 0x1bdf: 0x2109, 0x1be0: 0x1111, 0x1be1: 0x1429, 0x1be2: 0xbba1, 0x1be3: 0xbbb9, + 0x1be4: 0xbbd1, 0x1be5: 0x10e1, 0x1be6: 0x10f9, 0x1be7: 0xbbe9, 0x1be8: 0x2079, 0x1be9: 0xbc01, + 0x1bea: 0xbab1, 0x1beb: 0x1099, 0x1bec: 0x10b1, 0x1bed: 0x10c9, 0x1bee: 0xbac9, 0x1bef: 0xbae1, + 0x1bf0: 0xbaf9, 0x1bf1: 0x1429, 0x1bf2: 0x1a31, 0x1bf3: 0xbb11, 0x1bf4: 0xbb29, 0x1bf5: 0xbb41, + 0x1bf6: 0xbb59, 0x1bf7: 0xbb71, 0x1bf8: 0xbb89, 0x1bf9: 0x2109, 0x1bfa: 0x1111, 0x1bfb: 0xbba1, + 0x1bfc: 0xbba1, 0x1bfd: 0xbbb9, 0x1bfe: 0xbbd1, 0x1bff: 0x10e1, // Block 0x70, offset 0x1c00 - 0x1c00: 0xb189, 0x1c01: 0xb1a1, 0x1c02: 0xb201, 0x1c03: 0xb249, 0x1c04: 0x0040, 0x1c05: 0xb411, - 0x1c06: 0xb291, 0x1c07: 0xb219, 0x1c08: 0xb309, 0x1c09: 0xb429, 0x1c0a: 0xb399, 0x1c0b: 0xb3b1, - 0x1c0c: 0xb3c9, 0x1c0d: 0xb3e1, 0x1c0e: 0xb2a9, 0x1c0f: 0xb339, 0x1c10: 0xb369, 0x1c11: 0xb2d9, - 0x1c12: 0xb381, 0x1c13: 0xb279, 0x1c14: 0xb2c1, 0x1c15: 0xb1d1, 0x1c16: 0xb1e9, 0x1c17: 0xb231, - 0x1c18: 0xb261, 0x1c19: 0xb2f1, 0x1c1a: 0xb321, 0x1c1b: 0xb351, 0x1c1c: 0xbc59, 0x1c1d: 0x7949, - 0x1c1e: 0xbc71, 0x1c1f: 0xbc89, 0x1c20: 0x0040, 0x1c21: 0xb1a1, 0x1c22: 0xb201, 0x1c23: 0x0040, - 0x1c24: 0xb3f9, 0x1c25: 0x0040, 0x1c26: 0x0040, 0x1c27: 0xb219, 0x1c28: 0x0040, 0x1c29: 0xb429, - 0x1c2a: 0xb399, 0x1c2b: 0xb3b1, 0x1c2c: 0xb3c9, 0x1c2d: 0xb3e1, 0x1c2e: 0xb2a9, 0x1c2f: 0xb339, - 0x1c30: 0xb369, 0x1c31: 0xb2d9, 0x1c32: 0xb381, 0x1c33: 0x0040, 0x1c34: 0xb2c1, 0x1c35: 0xb1d1, - 0x1c36: 0xb1e9, 0x1c37: 0xb231, 0x1c38: 0x0040, 0x1c39: 0xb2f1, 0x1c3a: 0x0040, 0x1c3b: 0xb351, - 0x1c3c: 0x0040, 0x1c3d: 0x0040, 0x1c3e: 0x0040, 0x1c3f: 0x0040, + 0x1c00: 0x10f9, 0x1c01: 0xbbe9, 0x1c02: 0x2079, 0x1c03: 0xbc21, 0x1c04: 0xbac9, 0x1c05: 0x1429, + 0x1c06: 0xbb11, 0x1c07: 0x10e1, 0x1c08: 0x1111, 0x1c09: 0x2109, 0x1c0a: 0xbc41, 0x1c0b: 0xbc41, + 0x1c0c: 0x0040, 0x1c0d: 0x0040, 0x1c0e: 0x1f41, 0x1c0f: 0x00c9, 0x1c10: 0x0069, 0x1c11: 0x0079, + 0x1c12: 0x1f51, 0x1c13: 0x1f61, 0x1c14: 0x1f71, 0x1c15: 0x1f81, 0x1c16: 0x1f91, 0x1c17: 0x1fa1, + 0x1c18: 0x1f41, 0x1c19: 0x00c9, 0x1c1a: 0x0069, 0x1c1b: 0x0079, 0x1c1c: 0x1f51, 0x1c1d: 0x1f61, + 0x1c1e: 0x1f71, 0x1c1f: 0x1f81, 0x1c20: 0x1f91, 0x1c21: 0x1fa1, 0x1c22: 0x1f41, 0x1c23: 0x00c9, + 0x1c24: 0x0069, 0x1c25: 0x0079, 0x1c26: 0x1f51, 0x1c27: 0x1f61, 0x1c28: 0x1f71, 0x1c29: 0x1f81, + 0x1c2a: 0x1f91, 0x1c2b: 0x1fa1, 0x1c2c: 0x1f41, 0x1c2d: 0x00c9, 0x1c2e: 0x0069, 0x1c2f: 0x0079, + 0x1c30: 0x1f51, 0x1c31: 0x1f61, 0x1c32: 0x1f71, 0x1c33: 0x1f81, 0x1c34: 0x1f91, 0x1c35: 0x1fa1, + 0x1c36: 0x1f41, 0x1c37: 0x00c9, 0x1c38: 0x0069, 0x1c39: 0x0079, 0x1c3a: 0x1f51, 0x1c3b: 0x1f61, + 0x1c3c: 0x1f71, 0x1c3d: 0x1f81, 0x1c3e: 0x1f91, 0x1c3f: 0x1fa1, // Block 0x71, offset 0x1c40 - 0x1c40: 0x0040, 0x1c41: 0x0040, 0x1c42: 0xb201, 0x1c43: 0x0040, 0x1c44: 0x0040, 0x1c45: 0x0040, - 0x1c46: 0x0040, 0x1c47: 0xb219, 0x1c48: 0x0040, 0x1c49: 0xb429, 0x1c4a: 0x0040, 0x1c4b: 0xb3b1, - 0x1c4c: 0x0040, 0x1c4d: 0xb3e1, 0x1c4e: 0xb2a9, 0x1c4f: 0xb339, 0x1c50: 0x0040, 0x1c51: 0xb2d9, - 0x1c52: 0xb381, 0x1c53: 0x0040, 0x1c54: 0xb2c1, 0x1c55: 0x0040, 0x1c56: 0x0040, 0x1c57: 0xb231, - 0x1c58: 0x0040, 0x1c59: 0xb2f1, 0x1c5a: 0x0040, 0x1c5b: 0xb351, 0x1c5c: 0x0040, 0x1c5d: 0x7949, - 0x1c5e: 0x0040, 0x1c5f: 0xbc89, 0x1c60: 0x0040, 0x1c61: 0xb1a1, 0x1c62: 0xb201, 0x1c63: 0x0040, - 0x1c64: 0xb3f9, 0x1c65: 0x0040, 0x1c66: 0x0040, 0x1c67: 0xb219, 0x1c68: 0xb309, 0x1c69: 0xb429, - 0x1c6a: 0xb399, 0x1c6b: 0x0040, 0x1c6c: 0xb3c9, 0x1c6d: 0xb3e1, 0x1c6e: 0xb2a9, 0x1c6f: 0xb339, - 0x1c70: 0xb369, 0x1c71: 0xb2d9, 0x1c72: 0xb381, 0x1c73: 0x0040, 0x1c74: 0xb2c1, 0x1c75: 0xb1d1, - 0x1c76: 0xb1e9, 0x1c77: 0xb231, 0x1c78: 0x0040, 0x1c79: 0xb2f1, 0x1c7a: 0xb321, 0x1c7b: 0xb351, - 0x1c7c: 0xbc59, 0x1c7d: 0x0040, 0x1c7e: 0xbc71, 0x1c7f: 0x0040, + 0x1c40: 0xe115, 0x1c41: 0xe115, 0x1c42: 0xe135, 0x1c43: 0xe135, 0x1c44: 0xe115, 0x1c45: 0xe115, + 0x1c46: 0xe175, 0x1c47: 0xe175, 0x1c48: 0xe115, 0x1c49: 0xe115, 0x1c4a: 0xe135, 0x1c4b: 0xe135, + 0x1c4c: 0xe115, 0x1c4d: 0xe115, 0x1c4e: 0xe1f5, 0x1c4f: 0xe1f5, 0x1c50: 0xe115, 0x1c51: 0xe115, + 0x1c52: 0xe135, 0x1c53: 0xe135, 0x1c54: 0xe115, 0x1c55: 0xe115, 0x1c56: 0xe175, 0x1c57: 0xe175, + 0x1c58: 0xe115, 0x1c59: 0xe115, 0x1c5a: 0xe135, 0x1c5b: 0xe135, 0x1c5c: 0xe115, 0x1c5d: 0xe115, + 0x1c5e: 0x8b05, 0x1c5f: 0x8b05, 0x1c60: 0x04b5, 0x1c61: 0x04b5, 0x1c62: 0x0a08, 0x1c63: 0x0a08, + 0x1c64: 0x0a08, 0x1c65: 0x0a08, 0x1c66: 0x0a08, 0x1c67: 0x0a08, 0x1c68: 0x0a08, 0x1c69: 0x0a08, + 0x1c6a: 0x0a08, 0x1c6b: 0x0a08, 0x1c6c: 0x0a08, 0x1c6d: 0x0a08, 0x1c6e: 0x0a08, 0x1c6f: 0x0a08, + 0x1c70: 0x0a08, 0x1c71: 0x0a08, 0x1c72: 0x0a08, 0x1c73: 0x0a08, 0x1c74: 0x0a08, 0x1c75: 0x0a08, + 0x1c76: 0x0a08, 0x1c77: 0x0a08, 0x1c78: 0x0a08, 0x1c79: 0x0a08, 0x1c7a: 0x0a08, 0x1c7b: 0x0a08, + 0x1c7c: 0x0a08, 0x1c7d: 0x0a08, 0x1c7e: 0x0a08, 0x1c7f: 0x0a08, // Block 0x72, offset 0x1c80 - 0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0xb3f9, 0x1c85: 0xb411, - 0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0x0040, 0x1c8b: 0xb3b1, + 0x1c80: 0xb189, 0x1c81: 0xb1a1, 0x1c82: 0xb201, 0x1c83: 0xb249, 0x1c84: 0x0040, 0x1c85: 0xb411, + 0x1c86: 0xb291, 0x1c87: 0xb219, 0x1c88: 0xb309, 0x1c89: 0xb429, 0x1c8a: 0xb399, 0x1c8b: 0xb3b1, 0x1c8c: 0xb3c9, 0x1c8d: 0xb3e1, 0x1c8e: 0xb2a9, 0x1c8f: 0xb339, 0x1c90: 0xb369, 0x1c91: 0xb2d9, 0x1c92: 0xb381, 0x1c93: 0xb279, 0x1c94: 0xb2c1, 0x1c95: 0xb1d1, 0x1c96: 0xb1e9, 0x1c97: 0xb231, - 0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0x0040, 0x1c9d: 0x0040, - 0x1c9e: 0x0040, 0x1c9f: 0x0040, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0xb249, - 0x1ca4: 0x0040, 0x1ca5: 0xb411, 0x1ca6: 0xb291, 0x1ca7: 0xb219, 0x1ca8: 0xb309, 0x1ca9: 0xb429, - 0x1caa: 0x0040, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, - 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0xb279, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, - 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0xb261, 0x1cb9: 0xb2f1, 0x1cba: 0xb321, 0x1cbb: 0xb351, + 0x1c98: 0xb261, 0x1c99: 0xb2f1, 0x1c9a: 0xb321, 0x1c9b: 0xb351, 0x1c9c: 0xbc59, 0x1c9d: 0x7949, + 0x1c9e: 0xbc71, 0x1c9f: 0xbc89, 0x1ca0: 0x0040, 0x1ca1: 0xb1a1, 0x1ca2: 0xb201, 0x1ca3: 0x0040, + 0x1ca4: 0xb3f9, 0x1ca5: 0x0040, 0x1ca6: 0x0040, 0x1ca7: 0xb219, 0x1ca8: 0x0040, 0x1ca9: 0xb429, + 0x1caa: 0xb399, 0x1cab: 0xb3b1, 0x1cac: 0xb3c9, 0x1cad: 0xb3e1, 0x1cae: 0xb2a9, 0x1caf: 0xb339, + 0x1cb0: 0xb369, 0x1cb1: 0xb2d9, 0x1cb2: 0xb381, 0x1cb3: 0x0040, 0x1cb4: 0xb2c1, 0x1cb5: 0xb1d1, + 0x1cb6: 0xb1e9, 0x1cb7: 0xb231, 0x1cb8: 0x0040, 0x1cb9: 0xb2f1, 0x1cba: 0x0040, 0x1cbb: 0xb351, 0x1cbc: 0x0040, 0x1cbd: 0x0040, 0x1cbe: 0x0040, 0x1cbf: 0x0040, // Block 0x73, offset 0x1cc0 - 0x1cc0: 0x0040, 0x1cc1: 0xbca2, 0x1cc2: 0xbcba, 0x1cc3: 0xbcd2, 0x1cc4: 0xbcea, 0x1cc5: 0xbd02, - 0x1cc6: 0xbd1a, 0x1cc7: 0xbd32, 0x1cc8: 0xbd4a, 0x1cc9: 0xbd62, 0x1cca: 0xbd7a, 0x1ccb: 0x0018, - 0x1ccc: 0x0018, 0x1ccd: 0x0040, 0x1cce: 0x0040, 0x1ccf: 0x0040, 0x1cd0: 0xbd92, 0x1cd1: 0xbdb2, - 0x1cd2: 0xbdd2, 0x1cd3: 0xbdf2, 0x1cd4: 0xbe12, 0x1cd5: 0xbe32, 0x1cd6: 0xbe52, 0x1cd7: 0xbe72, - 0x1cd8: 0xbe92, 0x1cd9: 0xbeb2, 0x1cda: 0xbed2, 0x1cdb: 0xbef2, 0x1cdc: 0xbf12, 0x1cdd: 0xbf32, - 0x1cde: 0xbf52, 0x1cdf: 0xbf72, 0x1ce0: 0xbf92, 0x1ce1: 0xbfb2, 0x1ce2: 0xbfd2, 0x1ce3: 0xbff2, - 0x1ce4: 0xc012, 0x1ce5: 0xc032, 0x1ce6: 0xc052, 0x1ce7: 0xc072, 0x1ce8: 0xc092, 0x1ce9: 0xc0b2, - 0x1cea: 0xc0d1, 0x1ceb: 0x1159, 0x1cec: 0x0269, 0x1ced: 0x6671, 0x1cee: 0xc111, 0x1cef: 0x0040, - 0x1cf0: 0x0039, 0x1cf1: 0x0ee9, 0x1cf2: 0x1159, 0x1cf3: 0x0ef9, 0x1cf4: 0x0f09, 0x1cf5: 0x1199, - 0x1cf6: 0x0f31, 0x1cf7: 0x0249, 0x1cf8: 0x0f41, 0x1cf9: 0x0259, 0x1cfa: 0x0f51, 0x1cfb: 0x0359, - 0x1cfc: 0x0f61, 0x1cfd: 0x0f71, 0x1cfe: 0x00d9, 0x1cff: 0x0f99, + 0x1cc0: 0x0040, 0x1cc1: 0x0040, 0x1cc2: 0xb201, 0x1cc3: 0x0040, 0x1cc4: 0x0040, 0x1cc5: 0x0040, + 0x1cc6: 0x0040, 0x1cc7: 0xb219, 0x1cc8: 0x0040, 0x1cc9: 0xb429, 0x1cca: 0x0040, 0x1ccb: 0xb3b1, + 0x1ccc: 0x0040, 0x1ccd: 0xb3e1, 0x1cce: 0xb2a9, 0x1ccf: 0xb339, 0x1cd0: 0x0040, 0x1cd1: 0xb2d9, + 0x1cd2: 0xb381, 0x1cd3: 0x0040, 0x1cd4: 0xb2c1, 0x1cd5: 0x0040, 0x1cd6: 0x0040, 0x1cd7: 0xb231, + 0x1cd8: 0x0040, 0x1cd9: 0xb2f1, 0x1cda: 0x0040, 0x1cdb: 0xb351, 0x1cdc: 0x0040, 0x1cdd: 0x7949, + 0x1cde: 0x0040, 0x1cdf: 0xbc89, 0x1ce0: 0x0040, 0x1ce1: 0xb1a1, 0x1ce2: 0xb201, 0x1ce3: 0x0040, + 0x1ce4: 0xb3f9, 0x1ce5: 0x0040, 0x1ce6: 0x0040, 0x1ce7: 0xb219, 0x1ce8: 0xb309, 0x1ce9: 0xb429, + 0x1cea: 0xb399, 0x1ceb: 0x0040, 0x1cec: 0xb3c9, 0x1ced: 0xb3e1, 0x1cee: 0xb2a9, 0x1cef: 0xb339, + 0x1cf0: 0xb369, 0x1cf1: 0xb2d9, 0x1cf2: 0xb381, 0x1cf3: 0x0040, 0x1cf4: 0xb2c1, 0x1cf5: 0xb1d1, + 0x1cf6: 0xb1e9, 0x1cf7: 0xb231, 0x1cf8: 0x0040, 0x1cf9: 0xb2f1, 0x1cfa: 0xb321, 0x1cfb: 0xb351, + 0x1cfc: 0xbc59, 0x1cfd: 0x0040, 0x1cfe: 0xbc71, 0x1cff: 0x0040, // Block 0x74, offset 0x1d00 - 0x1d00: 0x2039, 0x1d01: 0x0269, 0x1d02: 0x01d9, 0x1d03: 0x0fa9, 0x1d04: 0x0fb9, 0x1d05: 0x1089, - 0x1d06: 0x0279, 0x1d07: 0x0369, 0x1d08: 0x0289, 0x1d09: 0x13d1, 0x1d0a: 0xc129, 0x1d0b: 0x65b1, - 0x1d0c: 0xc141, 0x1d0d: 0x1441, 0x1d0e: 0xc159, 0x1d0f: 0xc179, 0x1d10: 0x0018, 0x1d11: 0x0018, - 0x1d12: 0x0018, 0x1d13: 0x0018, 0x1d14: 0x0018, 0x1d15: 0x0018, 0x1d16: 0x0018, 0x1d17: 0x0018, - 0x1d18: 0x0018, 0x1d19: 0x0018, 0x1d1a: 0x0018, 0x1d1b: 0x0018, 0x1d1c: 0x0018, 0x1d1d: 0x0018, - 0x1d1e: 0x0018, 0x1d1f: 0x0018, 0x1d20: 0x0018, 0x1d21: 0x0018, 0x1d22: 0x0018, 0x1d23: 0x0018, - 0x1d24: 0x0018, 0x1d25: 0x0018, 0x1d26: 0x0018, 0x1d27: 0x0018, 0x1d28: 0x0018, 0x1d29: 0x0018, - 0x1d2a: 0xc191, 0x1d2b: 0xc1a9, 0x1d2c: 0x0040, 0x1d2d: 0x0040, 0x1d2e: 0x0040, 0x1d2f: 0x0040, - 0x1d30: 0x0018, 0x1d31: 0x0018, 0x1d32: 0x0018, 0x1d33: 0x0018, 0x1d34: 0x0018, 0x1d35: 0x0018, - 0x1d36: 0x0018, 0x1d37: 0x0018, 0x1d38: 0x0018, 0x1d39: 0x0018, 0x1d3a: 0x0018, 0x1d3b: 0x0018, - 0x1d3c: 0x0018, 0x1d3d: 0x0018, 0x1d3e: 0x0018, 0x1d3f: 0x0018, + 0x1d00: 0xb189, 0x1d01: 0xb1a1, 0x1d02: 0xb201, 0x1d03: 0xb249, 0x1d04: 0xb3f9, 0x1d05: 0xb411, + 0x1d06: 0xb291, 0x1d07: 0xb219, 0x1d08: 0xb309, 0x1d09: 0xb429, 0x1d0a: 0x0040, 0x1d0b: 0xb3b1, + 0x1d0c: 0xb3c9, 0x1d0d: 0xb3e1, 0x1d0e: 0xb2a9, 0x1d0f: 0xb339, 0x1d10: 0xb369, 0x1d11: 0xb2d9, + 0x1d12: 0xb381, 0x1d13: 0xb279, 0x1d14: 0xb2c1, 0x1d15: 0xb1d1, 0x1d16: 0xb1e9, 0x1d17: 0xb231, + 0x1d18: 0xb261, 0x1d19: 0xb2f1, 0x1d1a: 0xb321, 0x1d1b: 0xb351, 0x1d1c: 0x0040, 0x1d1d: 0x0040, + 0x1d1e: 0x0040, 0x1d1f: 0x0040, 0x1d20: 0x0040, 0x1d21: 0xb1a1, 0x1d22: 0xb201, 0x1d23: 0xb249, + 0x1d24: 0x0040, 0x1d25: 0xb411, 0x1d26: 0xb291, 0x1d27: 0xb219, 0x1d28: 0xb309, 0x1d29: 0xb429, + 0x1d2a: 0x0040, 0x1d2b: 0xb3b1, 0x1d2c: 0xb3c9, 0x1d2d: 0xb3e1, 0x1d2e: 0xb2a9, 0x1d2f: 0xb339, + 0x1d30: 0xb369, 0x1d31: 0xb2d9, 0x1d32: 0xb381, 0x1d33: 0xb279, 0x1d34: 0xb2c1, 0x1d35: 0xb1d1, + 0x1d36: 0xb1e9, 0x1d37: 0xb231, 0x1d38: 0xb261, 0x1d39: 0xb2f1, 0x1d3a: 0xb321, 0x1d3b: 0xb351, + 0x1d3c: 0x0040, 0x1d3d: 0x0040, 0x1d3e: 0x0040, 0x1d3f: 0x0040, // Block 0x75, offset 0x1d40 - 0x1d40: 0xc1d9, 0x1d41: 0xc211, 0x1d42: 0xc249, 0x1d43: 0x0040, 0x1d44: 0x0040, 0x1d45: 0x0040, - 0x1d46: 0x0040, 0x1d47: 0x0040, 0x1d48: 0x0040, 0x1d49: 0x0040, 0x1d4a: 0x0040, 0x1d4b: 0x0040, - 0x1d4c: 0x0040, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xc269, 0x1d51: 0xc289, - 0x1d52: 0xc2a9, 0x1d53: 0xc2c9, 0x1d54: 0xc2e9, 0x1d55: 0xc309, 0x1d56: 0xc329, 0x1d57: 0xc349, - 0x1d58: 0xc369, 0x1d59: 0xc389, 0x1d5a: 0xc3a9, 0x1d5b: 0xc3c9, 0x1d5c: 0xc3e9, 0x1d5d: 0xc409, - 0x1d5e: 0xc429, 0x1d5f: 0xc449, 0x1d60: 0xc469, 0x1d61: 0xc489, 0x1d62: 0xc4a9, 0x1d63: 0xc4c9, - 0x1d64: 0xc4e9, 0x1d65: 0xc509, 0x1d66: 0xc529, 0x1d67: 0xc549, 0x1d68: 0xc569, 0x1d69: 0xc589, - 0x1d6a: 0xc5a9, 0x1d6b: 0xc5c9, 0x1d6c: 0xc5e9, 0x1d6d: 0xc609, 0x1d6e: 0xc629, 0x1d6f: 0xc649, - 0x1d70: 0xc669, 0x1d71: 0xc689, 0x1d72: 0xc6a9, 0x1d73: 0xc6c9, 0x1d74: 0xc6e9, 0x1d75: 0xc709, - 0x1d76: 0xc729, 0x1d77: 0xc749, 0x1d78: 0xc769, 0x1d79: 0xc789, 0x1d7a: 0xc7a9, 0x1d7b: 0xc7c9, - 0x1d7c: 0x0040, 0x1d7d: 0x0040, 0x1d7e: 0x0040, 0x1d7f: 0x0040, + 0x1d40: 0x0040, 0x1d41: 0xbca2, 0x1d42: 0xbcba, 0x1d43: 0xbcd2, 0x1d44: 0xbcea, 0x1d45: 0xbd02, + 0x1d46: 0xbd1a, 0x1d47: 0xbd32, 0x1d48: 0xbd4a, 0x1d49: 0xbd62, 0x1d4a: 0xbd7a, 0x1d4b: 0x0018, + 0x1d4c: 0x0018, 0x1d4d: 0x0040, 0x1d4e: 0x0040, 0x1d4f: 0x0040, 0x1d50: 0xbd92, 0x1d51: 0xbdb2, + 0x1d52: 0xbdd2, 0x1d53: 0xbdf2, 0x1d54: 0xbe12, 0x1d55: 0xbe32, 0x1d56: 0xbe52, 0x1d57: 0xbe72, + 0x1d58: 0xbe92, 0x1d59: 0xbeb2, 0x1d5a: 0xbed2, 0x1d5b: 0xbef2, 0x1d5c: 0xbf12, 0x1d5d: 0xbf32, + 0x1d5e: 0xbf52, 0x1d5f: 0xbf72, 0x1d60: 0xbf92, 0x1d61: 0xbfb2, 0x1d62: 0xbfd2, 0x1d63: 0xbff2, + 0x1d64: 0xc012, 0x1d65: 0xc032, 0x1d66: 0xc052, 0x1d67: 0xc072, 0x1d68: 0xc092, 0x1d69: 0xc0b2, + 0x1d6a: 0xc0d1, 0x1d6b: 0x1159, 0x1d6c: 0x0269, 0x1d6d: 0x6671, 0x1d6e: 0xc111, 0x1d6f: 0x0040, + 0x1d70: 0x0039, 0x1d71: 0x0ee9, 0x1d72: 0x1159, 0x1d73: 0x0ef9, 0x1d74: 0x0f09, 0x1d75: 0x1199, + 0x1d76: 0x0f31, 0x1d77: 0x0249, 0x1d78: 0x0f41, 0x1d79: 0x0259, 0x1d7a: 0x0f51, 0x1d7b: 0x0359, + 0x1d7c: 0x0f61, 0x1d7d: 0x0f71, 0x1d7e: 0x00d9, 0x1d7f: 0x0f99, // Block 0x76, offset 0x1d80 - 0x1d80: 0xcaf9, 0x1d81: 0xcb19, 0x1d82: 0xcb39, 0x1d83: 0x8b1d, 0x1d84: 0xcb59, 0x1d85: 0xcb79, - 0x1d86: 0xcb99, 0x1d87: 0xcbb9, 0x1d88: 0xcbd9, 0x1d89: 0xcbf9, 0x1d8a: 0xcc19, 0x1d8b: 0xcc39, - 0x1d8c: 0xcc59, 0x1d8d: 0x8b3d, 0x1d8e: 0xcc79, 0x1d8f: 0xcc99, 0x1d90: 0xccb9, 0x1d91: 0xccd9, - 0x1d92: 0x8b5d, 0x1d93: 0xccf9, 0x1d94: 0xcd19, 0x1d95: 0xc429, 0x1d96: 0x8b7d, 0x1d97: 0xcd39, - 0x1d98: 0xcd59, 0x1d99: 0xcd79, 0x1d9a: 0xcd99, 0x1d9b: 0xcdb9, 0x1d9c: 0x8b9d, 0x1d9d: 0xcdd9, - 0x1d9e: 0xcdf9, 0x1d9f: 0xce19, 0x1da0: 0xce39, 0x1da1: 0xce59, 0x1da2: 0xc789, 0x1da3: 0xce79, - 0x1da4: 0xce99, 0x1da5: 0xceb9, 0x1da6: 0xced9, 0x1da7: 0xcef9, 0x1da8: 0xcf19, 0x1da9: 0xcf39, - 0x1daa: 0xcf59, 0x1dab: 0xcf79, 0x1dac: 0xcf99, 0x1dad: 0xcfb9, 0x1dae: 0xcfd9, 0x1daf: 0xcff9, - 0x1db0: 0xd019, 0x1db1: 0xd039, 0x1db2: 0xd039, 0x1db3: 0xd039, 0x1db4: 0x8bbd, 0x1db5: 0xd059, - 0x1db6: 0xd079, 0x1db7: 0xd099, 0x1db8: 0x8bdd, 0x1db9: 0xd0b9, 0x1dba: 0xd0d9, 0x1dbb: 0xd0f9, - 0x1dbc: 0xd119, 0x1dbd: 0xd139, 0x1dbe: 0xd159, 0x1dbf: 0xd179, + 0x1d80: 0x2039, 0x1d81: 0x0269, 0x1d82: 0x01d9, 0x1d83: 0x0fa9, 0x1d84: 0x0fb9, 0x1d85: 0x1089, + 0x1d86: 0x0279, 0x1d87: 0x0369, 0x1d88: 0x0289, 0x1d89: 0x13d1, 0x1d8a: 0xc129, 0x1d8b: 0x65b1, + 0x1d8c: 0xc141, 0x1d8d: 0x1441, 0x1d8e: 0xc159, 0x1d8f: 0xc179, 0x1d90: 0x0018, 0x1d91: 0x0018, + 0x1d92: 0x0018, 0x1d93: 0x0018, 0x1d94: 0x0018, 0x1d95: 0x0018, 0x1d96: 0x0018, 0x1d97: 0x0018, + 0x1d98: 0x0018, 0x1d99: 0x0018, 0x1d9a: 0x0018, 0x1d9b: 0x0018, 0x1d9c: 0x0018, 0x1d9d: 0x0018, + 0x1d9e: 0x0018, 0x1d9f: 0x0018, 0x1da0: 0x0018, 0x1da1: 0x0018, 0x1da2: 0x0018, 0x1da3: 0x0018, + 0x1da4: 0x0018, 0x1da5: 0x0018, 0x1da6: 0x0018, 0x1da7: 0x0018, 0x1da8: 0x0018, 0x1da9: 0x0018, + 0x1daa: 0xc191, 0x1dab: 0xc1a9, 0x1dac: 0x0040, 0x1dad: 0x0040, 0x1dae: 0x0040, 0x1daf: 0x0040, + 0x1db0: 0x0018, 0x1db1: 0x0018, 0x1db2: 0x0018, 0x1db3: 0x0018, 0x1db4: 0x0018, 0x1db5: 0x0018, + 0x1db6: 0x0018, 0x1db7: 0x0018, 0x1db8: 0x0018, 0x1db9: 0x0018, 0x1dba: 0x0018, 0x1dbb: 0x0018, + 0x1dbc: 0x0018, 0x1dbd: 0x0018, 0x1dbe: 0x0018, 0x1dbf: 0x0018, // Block 0x77, offset 0x1dc0 - 0x1dc0: 0xd199, 0x1dc1: 0xd1b9, 0x1dc2: 0xd1d9, 0x1dc3: 0xd1f9, 0x1dc4: 0xd219, 0x1dc5: 0xd239, - 0x1dc6: 0xd239, 0x1dc7: 0xd259, 0x1dc8: 0xd279, 0x1dc9: 0xd299, 0x1dca: 0xd2b9, 0x1dcb: 0xd2d9, - 0x1dcc: 0xd2f9, 0x1dcd: 0xd319, 0x1dce: 0xd339, 0x1dcf: 0xd359, 0x1dd0: 0xd379, 0x1dd1: 0xd399, - 0x1dd2: 0xd3b9, 0x1dd3: 0xd3d9, 0x1dd4: 0xd3f9, 0x1dd5: 0xd419, 0x1dd6: 0xd439, 0x1dd7: 0xd459, - 0x1dd8: 0xd479, 0x1dd9: 0x8bfd, 0x1dda: 0xd499, 0x1ddb: 0xd4b9, 0x1ddc: 0xd4d9, 0x1ddd: 0xc309, - 0x1dde: 0xd4f9, 0x1ddf: 0xd519, 0x1de0: 0x8c1d, 0x1de1: 0x8c3d, 0x1de2: 0xd539, 0x1de3: 0xd559, - 0x1de4: 0xd579, 0x1de5: 0xd599, 0x1de6: 0xd5b9, 0x1de7: 0xd5d9, 0x1de8: 0x0040, 0x1de9: 0xd5f9, - 0x1dea: 0xd619, 0x1deb: 0xd619, 0x1dec: 0x8c5d, 0x1ded: 0xd639, 0x1dee: 0xd659, 0x1def: 0xd679, - 0x1df0: 0xd699, 0x1df1: 0x8c7d, 0x1df2: 0xd6b9, 0x1df3: 0xd6d9, 0x1df4: 0x0040, 0x1df5: 0xd6f9, - 0x1df6: 0xd719, 0x1df7: 0xd739, 0x1df8: 0xd759, 0x1df9: 0xd779, 0x1dfa: 0xd799, 0x1dfb: 0x8c9d, - 0x1dfc: 0xd7b9, 0x1dfd: 0x8cbd, 0x1dfe: 0xd7d9, 0x1dff: 0xd7f9, + 0x1dc0: 0xc1d9, 0x1dc1: 0xc211, 0x1dc2: 0xc249, 0x1dc3: 0x0040, 0x1dc4: 0x0040, 0x1dc5: 0x0040, + 0x1dc6: 0x0040, 0x1dc7: 0x0040, 0x1dc8: 0x0040, 0x1dc9: 0x0040, 0x1dca: 0x0040, 0x1dcb: 0x0040, + 0x1dcc: 0x0040, 0x1dcd: 0x0040, 0x1dce: 0x0040, 0x1dcf: 0x0040, 0x1dd0: 0xc269, 0x1dd1: 0xc289, + 0x1dd2: 0xc2a9, 0x1dd3: 0xc2c9, 0x1dd4: 0xc2e9, 0x1dd5: 0xc309, 0x1dd6: 0xc329, 0x1dd7: 0xc349, + 0x1dd8: 0xc369, 0x1dd9: 0xc389, 0x1dda: 0xc3a9, 0x1ddb: 0xc3c9, 0x1ddc: 0xc3e9, 0x1ddd: 0xc409, + 0x1dde: 0xc429, 0x1ddf: 0xc449, 0x1de0: 0xc469, 0x1de1: 0xc489, 0x1de2: 0xc4a9, 0x1de3: 0xc4c9, + 0x1de4: 0xc4e9, 0x1de5: 0xc509, 0x1de6: 0xc529, 0x1de7: 0xc549, 0x1de8: 0xc569, 0x1de9: 0xc589, + 0x1dea: 0xc5a9, 0x1deb: 0xc5c9, 0x1dec: 0xc5e9, 0x1ded: 0xc609, 0x1dee: 0xc629, 0x1def: 0xc649, + 0x1df0: 0xc669, 0x1df1: 0xc689, 0x1df2: 0xc6a9, 0x1df3: 0xc6c9, 0x1df4: 0xc6e9, 0x1df5: 0xc709, + 0x1df6: 0xc729, 0x1df7: 0xc749, 0x1df8: 0xc769, 0x1df9: 0xc789, 0x1dfa: 0xc7a9, 0x1dfb: 0xc7c9, + 0x1dfc: 0x0040, 0x1dfd: 0x0040, 0x1dfe: 0x0040, 0x1dff: 0x0040, // Block 0x78, offset 0x1e00 - 0x1e00: 0xd819, 0x1e01: 0xd839, 0x1e02: 0xd859, 0x1e03: 0xd879, 0x1e04: 0xd899, 0x1e05: 0xd8b9, - 0x1e06: 0xd8d9, 0x1e07: 0xd8f9, 0x1e08: 0xd919, 0x1e09: 0x8cdd, 0x1e0a: 0xd939, 0x1e0b: 0xd959, - 0x1e0c: 0xd979, 0x1e0d: 0xd999, 0x1e0e: 0xd9b9, 0x1e0f: 0x8cfd, 0x1e10: 0xd9d9, 0x1e11: 0x8d1d, - 0x1e12: 0x8d3d, 0x1e13: 0xd9f9, 0x1e14: 0xda19, 0x1e15: 0xda19, 0x1e16: 0xda39, 0x1e17: 0x8d5d, - 0x1e18: 0x8d7d, 0x1e19: 0xda59, 0x1e1a: 0xda79, 0x1e1b: 0xda99, 0x1e1c: 0xdab9, 0x1e1d: 0xdad9, - 0x1e1e: 0xdaf9, 0x1e1f: 0xdb19, 0x1e20: 0xdb39, 0x1e21: 0xdb59, 0x1e22: 0xdb79, 0x1e23: 0xdb99, - 0x1e24: 0x8d9d, 0x1e25: 0xdbb9, 0x1e26: 0xdbd9, 0x1e27: 0xdbf9, 0x1e28: 0xdc19, 0x1e29: 0xdbf9, - 0x1e2a: 0xdc39, 0x1e2b: 0xdc59, 0x1e2c: 0xdc79, 0x1e2d: 0xdc99, 0x1e2e: 0xdcb9, 0x1e2f: 0xdcd9, - 0x1e30: 0xdcf9, 0x1e31: 0xdd19, 0x1e32: 0xdd39, 0x1e33: 0xdd59, 0x1e34: 0xdd79, 0x1e35: 0xdd99, - 0x1e36: 0xddb9, 0x1e37: 0xddd9, 0x1e38: 0x8dbd, 0x1e39: 0xddf9, 0x1e3a: 0xde19, 0x1e3b: 0xde39, - 0x1e3c: 0xde59, 0x1e3d: 0xde79, 0x1e3e: 0x8ddd, 0x1e3f: 0xde99, + 0x1e00: 0xcaf9, 0x1e01: 0xcb19, 0x1e02: 0xcb39, 0x1e03: 0x8b1d, 0x1e04: 0xcb59, 0x1e05: 0xcb79, + 0x1e06: 0xcb99, 0x1e07: 0xcbb9, 0x1e08: 0xcbd9, 0x1e09: 0xcbf9, 0x1e0a: 0xcc19, 0x1e0b: 0xcc39, + 0x1e0c: 0xcc59, 0x1e0d: 0x8b3d, 0x1e0e: 0xcc79, 0x1e0f: 0xcc99, 0x1e10: 0xccb9, 0x1e11: 0xccd9, + 0x1e12: 0x8b5d, 0x1e13: 0xccf9, 0x1e14: 0xcd19, 0x1e15: 0xc429, 0x1e16: 0x8b7d, 0x1e17: 0xcd39, + 0x1e18: 0xcd59, 0x1e19: 0xcd79, 0x1e1a: 0xcd99, 0x1e1b: 0xcdb9, 0x1e1c: 0x8b9d, 0x1e1d: 0xcdd9, + 0x1e1e: 0xcdf9, 0x1e1f: 0xce19, 0x1e20: 0xce39, 0x1e21: 0xce59, 0x1e22: 0xc789, 0x1e23: 0xce79, + 0x1e24: 0xce99, 0x1e25: 0xceb9, 0x1e26: 0xced9, 0x1e27: 0xcef9, 0x1e28: 0xcf19, 0x1e29: 0xcf39, + 0x1e2a: 0xcf59, 0x1e2b: 0xcf79, 0x1e2c: 0xcf99, 0x1e2d: 0xcfb9, 0x1e2e: 0xcfd9, 0x1e2f: 0xcff9, + 0x1e30: 0xd019, 0x1e31: 0xd039, 0x1e32: 0xd039, 0x1e33: 0xd039, 0x1e34: 0x8bbd, 0x1e35: 0xd059, + 0x1e36: 0xd079, 0x1e37: 0xd099, 0x1e38: 0x8bdd, 0x1e39: 0xd0b9, 0x1e3a: 0xd0d9, 0x1e3b: 0xd0f9, + 0x1e3c: 0xd119, 0x1e3d: 0xd139, 0x1e3e: 0xd159, 0x1e3f: 0xd179, // Block 0x79, offset 0x1e40 - 0x1e40: 0xe599, 0x1e41: 0xe5b9, 0x1e42: 0xe5d9, 0x1e43: 0xe5f9, 0x1e44: 0xe619, 0x1e45: 0xe639, - 0x1e46: 0x8efd, 0x1e47: 0xe659, 0x1e48: 0xe679, 0x1e49: 0xe699, 0x1e4a: 0xe6b9, 0x1e4b: 0xe6d9, - 0x1e4c: 0xe6f9, 0x1e4d: 0x8f1d, 0x1e4e: 0xe719, 0x1e4f: 0xe739, 0x1e50: 0x8f3d, 0x1e51: 0x8f5d, - 0x1e52: 0xe759, 0x1e53: 0xe779, 0x1e54: 0xe799, 0x1e55: 0xe7b9, 0x1e56: 0xe7d9, 0x1e57: 0xe7f9, - 0x1e58: 0xe819, 0x1e59: 0xe839, 0x1e5a: 0xe859, 0x1e5b: 0x8f7d, 0x1e5c: 0xe879, 0x1e5d: 0x8f9d, - 0x1e5e: 0xe899, 0x1e5f: 0x0040, 0x1e60: 0xe8b9, 0x1e61: 0xe8d9, 0x1e62: 0xe8f9, 0x1e63: 0x8fbd, - 0x1e64: 0xe919, 0x1e65: 0xe939, 0x1e66: 0x8fdd, 0x1e67: 0x8ffd, 0x1e68: 0xe959, 0x1e69: 0xe979, - 0x1e6a: 0xe999, 0x1e6b: 0xe9b9, 0x1e6c: 0xe9d9, 0x1e6d: 0xe9d9, 0x1e6e: 0xe9f9, 0x1e6f: 0xea19, - 0x1e70: 0xea39, 0x1e71: 0xea59, 0x1e72: 0xea79, 0x1e73: 0xea99, 0x1e74: 0xeab9, 0x1e75: 0x901d, - 0x1e76: 0xead9, 0x1e77: 0x903d, 0x1e78: 0xeaf9, 0x1e79: 0x905d, 0x1e7a: 0xeb19, 0x1e7b: 0x907d, - 0x1e7c: 0x909d, 0x1e7d: 0x90bd, 0x1e7e: 0xeb39, 0x1e7f: 0xeb59, + 0x1e40: 0xd199, 0x1e41: 0xd1b9, 0x1e42: 0xd1d9, 0x1e43: 0xd1f9, 0x1e44: 0xd219, 0x1e45: 0xd239, + 0x1e46: 0xd239, 0x1e47: 0xd259, 0x1e48: 0xd279, 0x1e49: 0xd299, 0x1e4a: 0xd2b9, 0x1e4b: 0xd2d9, + 0x1e4c: 0xd2f9, 0x1e4d: 0xd319, 0x1e4e: 0xd339, 0x1e4f: 0xd359, 0x1e50: 0xd379, 0x1e51: 0xd399, + 0x1e52: 0xd3b9, 0x1e53: 0xd3d9, 0x1e54: 0xd3f9, 0x1e55: 0xd419, 0x1e56: 0xd439, 0x1e57: 0xd459, + 0x1e58: 0xd479, 0x1e59: 0x8bfd, 0x1e5a: 0xd499, 0x1e5b: 0xd4b9, 0x1e5c: 0xd4d9, 0x1e5d: 0xc309, + 0x1e5e: 0xd4f9, 0x1e5f: 0xd519, 0x1e60: 0x8c1d, 0x1e61: 0x8c3d, 0x1e62: 0xd539, 0x1e63: 0xd559, + 0x1e64: 0xd579, 0x1e65: 0xd599, 0x1e66: 0xd5b9, 0x1e67: 0xd5d9, 0x1e68: 0x2040, 0x1e69: 0xd5f9, + 0x1e6a: 0xd619, 0x1e6b: 0xd619, 0x1e6c: 0x8c5d, 0x1e6d: 0xd639, 0x1e6e: 0xd659, 0x1e6f: 0xd679, + 0x1e70: 0xd699, 0x1e71: 0x8c7d, 0x1e72: 0xd6b9, 0x1e73: 0xd6d9, 0x1e74: 0x2040, 0x1e75: 0xd6f9, + 0x1e76: 0xd719, 0x1e77: 0xd739, 0x1e78: 0xd759, 0x1e79: 0xd779, 0x1e7a: 0xd799, 0x1e7b: 0x8c9d, + 0x1e7c: 0xd7b9, 0x1e7d: 0x8cbd, 0x1e7e: 0xd7d9, 0x1e7f: 0xd7f9, // Block 0x7a, offset 0x1e80 - 0x1e80: 0xeb79, 0x1e81: 0x90dd, 0x1e82: 0x90fd, 0x1e83: 0x911d, 0x1e84: 0x913d, 0x1e85: 0xeb99, - 0x1e86: 0xebb9, 0x1e87: 0xebb9, 0x1e88: 0xebd9, 0x1e89: 0xebf9, 0x1e8a: 0xec19, 0x1e8b: 0xec39, - 0x1e8c: 0xec59, 0x1e8d: 0x915d, 0x1e8e: 0xec79, 0x1e8f: 0xec99, 0x1e90: 0xecb9, 0x1e91: 0xecd9, - 0x1e92: 0x917d, 0x1e93: 0xecf9, 0x1e94: 0x919d, 0x1e95: 0x91bd, 0x1e96: 0xed19, 0x1e97: 0xed39, - 0x1e98: 0xed59, 0x1e99: 0xed79, 0x1e9a: 0xed99, 0x1e9b: 0xedb9, 0x1e9c: 0x91dd, 0x1e9d: 0x91fd, - 0x1e9e: 0x921d, 0x1e9f: 0x0040, 0x1ea0: 0xedd9, 0x1ea1: 0x923d, 0x1ea2: 0xedf9, 0x1ea3: 0xee19, - 0x1ea4: 0xee39, 0x1ea5: 0x925d, 0x1ea6: 0xee59, 0x1ea7: 0xee79, 0x1ea8: 0xee99, 0x1ea9: 0xeeb9, - 0x1eaa: 0xeed9, 0x1eab: 0x927d, 0x1eac: 0xeef9, 0x1ead: 0xef19, 0x1eae: 0xef39, 0x1eaf: 0xef59, - 0x1eb0: 0xef79, 0x1eb1: 0xef99, 0x1eb2: 0x929d, 0x1eb3: 0x92bd, 0x1eb4: 0xefb9, 0x1eb5: 0x92dd, - 0x1eb6: 0xefd9, 0x1eb7: 0x92fd, 0x1eb8: 0xeff9, 0x1eb9: 0xf019, 0x1eba: 0xf039, 0x1ebb: 0x931d, - 0x1ebc: 0x933d, 0x1ebd: 0xf059, 0x1ebe: 0x935d, 0x1ebf: 0xf079, + 0x1e80: 0xd819, 0x1e81: 0xd839, 0x1e82: 0xd859, 0x1e83: 0xd879, 0x1e84: 0xd899, 0x1e85: 0xd8b9, + 0x1e86: 0xd8d9, 0x1e87: 0xd8f9, 0x1e88: 0xd919, 0x1e89: 0x8cdd, 0x1e8a: 0xd939, 0x1e8b: 0xd959, + 0x1e8c: 0xd979, 0x1e8d: 0xd999, 0x1e8e: 0xd9b9, 0x1e8f: 0x8cfd, 0x1e90: 0xd9d9, 0x1e91: 0x8d1d, + 0x1e92: 0x8d3d, 0x1e93: 0xd9f9, 0x1e94: 0xda19, 0x1e95: 0xda19, 0x1e96: 0xda39, 0x1e97: 0x8d5d, + 0x1e98: 0x8d7d, 0x1e99: 0xda59, 0x1e9a: 0xda79, 0x1e9b: 0xda99, 0x1e9c: 0xdab9, 0x1e9d: 0xdad9, + 0x1e9e: 0xdaf9, 0x1e9f: 0xdb19, 0x1ea0: 0xdb39, 0x1ea1: 0xdb59, 0x1ea2: 0xdb79, 0x1ea3: 0xdb99, + 0x1ea4: 0x8d9d, 0x1ea5: 0xdbb9, 0x1ea6: 0xdbd9, 0x1ea7: 0xdbf9, 0x1ea8: 0xdc19, 0x1ea9: 0xdbf9, + 0x1eaa: 0xdc39, 0x1eab: 0xdc59, 0x1eac: 0xdc79, 0x1ead: 0xdc99, 0x1eae: 0xdcb9, 0x1eaf: 0xdcd9, + 0x1eb0: 0xdcf9, 0x1eb1: 0xdd19, 0x1eb2: 0xdd39, 0x1eb3: 0xdd59, 0x1eb4: 0xdd79, 0x1eb5: 0xdd99, + 0x1eb6: 0xddb9, 0x1eb7: 0xddd9, 0x1eb8: 0x8dbd, 0x1eb9: 0xddf9, 0x1eba: 0xde19, 0x1ebb: 0xde39, + 0x1ebc: 0xde59, 0x1ebd: 0xde79, 0x1ebe: 0x8ddd, 0x1ebf: 0xde99, // Block 0x7b, offset 0x1ec0 - 0x1ec0: 0xf6b9, 0x1ec1: 0xf6d9, 0x1ec2: 0xf6f9, 0x1ec3: 0xf719, 0x1ec4: 0xf739, 0x1ec5: 0x951d, - 0x1ec6: 0xf759, 0x1ec7: 0xf779, 0x1ec8: 0xf799, 0x1ec9: 0xf7b9, 0x1eca: 0xf7d9, 0x1ecb: 0x953d, - 0x1ecc: 0x955d, 0x1ecd: 0xf7f9, 0x1ece: 0xf819, 0x1ecf: 0xf839, 0x1ed0: 0xf859, 0x1ed1: 0xf879, - 0x1ed2: 0xf899, 0x1ed3: 0x957d, 0x1ed4: 0xf8b9, 0x1ed5: 0xf8d9, 0x1ed6: 0xf8f9, 0x1ed7: 0xf919, - 0x1ed8: 0x959d, 0x1ed9: 0x95bd, 0x1eda: 0xf939, 0x1edb: 0xf959, 0x1edc: 0xf979, 0x1edd: 0x95dd, - 0x1ede: 0xf999, 0x1edf: 0xf9b9, 0x1ee0: 0x6815, 0x1ee1: 0x95fd, 0x1ee2: 0xf9d9, 0x1ee3: 0xf9f9, - 0x1ee4: 0xfa19, 0x1ee5: 0x961d, 0x1ee6: 0xfa39, 0x1ee7: 0xfa59, 0x1ee8: 0xfa79, 0x1ee9: 0xfa99, - 0x1eea: 0xfab9, 0x1eeb: 0xfad9, 0x1eec: 0xfaf9, 0x1eed: 0x963d, 0x1eee: 0xfb19, 0x1eef: 0xfb39, - 0x1ef0: 0xfb59, 0x1ef1: 0x965d, 0x1ef2: 0xfb79, 0x1ef3: 0xfb99, 0x1ef4: 0xfbb9, 0x1ef5: 0xfbd9, - 0x1ef6: 0x7b35, 0x1ef7: 0x967d, 0x1ef8: 0xfbf9, 0x1ef9: 0xfc19, 0x1efa: 0xfc39, 0x1efb: 0x969d, - 0x1efc: 0xfc59, 0x1efd: 0x96bd, 0x1efe: 0xfc79, 0x1eff: 0xfc79, + 0x1ec0: 0xe599, 0x1ec1: 0xe5b9, 0x1ec2: 0xe5d9, 0x1ec3: 0xe5f9, 0x1ec4: 0xe619, 0x1ec5: 0xe639, + 0x1ec6: 0x8efd, 0x1ec7: 0xe659, 0x1ec8: 0xe679, 0x1ec9: 0xe699, 0x1eca: 0xe6b9, 0x1ecb: 0xe6d9, + 0x1ecc: 0xe6f9, 0x1ecd: 0x8f1d, 0x1ece: 0xe719, 0x1ecf: 0xe739, 0x1ed0: 0x8f3d, 0x1ed1: 0x8f5d, + 0x1ed2: 0xe759, 0x1ed3: 0xe779, 0x1ed4: 0xe799, 0x1ed5: 0xe7b9, 0x1ed6: 0xe7d9, 0x1ed7: 0xe7f9, + 0x1ed8: 0xe819, 0x1ed9: 0xe839, 0x1eda: 0xe859, 0x1edb: 0x8f7d, 0x1edc: 0xe879, 0x1edd: 0x8f9d, + 0x1ede: 0xe899, 0x1edf: 0x2040, 0x1ee0: 0xe8b9, 0x1ee1: 0xe8d9, 0x1ee2: 0xe8f9, 0x1ee3: 0x8fbd, + 0x1ee4: 0xe919, 0x1ee5: 0xe939, 0x1ee6: 0x8fdd, 0x1ee7: 0x8ffd, 0x1ee8: 0xe959, 0x1ee9: 0xe979, + 0x1eea: 0xe999, 0x1eeb: 0xe9b9, 0x1eec: 0xe9d9, 0x1eed: 0xe9d9, 0x1eee: 0xe9f9, 0x1eef: 0xea19, + 0x1ef0: 0xea39, 0x1ef1: 0xea59, 0x1ef2: 0xea79, 0x1ef3: 0xea99, 0x1ef4: 0xeab9, 0x1ef5: 0x901d, + 0x1ef6: 0xead9, 0x1ef7: 0x903d, 0x1ef8: 0xeaf9, 0x1ef9: 0x905d, 0x1efa: 0xeb19, 0x1efb: 0x907d, + 0x1efc: 0x909d, 0x1efd: 0x90bd, 0x1efe: 0xeb39, 0x1eff: 0xeb59, // Block 0x7c, offset 0x1f00 - 0x1f00: 0xfc99, 0x1f01: 0x96dd, 0x1f02: 0xfcb9, 0x1f03: 0xfcd9, 0x1f04: 0xfcf9, 0x1f05: 0xfd19, - 0x1f06: 0xfd39, 0x1f07: 0xfd59, 0x1f08: 0xfd79, 0x1f09: 0x96fd, 0x1f0a: 0xfd99, 0x1f0b: 0xfdb9, - 0x1f0c: 0xfdd9, 0x1f0d: 0xfdf9, 0x1f0e: 0xfe19, 0x1f0f: 0xfe39, 0x1f10: 0x971d, 0x1f11: 0xfe59, - 0x1f12: 0x973d, 0x1f13: 0x975d, 0x1f14: 0x977d, 0x1f15: 0xfe79, 0x1f16: 0xfe99, 0x1f17: 0xfeb9, - 0x1f18: 0xfed9, 0x1f19: 0xfef9, 0x1f1a: 0xff19, 0x1f1b: 0xff39, 0x1f1c: 0xff59, 0x1f1d: 0x979d, - 0x1f1e: 0x0040, 0x1f1f: 0x0040, 0x1f20: 0x0040, 0x1f21: 0x0040, 0x1f22: 0x0040, 0x1f23: 0x0040, - 0x1f24: 0x0040, 0x1f25: 0x0040, 0x1f26: 0x0040, 0x1f27: 0x0040, 0x1f28: 0x0040, 0x1f29: 0x0040, - 0x1f2a: 0x0040, 0x1f2b: 0x0040, 0x1f2c: 0x0040, 0x1f2d: 0x0040, 0x1f2e: 0x0040, 0x1f2f: 0x0040, - 0x1f30: 0x0040, 0x1f31: 0x0040, 0x1f32: 0x0040, 0x1f33: 0x0040, 0x1f34: 0x0040, 0x1f35: 0x0040, - 0x1f36: 0x0040, 0x1f37: 0x0040, 0x1f38: 0x0040, 0x1f39: 0x0040, 0x1f3a: 0x0040, 0x1f3b: 0x0040, - 0x1f3c: 0x0040, 0x1f3d: 0x0040, 0x1f3e: 0x0040, 0x1f3f: 0x0040, + 0x1f00: 0xeb79, 0x1f01: 0x90dd, 0x1f02: 0x90fd, 0x1f03: 0x911d, 0x1f04: 0x913d, 0x1f05: 0xeb99, + 0x1f06: 0xebb9, 0x1f07: 0xebb9, 0x1f08: 0xebd9, 0x1f09: 0xebf9, 0x1f0a: 0xec19, 0x1f0b: 0xec39, + 0x1f0c: 0xec59, 0x1f0d: 0x915d, 0x1f0e: 0xec79, 0x1f0f: 0xec99, 0x1f10: 0xecb9, 0x1f11: 0xecd9, + 0x1f12: 0x917d, 0x1f13: 0xecf9, 0x1f14: 0x919d, 0x1f15: 0x91bd, 0x1f16: 0xed19, 0x1f17: 0xed39, + 0x1f18: 0xed59, 0x1f19: 0xed79, 0x1f1a: 0xed99, 0x1f1b: 0xedb9, 0x1f1c: 0x91dd, 0x1f1d: 0x91fd, + 0x1f1e: 0x921d, 0x1f1f: 0x2040, 0x1f20: 0xedd9, 0x1f21: 0x923d, 0x1f22: 0xedf9, 0x1f23: 0xee19, + 0x1f24: 0xee39, 0x1f25: 0x925d, 0x1f26: 0xee59, 0x1f27: 0xee79, 0x1f28: 0xee99, 0x1f29: 0xeeb9, + 0x1f2a: 0xeed9, 0x1f2b: 0x927d, 0x1f2c: 0xeef9, 0x1f2d: 0xef19, 0x1f2e: 0xef39, 0x1f2f: 0xef59, + 0x1f30: 0xef79, 0x1f31: 0xef99, 0x1f32: 0x929d, 0x1f33: 0x92bd, 0x1f34: 0xefb9, 0x1f35: 0x92dd, + 0x1f36: 0xefd9, 0x1f37: 0x92fd, 0x1f38: 0xeff9, 0x1f39: 0xf019, 0x1f3a: 0xf039, 0x1f3b: 0x931d, + 0x1f3c: 0x933d, 0x1f3d: 0xf059, 0x1f3e: 0x935d, 0x1f3f: 0xf079, + // Block 0x7d, offset 0x1f40 + 0x1f40: 0xf6b9, 0x1f41: 0xf6d9, 0x1f42: 0xf6f9, 0x1f43: 0xf719, 0x1f44: 0xf739, 0x1f45: 0x951d, + 0x1f46: 0xf759, 0x1f47: 0xf779, 0x1f48: 0xf799, 0x1f49: 0xf7b9, 0x1f4a: 0xf7d9, 0x1f4b: 0x953d, + 0x1f4c: 0x955d, 0x1f4d: 0xf7f9, 0x1f4e: 0xf819, 0x1f4f: 0xf839, 0x1f50: 0xf859, 0x1f51: 0xf879, + 0x1f52: 0xf899, 0x1f53: 0x957d, 0x1f54: 0xf8b9, 0x1f55: 0xf8d9, 0x1f56: 0xf8f9, 0x1f57: 0xf919, + 0x1f58: 0x959d, 0x1f59: 0x95bd, 0x1f5a: 0xf939, 0x1f5b: 0xf959, 0x1f5c: 0xf979, 0x1f5d: 0x95dd, + 0x1f5e: 0xf999, 0x1f5f: 0xf9b9, 0x1f60: 0x6815, 0x1f61: 0x95fd, 0x1f62: 0xf9d9, 0x1f63: 0xf9f9, + 0x1f64: 0xfa19, 0x1f65: 0x961d, 0x1f66: 0xfa39, 0x1f67: 0xfa59, 0x1f68: 0xfa79, 0x1f69: 0xfa99, + 0x1f6a: 0xfab9, 0x1f6b: 0xfad9, 0x1f6c: 0xfaf9, 0x1f6d: 0x963d, 0x1f6e: 0xfb19, 0x1f6f: 0xfb39, + 0x1f70: 0xfb59, 0x1f71: 0x965d, 0x1f72: 0xfb79, 0x1f73: 0xfb99, 0x1f74: 0xfbb9, 0x1f75: 0xfbd9, + 0x1f76: 0x7b35, 0x1f77: 0x967d, 0x1f78: 0xfbf9, 0x1f79: 0xfc19, 0x1f7a: 0xfc39, 0x1f7b: 0x969d, + 0x1f7c: 0xfc59, 0x1f7d: 0x96bd, 0x1f7e: 0xfc79, 0x1f7f: 0xfc79, + // Block 0x7e, offset 0x1f80 + 0x1f80: 0xfc99, 0x1f81: 0x96dd, 0x1f82: 0xfcb9, 0x1f83: 0xfcd9, 0x1f84: 0xfcf9, 0x1f85: 0xfd19, + 0x1f86: 0xfd39, 0x1f87: 0xfd59, 0x1f88: 0xfd79, 0x1f89: 0x96fd, 0x1f8a: 0xfd99, 0x1f8b: 0xfdb9, + 0x1f8c: 0xfdd9, 0x1f8d: 0xfdf9, 0x1f8e: 0xfe19, 0x1f8f: 0xfe39, 0x1f90: 0x971d, 0x1f91: 0xfe59, + 0x1f92: 0x973d, 0x1f93: 0x975d, 0x1f94: 0x977d, 0x1f95: 0xfe79, 0x1f96: 0xfe99, 0x1f97: 0xfeb9, + 0x1f98: 0xfed9, 0x1f99: 0xfef9, 0x1f9a: 0xff19, 0x1f9b: 0xff39, 0x1f9c: 0xff59, 0x1f9d: 0x979d, + 0x1f9e: 0x0040, 0x1f9f: 0x0040, 0x1fa0: 0x0040, 0x1fa1: 0x0040, 0x1fa2: 0x0040, 0x1fa3: 0x0040, + 0x1fa4: 0x0040, 0x1fa5: 0x0040, 0x1fa6: 0x0040, 0x1fa7: 0x0040, 0x1fa8: 0x0040, 0x1fa9: 0x0040, + 0x1faa: 0x0040, 0x1fab: 0x0040, 0x1fac: 0x0040, 0x1fad: 0x0040, 0x1fae: 0x0040, 0x1faf: 0x0040, + 0x1fb0: 0x0040, 0x1fb1: 0x0040, 0x1fb2: 0x0040, 0x1fb3: 0x0040, 0x1fb4: 0x0040, 0x1fb5: 0x0040, + 0x1fb6: 0x0040, 0x1fb7: 0x0040, 0x1fb8: 0x0040, 0x1fb9: 0x0040, 0x1fba: 0x0040, 0x1fbb: 0x0040, + 0x1fbc: 0x0040, 0x1fbd: 0x0040, 0x1fbe: 0x0040, 0x1fbf: 0x0040, } -// idnaIndex: 35 blocks, 2240 entries, 4480 bytes +// idnaIndex: 36 blocks, 2304 entries, 4608 bytes // Block 0 is the zero block. -var idnaIndex = [2240]uint16{ +var idnaIndex = [2304]uint16{ // Block 0x0, offset 0x0 // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 - 0xc2: 0x01, 0xc3: 0x7b, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, - 0xc8: 0x06, 0xc9: 0x7c, 0xca: 0x7d, 0xcb: 0x07, 0xcc: 0x7e, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, - 0xd0: 0x7f, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x80, 0xd6: 0x81, 0xd7: 0x82, - 0xd8: 0x0f, 0xd9: 0x83, 0xda: 0x84, 0xdb: 0x10, 0xdc: 0x11, 0xdd: 0x85, 0xde: 0x86, 0xdf: 0x87, + 0xc2: 0x01, 0xc3: 0x7d, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x04, 0xc7: 0x05, + 0xc8: 0x06, 0xc9: 0x7e, 0xca: 0x7f, 0xcb: 0x07, 0xcc: 0x80, 0xcd: 0x08, 0xce: 0x09, 0xcf: 0x0a, + 0xd0: 0x81, 0xd1: 0x0b, 0xd2: 0x0c, 0xd3: 0x0d, 0xd4: 0x0e, 0xd5: 0x82, 0xd6: 0x83, 0xd7: 0x84, + 0xd8: 0x0f, 0xd9: 0x10, 0xda: 0x85, 0xdb: 0x11, 0xdc: 0x12, 0xdd: 0x86, 0xde: 0x87, 0xdf: 0x88, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07, 0xe8: 0x07, 0xe9: 0x08, 0xea: 0x09, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c, - 0xf0: 0x1c, 0xf1: 0x1d, 0xf2: 0x1d, 0xf3: 0x1f, 0xf4: 0x20, + 0xf0: 0x1d, 0xf1: 0x1e, 0xf2: 0x1e, 0xf3: 0x20, 0xf4: 0x21, // Block 0x4, offset 0x100 - 0x120: 0x88, 0x121: 0x89, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x12, 0x126: 0x13, 0x127: 0x14, - 0x128: 0x15, 0x129: 0x16, 0x12a: 0x17, 0x12b: 0x18, 0x12c: 0x19, 0x12d: 0x1a, 0x12e: 0x1b, 0x12f: 0x8d, - 0x130: 0x8e, 0x131: 0x1c, 0x132: 0x1d, 0x133: 0x1e, 0x134: 0x8f, 0x135: 0x1f, 0x136: 0x90, 0x137: 0x91, - 0x138: 0x92, 0x139: 0x93, 0x13a: 0x20, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x21, 0x13e: 0x22, 0x13f: 0x96, + 0x120: 0x89, 0x121: 0x13, 0x122: 0x8a, 0x123: 0x8b, 0x124: 0x8c, 0x125: 0x14, 0x126: 0x15, 0x127: 0x16, + 0x128: 0x17, 0x129: 0x18, 0x12a: 0x19, 0x12b: 0x1a, 0x12c: 0x1b, 0x12d: 0x1c, 0x12e: 0x1d, 0x12f: 0x8d, + 0x130: 0x8e, 0x131: 0x1e, 0x132: 0x1f, 0x133: 0x20, 0x134: 0x8f, 0x135: 0x21, 0x136: 0x90, 0x137: 0x91, + 0x138: 0x92, 0x139: 0x93, 0x13a: 0x22, 0x13b: 0x94, 0x13c: 0x95, 0x13d: 0x23, 0x13e: 0x24, 0x13f: 0x96, // Block 0x5, offset 0x140 - 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9b, 0x147: 0x9b, - 0x148: 0x9d, 0x149: 0x9e, 0x14a: 0x9f, 0x14b: 0xa0, 0x14c: 0xa1, 0x14d: 0xa2, 0x14e: 0xa3, 0x14f: 0xa4, - 0x150: 0xa5, 0x151: 0x9d, 0x152: 0x9d, 0x153: 0x9d, 0x154: 0x9d, 0x155: 0x9d, 0x156: 0x9d, 0x157: 0x9d, - 0x158: 0x9d, 0x159: 0xa6, 0x15a: 0xa7, 0x15b: 0xa8, 0x15c: 0xa9, 0x15d: 0xaa, 0x15e: 0xab, 0x15f: 0xac, - 0x160: 0xad, 0x161: 0xae, 0x162: 0xaf, 0x163: 0xb0, 0x164: 0xb1, 0x165: 0xb2, 0x166: 0xb3, 0x167: 0xb4, - 0x168: 0xb5, 0x169: 0xb6, 0x16a: 0xb7, 0x16b: 0xb8, 0x16c: 0xb9, 0x16d: 0xba, 0x16e: 0xbb, 0x16f: 0xbc, - 0x170: 0xbd, 0x171: 0xbe, 0x172: 0xbf, 0x173: 0xc0, 0x174: 0x23, 0x175: 0x24, 0x176: 0x25, 0x177: 0xc1, - 0x178: 0x26, 0x179: 0x26, 0x17a: 0x27, 0x17b: 0x26, 0x17c: 0xc2, 0x17d: 0x28, 0x17e: 0x29, 0x17f: 0x2a, + 0x140: 0x97, 0x141: 0x98, 0x142: 0x99, 0x143: 0x9a, 0x144: 0x9b, 0x145: 0x9c, 0x146: 0x9d, 0x147: 0x9e, + 0x148: 0x9f, 0x149: 0xa0, 0x14a: 0xa1, 0x14b: 0xa2, 0x14c: 0xa3, 0x14d: 0xa4, 0x14e: 0xa5, 0x14f: 0xa6, + 0x150: 0xa7, 0x151: 0x9f, 0x152: 0x9f, 0x153: 0x9f, 0x154: 0x9f, 0x155: 0x9f, 0x156: 0x9f, 0x157: 0x9f, + 0x158: 0x9f, 0x159: 0xa8, 0x15a: 0xa9, 0x15b: 0xaa, 0x15c: 0xab, 0x15d: 0xac, 0x15e: 0xad, 0x15f: 0xae, + 0x160: 0xaf, 0x161: 0xb0, 0x162: 0xb1, 0x163: 0xb2, 0x164: 0xb3, 0x165: 0xb4, 0x166: 0xb5, 0x167: 0xb6, + 0x168: 0xb7, 0x169: 0xb8, 0x16a: 0xb9, 0x16b: 0xba, 0x16c: 0xbb, 0x16d: 0xbc, 0x16e: 0xbd, 0x16f: 0xbe, + 0x170: 0xbf, 0x171: 0xc0, 0x172: 0xc1, 0x173: 0xc2, 0x174: 0x25, 0x175: 0x26, 0x176: 0x27, 0x177: 0xc3, + 0x178: 0x28, 0x179: 0x28, 0x17a: 0x29, 0x17b: 0x28, 0x17c: 0xc4, 0x17d: 0x2a, 0x17e: 0x2b, 0x17f: 0x2c, // Block 0x6, offset 0x180 - 0x180: 0x2b, 0x181: 0x2c, 0x182: 0x2d, 0x183: 0xc3, 0x184: 0x2e, 0x185: 0x2f, 0x186: 0xc4, 0x187: 0x9b, - 0x188: 0xc5, 0x189: 0xc6, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc7, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0xc8, - 0x190: 0xc9, 0x191: 0x30, 0x192: 0x31, 0x193: 0x32, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, + 0x180: 0x2d, 0x181: 0x2e, 0x182: 0x2f, 0x183: 0xc5, 0x184: 0x30, 0x185: 0x31, 0x186: 0xc6, 0x187: 0x9b, + 0x188: 0xc7, 0x189: 0xc8, 0x18a: 0x9b, 0x18b: 0x9b, 0x18c: 0xc9, 0x18d: 0x9b, 0x18e: 0x9b, 0x18f: 0x9b, + 0x190: 0xca, 0x191: 0x32, 0x192: 0x33, 0x193: 0x34, 0x194: 0x9b, 0x195: 0x9b, 0x196: 0x9b, 0x197: 0x9b, 0x198: 0x9b, 0x199: 0x9b, 0x19a: 0x9b, 0x19b: 0x9b, 0x19c: 0x9b, 0x19d: 0x9b, 0x19e: 0x9b, 0x19f: 0x9b, 0x1a0: 0x9b, 0x1a1: 0x9b, 0x1a2: 0x9b, 0x1a3: 0x9b, 0x1a4: 0x9b, 0x1a5: 0x9b, 0x1a6: 0x9b, 0x1a7: 0x9b, - 0x1a8: 0xca, 0x1a9: 0xcb, 0x1aa: 0x9b, 0x1ab: 0xcc, 0x1ac: 0x9b, 0x1ad: 0xcd, 0x1ae: 0xce, 0x1af: 0xcf, - 0x1b0: 0xd0, 0x1b1: 0x33, 0x1b2: 0x26, 0x1b3: 0x34, 0x1b4: 0xd1, 0x1b5: 0xd2, 0x1b6: 0xd3, 0x1b7: 0xd4, - 0x1b8: 0xd5, 0x1b9: 0xd6, 0x1ba: 0xd7, 0x1bb: 0xd8, 0x1bc: 0xd9, 0x1bd: 0xda, 0x1be: 0xdb, 0x1bf: 0x35, + 0x1a8: 0xcb, 0x1a9: 0xcc, 0x1aa: 0x9b, 0x1ab: 0xcd, 0x1ac: 0x9b, 0x1ad: 0xce, 0x1ae: 0xcf, 0x1af: 0xd0, + 0x1b0: 0xd1, 0x1b1: 0x35, 0x1b2: 0x28, 0x1b3: 0x36, 0x1b4: 0xd2, 0x1b5: 0xd3, 0x1b6: 0xd4, 0x1b7: 0xd5, + 0x1b8: 0xd6, 0x1b9: 0xd7, 0x1ba: 0xd8, 0x1bb: 0xd9, 0x1bc: 0xda, 0x1bd: 0xdb, 0x1be: 0xdc, 0x1bf: 0x37, // Block 0x7, offset 0x1c0 - 0x1c0: 0x36, 0x1c1: 0xdc, 0x1c2: 0xdd, 0x1c3: 0xde, 0x1c4: 0xdf, 0x1c5: 0x37, 0x1c6: 0x38, 0x1c7: 0xe0, - 0x1c8: 0xe1, 0x1c9: 0x39, 0x1ca: 0x3a, 0x1cb: 0x3b, 0x1cc: 0x3c, 0x1cd: 0x3d, 0x1ce: 0x3e, 0x1cf: 0x3f, - 0x1d0: 0x9d, 0x1d1: 0x9d, 0x1d2: 0x9d, 0x1d3: 0x9d, 0x1d4: 0x9d, 0x1d5: 0x9d, 0x1d6: 0x9d, 0x1d7: 0x9d, - 0x1d8: 0x9d, 0x1d9: 0x9d, 0x1da: 0x9d, 0x1db: 0x9d, 0x1dc: 0x9d, 0x1dd: 0x9d, 0x1de: 0x9d, 0x1df: 0x9d, - 0x1e0: 0x9d, 0x1e1: 0x9d, 0x1e2: 0x9d, 0x1e3: 0x9d, 0x1e4: 0x9d, 0x1e5: 0x9d, 0x1e6: 0x9d, 0x1e7: 0x9d, - 0x1e8: 0x9d, 0x1e9: 0x9d, 0x1ea: 0x9d, 0x1eb: 0x9d, 0x1ec: 0x9d, 0x1ed: 0x9d, 0x1ee: 0x9d, 0x1ef: 0x9d, - 0x1f0: 0x9d, 0x1f1: 0x9d, 0x1f2: 0x9d, 0x1f3: 0x9d, 0x1f4: 0x9d, 0x1f5: 0x9d, 0x1f6: 0x9d, 0x1f7: 0x9d, - 0x1f8: 0x9d, 0x1f9: 0x9d, 0x1fa: 0x9d, 0x1fb: 0x9d, 0x1fc: 0x9d, 0x1fd: 0x9d, 0x1fe: 0x9d, 0x1ff: 0x9d, + 0x1c0: 0x38, 0x1c1: 0xdd, 0x1c2: 0xde, 0x1c3: 0xdf, 0x1c4: 0xe0, 0x1c5: 0x39, 0x1c6: 0x3a, 0x1c7: 0xe1, + 0x1c8: 0xe2, 0x1c9: 0x3b, 0x1ca: 0x3c, 0x1cb: 0x3d, 0x1cc: 0x3e, 0x1cd: 0x3f, 0x1ce: 0x40, 0x1cf: 0x41, + 0x1d0: 0x9f, 0x1d1: 0x9f, 0x1d2: 0x9f, 0x1d3: 0x9f, 0x1d4: 0x9f, 0x1d5: 0x9f, 0x1d6: 0x9f, 0x1d7: 0x9f, + 0x1d8: 0x9f, 0x1d9: 0x9f, 0x1da: 0x9f, 0x1db: 0x9f, 0x1dc: 0x9f, 0x1dd: 0x9f, 0x1de: 0x9f, 0x1df: 0x9f, + 0x1e0: 0x9f, 0x1e1: 0x9f, 0x1e2: 0x9f, 0x1e3: 0x9f, 0x1e4: 0x9f, 0x1e5: 0x9f, 0x1e6: 0x9f, 0x1e7: 0x9f, + 0x1e8: 0x9f, 0x1e9: 0x9f, 0x1ea: 0x9f, 0x1eb: 0x9f, 0x1ec: 0x9f, 0x1ed: 0x9f, 0x1ee: 0x9f, 0x1ef: 0x9f, + 0x1f0: 0x9f, 0x1f1: 0x9f, 0x1f2: 0x9f, 0x1f3: 0x9f, 0x1f4: 0x9f, 0x1f5: 0x9f, 0x1f6: 0x9f, 0x1f7: 0x9f, + 0x1f8: 0x9f, 0x1f9: 0x9f, 0x1fa: 0x9f, 0x1fb: 0x9f, 0x1fc: 0x9f, 0x1fd: 0x9f, 0x1fe: 0x9f, 0x1ff: 0x9f, // Block 0x8, offset 0x200 - 0x200: 0x9d, 0x201: 0x9d, 0x202: 0x9d, 0x203: 0x9d, 0x204: 0x9d, 0x205: 0x9d, 0x206: 0x9d, 0x207: 0x9d, - 0x208: 0x9d, 0x209: 0x9d, 0x20a: 0x9d, 0x20b: 0x9d, 0x20c: 0x9d, 0x20d: 0x9d, 0x20e: 0x9d, 0x20f: 0x9d, - 0x210: 0x9d, 0x211: 0x9d, 0x212: 0x9d, 0x213: 0x9d, 0x214: 0x9d, 0x215: 0x9d, 0x216: 0x9d, 0x217: 0x9d, - 0x218: 0x9d, 0x219: 0x9d, 0x21a: 0x9d, 0x21b: 0x9d, 0x21c: 0x9d, 0x21d: 0x9d, 0x21e: 0x9d, 0x21f: 0x9d, - 0x220: 0x9d, 0x221: 0x9d, 0x222: 0x9d, 0x223: 0x9d, 0x224: 0x9d, 0x225: 0x9d, 0x226: 0x9d, 0x227: 0x9d, - 0x228: 0x9d, 0x229: 0x9d, 0x22a: 0x9d, 0x22b: 0x9d, 0x22c: 0x9d, 0x22d: 0x9d, 0x22e: 0x9d, 0x22f: 0x9d, - 0x230: 0x9d, 0x231: 0x9d, 0x232: 0x9d, 0x233: 0x9d, 0x234: 0x9d, 0x235: 0x9d, 0x236: 0xb0, 0x237: 0x9b, - 0x238: 0x9d, 0x239: 0x9d, 0x23a: 0x9d, 0x23b: 0x9d, 0x23c: 0x9d, 0x23d: 0x9d, 0x23e: 0x9d, 0x23f: 0x9d, + 0x200: 0x9f, 0x201: 0x9f, 0x202: 0x9f, 0x203: 0x9f, 0x204: 0x9f, 0x205: 0x9f, 0x206: 0x9f, 0x207: 0x9f, + 0x208: 0x9f, 0x209: 0x9f, 0x20a: 0x9f, 0x20b: 0x9f, 0x20c: 0x9f, 0x20d: 0x9f, 0x20e: 0x9f, 0x20f: 0x9f, + 0x210: 0x9f, 0x211: 0x9f, 0x212: 0x9f, 0x213: 0x9f, 0x214: 0x9f, 0x215: 0x9f, 0x216: 0x9f, 0x217: 0x9f, + 0x218: 0x9f, 0x219: 0x9f, 0x21a: 0x9f, 0x21b: 0x9f, 0x21c: 0x9f, 0x21d: 0x9f, 0x21e: 0x9f, 0x21f: 0x9f, + 0x220: 0x9f, 0x221: 0x9f, 0x222: 0x9f, 0x223: 0x9f, 0x224: 0x9f, 0x225: 0x9f, 0x226: 0x9f, 0x227: 0x9f, + 0x228: 0x9f, 0x229: 0x9f, 0x22a: 0x9f, 0x22b: 0x9f, 0x22c: 0x9f, 0x22d: 0x9f, 0x22e: 0x9f, 0x22f: 0x9f, + 0x230: 0x9f, 0x231: 0x9f, 0x232: 0x9f, 0x233: 0x9f, 0x234: 0x9f, 0x235: 0x9f, 0x236: 0xb2, 0x237: 0x9b, + 0x238: 0x9f, 0x239: 0x9f, 0x23a: 0x9f, 0x23b: 0x9f, 0x23c: 0x9f, 0x23d: 0x9f, 0x23e: 0x9f, 0x23f: 0x9f, // Block 0x9, offset 0x240 - 0x240: 0x9d, 0x241: 0x9d, 0x242: 0x9d, 0x243: 0x9d, 0x244: 0x9d, 0x245: 0x9d, 0x246: 0x9d, 0x247: 0x9d, - 0x248: 0x9d, 0x249: 0x9d, 0x24a: 0x9d, 0x24b: 0x9d, 0x24c: 0x9d, 0x24d: 0x9d, 0x24e: 0x9d, 0x24f: 0x9d, - 0x250: 0x9d, 0x251: 0x9d, 0x252: 0x9d, 0x253: 0x9d, 0x254: 0x9d, 0x255: 0x9d, 0x256: 0x9d, 0x257: 0x9d, - 0x258: 0x9d, 0x259: 0x9d, 0x25a: 0x9d, 0x25b: 0x9d, 0x25c: 0x9d, 0x25d: 0x9d, 0x25e: 0x9d, 0x25f: 0x9d, - 0x260: 0x9d, 0x261: 0x9d, 0x262: 0x9d, 0x263: 0x9d, 0x264: 0x9d, 0x265: 0x9d, 0x266: 0x9d, 0x267: 0x9d, - 0x268: 0x9d, 0x269: 0x9d, 0x26a: 0x9d, 0x26b: 0x9d, 0x26c: 0x9d, 0x26d: 0x9d, 0x26e: 0x9d, 0x26f: 0x9d, - 0x270: 0x9d, 0x271: 0x9d, 0x272: 0x9d, 0x273: 0x9d, 0x274: 0x9d, 0x275: 0x9d, 0x276: 0x9d, 0x277: 0x9d, - 0x278: 0x9d, 0x279: 0x9d, 0x27a: 0x9d, 0x27b: 0x9d, 0x27c: 0x9d, 0x27d: 0x9d, 0x27e: 0x9d, 0x27f: 0x9d, + 0x240: 0x9f, 0x241: 0x9f, 0x242: 0x9f, 0x243: 0x9f, 0x244: 0x9f, 0x245: 0x9f, 0x246: 0x9f, 0x247: 0x9f, + 0x248: 0x9f, 0x249: 0x9f, 0x24a: 0x9f, 0x24b: 0x9f, 0x24c: 0x9f, 0x24d: 0x9f, 0x24e: 0x9f, 0x24f: 0x9f, + 0x250: 0x9f, 0x251: 0x9f, 0x252: 0x9f, 0x253: 0x9f, 0x254: 0x9f, 0x255: 0x9f, 0x256: 0x9f, 0x257: 0x9f, + 0x258: 0x9f, 0x259: 0x9f, 0x25a: 0x9f, 0x25b: 0x9f, 0x25c: 0x9f, 0x25d: 0x9f, 0x25e: 0x9f, 0x25f: 0x9f, + 0x260: 0x9f, 0x261: 0x9f, 0x262: 0x9f, 0x263: 0x9f, 0x264: 0x9f, 0x265: 0x9f, 0x266: 0x9f, 0x267: 0x9f, + 0x268: 0x9f, 0x269: 0x9f, 0x26a: 0x9f, 0x26b: 0x9f, 0x26c: 0x9f, 0x26d: 0x9f, 0x26e: 0x9f, 0x26f: 0x9f, + 0x270: 0x9f, 0x271: 0x9f, 0x272: 0x9f, 0x273: 0x9f, 0x274: 0x9f, 0x275: 0x9f, 0x276: 0x9f, 0x277: 0x9f, + 0x278: 0x9f, 0x279: 0x9f, 0x27a: 0x9f, 0x27b: 0x9f, 0x27c: 0x9f, 0x27d: 0x9f, 0x27e: 0x9f, 0x27f: 0x9f, // Block 0xa, offset 0x280 - 0x280: 0x9d, 0x281: 0x9d, 0x282: 0x9d, 0x283: 0x9d, 0x284: 0x9d, 0x285: 0x9d, 0x286: 0x9d, 0x287: 0x9d, - 0x288: 0x9d, 0x289: 0x9d, 0x28a: 0x9d, 0x28b: 0x9d, 0x28c: 0x9d, 0x28d: 0x9d, 0x28e: 0x9d, 0x28f: 0x9d, - 0x290: 0x9d, 0x291: 0x9d, 0x292: 0x9d, 0x293: 0x9d, 0x294: 0x9d, 0x295: 0x9d, 0x296: 0x9d, 0x297: 0x9d, - 0x298: 0x9d, 0x299: 0x9d, 0x29a: 0x9d, 0x29b: 0x9d, 0x29c: 0x9d, 0x29d: 0x9d, 0x29e: 0x9d, 0x29f: 0x9d, - 0x2a0: 0x9d, 0x2a1: 0x9d, 0x2a2: 0x9d, 0x2a3: 0x9d, 0x2a4: 0x9d, 0x2a5: 0x9d, 0x2a6: 0x9d, 0x2a7: 0x9d, - 0x2a8: 0x9d, 0x2a9: 0x9d, 0x2aa: 0x9d, 0x2ab: 0x9d, 0x2ac: 0x9d, 0x2ad: 0x9d, 0x2ae: 0x9d, 0x2af: 0x9d, - 0x2b0: 0x9d, 0x2b1: 0x9d, 0x2b2: 0x9d, 0x2b3: 0x9d, 0x2b4: 0x9d, 0x2b5: 0x9d, 0x2b6: 0x9d, 0x2b7: 0x9d, - 0x2b8: 0x9d, 0x2b9: 0x9d, 0x2ba: 0x9d, 0x2bb: 0x9d, 0x2bc: 0x9d, 0x2bd: 0x9d, 0x2be: 0x9d, 0x2bf: 0xe2, + 0x280: 0x9f, 0x281: 0x9f, 0x282: 0x9f, 0x283: 0x9f, 0x284: 0x9f, 0x285: 0x9f, 0x286: 0x9f, 0x287: 0x9f, + 0x288: 0x9f, 0x289: 0x9f, 0x28a: 0x9f, 0x28b: 0x9f, 0x28c: 0x9f, 0x28d: 0x9f, 0x28e: 0x9f, 0x28f: 0x9f, + 0x290: 0x9f, 0x291: 0x9f, 0x292: 0x9f, 0x293: 0x9f, 0x294: 0x9f, 0x295: 0x9f, 0x296: 0x9f, 0x297: 0x9f, + 0x298: 0x9f, 0x299: 0x9f, 0x29a: 0x9f, 0x29b: 0x9f, 0x29c: 0x9f, 0x29d: 0x9f, 0x29e: 0x9f, 0x29f: 0x9f, + 0x2a0: 0x9f, 0x2a1: 0x9f, 0x2a2: 0x9f, 0x2a3: 0x9f, 0x2a4: 0x9f, 0x2a5: 0x9f, 0x2a6: 0x9f, 0x2a7: 0x9f, + 0x2a8: 0x9f, 0x2a9: 0x9f, 0x2aa: 0x9f, 0x2ab: 0x9f, 0x2ac: 0x9f, 0x2ad: 0x9f, 0x2ae: 0x9f, 0x2af: 0x9f, + 0x2b0: 0x9f, 0x2b1: 0x9f, 0x2b2: 0x9f, 0x2b3: 0x9f, 0x2b4: 0x9f, 0x2b5: 0x9f, 0x2b6: 0x9f, 0x2b7: 0x9f, + 0x2b8: 0x9f, 0x2b9: 0x9f, 0x2ba: 0x9f, 0x2bb: 0x9f, 0x2bc: 0x9f, 0x2bd: 0x9f, 0x2be: 0x9f, 0x2bf: 0xe3, // Block 0xb, offset 0x2c0 - 0x2c0: 0x9d, 0x2c1: 0x9d, 0x2c2: 0x9d, 0x2c3: 0x9d, 0x2c4: 0x9d, 0x2c5: 0x9d, 0x2c6: 0x9d, 0x2c7: 0x9d, - 0x2c8: 0x9d, 0x2c9: 0x9d, 0x2ca: 0x9d, 0x2cb: 0x9d, 0x2cc: 0x9d, 0x2cd: 0x9d, 0x2ce: 0x9d, 0x2cf: 0x9d, - 0x2d0: 0x9d, 0x2d1: 0x9d, 0x2d2: 0xe3, 0x2d3: 0xe4, 0x2d4: 0x9d, 0x2d5: 0x9d, 0x2d6: 0x9d, 0x2d7: 0x9d, - 0x2d8: 0xe5, 0x2d9: 0x40, 0x2da: 0x41, 0x2db: 0xe6, 0x2dc: 0x42, 0x2dd: 0x43, 0x2de: 0x44, 0x2df: 0xe7, - 0x2e0: 0xe8, 0x2e1: 0xe9, 0x2e2: 0xea, 0x2e3: 0xeb, 0x2e4: 0xec, 0x2e5: 0xed, 0x2e6: 0xee, 0x2e7: 0xef, - 0x2e8: 0xf0, 0x2e9: 0xf1, 0x2ea: 0xf2, 0x2eb: 0xf3, 0x2ec: 0xf4, 0x2ed: 0xf5, 0x2ee: 0xf6, 0x2ef: 0xf7, - 0x2f0: 0x9d, 0x2f1: 0x9d, 0x2f2: 0x9d, 0x2f3: 0x9d, 0x2f4: 0x9d, 0x2f5: 0x9d, 0x2f6: 0x9d, 0x2f7: 0x9d, - 0x2f8: 0x9d, 0x2f9: 0x9d, 0x2fa: 0x9d, 0x2fb: 0x9d, 0x2fc: 0x9d, 0x2fd: 0x9d, 0x2fe: 0x9d, 0x2ff: 0x9d, + 0x2c0: 0x9f, 0x2c1: 0x9f, 0x2c2: 0x9f, 0x2c3: 0x9f, 0x2c4: 0x9f, 0x2c5: 0x9f, 0x2c6: 0x9f, 0x2c7: 0x9f, + 0x2c8: 0x9f, 0x2c9: 0x9f, 0x2ca: 0x9f, 0x2cb: 0x9f, 0x2cc: 0x9f, 0x2cd: 0x9f, 0x2ce: 0x9f, 0x2cf: 0x9f, + 0x2d0: 0x9f, 0x2d1: 0x9f, 0x2d2: 0xe4, 0x2d3: 0xe5, 0x2d4: 0x9f, 0x2d5: 0x9f, 0x2d6: 0x9f, 0x2d7: 0x9f, + 0x2d8: 0xe6, 0x2d9: 0x42, 0x2da: 0x43, 0x2db: 0xe7, 0x2dc: 0x44, 0x2dd: 0x45, 0x2de: 0x46, 0x2df: 0xe8, + 0x2e0: 0xe9, 0x2e1: 0xea, 0x2e2: 0xeb, 0x2e3: 0xec, 0x2e4: 0xed, 0x2e5: 0xee, 0x2e6: 0xef, 0x2e7: 0xf0, + 0x2e8: 0xf1, 0x2e9: 0xf2, 0x2ea: 0xf3, 0x2eb: 0xf4, 0x2ec: 0xf5, 0x2ed: 0xf6, 0x2ee: 0xf7, 0x2ef: 0xf8, + 0x2f0: 0x9f, 0x2f1: 0x9f, 0x2f2: 0x9f, 0x2f3: 0x9f, 0x2f4: 0x9f, 0x2f5: 0x9f, 0x2f6: 0x9f, 0x2f7: 0x9f, + 0x2f8: 0x9f, 0x2f9: 0x9f, 0x2fa: 0x9f, 0x2fb: 0x9f, 0x2fc: 0x9f, 0x2fd: 0x9f, 0x2fe: 0x9f, 0x2ff: 0x9f, // Block 0xc, offset 0x300 - 0x300: 0x9d, 0x301: 0x9d, 0x302: 0x9d, 0x303: 0x9d, 0x304: 0x9d, 0x305: 0x9d, 0x306: 0x9d, 0x307: 0x9d, - 0x308: 0x9d, 0x309: 0x9d, 0x30a: 0x9d, 0x30b: 0x9d, 0x30c: 0x9d, 0x30d: 0x9d, 0x30e: 0x9d, 0x30f: 0x9d, - 0x310: 0x9d, 0x311: 0x9d, 0x312: 0x9d, 0x313: 0x9d, 0x314: 0x9d, 0x315: 0x9d, 0x316: 0x9d, 0x317: 0x9d, - 0x318: 0x9d, 0x319: 0x9d, 0x31a: 0x9d, 0x31b: 0x9d, 0x31c: 0x9d, 0x31d: 0x9d, 0x31e: 0xf8, 0x31f: 0xf9, + 0x300: 0x9f, 0x301: 0x9f, 0x302: 0x9f, 0x303: 0x9f, 0x304: 0x9f, 0x305: 0x9f, 0x306: 0x9f, 0x307: 0x9f, + 0x308: 0x9f, 0x309: 0x9f, 0x30a: 0x9f, 0x30b: 0x9f, 0x30c: 0x9f, 0x30d: 0x9f, 0x30e: 0x9f, 0x30f: 0x9f, + 0x310: 0x9f, 0x311: 0x9f, 0x312: 0x9f, 0x313: 0x9f, 0x314: 0x9f, 0x315: 0x9f, 0x316: 0x9f, 0x317: 0x9f, + 0x318: 0x9f, 0x319: 0x9f, 0x31a: 0x9f, 0x31b: 0x9f, 0x31c: 0x9f, 0x31d: 0x9f, 0x31e: 0xf9, 0x31f: 0xfa, // Block 0xd, offset 0x340 - 0x340: 0xb8, 0x341: 0xb8, 0x342: 0xb8, 0x343: 0xb8, 0x344: 0xb8, 0x345: 0xb8, 0x346: 0xb8, 0x347: 0xb8, - 0x348: 0xb8, 0x349: 0xb8, 0x34a: 0xb8, 0x34b: 0xb8, 0x34c: 0xb8, 0x34d: 0xb8, 0x34e: 0xb8, 0x34f: 0xb8, - 0x350: 0xb8, 0x351: 0xb8, 0x352: 0xb8, 0x353: 0xb8, 0x354: 0xb8, 0x355: 0xb8, 0x356: 0xb8, 0x357: 0xb8, - 0x358: 0xb8, 0x359: 0xb8, 0x35a: 0xb8, 0x35b: 0xb8, 0x35c: 0xb8, 0x35d: 0xb8, 0x35e: 0xb8, 0x35f: 0xb8, - 0x360: 0xb8, 0x361: 0xb8, 0x362: 0xb8, 0x363: 0xb8, 0x364: 0xb8, 0x365: 0xb8, 0x366: 0xb8, 0x367: 0xb8, - 0x368: 0xb8, 0x369: 0xb8, 0x36a: 0xb8, 0x36b: 0xb8, 0x36c: 0xb8, 0x36d: 0xb8, 0x36e: 0xb8, 0x36f: 0xb8, - 0x370: 0xb8, 0x371: 0xb8, 0x372: 0xb8, 0x373: 0xb8, 0x374: 0xb8, 0x375: 0xb8, 0x376: 0xb8, 0x377: 0xb8, - 0x378: 0xb8, 0x379: 0xb8, 0x37a: 0xb8, 0x37b: 0xb8, 0x37c: 0xb8, 0x37d: 0xb8, 0x37e: 0xb8, 0x37f: 0xb8, + 0x340: 0xba, 0x341: 0xba, 0x342: 0xba, 0x343: 0xba, 0x344: 0xba, 0x345: 0xba, 0x346: 0xba, 0x347: 0xba, + 0x348: 0xba, 0x349: 0xba, 0x34a: 0xba, 0x34b: 0xba, 0x34c: 0xba, 0x34d: 0xba, 0x34e: 0xba, 0x34f: 0xba, + 0x350: 0xba, 0x351: 0xba, 0x352: 0xba, 0x353: 0xba, 0x354: 0xba, 0x355: 0xba, 0x356: 0xba, 0x357: 0xba, + 0x358: 0xba, 0x359: 0xba, 0x35a: 0xba, 0x35b: 0xba, 0x35c: 0xba, 0x35d: 0xba, 0x35e: 0xba, 0x35f: 0xba, + 0x360: 0xba, 0x361: 0xba, 0x362: 0xba, 0x363: 0xba, 0x364: 0xba, 0x365: 0xba, 0x366: 0xba, 0x367: 0xba, + 0x368: 0xba, 0x369: 0xba, 0x36a: 0xba, 0x36b: 0xba, 0x36c: 0xba, 0x36d: 0xba, 0x36e: 0xba, 0x36f: 0xba, + 0x370: 0xba, 0x371: 0xba, 0x372: 0xba, 0x373: 0xba, 0x374: 0xba, 0x375: 0xba, 0x376: 0xba, 0x377: 0xba, + 0x378: 0xba, 0x379: 0xba, 0x37a: 0xba, 0x37b: 0xba, 0x37c: 0xba, 0x37d: 0xba, 0x37e: 0xba, 0x37f: 0xba, // Block 0xe, offset 0x380 - 0x380: 0xb8, 0x381: 0xb8, 0x382: 0xb8, 0x383: 0xb8, 0x384: 0xb8, 0x385: 0xb8, 0x386: 0xb8, 0x387: 0xb8, - 0x388: 0xb8, 0x389: 0xb8, 0x38a: 0xb8, 0x38b: 0xb8, 0x38c: 0xb8, 0x38d: 0xb8, 0x38e: 0xb8, 0x38f: 0xb8, - 0x390: 0xb8, 0x391: 0xb8, 0x392: 0xb8, 0x393: 0xb8, 0x394: 0xb8, 0x395: 0xb8, 0x396: 0xb8, 0x397: 0xb8, - 0x398: 0xb8, 0x399: 0xb8, 0x39a: 0xb8, 0x39b: 0xb8, 0x39c: 0xb8, 0x39d: 0xb8, 0x39e: 0xb8, 0x39f: 0xb8, - 0x3a0: 0xb8, 0x3a1: 0xb8, 0x3a2: 0xb8, 0x3a3: 0xb8, 0x3a4: 0xfa, 0x3a5: 0xfb, 0x3a6: 0xfc, 0x3a7: 0xfd, - 0x3a8: 0x45, 0x3a9: 0xfe, 0x3aa: 0xff, 0x3ab: 0x46, 0x3ac: 0x47, 0x3ad: 0x48, 0x3ae: 0x49, 0x3af: 0x4a, - 0x3b0: 0x100, 0x3b1: 0x4b, 0x3b2: 0x4c, 0x3b3: 0x4d, 0x3b4: 0x4e, 0x3b5: 0x4f, 0x3b6: 0x101, 0x3b7: 0x50, - 0x3b8: 0x51, 0x3b9: 0x52, 0x3ba: 0x53, 0x3bb: 0x54, 0x3bc: 0x55, 0x3bd: 0x56, 0x3be: 0x57, 0x3bf: 0x58, + 0x380: 0xba, 0x381: 0xba, 0x382: 0xba, 0x383: 0xba, 0x384: 0xba, 0x385: 0xba, 0x386: 0xba, 0x387: 0xba, + 0x388: 0xba, 0x389: 0xba, 0x38a: 0xba, 0x38b: 0xba, 0x38c: 0xba, 0x38d: 0xba, 0x38e: 0xba, 0x38f: 0xba, + 0x390: 0xba, 0x391: 0xba, 0x392: 0xba, 0x393: 0xba, 0x394: 0xba, 0x395: 0xba, 0x396: 0xba, 0x397: 0xba, + 0x398: 0xba, 0x399: 0xba, 0x39a: 0xba, 0x39b: 0xba, 0x39c: 0xba, 0x39d: 0xba, 0x39e: 0xba, 0x39f: 0xba, + 0x3a0: 0xba, 0x3a1: 0xba, 0x3a2: 0xba, 0x3a3: 0xba, 0x3a4: 0xfb, 0x3a5: 0xfc, 0x3a6: 0xfd, 0x3a7: 0xfe, + 0x3a8: 0x47, 0x3a9: 0xff, 0x3aa: 0x100, 0x3ab: 0x48, 0x3ac: 0x49, 0x3ad: 0x4a, 0x3ae: 0x4b, 0x3af: 0x4c, + 0x3b0: 0x101, 0x3b1: 0x4d, 0x3b2: 0x4e, 0x3b3: 0x4f, 0x3b4: 0x50, 0x3b5: 0x51, 0x3b6: 0x102, 0x3b7: 0x52, + 0x3b8: 0x53, 0x3b9: 0x54, 0x3ba: 0x55, 0x3bb: 0x56, 0x3bc: 0x57, 0x3bd: 0x58, 0x3be: 0x59, 0x3bf: 0x5a, // Block 0xf, offset 0x3c0 - 0x3c0: 0x102, 0x3c1: 0x103, 0x3c2: 0x9d, 0x3c3: 0x104, 0x3c4: 0x105, 0x3c5: 0x9b, 0x3c6: 0x106, 0x3c7: 0x107, - 0x3c8: 0xb8, 0x3c9: 0xb8, 0x3ca: 0x108, 0x3cb: 0x109, 0x3cc: 0x10a, 0x3cd: 0x10b, 0x3ce: 0x10c, 0x3cf: 0x10d, - 0x3d0: 0x10e, 0x3d1: 0x9d, 0x3d2: 0x10f, 0x3d3: 0x110, 0x3d4: 0x111, 0x3d5: 0x112, 0x3d6: 0xb8, 0x3d7: 0xb8, - 0x3d8: 0x9d, 0x3d9: 0x9d, 0x3da: 0x9d, 0x3db: 0x9d, 0x3dc: 0x113, 0x3dd: 0x114, 0x3de: 0xb8, 0x3df: 0xb8, - 0x3e0: 0x115, 0x3e1: 0x116, 0x3e2: 0x117, 0x3e3: 0x118, 0x3e4: 0x119, 0x3e5: 0xb8, 0x3e6: 0x11a, 0x3e7: 0x11b, - 0x3e8: 0x11c, 0x3e9: 0x11d, 0x3ea: 0x11e, 0x3eb: 0x59, 0x3ec: 0x11f, 0x3ed: 0x120, 0x3ee: 0x5a, 0x3ef: 0xb8, - 0x3f0: 0x9d, 0x3f1: 0x121, 0x3f2: 0x122, 0x3f3: 0x123, 0x3f4: 0xb8, 0x3f5: 0xb8, 0x3f6: 0xb8, 0x3f7: 0xb8, - 0x3f8: 0xb8, 0x3f9: 0x124, 0x3fa: 0xb8, 0x3fb: 0xb8, 0x3fc: 0xb8, 0x3fd: 0xb8, 0x3fe: 0xb8, 0x3ff: 0xb8, + 0x3c0: 0x103, 0x3c1: 0x104, 0x3c2: 0x9f, 0x3c3: 0x105, 0x3c4: 0x106, 0x3c5: 0x9b, 0x3c6: 0x107, 0x3c7: 0x108, + 0x3c8: 0xba, 0x3c9: 0xba, 0x3ca: 0x109, 0x3cb: 0x10a, 0x3cc: 0x10b, 0x3cd: 0x10c, 0x3ce: 0x10d, 0x3cf: 0x10e, + 0x3d0: 0x10f, 0x3d1: 0x9f, 0x3d2: 0x110, 0x3d3: 0x111, 0x3d4: 0x112, 0x3d5: 0x113, 0x3d6: 0xba, 0x3d7: 0xba, + 0x3d8: 0x9f, 0x3d9: 0x9f, 0x3da: 0x9f, 0x3db: 0x9f, 0x3dc: 0x114, 0x3dd: 0x115, 0x3de: 0xba, 0x3df: 0xba, + 0x3e0: 0x116, 0x3e1: 0x117, 0x3e2: 0x118, 0x3e3: 0x119, 0x3e4: 0x11a, 0x3e5: 0xba, 0x3e6: 0x11b, 0x3e7: 0x11c, + 0x3e8: 0x11d, 0x3e9: 0x11e, 0x3ea: 0x11f, 0x3eb: 0x5b, 0x3ec: 0x120, 0x3ed: 0x121, 0x3ee: 0x5c, 0x3ef: 0xba, + 0x3f0: 0x122, 0x3f1: 0x123, 0x3f2: 0x124, 0x3f3: 0x125, 0x3f4: 0xba, 0x3f5: 0xba, 0x3f6: 0xba, 0x3f7: 0xba, + 0x3f8: 0xba, 0x3f9: 0x126, 0x3fa: 0xba, 0x3fb: 0xba, 0x3fc: 0xba, 0x3fd: 0xba, 0x3fe: 0xba, 0x3ff: 0xba, // Block 0x10, offset 0x400 - 0x400: 0x125, 0x401: 0x126, 0x402: 0x127, 0x403: 0x128, 0x404: 0x129, 0x405: 0x12a, 0x406: 0x12b, 0x407: 0x12c, - 0x408: 0x12d, 0x409: 0xb8, 0x40a: 0x12e, 0x40b: 0x12f, 0x40c: 0x5b, 0x40d: 0x5c, 0x40e: 0xb8, 0x40f: 0xb8, - 0x410: 0x130, 0x411: 0x131, 0x412: 0x132, 0x413: 0x133, 0x414: 0xb8, 0x415: 0xb8, 0x416: 0x134, 0x417: 0x135, - 0x418: 0x136, 0x419: 0x137, 0x41a: 0x138, 0x41b: 0x139, 0x41c: 0x13a, 0x41d: 0xb8, 0x41e: 0xb8, 0x41f: 0xb8, - 0x420: 0xb8, 0x421: 0xb8, 0x422: 0x13b, 0x423: 0x13c, 0x424: 0xb8, 0x425: 0xb8, 0x426: 0xb8, 0x427: 0xb8, - 0x428: 0xb8, 0x429: 0xb8, 0x42a: 0xb8, 0x42b: 0x13d, 0x42c: 0xb8, 0x42d: 0xb8, 0x42e: 0xb8, 0x42f: 0xb8, - 0x430: 0x13e, 0x431: 0x13f, 0x432: 0x140, 0x433: 0xb8, 0x434: 0xb8, 0x435: 0xb8, 0x436: 0xb8, 0x437: 0xb8, - 0x438: 0xb8, 0x439: 0xb8, 0x43a: 0xb8, 0x43b: 0xb8, 0x43c: 0xb8, 0x43d: 0xb8, 0x43e: 0xb8, 0x43f: 0xb8, + 0x400: 0x127, 0x401: 0x128, 0x402: 0x129, 0x403: 0x12a, 0x404: 0x12b, 0x405: 0x12c, 0x406: 0x12d, 0x407: 0x12e, + 0x408: 0x12f, 0x409: 0xba, 0x40a: 0x130, 0x40b: 0x131, 0x40c: 0x5d, 0x40d: 0x5e, 0x40e: 0xba, 0x40f: 0xba, + 0x410: 0x132, 0x411: 0x133, 0x412: 0x134, 0x413: 0x135, 0x414: 0xba, 0x415: 0xba, 0x416: 0x136, 0x417: 0x137, + 0x418: 0x138, 0x419: 0x139, 0x41a: 0x13a, 0x41b: 0x13b, 0x41c: 0x13c, 0x41d: 0xba, 0x41e: 0xba, 0x41f: 0xba, + 0x420: 0xba, 0x421: 0xba, 0x422: 0x13d, 0x423: 0x13e, 0x424: 0xba, 0x425: 0xba, 0x426: 0xba, 0x427: 0xba, + 0x428: 0x13f, 0x429: 0x140, 0x42a: 0x141, 0x42b: 0x142, 0x42c: 0xba, 0x42d: 0xba, 0x42e: 0xba, 0x42f: 0xba, + 0x430: 0x143, 0x431: 0x144, 0x432: 0x145, 0x433: 0xba, 0x434: 0x146, 0x435: 0x147, 0x436: 0xba, 0x437: 0xba, + 0x438: 0xba, 0x439: 0xba, 0x43a: 0xba, 0x43b: 0xba, 0x43c: 0xba, 0x43d: 0xba, 0x43e: 0xba, 0x43f: 0xba, // Block 0x11, offset 0x440 - 0x440: 0x9d, 0x441: 0x9d, 0x442: 0x9d, 0x443: 0x9d, 0x444: 0x9d, 0x445: 0x9d, 0x446: 0x9d, 0x447: 0x9d, - 0x448: 0x9d, 0x449: 0x9d, 0x44a: 0x9d, 0x44b: 0x9d, 0x44c: 0x9d, 0x44d: 0x9d, 0x44e: 0x141, 0x44f: 0xb8, - 0x450: 0x9b, 0x451: 0x142, 0x452: 0x9d, 0x453: 0x9d, 0x454: 0x9d, 0x455: 0x143, 0x456: 0xb8, 0x457: 0xb8, - 0x458: 0xb8, 0x459: 0xb8, 0x45a: 0xb8, 0x45b: 0xb8, 0x45c: 0xb8, 0x45d: 0xb8, 0x45e: 0xb8, 0x45f: 0xb8, - 0x460: 0xb8, 0x461: 0xb8, 0x462: 0xb8, 0x463: 0xb8, 0x464: 0xb8, 0x465: 0xb8, 0x466: 0xb8, 0x467: 0xb8, - 0x468: 0xb8, 0x469: 0xb8, 0x46a: 0xb8, 0x46b: 0xb8, 0x46c: 0xb8, 0x46d: 0xb8, 0x46e: 0xb8, 0x46f: 0xb8, - 0x470: 0xb8, 0x471: 0xb8, 0x472: 0xb8, 0x473: 0xb8, 0x474: 0xb8, 0x475: 0xb8, 0x476: 0xb8, 0x477: 0xb8, - 0x478: 0xb8, 0x479: 0xb8, 0x47a: 0xb8, 0x47b: 0xb8, 0x47c: 0xb8, 0x47d: 0xb8, 0x47e: 0xb8, 0x47f: 0xb8, + 0x440: 0x9f, 0x441: 0x9f, 0x442: 0x9f, 0x443: 0x9f, 0x444: 0x9f, 0x445: 0x9f, 0x446: 0x9f, 0x447: 0x9f, + 0x448: 0x9f, 0x449: 0x9f, 0x44a: 0x9f, 0x44b: 0x9f, 0x44c: 0x9f, 0x44d: 0x9f, 0x44e: 0x148, 0x44f: 0xba, + 0x450: 0x9b, 0x451: 0x149, 0x452: 0x9f, 0x453: 0x9f, 0x454: 0x9f, 0x455: 0x14a, 0x456: 0xba, 0x457: 0xba, + 0x458: 0xba, 0x459: 0xba, 0x45a: 0xba, 0x45b: 0xba, 0x45c: 0xba, 0x45d: 0xba, 0x45e: 0xba, 0x45f: 0xba, + 0x460: 0xba, 0x461: 0xba, 0x462: 0xba, 0x463: 0xba, 0x464: 0xba, 0x465: 0xba, 0x466: 0xba, 0x467: 0xba, + 0x468: 0xba, 0x469: 0xba, 0x46a: 0xba, 0x46b: 0xba, 0x46c: 0xba, 0x46d: 0xba, 0x46e: 0xba, 0x46f: 0xba, + 0x470: 0xba, 0x471: 0xba, 0x472: 0xba, 0x473: 0xba, 0x474: 0xba, 0x475: 0xba, 0x476: 0xba, 0x477: 0xba, + 0x478: 0xba, 0x479: 0xba, 0x47a: 0xba, 0x47b: 0xba, 0x47c: 0xba, 0x47d: 0xba, 0x47e: 0xba, 0x47f: 0xba, // Block 0x12, offset 0x480 - 0x480: 0x9d, 0x481: 0x9d, 0x482: 0x9d, 0x483: 0x9d, 0x484: 0x9d, 0x485: 0x9d, 0x486: 0x9d, 0x487: 0x9d, - 0x488: 0x9d, 0x489: 0x9d, 0x48a: 0x9d, 0x48b: 0x9d, 0x48c: 0x9d, 0x48d: 0x9d, 0x48e: 0x9d, 0x48f: 0x9d, - 0x490: 0x144, 0x491: 0xb8, 0x492: 0xb8, 0x493: 0xb8, 0x494: 0xb8, 0x495: 0xb8, 0x496: 0xb8, 0x497: 0xb8, - 0x498: 0xb8, 0x499: 0xb8, 0x49a: 0xb8, 0x49b: 0xb8, 0x49c: 0xb8, 0x49d: 0xb8, 0x49e: 0xb8, 0x49f: 0xb8, - 0x4a0: 0xb8, 0x4a1: 0xb8, 0x4a2: 0xb8, 0x4a3: 0xb8, 0x4a4: 0xb8, 0x4a5: 0xb8, 0x4a6: 0xb8, 0x4a7: 0xb8, - 0x4a8: 0xb8, 0x4a9: 0xb8, 0x4aa: 0xb8, 0x4ab: 0xb8, 0x4ac: 0xb8, 0x4ad: 0xb8, 0x4ae: 0xb8, 0x4af: 0xb8, - 0x4b0: 0xb8, 0x4b1: 0xb8, 0x4b2: 0xb8, 0x4b3: 0xb8, 0x4b4: 0xb8, 0x4b5: 0xb8, 0x4b6: 0xb8, 0x4b7: 0xb8, - 0x4b8: 0xb8, 0x4b9: 0xb8, 0x4ba: 0xb8, 0x4bb: 0xb8, 0x4bc: 0xb8, 0x4bd: 0xb8, 0x4be: 0xb8, 0x4bf: 0xb8, + 0x480: 0x9f, 0x481: 0x9f, 0x482: 0x9f, 0x483: 0x9f, 0x484: 0x9f, 0x485: 0x9f, 0x486: 0x9f, 0x487: 0x9f, + 0x488: 0x9f, 0x489: 0x9f, 0x48a: 0x9f, 0x48b: 0x9f, 0x48c: 0x9f, 0x48d: 0x9f, 0x48e: 0x9f, 0x48f: 0x9f, + 0x490: 0x14b, 0x491: 0xba, 0x492: 0xba, 0x493: 0xba, 0x494: 0xba, 0x495: 0xba, 0x496: 0xba, 0x497: 0xba, + 0x498: 0xba, 0x499: 0xba, 0x49a: 0xba, 0x49b: 0xba, 0x49c: 0xba, 0x49d: 0xba, 0x49e: 0xba, 0x49f: 0xba, + 0x4a0: 0xba, 0x4a1: 0xba, 0x4a2: 0xba, 0x4a3: 0xba, 0x4a4: 0xba, 0x4a5: 0xba, 0x4a6: 0xba, 0x4a7: 0xba, + 0x4a8: 0xba, 0x4a9: 0xba, 0x4aa: 0xba, 0x4ab: 0xba, 0x4ac: 0xba, 0x4ad: 0xba, 0x4ae: 0xba, 0x4af: 0xba, + 0x4b0: 0xba, 0x4b1: 0xba, 0x4b2: 0xba, 0x4b3: 0xba, 0x4b4: 0xba, 0x4b5: 0xba, 0x4b6: 0xba, 0x4b7: 0xba, + 0x4b8: 0xba, 0x4b9: 0xba, 0x4ba: 0xba, 0x4bb: 0xba, 0x4bc: 0xba, 0x4bd: 0xba, 0x4be: 0xba, 0x4bf: 0xba, // Block 0x13, offset 0x4c0 - 0x4c0: 0xb8, 0x4c1: 0xb8, 0x4c2: 0xb8, 0x4c3: 0xb8, 0x4c4: 0xb8, 0x4c5: 0xb8, 0x4c6: 0xb8, 0x4c7: 0xb8, - 0x4c8: 0xb8, 0x4c9: 0xb8, 0x4ca: 0xb8, 0x4cb: 0xb8, 0x4cc: 0xb8, 0x4cd: 0xb8, 0x4ce: 0xb8, 0x4cf: 0xb8, - 0x4d0: 0x9d, 0x4d1: 0x9d, 0x4d2: 0x9d, 0x4d3: 0x9d, 0x4d4: 0x9d, 0x4d5: 0x9d, 0x4d6: 0x9d, 0x4d7: 0x9d, - 0x4d8: 0x9d, 0x4d9: 0x145, 0x4da: 0xb8, 0x4db: 0xb8, 0x4dc: 0xb8, 0x4dd: 0xb8, 0x4de: 0xb8, 0x4df: 0xb8, - 0x4e0: 0xb8, 0x4e1: 0xb8, 0x4e2: 0xb8, 0x4e3: 0xb8, 0x4e4: 0xb8, 0x4e5: 0xb8, 0x4e6: 0xb8, 0x4e7: 0xb8, - 0x4e8: 0xb8, 0x4e9: 0xb8, 0x4ea: 0xb8, 0x4eb: 0xb8, 0x4ec: 0xb8, 0x4ed: 0xb8, 0x4ee: 0xb8, 0x4ef: 0xb8, - 0x4f0: 0xb8, 0x4f1: 0xb8, 0x4f2: 0xb8, 0x4f3: 0xb8, 0x4f4: 0xb8, 0x4f5: 0xb8, 0x4f6: 0xb8, 0x4f7: 0xb8, - 0x4f8: 0xb8, 0x4f9: 0xb8, 0x4fa: 0xb8, 0x4fb: 0xb8, 0x4fc: 0xb8, 0x4fd: 0xb8, 0x4fe: 0xb8, 0x4ff: 0xb8, + 0x4c0: 0xba, 0x4c1: 0xba, 0x4c2: 0xba, 0x4c3: 0xba, 0x4c4: 0xba, 0x4c5: 0xba, 0x4c6: 0xba, 0x4c7: 0xba, + 0x4c8: 0xba, 0x4c9: 0xba, 0x4ca: 0xba, 0x4cb: 0xba, 0x4cc: 0xba, 0x4cd: 0xba, 0x4ce: 0xba, 0x4cf: 0xba, + 0x4d0: 0x9f, 0x4d1: 0x9f, 0x4d2: 0x9f, 0x4d3: 0x9f, 0x4d4: 0x9f, 0x4d5: 0x9f, 0x4d6: 0x9f, 0x4d7: 0x9f, + 0x4d8: 0x9f, 0x4d9: 0x14c, 0x4da: 0xba, 0x4db: 0xba, 0x4dc: 0xba, 0x4dd: 0xba, 0x4de: 0xba, 0x4df: 0xba, + 0x4e0: 0xba, 0x4e1: 0xba, 0x4e2: 0xba, 0x4e3: 0xba, 0x4e4: 0xba, 0x4e5: 0xba, 0x4e6: 0xba, 0x4e7: 0xba, + 0x4e8: 0xba, 0x4e9: 0xba, 0x4ea: 0xba, 0x4eb: 0xba, 0x4ec: 0xba, 0x4ed: 0xba, 0x4ee: 0xba, 0x4ef: 0xba, + 0x4f0: 0xba, 0x4f1: 0xba, 0x4f2: 0xba, 0x4f3: 0xba, 0x4f4: 0xba, 0x4f5: 0xba, 0x4f6: 0xba, 0x4f7: 0xba, + 0x4f8: 0xba, 0x4f9: 0xba, 0x4fa: 0xba, 0x4fb: 0xba, 0x4fc: 0xba, 0x4fd: 0xba, 0x4fe: 0xba, 0x4ff: 0xba, // Block 0x14, offset 0x500 - 0x500: 0xb8, 0x501: 0xb8, 0x502: 0xb8, 0x503: 0xb8, 0x504: 0xb8, 0x505: 0xb8, 0x506: 0xb8, 0x507: 0xb8, - 0x508: 0xb8, 0x509: 0xb8, 0x50a: 0xb8, 0x50b: 0xb8, 0x50c: 0xb8, 0x50d: 0xb8, 0x50e: 0xb8, 0x50f: 0xb8, - 0x510: 0xb8, 0x511: 0xb8, 0x512: 0xb8, 0x513: 0xb8, 0x514: 0xb8, 0x515: 0xb8, 0x516: 0xb8, 0x517: 0xb8, - 0x518: 0xb8, 0x519: 0xb8, 0x51a: 0xb8, 0x51b: 0xb8, 0x51c: 0xb8, 0x51d: 0xb8, 0x51e: 0xb8, 0x51f: 0xb8, - 0x520: 0x9d, 0x521: 0x9d, 0x522: 0x9d, 0x523: 0x9d, 0x524: 0x9d, 0x525: 0x9d, 0x526: 0x9d, 0x527: 0x9d, - 0x528: 0x13d, 0x529: 0x146, 0x52a: 0xb8, 0x52b: 0x147, 0x52c: 0x148, 0x52d: 0x149, 0x52e: 0x14a, 0x52f: 0xb8, - 0x530: 0xb8, 0x531: 0xb8, 0x532: 0xb8, 0x533: 0xb8, 0x534: 0xb8, 0x535: 0xb8, 0x536: 0xb8, 0x537: 0xb8, - 0x538: 0xb8, 0x539: 0xb8, 0x53a: 0xb8, 0x53b: 0xb8, 0x53c: 0x9d, 0x53d: 0x14b, 0x53e: 0x14c, 0x53f: 0x14d, + 0x500: 0xba, 0x501: 0xba, 0x502: 0xba, 0x503: 0xba, 0x504: 0xba, 0x505: 0xba, 0x506: 0xba, 0x507: 0xba, + 0x508: 0xba, 0x509: 0xba, 0x50a: 0xba, 0x50b: 0xba, 0x50c: 0xba, 0x50d: 0xba, 0x50e: 0xba, 0x50f: 0xba, + 0x510: 0xba, 0x511: 0xba, 0x512: 0xba, 0x513: 0xba, 0x514: 0xba, 0x515: 0xba, 0x516: 0xba, 0x517: 0xba, + 0x518: 0xba, 0x519: 0xba, 0x51a: 0xba, 0x51b: 0xba, 0x51c: 0xba, 0x51d: 0xba, 0x51e: 0xba, 0x51f: 0xba, + 0x520: 0x9f, 0x521: 0x9f, 0x522: 0x9f, 0x523: 0x9f, 0x524: 0x9f, 0x525: 0x9f, 0x526: 0x9f, 0x527: 0x9f, + 0x528: 0x142, 0x529: 0x14d, 0x52a: 0xba, 0x52b: 0x14e, 0x52c: 0x14f, 0x52d: 0x150, 0x52e: 0x151, 0x52f: 0xba, + 0x530: 0xba, 0x531: 0xba, 0x532: 0xba, 0x533: 0xba, 0x534: 0xba, 0x535: 0xba, 0x536: 0xba, 0x537: 0xba, + 0x538: 0xba, 0x539: 0xba, 0x53a: 0xba, 0x53b: 0xba, 0x53c: 0x9f, 0x53d: 0x152, 0x53e: 0x153, 0x53f: 0x154, // Block 0x15, offset 0x540 - 0x540: 0x9d, 0x541: 0x9d, 0x542: 0x9d, 0x543: 0x9d, 0x544: 0x9d, 0x545: 0x9d, 0x546: 0x9d, 0x547: 0x9d, - 0x548: 0x9d, 0x549: 0x9d, 0x54a: 0x9d, 0x54b: 0x9d, 0x54c: 0x9d, 0x54d: 0x9d, 0x54e: 0x9d, 0x54f: 0x9d, - 0x550: 0x9d, 0x551: 0x9d, 0x552: 0x9d, 0x553: 0x9d, 0x554: 0x9d, 0x555: 0x9d, 0x556: 0x9d, 0x557: 0x9d, - 0x558: 0x9d, 0x559: 0x9d, 0x55a: 0x9d, 0x55b: 0x9d, 0x55c: 0x9d, 0x55d: 0x9d, 0x55e: 0x9d, 0x55f: 0x14e, - 0x560: 0x9d, 0x561: 0x9d, 0x562: 0x9d, 0x563: 0x9d, 0x564: 0x9d, 0x565: 0x9d, 0x566: 0x9d, 0x567: 0x9d, - 0x568: 0x9d, 0x569: 0x9d, 0x56a: 0x9d, 0x56b: 0x14f, 0x56c: 0xb8, 0x56d: 0xb8, 0x56e: 0xb8, 0x56f: 0xb8, - 0x570: 0xb8, 0x571: 0xb8, 0x572: 0xb8, 0x573: 0xb8, 0x574: 0xb8, 0x575: 0xb8, 0x576: 0xb8, 0x577: 0xb8, - 0x578: 0xb8, 0x579: 0xb8, 0x57a: 0xb8, 0x57b: 0xb8, 0x57c: 0xb8, 0x57d: 0xb8, 0x57e: 0xb8, 0x57f: 0xb8, + 0x540: 0x9f, 0x541: 0x9f, 0x542: 0x9f, 0x543: 0x9f, 0x544: 0x9f, 0x545: 0x9f, 0x546: 0x9f, 0x547: 0x9f, + 0x548: 0x9f, 0x549: 0x9f, 0x54a: 0x9f, 0x54b: 0x9f, 0x54c: 0x9f, 0x54d: 0x9f, 0x54e: 0x9f, 0x54f: 0x9f, + 0x550: 0x9f, 0x551: 0x9f, 0x552: 0x9f, 0x553: 0x9f, 0x554: 0x9f, 0x555: 0x9f, 0x556: 0x9f, 0x557: 0x9f, + 0x558: 0x9f, 0x559: 0x9f, 0x55a: 0x9f, 0x55b: 0x9f, 0x55c: 0x9f, 0x55d: 0x9f, 0x55e: 0x9f, 0x55f: 0x155, + 0x560: 0x9f, 0x561: 0x9f, 0x562: 0x9f, 0x563: 0x9f, 0x564: 0x9f, 0x565: 0x9f, 0x566: 0x9f, 0x567: 0x9f, + 0x568: 0x9f, 0x569: 0x9f, 0x56a: 0x9f, 0x56b: 0x156, 0x56c: 0xba, 0x56d: 0xba, 0x56e: 0xba, 0x56f: 0xba, + 0x570: 0xba, 0x571: 0xba, 0x572: 0xba, 0x573: 0xba, 0x574: 0xba, 0x575: 0xba, 0x576: 0xba, 0x577: 0xba, + 0x578: 0xba, 0x579: 0xba, 0x57a: 0xba, 0x57b: 0xba, 0x57c: 0xba, 0x57d: 0xba, 0x57e: 0xba, 0x57f: 0xba, // Block 0x16, offset 0x580 - 0x580: 0x150, 0x581: 0xb8, 0x582: 0xb8, 0x583: 0xb8, 0x584: 0xb8, 0x585: 0xb8, 0x586: 0xb8, 0x587: 0xb8, - 0x588: 0xb8, 0x589: 0xb8, 0x58a: 0xb8, 0x58b: 0xb8, 0x58c: 0xb8, 0x58d: 0xb8, 0x58e: 0xb8, 0x58f: 0xb8, - 0x590: 0xb8, 0x591: 0xb8, 0x592: 0xb8, 0x593: 0xb8, 0x594: 0xb8, 0x595: 0xb8, 0x596: 0xb8, 0x597: 0xb8, - 0x598: 0xb8, 0x599: 0xb8, 0x59a: 0xb8, 0x59b: 0xb8, 0x59c: 0xb8, 0x59d: 0xb8, 0x59e: 0xb8, 0x59f: 0xb8, - 0x5a0: 0xb8, 0x5a1: 0xb8, 0x5a2: 0xb8, 0x5a3: 0xb8, 0x5a4: 0xb8, 0x5a5: 0xb8, 0x5a6: 0xb8, 0x5a7: 0xb8, - 0x5a8: 0xb8, 0x5a9: 0xb8, 0x5aa: 0xb8, 0x5ab: 0xb8, 0x5ac: 0xb8, 0x5ad: 0xb8, 0x5ae: 0xb8, 0x5af: 0xb8, - 0x5b0: 0x9d, 0x5b1: 0x151, 0x5b2: 0x152, 0x5b3: 0xb8, 0x5b4: 0xb8, 0x5b5: 0xb8, 0x5b6: 0xb8, 0x5b7: 0xb8, - 0x5b8: 0xb8, 0x5b9: 0xb8, 0x5ba: 0xb8, 0x5bb: 0xb8, 0x5bc: 0xb8, 0x5bd: 0xb8, 0x5be: 0xb8, 0x5bf: 0xb8, + 0x580: 0x9f, 0x581: 0x9f, 0x582: 0x9f, 0x583: 0x9f, 0x584: 0x157, 0x585: 0x158, 0x586: 0x9f, 0x587: 0x9f, + 0x588: 0x9f, 0x589: 0x9f, 0x58a: 0x9f, 0x58b: 0x159, 0x58c: 0xba, 0x58d: 0xba, 0x58e: 0xba, 0x58f: 0xba, + 0x590: 0xba, 0x591: 0xba, 0x592: 0xba, 0x593: 0xba, 0x594: 0xba, 0x595: 0xba, 0x596: 0xba, 0x597: 0xba, + 0x598: 0xba, 0x599: 0xba, 0x59a: 0xba, 0x59b: 0xba, 0x59c: 0xba, 0x59d: 0xba, 0x59e: 0xba, 0x59f: 0xba, + 0x5a0: 0xba, 0x5a1: 0xba, 0x5a2: 0xba, 0x5a3: 0xba, 0x5a4: 0xba, 0x5a5: 0xba, 0x5a6: 0xba, 0x5a7: 0xba, + 0x5a8: 0xba, 0x5a9: 0xba, 0x5aa: 0xba, 0x5ab: 0xba, 0x5ac: 0xba, 0x5ad: 0xba, 0x5ae: 0xba, 0x5af: 0xba, + 0x5b0: 0x9f, 0x5b1: 0x15a, 0x5b2: 0x15b, 0x5b3: 0xba, 0x5b4: 0xba, 0x5b5: 0xba, 0x5b6: 0xba, 0x5b7: 0xba, + 0x5b8: 0xba, 0x5b9: 0xba, 0x5ba: 0xba, 0x5bb: 0xba, 0x5bc: 0xba, 0x5bd: 0xba, 0x5be: 0xba, 0x5bf: 0xba, // Block 0x17, offset 0x5c0 - 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x153, 0x5c4: 0x154, 0x5c5: 0x155, 0x5c6: 0x156, 0x5c7: 0x157, - 0x5c8: 0x9b, 0x5c9: 0x158, 0x5ca: 0xb8, 0x5cb: 0xb8, 0x5cc: 0x9b, 0x5cd: 0x159, 0x5ce: 0xb8, 0x5cf: 0xb8, - 0x5d0: 0x5d, 0x5d1: 0x5e, 0x5d2: 0x5f, 0x5d3: 0x60, 0x5d4: 0x61, 0x5d5: 0x62, 0x5d6: 0x63, 0x5d7: 0x64, - 0x5d8: 0x65, 0x5d9: 0x66, 0x5da: 0x67, 0x5db: 0x68, 0x5dc: 0x69, 0x5dd: 0x6a, 0x5de: 0x6b, 0x5df: 0x6c, + 0x5c0: 0x9b, 0x5c1: 0x9b, 0x5c2: 0x9b, 0x5c3: 0x15c, 0x5c4: 0x15d, 0x5c5: 0x15e, 0x5c6: 0x15f, 0x5c7: 0x160, + 0x5c8: 0x9b, 0x5c9: 0x161, 0x5ca: 0xba, 0x5cb: 0xba, 0x5cc: 0x9b, 0x5cd: 0x162, 0x5ce: 0xba, 0x5cf: 0xba, + 0x5d0: 0x5f, 0x5d1: 0x60, 0x5d2: 0x61, 0x5d3: 0x62, 0x5d4: 0x63, 0x5d5: 0x64, 0x5d6: 0x65, 0x5d7: 0x66, + 0x5d8: 0x67, 0x5d9: 0x68, 0x5da: 0x69, 0x5db: 0x6a, 0x5dc: 0x6b, 0x5dd: 0x6c, 0x5de: 0x6d, 0x5df: 0x6e, 0x5e0: 0x9b, 0x5e1: 0x9b, 0x5e2: 0x9b, 0x5e3: 0x9b, 0x5e4: 0x9b, 0x5e5: 0x9b, 0x5e6: 0x9b, 0x5e7: 0x9b, - 0x5e8: 0x15a, 0x5e9: 0x15b, 0x5ea: 0x15c, 0x5eb: 0xb8, 0x5ec: 0xb8, 0x5ed: 0xb8, 0x5ee: 0xb8, 0x5ef: 0xb8, - 0x5f0: 0xb8, 0x5f1: 0xb8, 0x5f2: 0xb8, 0x5f3: 0xb8, 0x5f4: 0xb8, 0x5f5: 0xb8, 0x5f6: 0xb8, 0x5f7: 0xb8, - 0x5f8: 0xb8, 0x5f9: 0xb8, 0x5fa: 0xb8, 0x5fb: 0xb8, 0x5fc: 0xb8, 0x5fd: 0xb8, 0x5fe: 0xb8, 0x5ff: 0xb8, + 0x5e8: 0x163, 0x5e9: 0x164, 0x5ea: 0x165, 0x5eb: 0xba, 0x5ec: 0xba, 0x5ed: 0xba, 0x5ee: 0xba, 0x5ef: 0xba, + 0x5f0: 0xba, 0x5f1: 0xba, 0x5f2: 0xba, 0x5f3: 0xba, 0x5f4: 0xba, 0x5f5: 0xba, 0x5f6: 0xba, 0x5f7: 0xba, + 0x5f8: 0xba, 0x5f9: 0xba, 0x5fa: 0xba, 0x5fb: 0xba, 0x5fc: 0xba, 0x5fd: 0xba, 0x5fe: 0xba, 0x5ff: 0xba, // Block 0x18, offset 0x600 - 0x600: 0x15d, 0x601: 0xb8, 0x602: 0xb8, 0x603: 0xb8, 0x604: 0xb8, 0x605: 0xb8, 0x606: 0xb8, 0x607: 0xb8, - 0x608: 0xb8, 0x609: 0xb8, 0x60a: 0xb8, 0x60b: 0xb8, 0x60c: 0xb8, 0x60d: 0xb8, 0x60e: 0xb8, 0x60f: 0xb8, - 0x610: 0xb8, 0x611: 0xb8, 0x612: 0xb8, 0x613: 0xb8, 0x614: 0xb8, 0x615: 0xb8, 0x616: 0xb8, 0x617: 0xb8, - 0x618: 0xb8, 0x619: 0xb8, 0x61a: 0xb8, 0x61b: 0xb8, 0x61c: 0xb8, 0x61d: 0xb8, 0x61e: 0xb8, 0x61f: 0xb8, - 0x620: 0x9d, 0x621: 0x9d, 0x622: 0x9d, 0x623: 0x15e, 0x624: 0x6d, 0x625: 0x15f, 0x626: 0xb8, 0x627: 0xb8, - 0x628: 0xb8, 0x629: 0xb8, 0x62a: 0xb8, 0x62b: 0xb8, 0x62c: 0xb8, 0x62d: 0xb8, 0x62e: 0xb8, 0x62f: 0xb8, - 0x630: 0xb8, 0x631: 0xb8, 0x632: 0xb8, 0x633: 0xb8, 0x634: 0xb8, 0x635: 0xb8, 0x636: 0xb8, 0x637: 0xb8, - 0x638: 0x6e, 0x639: 0x6f, 0x63a: 0x70, 0x63b: 0x160, 0x63c: 0xb8, 0x63d: 0xb8, 0x63e: 0xb8, 0x63f: 0xb8, + 0x600: 0x166, 0x601: 0xba, 0x602: 0xba, 0x603: 0xba, 0x604: 0xba, 0x605: 0xba, 0x606: 0xba, 0x607: 0xba, + 0x608: 0xba, 0x609: 0xba, 0x60a: 0xba, 0x60b: 0xba, 0x60c: 0xba, 0x60d: 0xba, 0x60e: 0xba, 0x60f: 0xba, + 0x610: 0xba, 0x611: 0xba, 0x612: 0xba, 0x613: 0xba, 0x614: 0xba, 0x615: 0xba, 0x616: 0xba, 0x617: 0xba, + 0x618: 0xba, 0x619: 0xba, 0x61a: 0xba, 0x61b: 0xba, 0x61c: 0xba, 0x61d: 0xba, 0x61e: 0xba, 0x61f: 0xba, + 0x620: 0x122, 0x621: 0x122, 0x622: 0x122, 0x623: 0x167, 0x624: 0x6f, 0x625: 0x168, 0x626: 0xba, 0x627: 0xba, + 0x628: 0xba, 0x629: 0xba, 0x62a: 0xba, 0x62b: 0xba, 0x62c: 0xba, 0x62d: 0xba, 0x62e: 0xba, 0x62f: 0xba, + 0x630: 0xba, 0x631: 0xba, 0x632: 0xba, 0x633: 0xba, 0x634: 0xba, 0x635: 0xba, 0x636: 0xba, 0x637: 0xba, + 0x638: 0x70, 0x639: 0x71, 0x63a: 0x72, 0x63b: 0x169, 0x63c: 0xba, 0x63d: 0xba, 0x63e: 0xba, 0x63f: 0xba, // Block 0x19, offset 0x640 - 0x640: 0x161, 0x641: 0x9b, 0x642: 0x162, 0x643: 0x163, 0x644: 0x71, 0x645: 0x72, 0x646: 0x164, 0x647: 0x165, - 0x648: 0x73, 0x649: 0x166, 0x64a: 0xb8, 0x64b: 0xb8, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, + 0x640: 0x16a, 0x641: 0x9b, 0x642: 0x16b, 0x643: 0x16c, 0x644: 0x73, 0x645: 0x74, 0x646: 0x16d, 0x647: 0x16e, + 0x648: 0x75, 0x649: 0x16f, 0x64a: 0xba, 0x64b: 0xba, 0x64c: 0x9b, 0x64d: 0x9b, 0x64e: 0x9b, 0x64f: 0x9b, 0x650: 0x9b, 0x651: 0x9b, 0x652: 0x9b, 0x653: 0x9b, 0x654: 0x9b, 0x655: 0x9b, 0x656: 0x9b, 0x657: 0x9b, - 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x167, 0x65c: 0x9b, 0x65d: 0x168, 0x65e: 0x9b, 0x65f: 0x169, - 0x660: 0x16a, 0x661: 0x16b, 0x662: 0x16c, 0x663: 0xb8, 0x664: 0x16d, 0x665: 0x16e, 0x666: 0x16f, 0x667: 0x170, - 0x668: 0xb8, 0x669: 0xb8, 0x66a: 0xb8, 0x66b: 0xb8, 0x66c: 0xb8, 0x66d: 0xb8, 0x66e: 0xb8, 0x66f: 0xb8, - 0x670: 0xb8, 0x671: 0xb8, 0x672: 0xb8, 0x673: 0xb8, 0x674: 0xb8, 0x675: 0xb8, 0x676: 0xb8, 0x677: 0xb8, - 0x678: 0xb8, 0x679: 0xb8, 0x67a: 0xb8, 0x67b: 0xb8, 0x67c: 0xb8, 0x67d: 0xb8, 0x67e: 0xb8, 0x67f: 0xb8, + 0x658: 0x9b, 0x659: 0x9b, 0x65a: 0x9b, 0x65b: 0x170, 0x65c: 0x9b, 0x65d: 0x171, 0x65e: 0x9b, 0x65f: 0x172, + 0x660: 0x173, 0x661: 0x174, 0x662: 0x175, 0x663: 0xba, 0x664: 0x176, 0x665: 0x177, 0x666: 0x178, 0x667: 0x179, + 0x668: 0xba, 0x669: 0xba, 0x66a: 0xba, 0x66b: 0xba, 0x66c: 0xba, 0x66d: 0xba, 0x66e: 0xba, 0x66f: 0xba, + 0x670: 0xba, 0x671: 0xba, 0x672: 0xba, 0x673: 0xba, 0x674: 0xba, 0x675: 0xba, 0x676: 0xba, 0x677: 0xba, + 0x678: 0xba, 0x679: 0xba, 0x67a: 0xba, 0x67b: 0xba, 0x67c: 0xba, 0x67d: 0xba, 0x67e: 0xba, 0x67f: 0xba, // Block 0x1a, offset 0x680 - 0x680: 0x9d, 0x681: 0x9d, 0x682: 0x9d, 0x683: 0x9d, 0x684: 0x9d, 0x685: 0x9d, 0x686: 0x9d, 0x687: 0x9d, - 0x688: 0x9d, 0x689: 0x9d, 0x68a: 0x9d, 0x68b: 0x9d, 0x68c: 0x9d, 0x68d: 0x9d, 0x68e: 0x9d, 0x68f: 0x9d, - 0x690: 0x9d, 0x691: 0x9d, 0x692: 0x9d, 0x693: 0x9d, 0x694: 0x9d, 0x695: 0x9d, 0x696: 0x9d, 0x697: 0x9d, - 0x698: 0x9d, 0x699: 0x9d, 0x69a: 0x9d, 0x69b: 0x171, 0x69c: 0x9d, 0x69d: 0x9d, 0x69e: 0x9d, 0x69f: 0x9d, - 0x6a0: 0x9d, 0x6a1: 0x9d, 0x6a2: 0x9d, 0x6a3: 0x9d, 0x6a4: 0x9d, 0x6a5: 0x9d, 0x6a6: 0x9d, 0x6a7: 0x9d, - 0x6a8: 0x9d, 0x6a9: 0x9d, 0x6aa: 0x9d, 0x6ab: 0x9d, 0x6ac: 0x9d, 0x6ad: 0x9d, 0x6ae: 0x9d, 0x6af: 0x9d, - 0x6b0: 0x9d, 0x6b1: 0x9d, 0x6b2: 0x9d, 0x6b3: 0x9d, 0x6b4: 0x9d, 0x6b5: 0x9d, 0x6b6: 0x9d, 0x6b7: 0x9d, - 0x6b8: 0x9d, 0x6b9: 0x9d, 0x6ba: 0x9d, 0x6bb: 0x9d, 0x6bc: 0x9d, 0x6bd: 0x9d, 0x6be: 0x9d, 0x6bf: 0x9d, + 0x680: 0x9f, 0x681: 0x9f, 0x682: 0x9f, 0x683: 0x9f, 0x684: 0x9f, 0x685: 0x9f, 0x686: 0x9f, 0x687: 0x9f, + 0x688: 0x9f, 0x689: 0x9f, 0x68a: 0x9f, 0x68b: 0x9f, 0x68c: 0x9f, 0x68d: 0x9f, 0x68e: 0x9f, 0x68f: 0x9f, + 0x690: 0x9f, 0x691: 0x9f, 0x692: 0x9f, 0x693: 0x9f, 0x694: 0x9f, 0x695: 0x9f, 0x696: 0x9f, 0x697: 0x9f, + 0x698: 0x9f, 0x699: 0x9f, 0x69a: 0x9f, 0x69b: 0x17a, 0x69c: 0x9f, 0x69d: 0x9f, 0x69e: 0x9f, 0x69f: 0x9f, + 0x6a0: 0x9f, 0x6a1: 0x9f, 0x6a2: 0x9f, 0x6a3: 0x9f, 0x6a4: 0x9f, 0x6a5: 0x9f, 0x6a6: 0x9f, 0x6a7: 0x9f, + 0x6a8: 0x9f, 0x6a9: 0x9f, 0x6aa: 0x9f, 0x6ab: 0x9f, 0x6ac: 0x9f, 0x6ad: 0x9f, 0x6ae: 0x9f, 0x6af: 0x9f, + 0x6b0: 0x9f, 0x6b1: 0x9f, 0x6b2: 0x9f, 0x6b3: 0x9f, 0x6b4: 0x9f, 0x6b5: 0x9f, 0x6b6: 0x9f, 0x6b7: 0x9f, + 0x6b8: 0x9f, 0x6b9: 0x9f, 0x6ba: 0x9f, 0x6bb: 0x9f, 0x6bc: 0x9f, 0x6bd: 0x9f, 0x6be: 0x9f, 0x6bf: 0x9f, // Block 0x1b, offset 0x6c0 - 0x6c0: 0x9d, 0x6c1: 0x9d, 0x6c2: 0x9d, 0x6c3: 0x9d, 0x6c4: 0x9d, 0x6c5: 0x9d, 0x6c6: 0x9d, 0x6c7: 0x9d, - 0x6c8: 0x9d, 0x6c9: 0x9d, 0x6ca: 0x9d, 0x6cb: 0x9d, 0x6cc: 0x9d, 0x6cd: 0x9d, 0x6ce: 0x9d, 0x6cf: 0x9d, - 0x6d0: 0x9d, 0x6d1: 0x9d, 0x6d2: 0x9d, 0x6d3: 0x9d, 0x6d4: 0x9d, 0x6d5: 0x9d, 0x6d6: 0x9d, 0x6d7: 0x9d, - 0x6d8: 0x9d, 0x6d9: 0x9d, 0x6da: 0x9d, 0x6db: 0x9d, 0x6dc: 0x172, 0x6dd: 0x9d, 0x6de: 0x9d, 0x6df: 0x9d, - 0x6e0: 0x173, 0x6e1: 0x9d, 0x6e2: 0x9d, 0x6e3: 0x9d, 0x6e4: 0x9d, 0x6e5: 0x9d, 0x6e6: 0x9d, 0x6e7: 0x9d, - 0x6e8: 0x9d, 0x6e9: 0x9d, 0x6ea: 0x9d, 0x6eb: 0x9d, 0x6ec: 0x9d, 0x6ed: 0x9d, 0x6ee: 0x9d, 0x6ef: 0x9d, - 0x6f0: 0x9d, 0x6f1: 0x9d, 0x6f2: 0x9d, 0x6f3: 0x9d, 0x6f4: 0x9d, 0x6f5: 0x9d, 0x6f6: 0x9d, 0x6f7: 0x9d, - 0x6f8: 0x9d, 0x6f9: 0x9d, 0x6fa: 0x9d, 0x6fb: 0x9d, 0x6fc: 0x9d, 0x6fd: 0x9d, 0x6fe: 0x9d, 0x6ff: 0x9d, + 0x6c0: 0x9f, 0x6c1: 0x9f, 0x6c2: 0x9f, 0x6c3: 0x9f, 0x6c4: 0x9f, 0x6c5: 0x9f, 0x6c6: 0x9f, 0x6c7: 0x9f, + 0x6c8: 0x9f, 0x6c9: 0x9f, 0x6ca: 0x9f, 0x6cb: 0x9f, 0x6cc: 0x9f, 0x6cd: 0x9f, 0x6ce: 0x9f, 0x6cf: 0x9f, + 0x6d0: 0x9f, 0x6d1: 0x9f, 0x6d2: 0x9f, 0x6d3: 0x9f, 0x6d4: 0x9f, 0x6d5: 0x9f, 0x6d6: 0x9f, 0x6d7: 0x9f, + 0x6d8: 0x9f, 0x6d9: 0x9f, 0x6da: 0x9f, 0x6db: 0x9f, 0x6dc: 0x17b, 0x6dd: 0x9f, 0x6de: 0x9f, 0x6df: 0x9f, + 0x6e0: 0x17c, 0x6e1: 0x9f, 0x6e2: 0x9f, 0x6e3: 0x9f, 0x6e4: 0x9f, 0x6e5: 0x9f, 0x6e6: 0x9f, 0x6e7: 0x9f, + 0x6e8: 0x9f, 0x6e9: 0x9f, 0x6ea: 0x9f, 0x6eb: 0x9f, 0x6ec: 0x9f, 0x6ed: 0x9f, 0x6ee: 0x9f, 0x6ef: 0x9f, + 0x6f0: 0x9f, 0x6f1: 0x9f, 0x6f2: 0x9f, 0x6f3: 0x9f, 0x6f4: 0x9f, 0x6f5: 0x9f, 0x6f6: 0x9f, 0x6f7: 0x9f, + 0x6f8: 0x9f, 0x6f9: 0x9f, 0x6fa: 0x9f, 0x6fb: 0x9f, 0x6fc: 0x9f, 0x6fd: 0x9f, 0x6fe: 0x9f, 0x6ff: 0x9f, // Block 0x1c, offset 0x700 - 0x700: 0x9d, 0x701: 0x9d, 0x702: 0x9d, 0x703: 0x9d, 0x704: 0x9d, 0x705: 0x9d, 0x706: 0x9d, 0x707: 0x9d, - 0x708: 0x9d, 0x709: 0x9d, 0x70a: 0x9d, 0x70b: 0x9d, 0x70c: 0x9d, 0x70d: 0x9d, 0x70e: 0x9d, 0x70f: 0x9d, - 0x710: 0x9d, 0x711: 0x9d, 0x712: 0x9d, 0x713: 0x9d, 0x714: 0x9d, 0x715: 0x9d, 0x716: 0x9d, 0x717: 0x9d, - 0x718: 0x9d, 0x719: 0x9d, 0x71a: 0x9d, 0x71b: 0x9d, 0x71c: 0x9d, 0x71d: 0x9d, 0x71e: 0x9d, 0x71f: 0x9d, - 0x720: 0x9d, 0x721: 0x9d, 0x722: 0x9d, 0x723: 0x9d, 0x724: 0x9d, 0x725: 0x9d, 0x726: 0x9d, 0x727: 0x9d, - 0x728: 0x9d, 0x729: 0x9d, 0x72a: 0x9d, 0x72b: 0x9d, 0x72c: 0x9d, 0x72d: 0x9d, 0x72e: 0x9d, 0x72f: 0x9d, - 0x730: 0x9d, 0x731: 0x9d, 0x732: 0x9d, 0x733: 0x9d, 0x734: 0x9d, 0x735: 0x9d, 0x736: 0x9d, 0x737: 0x9d, - 0x738: 0x9d, 0x739: 0x9d, 0x73a: 0x174, 0x73b: 0xb8, 0x73c: 0xb8, 0x73d: 0xb8, 0x73e: 0xb8, 0x73f: 0xb8, + 0x700: 0x9f, 0x701: 0x9f, 0x702: 0x9f, 0x703: 0x9f, 0x704: 0x9f, 0x705: 0x9f, 0x706: 0x9f, 0x707: 0x9f, + 0x708: 0x9f, 0x709: 0x9f, 0x70a: 0x9f, 0x70b: 0x9f, 0x70c: 0x9f, 0x70d: 0x9f, 0x70e: 0x9f, 0x70f: 0x9f, + 0x710: 0x9f, 0x711: 0x9f, 0x712: 0x9f, 0x713: 0x9f, 0x714: 0x9f, 0x715: 0x9f, 0x716: 0x9f, 0x717: 0x9f, + 0x718: 0x9f, 0x719: 0x9f, 0x71a: 0x9f, 0x71b: 0x9f, 0x71c: 0x9f, 0x71d: 0x9f, 0x71e: 0x9f, 0x71f: 0x9f, + 0x720: 0x9f, 0x721: 0x9f, 0x722: 0x9f, 0x723: 0x9f, 0x724: 0x9f, 0x725: 0x9f, 0x726: 0x9f, 0x727: 0x9f, + 0x728: 0x9f, 0x729: 0x9f, 0x72a: 0x9f, 0x72b: 0x9f, 0x72c: 0x9f, 0x72d: 0x9f, 0x72e: 0x9f, 0x72f: 0x9f, + 0x730: 0x9f, 0x731: 0x9f, 0x732: 0x9f, 0x733: 0x9f, 0x734: 0x9f, 0x735: 0x9f, 0x736: 0x9f, 0x737: 0x9f, + 0x738: 0x9f, 0x739: 0x9f, 0x73a: 0x17d, 0x73b: 0x9f, 0x73c: 0x9f, 0x73d: 0x9f, 0x73e: 0x9f, 0x73f: 0x9f, // Block 0x1d, offset 0x740 - 0x740: 0xb8, 0x741: 0xb8, 0x742: 0xb8, 0x743: 0xb8, 0x744: 0xb8, 0x745: 0xb8, 0x746: 0xb8, 0x747: 0xb8, - 0x748: 0xb8, 0x749: 0xb8, 0x74a: 0xb8, 0x74b: 0xb8, 0x74c: 0xb8, 0x74d: 0xb8, 0x74e: 0xb8, 0x74f: 0xb8, - 0x750: 0xb8, 0x751: 0xb8, 0x752: 0xb8, 0x753: 0xb8, 0x754: 0xb8, 0x755: 0xb8, 0x756: 0xb8, 0x757: 0xb8, - 0x758: 0xb8, 0x759: 0xb8, 0x75a: 0xb8, 0x75b: 0xb8, 0x75c: 0xb8, 0x75d: 0xb8, 0x75e: 0xb8, 0x75f: 0xb8, - 0x760: 0x74, 0x761: 0x75, 0x762: 0x76, 0x763: 0x175, 0x764: 0x77, 0x765: 0x78, 0x766: 0x176, 0x767: 0x79, - 0x768: 0x7a, 0x769: 0xb8, 0x76a: 0xb8, 0x76b: 0xb8, 0x76c: 0xb8, 0x76d: 0xb8, 0x76e: 0xb8, 0x76f: 0xb8, - 0x770: 0xb8, 0x771: 0xb8, 0x772: 0xb8, 0x773: 0xb8, 0x774: 0xb8, 0x775: 0xb8, 0x776: 0xb8, 0x777: 0xb8, - 0x778: 0xb8, 0x779: 0xb8, 0x77a: 0xb8, 0x77b: 0xb8, 0x77c: 0xb8, 0x77d: 0xb8, 0x77e: 0xb8, 0x77f: 0xb8, + 0x740: 0x9f, 0x741: 0x9f, 0x742: 0x9f, 0x743: 0x9f, 0x744: 0x9f, 0x745: 0x9f, 0x746: 0x9f, 0x747: 0x9f, + 0x748: 0x9f, 0x749: 0x9f, 0x74a: 0x9f, 0x74b: 0x9f, 0x74c: 0x9f, 0x74d: 0x9f, 0x74e: 0x9f, 0x74f: 0x9f, + 0x750: 0x9f, 0x751: 0x9f, 0x752: 0x9f, 0x753: 0x9f, 0x754: 0x9f, 0x755: 0x9f, 0x756: 0x9f, 0x757: 0x9f, + 0x758: 0x9f, 0x759: 0x9f, 0x75a: 0x9f, 0x75b: 0x9f, 0x75c: 0x9f, 0x75d: 0x9f, 0x75e: 0x9f, 0x75f: 0x9f, + 0x760: 0x9f, 0x761: 0x9f, 0x762: 0x9f, 0x763: 0x9f, 0x764: 0x9f, 0x765: 0x9f, 0x766: 0x9f, 0x767: 0x9f, + 0x768: 0x9f, 0x769: 0x9f, 0x76a: 0x9f, 0x76b: 0x9f, 0x76c: 0x9f, 0x76d: 0x9f, 0x76e: 0x9f, 0x76f: 0x17e, + 0x770: 0xba, 0x771: 0xba, 0x772: 0xba, 0x773: 0xba, 0x774: 0xba, 0x775: 0xba, 0x776: 0xba, 0x777: 0xba, + 0x778: 0xba, 0x779: 0xba, 0x77a: 0xba, 0x77b: 0xba, 0x77c: 0xba, 0x77d: 0xba, 0x77e: 0xba, 0x77f: 0xba, // Block 0x1e, offset 0x780 - 0x790: 0x0d, 0x791: 0x0e, 0x792: 0x0f, 0x793: 0x10, 0x794: 0x11, 0x795: 0x0b, 0x796: 0x12, 0x797: 0x07, - 0x798: 0x13, 0x799: 0x0b, 0x79a: 0x0b, 0x79b: 0x14, 0x79c: 0x0b, 0x79d: 0x15, 0x79e: 0x16, 0x79f: 0x17, - 0x7a0: 0x07, 0x7a1: 0x07, 0x7a2: 0x07, 0x7a3: 0x07, 0x7a4: 0x07, 0x7a5: 0x07, 0x7a6: 0x07, 0x7a7: 0x07, - 0x7a8: 0x07, 0x7a9: 0x07, 0x7aa: 0x18, 0x7ab: 0x19, 0x7ac: 0x1a, 0x7ad: 0x0b, 0x7ae: 0x0b, 0x7af: 0x1b, - 0x7b0: 0x0b, 0x7b1: 0x0b, 0x7b2: 0x0b, 0x7b3: 0x0b, 0x7b4: 0x0b, 0x7b5: 0x0b, 0x7b6: 0x0b, 0x7b7: 0x0b, - 0x7b8: 0x0b, 0x7b9: 0x0b, 0x7ba: 0x0b, 0x7bb: 0x0b, 0x7bc: 0x0b, 0x7bd: 0x0b, 0x7be: 0x0b, 0x7bf: 0x0b, + 0x780: 0xba, 0x781: 0xba, 0x782: 0xba, 0x783: 0xba, 0x784: 0xba, 0x785: 0xba, 0x786: 0xba, 0x787: 0xba, + 0x788: 0xba, 0x789: 0xba, 0x78a: 0xba, 0x78b: 0xba, 0x78c: 0xba, 0x78d: 0xba, 0x78e: 0xba, 0x78f: 0xba, + 0x790: 0xba, 0x791: 0xba, 0x792: 0xba, 0x793: 0xba, 0x794: 0xba, 0x795: 0xba, 0x796: 0xba, 0x797: 0xba, + 0x798: 0xba, 0x799: 0xba, 0x79a: 0xba, 0x79b: 0xba, 0x79c: 0xba, 0x79d: 0xba, 0x79e: 0xba, 0x79f: 0xba, + 0x7a0: 0x76, 0x7a1: 0x77, 0x7a2: 0x78, 0x7a3: 0x17f, 0x7a4: 0x79, 0x7a5: 0x7a, 0x7a6: 0x180, 0x7a7: 0x7b, + 0x7a8: 0x7c, 0x7a9: 0xba, 0x7aa: 0xba, 0x7ab: 0xba, 0x7ac: 0xba, 0x7ad: 0xba, 0x7ae: 0xba, 0x7af: 0xba, + 0x7b0: 0xba, 0x7b1: 0xba, 0x7b2: 0xba, 0x7b3: 0xba, 0x7b4: 0xba, 0x7b5: 0xba, 0x7b6: 0xba, 0x7b7: 0xba, + 0x7b8: 0xba, 0x7b9: 0xba, 0x7ba: 0xba, 0x7bb: 0xba, 0x7bc: 0xba, 0x7bd: 0xba, 0x7be: 0xba, 0x7bf: 0xba, // Block 0x1f, offset 0x7c0 - 0x7c0: 0x0b, 0x7c1: 0x0b, 0x7c2: 0x0b, 0x7c3: 0x0b, 0x7c4: 0x0b, 0x7c5: 0x0b, 0x7c6: 0x0b, 0x7c7: 0x0b, - 0x7c8: 0x0b, 0x7c9: 0x0b, 0x7ca: 0x0b, 0x7cb: 0x0b, 0x7cc: 0x0b, 0x7cd: 0x0b, 0x7ce: 0x0b, 0x7cf: 0x0b, - 0x7d0: 0x0b, 0x7d1: 0x0b, 0x7d2: 0x0b, 0x7d3: 0x0b, 0x7d4: 0x0b, 0x7d5: 0x0b, 0x7d6: 0x0b, 0x7d7: 0x0b, - 0x7d8: 0x0b, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x0b, 0x7dc: 0x0b, 0x7dd: 0x0b, 0x7de: 0x0b, 0x7df: 0x0b, - 0x7e0: 0x0b, 0x7e1: 0x0b, 0x7e2: 0x0b, 0x7e3: 0x0b, 0x7e4: 0x0b, 0x7e5: 0x0b, 0x7e6: 0x0b, 0x7e7: 0x0b, - 0x7e8: 0x0b, 0x7e9: 0x0b, 0x7ea: 0x0b, 0x7eb: 0x0b, 0x7ec: 0x0b, 0x7ed: 0x0b, 0x7ee: 0x0b, 0x7ef: 0x0b, + 0x7d0: 0x0d, 0x7d1: 0x0e, 0x7d2: 0x0f, 0x7d3: 0x10, 0x7d4: 0x11, 0x7d5: 0x0b, 0x7d6: 0x12, 0x7d7: 0x07, + 0x7d8: 0x13, 0x7d9: 0x0b, 0x7da: 0x0b, 0x7db: 0x14, 0x7dc: 0x0b, 0x7dd: 0x15, 0x7de: 0x16, 0x7df: 0x17, + 0x7e0: 0x07, 0x7e1: 0x07, 0x7e2: 0x07, 0x7e3: 0x07, 0x7e4: 0x07, 0x7e5: 0x07, 0x7e6: 0x07, 0x7e7: 0x07, + 0x7e8: 0x07, 0x7e9: 0x07, 0x7ea: 0x18, 0x7eb: 0x19, 0x7ec: 0x1a, 0x7ed: 0x07, 0x7ee: 0x1b, 0x7ef: 0x1c, 0x7f0: 0x0b, 0x7f1: 0x0b, 0x7f2: 0x0b, 0x7f3: 0x0b, 0x7f4: 0x0b, 0x7f5: 0x0b, 0x7f6: 0x0b, 0x7f7: 0x0b, 0x7f8: 0x0b, 0x7f9: 0x0b, 0x7fa: 0x0b, 0x7fb: 0x0b, 0x7fc: 0x0b, 0x7fd: 0x0b, 0x7fe: 0x0b, 0x7ff: 0x0b, // Block 0x20, offset 0x800 - 0x800: 0x177, 0x801: 0x178, 0x802: 0xb8, 0x803: 0xb8, 0x804: 0x179, 0x805: 0x179, 0x806: 0x179, 0x807: 0x17a, - 0x808: 0xb8, 0x809: 0xb8, 0x80a: 0xb8, 0x80b: 0xb8, 0x80c: 0xb8, 0x80d: 0xb8, 0x80e: 0xb8, 0x80f: 0xb8, - 0x810: 0xb8, 0x811: 0xb8, 0x812: 0xb8, 0x813: 0xb8, 0x814: 0xb8, 0x815: 0xb8, 0x816: 0xb8, 0x817: 0xb8, - 0x818: 0xb8, 0x819: 0xb8, 0x81a: 0xb8, 0x81b: 0xb8, 0x81c: 0xb8, 0x81d: 0xb8, 0x81e: 0xb8, 0x81f: 0xb8, - 0x820: 0xb8, 0x821: 0xb8, 0x822: 0xb8, 0x823: 0xb8, 0x824: 0xb8, 0x825: 0xb8, 0x826: 0xb8, 0x827: 0xb8, - 0x828: 0xb8, 0x829: 0xb8, 0x82a: 0xb8, 0x82b: 0xb8, 0x82c: 0xb8, 0x82d: 0xb8, 0x82e: 0xb8, 0x82f: 0xb8, - 0x830: 0xb8, 0x831: 0xb8, 0x832: 0xb8, 0x833: 0xb8, 0x834: 0xb8, 0x835: 0xb8, 0x836: 0xb8, 0x837: 0xb8, - 0x838: 0xb8, 0x839: 0xb8, 0x83a: 0xb8, 0x83b: 0xb8, 0x83c: 0xb8, 0x83d: 0xb8, 0x83e: 0xb8, 0x83f: 0xb8, + 0x800: 0x0b, 0x801: 0x0b, 0x802: 0x0b, 0x803: 0x0b, 0x804: 0x0b, 0x805: 0x0b, 0x806: 0x0b, 0x807: 0x0b, + 0x808: 0x0b, 0x809: 0x0b, 0x80a: 0x0b, 0x80b: 0x0b, 0x80c: 0x0b, 0x80d: 0x0b, 0x80e: 0x0b, 0x80f: 0x0b, + 0x810: 0x0b, 0x811: 0x0b, 0x812: 0x0b, 0x813: 0x0b, 0x814: 0x0b, 0x815: 0x0b, 0x816: 0x0b, 0x817: 0x0b, + 0x818: 0x0b, 0x819: 0x0b, 0x81a: 0x0b, 0x81b: 0x0b, 0x81c: 0x0b, 0x81d: 0x0b, 0x81e: 0x0b, 0x81f: 0x0b, + 0x820: 0x0b, 0x821: 0x0b, 0x822: 0x0b, 0x823: 0x0b, 0x824: 0x0b, 0x825: 0x0b, 0x826: 0x0b, 0x827: 0x0b, + 0x828: 0x0b, 0x829: 0x0b, 0x82a: 0x0b, 0x82b: 0x0b, 0x82c: 0x0b, 0x82d: 0x0b, 0x82e: 0x0b, 0x82f: 0x0b, + 0x830: 0x0b, 0x831: 0x0b, 0x832: 0x0b, 0x833: 0x0b, 0x834: 0x0b, 0x835: 0x0b, 0x836: 0x0b, 0x837: 0x0b, + 0x838: 0x0b, 0x839: 0x0b, 0x83a: 0x0b, 0x83b: 0x0b, 0x83c: 0x0b, 0x83d: 0x0b, 0x83e: 0x0b, 0x83f: 0x0b, // Block 0x21, offset 0x840 - 0x840: 0x0b, 0x841: 0x0b, 0x842: 0x0b, 0x843: 0x0b, 0x844: 0x0b, 0x845: 0x0b, 0x846: 0x0b, 0x847: 0x0b, - 0x848: 0x0b, 0x849: 0x0b, 0x84a: 0x0b, 0x84b: 0x0b, 0x84c: 0x0b, 0x84d: 0x0b, 0x84e: 0x0b, 0x84f: 0x0b, - 0x850: 0x0b, 0x851: 0x0b, 0x852: 0x0b, 0x853: 0x0b, 0x854: 0x0b, 0x855: 0x0b, 0x856: 0x0b, 0x857: 0x0b, - 0x858: 0x0b, 0x859: 0x0b, 0x85a: 0x0b, 0x85b: 0x0b, 0x85c: 0x0b, 0x85d: 0x0b, 0x85e: 0x0b, 0x85f: 0x0b, - 0x860: 0x1e, 0x861: 0x0b, 0x862: 0x0b, 0x863: 0x0b, 0x864: 0x0b, 0x865: 0x0b, 0x866: 0x0b, 0x867: 0x0b, - 0x868: 0x0b, 0x869: 0x0b, 0x86a: 0x0b, 0x86b: 0x0b, 0x86c: 0x0b, 0x86d: 0x0b, 0x86e: 0x0b, 0x86f: 0x0b, - 0x870: 0x0b, 0x871: 0x0b, 0x872: 0x0b, 0x873: 0x0b, 0x874: 0x0b, 0x875: 0x0b, 0x876: 0x0b, 0x877: 0x0b, - 0x878: 0x0b, 0x879: 0x0b, 0x87a: 0x0b, 0x87b: 0x0b, 0x87c: 0x0b, 0x87d: 0x0b, 0x87e: 0x0b, 0x87f: 0x0b, + 0x840: 0x181, 0x841: 0x182, 0x842: 0xba, 0x843: 0xba, 0x844: 0x183, 0x845: 0x183, 0x846: 0x183, 0x847: 0x184, + 0x848: 0xba, 0x849: 0xba, 0x84a: 0xba, 0x84b: 0xba, 0x84c: 0xba, 0x84d: 0xba, 0x84e: 0xba, 0x84f: 0xba, + 0x850: 0xba, 0x851: 0xba, 0x852: 0xba, 0x853: 0xba, 0x854: 0xba, 0x855: 0xba, 0x856: 0xba, 0x857: 0xba, + 0x858: 0xba, 0x859: 0xba, 0x85a: 0xba, 0x85b: 0xba, 0x85c: 0xba, 0x85d: 0xba, 0x85e: 0xba, 0x85f: 0xba, + 0x860: 0xba, 0x861: 0xba, 0x862: 0xba, 0x863: 0xba, 0x864: 0xba, 0x865: 0xba, 0x866: 0xba, 0x867: 0xba, + 0x868: 0xba, 0x869: 0xba, 0x86a: 0xba, 0x86b: 0xba, 0x86c: 0xba, 0x86d: 0xba, 0x86e: 0xba, 0x86f: 0xba, + 0x870: 0xba, 0x871: 0xba, 0x872: 0xba, 0x873: 0xba, 0x874: 0xba, 0x875: 0xba, 0x876: 0xba, 0x877: 0xba, + 0x878: 0xba, 0x879: 0xba, 0x87a: 0xba, 0x87b: 0xba, 0x87c: 0xba, 0x87d: 0xba, 0x87e: 0xba, 0x87f: 0xba, // Block 0x22, offset 0x880 0x880: 0x0b, 0x881: 0x0b, 0x882: 0x0b, 0x883: 0x0b, 0x884: 0x0b, 0x885: 0x0b, 0x886: 0x0b, 0x887: 0x0b, 0x888: 0x0b, 0x889: 0x0b, 0x88a: 0x0b, 0x88b: 0x0b, 0x88c: 0x0b, 0x88d: 0x0b, 0x88e: 0x0b, 0x88f: 0x0b, + 0x890: 0x0b, 0x891: 0x0b, 0x892: 0x0b, 0x893: 0x0b, 0x894: 0x0b, 0x895: 0x0b, 0x896: 0x0b, 0x897: 0x0b, + 0x898: 0x0b, 0x899: 0x0b, 0x89a: 0x0b, 0x89b: 0x0b, 0x89c: 0x0b, 0x89d: 0x0b, 0x89e: 0x0b, 0x89f: 0x0b, + 0x8a0: 0x1f, 0x8a1: 0x0b, 0x8a2: 0x0b, 0x8a3: 0x0b, 0x8a4: 0x0b, 0x8a5: 0x0b, 0x8a6: 0x0b, 0x8a7: 0x0b, + 0x8a8: 0x0b, 0x8a9: 0x0b, 0x8aa: 0x0b, 0x8ab: 0x0b, 0x8ac: 0x0b, 0x8ad: 0x0b, 0x8ae: 0x0b, 0x8af: 0x0b, + 0x8b0: 0x0b, 0x8b1: 0x0b, 0x8b2: 0x0b, 0x8b3: 0x0b, 0x8b4: 0x0b, 0x8b5: 0x0b, 0x8b6: 0x0b, 0x8b7: 0x0b, + 0x8b8: 0x0b, 0x8b9: 0x0b, 0x8ba: 0x0b, 0x8bb: 0x0b, 0x8bc: 0x0b, 0x8bd: 0x0b, 0x8be: 0x0b, 0x8bf: 0x0b, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0b, 0x8c1: 0x0b, 0x8c2: 0x0b, 0x8c3: 0x0b, 0x8c4: 0x0b, 0x8c5: 0x0b, 0x8c6: 0x0b, 0x8c7: 0x0b, + 0x8c8: 0x0b, 0x8c9: 0x0b, 0x8ca: 0x0b, 0x8cb: 0x0b, 0x8cc: 0x0b, 0x8cd: 0x0b, 0x8ce: 0x0b, 0x8cf: 0x0b, } -// idnaSparseOffset: 256 entries, 512 bytes -var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x5c, 0x60, 0x6f, 0x74, 0x7b, 0x87, 0x95, 0xa3, 0xa8, 0xb1, 0xc1, 0xcf, 0xdc, 0xe8, 0xf9, 0x103, 0x10a, 0x117, 0x128, 0x12f, 0x13a, 0x149, 0x157, 0x161, 0x163, 0x167, 0x169, 0x175, 0x180, 0x188, 0x18e, 0x194, 0x199, 0x19e, 0x1a1, 0x1a5, 0x1ab, 0x1b0, 0x1bc, 0x1c6, 0x1cc, 0x1dd, 0x1e7, 0x1ea, 0x1f2, 0x1f5, 0x202, 0x20a, 0x20e, 0x215, 0x21d, 0x22d, 0x239, 0x23b, 0x245, 0x251, 0x25d, 0x269, 0x271, 0x276, 0x280, 0x291, 0x295, 0x2a0, 0x2a4, 0x2ad, 0x2b5, 0x2bb, 0x2c0, 0x2c3, 0x2c6, 0x2ca, 0x2d0, 0x2d4, 0x2d8, 0x2de, 0x2e5, 0x2eb, 0x2f3, 0x2fa, 0x305, 0x30f, 0x313, 0x316, 0x31c, 0x320, 0x322, 0x325, 0x327, 0x32a, 0x334, 0x337, 0x346, 0x34a, 0x34f, 0x352, 0x356, 0x35b, 0x360, 0x366, 0x36c, 0x37b, 0x381, 0x385, 0x394, 0x399, 0x3a1, 0x3ab, 0x3b6, 0x3be, 0x3cf, 0x3d8, 0x3e8, 0x3f5, 0x3ff, 0x404, 0x411, 0x415, 0x41a, 0x41c, 0x420, 0x422, 0x426, 0x42f, 0x435, 0x439, 0x449, 0x453, 0x458, 0x45b, 0x461, 0x468, 0x46d, 0x471, 0x477, 0x47c, 0x485, 0x48a, 0x490, 0x497, 0x49e, 0x4a5, 0x4a9, 0x4ae, 0x4b1, 0x4b6, 0x4c2, 0x4c8, 0x4cd, 0x4d4, 0x4dc, 0x4e1, 0x4e5, 0x4f5, 0x4fc, 0x500, 0x504, 0x50b, 0x50e, 0x511, 0x515, 0x519, 0x51f, 0x528, 0x534, 0x53b, 0x544, 0x54c, 0x553, 0x561, 0x56e, 0x57b, 0x584, 0x588, 0x596, 0x59e, 0x5a9, 0x5b2, 0x5b8, 0x5c0, 0x5c9, 0x5d3, 0x5d6, 0x5e2, 0x5e5, 0x5ea, 0x5ed, 0x5f7, 0x600, 0x60c, 0x60f, 0x614, 0x617, 0x61a, 0x61d, 0x624, 0x62b, 0x62f, 0x63a, 0x63d, 0x643, 0x648, 0x64c, 0x64f, 0x652, 0x655, 0x65a, 0x664, 0x667, 0x66b, 0x67a, 0x686, 0x68a, 0x68f, 0x694, 0x698, 0x69d, 0x6a6, 0x6b1, 0x6b7, 0x6bf, 0x6c3, 0x6c7, 0x6cd, 0x6d3, 0x6d8, 0x6db, 0x6e9, 0x6f0, 0x6f3, 0x6f6, 0x6fa, 0x700, 0x705, 0x70f, 0x714, 0x717, 0x71a, 0x71d, 0x720, 0x724, 0x727, 0x737, 0x748, 0x74d, 0x74f, 0x751} +// idnaSparseOffset: 264 entries, 528 bytes +var idnaSparseOffset = []uint16{0x0, 0x8, 0x19, 0x25, 0x27, 0x2c, 0x34, 0x3f, 0x4b, 0x4f, 0x5e, 0x63, 0x6b, 0x77, 0x85, 0x8a, 0x93, 0xa3, 0xb1, 0xbd, 0xc9, 0xda, 0xe4, 0xeb, 0xf8, 0x109, 0x110, 0x11b, 0x12a, 0x138, 0x142, 0x144, 0x149, 0x14c, 0x14f, 0x151, 0x15d, 0x168, 0x170, 0x176, 0x17c, 0x181, 0x186, 0x189, 0x18d, 0x193, 0x198, 0x1a4, 0x1ae, 0x1b4, 0x1c5, 0x1cf, 0x1d2, 0x1da, 0x1dd, 0x1ea, 0x1f2, 0x1f6, 0x1fd, 0x205, 0x215, 0x221, 0x223, 0x22d, 0x239, 0x245, 0x251, 0x259, 0x25e, 0x268, 0x279, 0x27d, 0x288, 0x28c, 0x295, 0x29d, 0x2a3, 0x2a8, 0x2ab, 0x2af, 0x2b5, 0x2b9, 0x2bd, 0x2c3, 0x2ca, 0x2d0, 0x2d8, 0x2df, 0x2ea, 0x2f4, 0x2f8, 0x2fb, 0x301, 0x305, 0x307, 0x30a, 0x30c, 0x30f, 0x319, 0x31c, 0x32b, 0x32f, 0x334, 0x337, 0x33b, 0x340, 0x345, 0x34b, 0x351, 0x360, 0x366, 0x36a, 0x379, 0x37e, 0x386, 0x390, 0x39b, 0x3a3, 0x3b4, 0x3bd, 0x3cd, 0x3da, 0x3e4, 0x3e9, 0x3f6, 0x3fa, 0x3ff, 0x401, 0x405, 0x407, 0x40b, 0x414, 0x41a, 0x41e, 0x42e, 0x438, 0x43d, 0x440, 0x446, 0x44d, 0x452, 0x456, 0x45c, 0x461, 0x46a, 0x46f, 0x475, 0x47c, 0x483, 0x48a, 0x48e, 0x493, 0x496, 0x49b, 0x4a7, 0x4ad, 0x4b2, 0x4b9, 0x4c1, 0x4c6, 0x4ca, 0x4da, 0x4e1, 0x4e5, 0x4e9, 0x4f0, 0x4f2, 0x4f5, 0x4f8, 0x4fc, 0x500, 0x506, 0x50f, 0x51b, 0x522, 0x52b, 0x533, 0x53a, 0x548, 0x555, 0x562, 0x56b, 0x56f, 0x57d, 0x585, 0x590, 0x599, 0x59f, 0x5a7, 0x5b0, 0x5ba, 0x5bd, 0x5c9, 0x5cc, 0x5d1, 0x5de, 0x5e7, 0x5f3, 0x5f6, 0x600, 0x609, 0x615, 0x622, 0x62a, 0x62d, 0x632, 0x635, 0x638, 0x63b, 0x642, 0x649, 0x64d, 0x658, 0x65b, 0x661, 0x666, 0x66a, 0x66d, 0x670, 0x673, 0x676, 0x679, 0x67e, 0x688, 0x68b, 0x68f, 0x69e, 0x6aa, 0x6ae, 0x6b3, 0x6b8, 0x6bc, 0x6c1, 0x6ca, 0x6d5, 0x6db, 0x6e3, 0x6e7, 0x6eb, 0x6f1, 0x6f7, 0x6fc, 0x6ff, 0x70f, 0x716, 0x719, 0x71c, 0x720, 0x726, 0x72b, 0x730, 0x735, 0x738, 0x73d, 0x740, 0x743, 0x747, 0x74b, 0x74e, 0x75e, 0x76f, 0x774, 0x776, 0x778} -// idnaSparseValues: 1876 entries, 7504 bytes -var idnaSparseValues = [1876]valueRange{ +// idnaSparseValues: 1915 entries, 7660 bytes +var idnaSparseValues = [1915]valueRange{ // Block 0x0, offset 0x0 {value: 0x0000, lo: 0x07}, {value: 0xe105, lo: 0x80, hi: 0x96}, @@ -2384,7 +2417,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xb9, hi: 0xbf}, // Block 0x3, offset 0x25 {value: 0x0000, lo: 0x01}, - {value: 0x1308, lo: 0x80, hi: 0xbf}, + {value: 0x3308, lo: 0x80, hi: 0xbf}, // Block 0x4, offset 0x27 {value: 0x0000, lo: 0x04}, {value: 0x03f5, lo: 0x80, hi: 0x8f}, @@ -2409,155 +2442,123 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x8b, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, - {value: 0x1308, lo: 0x91, hi: 0xbd}, - {value: 0x0018, lo: 0xbe, hi: 0xbe}, - {value: 0x1308, lo: 0xbf, hi: 0xbf}, + {value: 0x3308, lo: 0x91, hi: 0xbd}, + {value: 0x0818, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, // Block 0x7, offset 0x3f {value: 0x0000, lo: 0x0b}, - {value: 0x0018, lo: 0x80, hi: 0x80}, - {value: 0x1308, lo: 0x81, hi: 0x82}, - {value: 0x0018, lo: 0x83, hi: 0x83}, - {value: 0x1308, lo: 0x84, hi: 0x85}, - {value: 0x0018, lo: 0x86, hi: 0x86}, - {value: 0x1308, lo: 0x87, hi: 0x87}, + {value: 0x0818, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x82}, + {value: 0x0818, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x84, hi: 0x85}, + {value: 0x0818, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, - {value: 0x0008, lo: 0x90, hi: 0xaa}, + {value: 0x0808, lo: 0x90, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, - {value: 0x0008, lo: 0xb0, hi: 0xb4}, + {value: 0x0808, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, // Block 0x8, offset 0x4b - {value: 0x0000, lo: 0x10}, - {value: 0x0018, lo: 0x80, hi: 0x80}, - {value: 0x0208, lo: 0x81, hi: 0x87}, - {value: 0x0408, lo: 0x88, hi: 0x88}, - {value: 0x0208, lo: 0x89, hi: 0x8a}, - {value: 0x1308, lo: 0x8b, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xa9}, - {value: 0x0018, lo: 0xaa, hi: 0xad}, - {value: 0x0208, lo: 0xae, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb0}, - {value: 0x0408, lo: 0xb1, hi: 0xb3}, - {value: 0x0008, lo: 0xb4, hi: 0xb4}, - {value: 0x0429, lo: 0xb5, hi: 0xb5}, - {value: 0x0451, lo: 0xb6, hi: 0xb6}, - {value: 0x0479, lo: 0xb7, hi: 0xb7}, - {value: 0x04a1, lo: 0xb8, hi: 0xb8}, - {value: 0x0208, lo: 0xb9, hi: 0xbf}, - // Block 0x9, offset 0x5c {value: 0x0000, lo: 0x03}, - {value: 0x0208, lo: 0x80, hi: 0x87}, - {value: 0x0408, lo: 0x88, hi: 0x99}, - {value: 0x0208, lo: 0x9a, hi: 0xbf}, - // Block 0xa, offset 0x60 + {value: 0x0a08, lo: 0x80, hi: 0x87}, + {value: 0x0c08, lo: 0x88, hi: 0x99}, + {value: 0x0a08, lo: 0x9a, hi: 0xbf}, + // Block 0x9, offset 0x4f {value: 0x0000, lo: 0x0e}, - {value: 0x1308, lo: 0x80, hi: 0x8a}, + {value: 0x3308, lo: 0x80, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8c}, - {value: 0x0408, lo: 0x8d, hi: 0x8d}, - {value: 0x0208, lo: 0x8e, hi: 0x98}, - {value: 0x0408, lo: 0x99, hi: 0x9b}, - {value: 0x0208, lo: 0x9c, hi: 0xaa}, - {value: 0x0408, lo: 0xab, hi: 0xac}, - {value: 0x0208, lo: 0xad, hi: 0xb0}, - {value: 0x0408, lo: 0xb1, hi: 0xb1}, - {value: 0x0208, lo: 0xb2, hi: 0xb2}, - {value: 0x0408, lo: 0xb3, hi: 0xb4}, - {value: 0x0208, lo: 0xb5, hi: 0xb7}, - {value: 0x0408, lo: 0xb8, hi: 0xb9}, - {value: 0x0208, lo: 0xba, hi: 0xbf}, - // Block 0xb, offset 0x6f + {value: 0x0c08, lo: 0x8d, hi: 0x8d}, + {value: 0x0a08, lo: 0x8e, hi: 0x98}, + {value: 0x0c08, lo: 0x99, hi: 0x9b}, + {value: 0x0a08, lo: 0x9c, hi: 0xaa}, + {value: 0x0c08, lo: 0xab, hi: 0xac}, + {value: 0x0a08, lo: 0xad, hi: 0xb0}, + {value: 0x0c08, lo: 0xb1, hi: 0xb1}, + {value: 0x0a08, lo: 0xb2, hi: 0xb2}, + {value: 0x0c08, lo: 0xb3, hi: 0xb4}, + {value: 0x0a08, lo: 0xb5, hi: 0xb7}, + {value: 0x0c08, lo: 0xb8, hi: 0xb9}, + {value: 0x0a08, lo: 0xba, hi: 0xbf}, + // Block 0xa, offset 0x5e {value: 0x0000, lo: 0x04}, - {value: 0x0008, lo: 0x80, hi: 0xa5}, - {value: 0x1308, lo: 0xa6, hi: 0xb0}, - {value: 0x0008, lo: 0xb1, hi: 0xb1}, + {value: 0x0808, lo: 0x80, hi: 0xa5}, + {value: 0x3308, lo: 0xa6, hi: 0xb0}, + {value: 0x0808, lo: 0xb1, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, - // Block 0xc, offset 0x74 - {value: 0x0000, lo: 0x06}, - {value: 0x0008, lo: 0x80, hi: 0x89}, - {value: 0x0208, lo: 0x8a, hi: 0xaa}, - {value: 0x1308, lo: 0xab, hi: 0xb3}, - {value: 0x0008, lo: 0xb4, hi: 0xb5}, - {value: 0x0018, lo: 0xb6, hi: 0xba}, + // Block 0xb, offset 0x63 + {value: 0x0000, lo: 0x07}, + {value: 0x0808, lo: 0x80, hi: 0x89}, + {value: 0x0a08, lo: 0x8a, hi: 0xaa}, + {value: 0x3308, lo: 0xab, hi: 0xb3}, + {value: 0x0808, lo: 0xb4, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xb9}, + {value: 0x0818, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, - // Block 0xd, offset 0x7b + // Block 0xc, offset 0x6b {value: 0x0000, lo: 0x0b}, - {value: 0x0008, lo: 0x80, hi: 0x95}, - {value: 0x1308, lo: 0x96, hi: 0x99}, - {value: 0x0008, lo: 0x9a, hi: 0x9a}, - {value: 0x1308, lo: 0x9b, hi: 0xa3}, - {value: 0x0008, lo: 0xa4, hi: 0xa4}, - {value: 0x1308, lo: 0xa5, hi: 0xa7}, - {value: 0x0008, lo: 0xa8, hi: 0xa8}, - {value: 0x1308, lo: 0xa9, hi: 0xad}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x3308, lo: 0x96, hi: 0x99}, + {value: 0x0808, lo: 0x9a, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0xa3}, + {value: 0x0808, lo: 0xa4, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa7}, + {value: 0x0808, lo: 0xa8, hi: 0xa8}, + {value: 0x3308, lo: 0xa9, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, - {value: 0x0018, lo: 0xb0, hi: 0xbe}, + {value: 0x0818, lo: 0xb0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xe, offset 0x87 - {value: 0x0000, lo: 0x0d}, - {value: 0x0408, lo: 0x80, hi: 0x80}, - {value: 0x0208, lo: 0x81, hi: 0x85}, - {value: 0x0408, lo: 0x86, hi: 0x87}, - {value: 0x0208, lo: 0x88, hi: 0x88}, - {value: 0x0408, lo: 0x89, hi: 0x89}, - {value: 0x0208, lo: 0x8a, hi: 0x93}, - {value: 0x0408, lo: 0x94, hi: 0x94}, - {value: 0x0208, lo: 0x95, hi: 0x95}, - {value: 0x0008, lo: 0x96, hi: 0x98}, - {value: 0x1308, lo: 0x99, hi: 0x9b}, - {value: 0x0040, lo: 0x9c, hi: 0x9d}, - {value: 0x0018, lo: 0x9e, hi: 0x9e}, - {value: 0x0040, lo: 0x9f, hi: 0xbf}, - // Block 0xf, offset 0x95 + // Block 0xd, offset 0x77 {value: 0x0000, lo: 0x0d}, {value: 0x0040, lo: 0x80, hi: 0x9f}, - {value: 0x0208, lo: 0xa0, hi: 0xa9}, - {value: 0x0408, lo: 0xaa, hi: 0xac}, - {value: 0x0008, lo: 0xad, hi: 0xad}, - {value: 0x0408, lo: 0xae, hi: 0xae}, - {value: 0x0208, lo: 0xaf, hi: 0xb0}, - {value: 0x0408, lo: 0xb1, hi: 0xb2}, - {value: 0x0208, lo: 0xb3, hi: 0xb4}, + {value: 0x0a08, lo: 0xa0, hi: 0xa9}, + {value: 0x0c08, lo: 0xaa, hi: 0xac}, + {value: 0x0808, lo: 0xad, hi: 0xad}, + {value: 0x0c08, lo: 0xae, hi: 0xae}, + {value: 0x0a08, lo: 0xaf, hi: 0xb0}, + {value: 0x0c08, lo: 0xb1, hi: 0xb2}, + {value: 0x0a08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, - {value: 0x0208, lo: 0xb6, hi: 0xb8}, - {value: 0x0408, lo: 0xb9, hi: 0xb9}, - {value: 0x0208, lo: 0xba, hi: 0xbd}, + {value: 0x0a08, lo: 0xb6, hi: 0xb8}, + {value: 0x0c08, lo: 0xb9, hi: 0xb9}, + {value: 0x0a08, lo: 0xba, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, - // Block 0x10, offset 0xa3 + // Block 0xe, offset 0x85 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x93}, - {value: 0x1308, lo: 0x94, hi: 0xa1}, - {value: 0x0040, lo: 0xa2, hi: 0xa2}, - {value: 0x1308, lo: 0xa3, hi: 0xbf}, - // Block 0x11, offset 0xa8 + {value: 0x3308, lo: 0x94, hi: 0xa1}, + {value: 0x0840, lo: 0xa2, hi: 0xa2}, + {value: 0x3308, lo: 0xa3, hi: 0xbf}, + // Block 0xf, offset 0x8a {value: 0x0000, lo: 0x08}, - {value: 0x1308, lo: 0x80, hi: 0x82}, - {value: 0x1008, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x80, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb9}, - {value: 0x1308, lo: 0xba, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbb}, - {value: 0x1308, lo: 0xbc, hi: 0xbc}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbf}, - // Block 0x12, offset 0xb1 + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x10, offset 0x93 {value: 0x0000, lo: 0x0f}, - {value: 0x1308, lo: 0x80, hi: 0x80}, - {value: 0x1008, lo: 0x81, hi: 0x82}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x85}, - {value: 0x1008, lo: 0x86, hi: 0x88}, + {value: 0x3008, lo: 0x86, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, - {value: 0x1008, lo: 0x8a, hi: 0x8c}, - {value: 0x1b08, lo: 0x8d, hi: 0x8d}, + {value: 0x3008, lo: 0x8a, hi: 0x8c}, + {value: 0x3b08, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x96}, - {value: 0x1008, lo: 0x97, hi: 0x97}, + {value: 0x3008, lo: 0x97, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, - // Block 0x13, offset 0xc1 + // Block 0x11, offset 0xa3 {value: 0x0000, lo: 0x0d}, - {value: 0x1308, lo: 0x80, hi: 0x80}, - {value: 0x1008, lo: 0x81, hi: 0x83}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, @@ -2568,25 +2569,24 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xaa, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, - {value: 0x1308, lo: 0xbe, hi: 0xbf}, - // Block 0x14, offset 0xcf - {value: 0x0000, lo: 0x0c}, - {value: 0x0040, lo: 0x80, hi: 0x80}, - {value: 0x1308, lo: 0x81, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x83}, + {value: 0x3308, lo: 0xbe, hi: 0xbf}, + // Block 0x12, offset 0xb1 + {value: 0x0000, lo: 0x0b}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0xba}, - {value: 0x0040, lo: 0xbb, hi: 0xbc}, + {value: 0x3b08, lo: 0xbb, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbf}, - // Block 0x15, offset 0xdc + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x13, offset 0xbd {value: 0x0000, lo: 0x0b}, {value: 0x0040, lo: 0x80, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x83}, + {value: 0x3008, lo: 0x82, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x99}, @@ -2596,50 +2596,50 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, - // Block 0x16, offset 0xe8 + // Block 0x14, offset 0xc9 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x89}, - {value: 0x1b08, lo: 0x8a, hi: 0x8a}, + {value: 0x3b08, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8e}, - {value: 0x1008, lo: 0x8f, hi: 0x91}, - {value: 0x1308, lo: 0x92, hi: 0x94}, + {value: 0x3008, lo: 0x8f, hi: 0x91}, + {value: 0x3308, lo: 0x92, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x95}, - {value: 0x1308, lo: 0x96, hi: 0x96}, + {value: 0x3308, lo: 0x96, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, - {value: 0x1008, lo: 0x98, hi: 0x9f}, + {value: 0x3008, lo: 0x98, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xb1}, - {value: 0x1008, lo: 0xb2, hi: 0xb3}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, - // Block 0x17, offset 0xf9 + // Block 0x15, offset 0xda {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xb0}, - {value: 0x1308, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb1, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb2}, {value: 0x08f1, lo: 0xb3, hi: 0xb3}, - {value: 0x1308, lo: 0xb4, hi: 0xb9}, - {value: 0x1b08, lo: 0xba, hi: 0xba}, + {value: 0x3308, lo: 0xb4, hi: 0xb9}, + {value: 0x3b08, lo: 0xba, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, {value: 0x0018, lo: 0xbf, hi: 0xbf}, - // Block 0x18, offset 0x103 + // Block 0x16, offset 0xe4 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x86}, - {value: 0x1308, lo: 0x87, hi: 0x8e}, + {value: 0x3308, lo: 0x87, hi: 0x8e}, {value: 0x0018, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0xbf}, - // Block 0x19, offset 0x10a + // Block 0x17, offset 0xeb {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x85}, {value: 0x0008, lo: 0x86, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, - {value: 0x1308, lo: 0x88, hi: 0x8d}, + {value: 0x3308, lo: 0x88, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, @@ -2647,76 +2647,76 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0999, lo: 0x9d, hi: 0x9d}, {value: 0x0008, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, - // Block 0x1a, offset 0x117 + // Block 0x18, offset 0xf8 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8a}, {value: 0x0008, lo: 0x8b, hi: 0x8b}, {value: 0xe03d, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x97}, - {value: 0x1308, lo: 0x98, hi: 0x99}, + {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb4}, - {value: 0x1308, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xb6}, - {value: 0x1308, lo: 0xb7, hi: 0xb7}, + {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xb8}, - {value: 0x1308, lo: 0xb9, hi: 0xb9}, + {value: 0x3308, lo: 0xb9, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbf}, - // Block 0x1b, offset 0x128 + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x19, offset 0x109 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x85}, - {value: 0x1308, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0xbf}, - // Block 0x1c, offset 0x12f + // Block 0x1a, offset 0x110 {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0xaa}, - {value: 0x1008, lo: 0xab, hi: 0xac}, - {value: 0x1308, lo: 0xad, hi: 0xb0}, - {value: 0x1008, lo: 0xb1, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb7}, - {value: 0x1008, lo: 0xb8, hi: 0xb8}, - {value: 0x1b08, lo: 0xb9, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbc}, - {value: 0x1308, lo: 0xbd, hi: 0xbe}, + {value: 0x3008, lo: 0xab, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xb0}, + {value: 0x3008, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb7}, + {value: 0x3008, lo: 0xb8, hi: 0xb8}, + {value: 0x3b08, lo: 0xb9, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbc}, + {value: 0x3308, lo: 0xbd, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, - // Block 0x1d, offset 0x13a + // Block 0x1b, offset 0x11b {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0018, lo: 0x8a, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x95}, - {value: 0x1008, lo: 0x96, hi: 0x97}, - {value: 0x1308, lo: 0x98, hi: 0x99}, + {value: 0x3008, lo: 0x96, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x99}, {value: 0x0008, lo: 0x9a, hi: 0x9d}, - {value: 0x1308, lo: 0x9e, hi: 0xa0}, + {value: 0x3308, lo: 0x9e, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xa1}, - {value: 0x1008, lo: 0xa2, hi: 0xa4}, + {value: 0x3008, lo: 0xa2, hi: 0xa4}, {value: 0x0008, lo: 0xa5, hi: 0xa6}, - {value: 0x1008, lo: 0xa7, hi: 0xad}, + {value: 0x3008, lo: 0xa7, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, - {value: 0x1308, lo: 0xb1, hi: 0xb4}, + {value: 0x3308, lo: 0xb1, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xbf}, - // Block 0x1e, offset 0x149 + // Block 0x1c, offset 0x12a {value: 0x0000, lo: 0x0d}, {value: 0x0008, lo: 0x80, hi: 0x81}, - {value: 0x1308, lo: 0x82, hi: 0x82}, - {value: 0x1008, lo: 0x83, hi: 0x84}, - {value: 0x1308, lo: 0x85, hi: 0x86}, - {value: 0x1008, lo: 0x87, hi: 0x8c}, - {value: 0x1308, lo: 0x8d, hi: 0x8d}, + {value: 0x3308, lo: 0x82, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x8c}, + {value: 0x3308, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x8e}, - {value: 0x1008, lo: 0x8f, hi: 0x8f}, + {value: 0x3008, lo: 0x8f, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, - {value: 0x1008, lo: 0x9a, hi: 0x9c}, - {value: 0x1308, lo: 0x9d, hi: 0x9d}, + {value: 0x3008, lo: 0x9a, hi: 0x9c}, + {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, - // Block 0x1f, offset 0x157 + // Block 0x1d, offset 0x138 {value: 0x0000, lo: 0x09}, {value: 0x0040, lo: 0x80, hi: 0x86}, {value: 0x055d, lo: 0x87, hi: 0x87}, @@ -2727,18 +2727,27 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0018, lo: 0xbb, hi: 0xbb}, {value: 0xe105, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, - // Block 0x20, offset 0x161 + // Block 0x1e, offset 0x142 {value: 0x0000, lo: 0x01}, {value: 0x0018, lo: 0x80, hi: 0xbf}, - // Block 0x21, offset 0x163 - {value: 0x0000, lo: 0x03}, + // Block 0x1f, offset 0x144 + {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa0}, - {value: 0x0018, lo: 0xa1, hi: 0xbf}, - // Block 0x22, offset 0x167 + {value: 0x2018, lo: 0xa1, hi: 0xb5}, + {value: 0x0018, lo: 0xb6, hi: 0xbf}, + // Block 0x20, offset 0x149 + {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0xa7}, + {value: 0x2018, lo: 0xa8, hi: 0xbf}, + // Block 0x21, offset 0x14c + {value: 0x0000, lo: 0x02}, + {value: 0x2018, lo: 0x80, hi: 0x82}, + {value: 0x0018, lo: 0x83, hi: 0xbf}, + // Block 0x22, offset 0x14f {value: 0x0000, lo: 0x01}, {value: 0x0008, lo: 0x80, hi: 0xbf}, - // Block 0x23, offset 0x169 + // Block 0x23, offset 0x151 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, @@ -2751,7 +2760,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0x9a, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x24, offset 0x175 + // Block 0x24, offset 0x15d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, @@ -2763,7 +2772,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0x25, offset 0x180 + // Block 0x25, offset 0x168 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x81}, @@ -2772,146 +2781,146 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0x88, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, - // Block 0x26, offset 0x188 + // Block 0x26, offset 0x170 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x91}, {value: 0x0008, lo: 0x92, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbf}, - // Block 0x27, offset 0x18e + // Block 0x27, offset 0x176 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9c}, - {value: 0x1308, lo: 0x9d, hi: 0x9f}, + {value: 0x3308, lo: 0x9d, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, - // Block 0x28, offset 0x194 + // Block 0x28, offset 0x17c {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x29, offset 0x199 + // Block 0x29, offset 0x181 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, - // Block 0x2a, offset 0x19e + // Block 0x2a, offset 0x186 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, - // Block 0x2b, offset 0x1a1 + // Block 0x2b, offset 0x189 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xbf}, - // Block 0x2c, offset 0x1a5 + // Block 0x2c, offset 0x18d {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x2d, offset 0x1ab + // Block 0x2d, offset 0x193 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, - // Block 0x2e, offset 0x1b0 + // Block 0x2e, offset 0x198 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8d}, {value: 0x0008, lo: 0x8e, hi: 0x91}, - {value: 0x1308, lo: 0x92, hi: 0x93}, - {value: 0x1b08, lo: 0x94, hi: 0x94}, + {value: 0x3308, lo: 0x92, hi: 0x93}, + {value: 0x3b08, lo: 0x94, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb3}, - {value: 0x1b08, lo: 0xb4, hi: 0xb4}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, + {value: 0x3b08, lo: 0xb4, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0x2f, offset 0x1bc + // Block 0x2f, offset 0x1a4 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x91}, - {value: 0x1308, lo: 0x92, hi: 0x93}, + {value: 0x3308, lo: 0x92, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, - // Block 0x30, offset 0x1c6 + // Block 0x30, offset 0x1ae {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xb3}, - {value: 0x1340, lo: 0xb4, hi: 0xb5}, - {value: 0x1008, lo: 0xb6, hi: 0xb6}, - {value: 0x1308, lo: 0xb7, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbf}, - // Block 0x31, offset 0x1cc + {value: 0x3340, lo: 0xb4, hi: 0xb5}, + {value: 0x3008, lo: 0xb6, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbf}, + // Block 0x31, offset 0x1b4 {value: 0x0000, lo: 0x10}, - {value: 0x1008, lo: 0x80, hi: 0x85}, - {value: 0x1308, lo: 0x86, hi: 0x86}, - {value: 0x1008, lo: 0x87, hi: 0x88}, - {value: 0x1308, lo: 0x89, hi: 0x91}, - {value: 0x1b08, lo: 0x92, hi: 0x92}, - {value: 0x1308, lo: 0x93, hi: 0x93}, + {value: 0x3008, lo: 0x80, hi: 0x85}, + {value: 0x3308, lo: 0x86, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x88}, + {value: 0x3308, lo: 0x89, hi: 0x91}, + {value: 0x3b08, lo: 0x92, hi: 0x92}, + {value: 0x3308, lo: 0x93, hi: 0x93}, {value: 0x0018, lo: 0x94, hi: 0x96}, {value: 0x0008, lo: 0x97, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0x9b}, {value: 0x0008, lo: 0x9c, hi: 0x9c}, - {value: 0x1308, lo: 0x9d, hi: 0x9d}, + {value: 0x3308, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0x32, offset 0x1dd + // Block 0x32, offset 0x1c5 {value: 0x0000, lo: 0x09}, {value: 0x0018, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x86}, {value: 0x0218, lo: 0x87, hi: 0x87}, {value: 0x0018, lo: 0x88, hi: 0x8a}, - {value: 0x13c0, lo: 0x8b, hi: 0x8d}, + {value: 0x33c0, lo: 0x8b, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0208, lo: 0xa0, hi: 0xbf}, - // Block 0x33, offset 0x1e7 + // Block 0x33, offset 0x1cf {value: 0x0000, lo: 0x02}, {value: 0x0208, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, - // Block 0x34, offset 0x1ea + // Block 0x34, offset 0x1d2 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x84}, - {value: 0x1308, lo: 0x85, hi: 0x86}, + {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0208, lo: 0x87, hi: 0xa8}, - {value: 0x1308, lo: 0xa9, hi: 0xa9}, + {value: 0x3308, lo: 0xa9, hi: 0xa9}, {value: 0x0208, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x35, offset 0x1f2 + // Block 0x35, offset 0x1da {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, - // Block 0x36, offset 0x1f5 + // Block 0x36, offset 0x1dd {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, - {value: 0x1308, lo: 0xa0, hi: 0xa2}, - {value: 0x1008, lo: 0xa3, hi: 0xa6}, - {value: 0x1308, lo: 0xa7, hi: 0xa8}, - {value: 0x1008, lo: 0xa9, hi: 0xab}, + {value: 0x3308, lo: 0xa0, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa6}, + {value: 0x3308, lo: 0xa7, hi: 0xa8}, + {value: 0x3008, lo: 0xa9, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, - {value: 0x1008, lo: 0xb0, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb2}, - {value: 0x1008, lo: 0xb3, hi: 0xb8}, - {value: 0x1308, lo: 0xb9, hi: 0xbb}, + {value: 0x3008, lo: 0xb0, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb2}, + {value: 0x3008, lo: 0xb3, hi: 0xb8}, + {value: 0x3308, lo: 0xb9, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, - // Block 0x37, offset 0x202 + // Block 0x37, offset 0x1ea {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x80}, {value: 0x0040, lo: 0x81, hi: 0x83}, @@ -2920,12 +2929,12 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, - // Block 0x38, offset 0x20a + // Block 0x38, offset 0x1f2 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x39, offset 0x20e + // Block 0x39, offset 0x1f6 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, @@ -2933,33 +2942,33 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0028, lo: 0x9a, hi: 0x9a}, {value: 0x0040, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0xbf}, - // Block 0x3a, offset 0x215 + // Block 0x3a, offset 0x1fd {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x96}, - {value: 0x1308, lo: 0x97, hi: 0x98}, - {value: 0x1008, lo: 0x99, hi: 0x9a}, - {value: 0x1308, lo: 0x9b, hi: 0x9b}, + {value: 0x3308, lo: 0x97, hi: 0x98}, + {value: 0x3008, lo: 0x99, hi: 0x9a}, + {value: 0x3308, lo: 0x9b, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x3b, offset 0x21d + // Block 0x3b, offset 0x205 {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x94}, - {value: 0x1008, lo: 0x95, hi: 0x95}, - {value: 0x1308, lo: 0x96, hi: 0x96}, - {value: 0x1008, lo: 0x97, hi: 0x97}, - {value: 0x1308, lo: 0x98, hi: 0x9e}, + {value: 0x3008, lo: 0x95, hi: 0x95}, + {value: 0x3308, lo: 0x96, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, - {value: 0x1b08, lo: 0xa0, hi: 0xa0}, - {value: 0x1008, lo: 0xa1, hi: 0xa1}, - {value: 0x1308, lo: 0xa2, hi: 0xa2}, - {value: 0x1008, lo: 0xa3, hi: 0xa4}, - {value: 0x1308, lo: 0xa5, hi: 0xac}, - {value: 0x1008, lo: 0xad, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xbc}, + {value: 0x3b08, lo: 0xa0, hi: 0xa0}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa2}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xac}, + {value: 0x3008, lo: 0xad, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, - {value: 0x1308, lo: 0xbf, hi: 0xbf}, - // Block 0x3c, offset 0x22d + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0x3c, offset 0x215 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8f}, @@ -2969,78 +2978,78 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xbd}, - {value: 0x1318, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xb0, hi: 0xbd}, + {value: 0x3318, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0x3d, offset 0x239 + // Block 0x3d, offset 0x221 {value: 0x0000, lo: 0x01}, {value: 0x0040, lo: 0x80, hi: 0xbf}, - // Block 0x3e, offset 0x23b + // Block 0x3e, offset 0x223 {value: 0x0000, lo: 0x09}, - {value: 0x1308, lo: 0x80, hi: 0x83}, - {value: 0x1008, lo: 0x84, hi: 0x84}, + {value: 0x3308, lo: 0x80, hi: 0x83}, + {value: 0x3008, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0xb3}, - {value: 0x1308, lo: 0xb4, hi: 0xb4}, - {value: 0x1008, lo: 0xb5, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbb}, - {value: 0x1308, lo: 0xbc, hi: 0xbc}, - {value: 0x1008, lo: 0xbd, hi: 0xbf}, - // Block 0x3f, offset 0x245 + {value: 0x3308, lo: 0xb4, hi: 0xb4}, + {value: 0x3008, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbf}, + // Block 0x3f, offset 0x22d {value: 0x0000, lo: 0x0b}, - {value: 0x1008, lo: 0x80, hi: 0x81}, - {value: 0x1308, lo: 0x82, hi: 0x82}, - {value: 0x1008, lo: 0x83, hi: 0x83}, - {value: 0x1808, lo: 0x84, hi: 0x84}, + {value: 0x3008, lo: 0x80, hi: 0x81}, + {value: 0x3308, lo: 0x82, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, + {value: 0x3808, lo: 0x84, hi: 0x84}, {value: 0x0008, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0018, lo: 0x9a, hi: 0xaa}, - {value: 0x1308, lo: 0xab, hi: 0xb3}, + {value: 0x3308, lo: 0xab, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, - // Block 0x40, offset 0x251 + // Block 0x40, offset 0x239 {value: 0x0000, lo: 0x0b}, - {value: 0x1308, lo: 0x80, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa0}, - {value: 0x1008, lo: 0xa1, hi: 0xa1}, - {value: 0x1308, lo: 0xa2, hi: 0xa5}, - {value: 0x1008, lo: 0xa6, hi: 0xa7}, - {value: 0x1308, lo: 0xa8, hi: 0xa9}, - {value: 0x1808, lo: 0xaa, hi: 0xaa}, - {value: 0x1b08, lo: 0xab, hi: 0xab}, - {value: 0x1308, lo: 0xac, hi: 0xad}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa9}, + {value: 0x3808, lo: 0xaa, hi: 0xaa}, + {value: 0x3b08, lo: 0xab, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xbf}, - // Block 0x41, offset 0x25d + // Block 0x41, offset 0x245 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0xa5}, - {value: 0x1308, lo: 0xa6, hi: 0xa6}, - {value: 0x1008, lo: 0xa7, hi: 0xa7}, - {value: 0x1308, lo: 0xa8, hi: 0xa9}, - {value: 0x1008, lo: 0xaa, hi: 0xac}, - {value: 0x1308, lo: 0xad, hi: 0xad}, - {value: 0x1008, lo: 0xae, hi: 0xae}, - {value: 0x1308, lo: 0xaf, hi: 0xb1}, - {value: 0x1808, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xa6, hi: 0xa6}, + {value: 0x3008, lo: 0xa7, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa9}, + {value: 0x3008, lo: 0xaa, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xae}, + {value: 0x3308, lo: 0xaf, hi: 0xb1}, + {value: 0x3808, lo: 0xb2, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbf}, - // Block 0x42, offset 0x269 + // Block 0x42, offset 0x251 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa3}, - {value: 0x1008, lo: 0xa4, hi: 0xab}, - {value: 0x1308, lo: 0xac, hi: 0xb3}, - {value: 0x1008, lo: 0xb4, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xb7}, + {value: 0x3008, lo: 0xa4, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbf}, - // Block 0x43, offset 0x271 + // Block 0x43, offset 0x259 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0x8c}, {value: 0x0008, lo: 0x8d, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, - // Block 0x44, offset 0x276 + // Block 0x44, offset 0x25e {value: 0x0000, lo: 0x09}, {value: 0x0e29, lo: 0x80, hi: 0x80}, {value: 0x0e41, lo: 0x81, hi: 0x81}, @@ -3051,30 +3060,30 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0eb9, lo: 0x87, hi: 0x87}, {value: 0x057d, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, - // Block 0x45, offset 0x280 + // Block 0x45, offset 0x268 {value: 0x0000, lo: 0x10}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, - {value: 0x1308, lo: 0x90, hi: 0x92}, + {value: 0x3308, lo: 0x90, hi: 0x92}, {value: 0x0018, lo: 0x93, hi: 0x93}, - {value: 0x1308, lo: 0x94, hi: 0xa0}, - {value: 0x1008, lo: 0xa1, hi: 0xa1}, - {value: 0x1308, lo: 0xa2, hi: 0xa8}, + {value: 0x3308, lo: 0x94, hi: 0xa0}, + {value: 0x3008, lo: 0xa1, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa8}, {value: 0x0008, lo: 0xa9, hi: 0xac}, - {value: 0x1308, lo: 0xad, hi: 0xad}, + {value: 0x3308, lo: 0xad, hi: 0xad}, {value: 0x0008, lo: 0xae, hi: 0xb1}, - {value: 0x1008, lo: 0xb2, hi: 0xb3}, - {value: 0x1308, lo: 0xb4, hi: 0xb4}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, - {value: 0x0040, lo: 0xb7, hi: 0xb7}, - {value: 0x1308, lo: 0xb8, hi: 0xb9}, + {value: 0x3008, lo: 0xb7, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0x46, offset 0x291 + // Block 0x46, offset 0x279 {value: 0x0000, lo: 0x03}, - {value: 0x1308, lo: 0x80, hi: 0xb5}, - {value: 0x0040, lo: 0xb6, hi: 0xba}, - {value: 0x1308, lo: 0xbb, hi: 0xbf}, - // Block 0x47, offset 0x295 + {value: 0x3308, lo: 0x80, hi: 0xb9}, + {value: 0x0040, lo: 0xba, hi: 0xba}, + {value: 0x3308, lo: 0xbb, hi: 0xbf}, + // Block 0x47, offset 0x27d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x87}, {value: 0xe045, lo: 0x88, hi: 0x8f}, @@ -3086,12 +3095,12 @@ var idnaSparseValues = [1876]valueRange{ {value: 0xe045, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb7}, {value: 0xe045, lo: 0xb8, hi: 0xbf}, - // Block 0x48, offset 0x2a0 + // Block 0x48, offset 0x288 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x8f}, - {value: 0x1318, lo: 0x90, hi: 0xb0}, + {value: 0x3318, lo: 0x90, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbf}, - // Block 0x49, offset 0x2a4 + // Block 0x49, offset 0x28c {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x83}, @@ -3101,7 +3110,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0018, lo: 0x8a, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, - // Block 0x4a, offset 0x2ad + // Block 0x4a, offset 0x295 {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x24f1, lo: 0xac, hi: 0xac}, @@ -3110,72 +3119,68 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x2579, lo: 0xaf, hi: 0xaf}, {value: 0x25b1, lo: 0xb0, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, - // Block 0x4b, offset 0x2b5 + // Block 0x4b, offset 0x29d {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x9f}, {value: 0x0080, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xad}, {value: 0x0080, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, - // Block 0x4c, offset 0x2bb + // Block 0x4c, offset 0x2a3 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xa8}, {value: 0x09c5, lo: 0xa9, hi: 0xa9}, {value: 0x09e5, lo: 0xaa, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xbf}, - // Block 0x4d, offset 0x2c0 - {value: 0x0000, lo: 0x02}, - {value: 0x0018, lo: 0x80, hi: 0xbe}, - {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0x4e, offset 0x2c3 + // Block 0x4d, offset 0x2a8 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xbf}, - // Block 0x4f, offset 0x2c6 + // Block 0x4e, offset 0x2ab {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x28c1, lo: 0x8c, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0xbf}, - // Block 0x50, offset 0x2ca + // Block 0x4f, offset 0x2af {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0e66, lo: 0xb4, hi: 0xb4}, {value: 0x292a, lo: 0xb5, hi: 0xb5}, {value: 0x0e86, lo: 0xb6, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, - // Block 0x51, offset 0x2d0 + // Block 0x50, offset 0x2b5 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x9b}, {value: 0x2941, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0xbf}, - // Block 0x52, offset 0x2d4 + // Block 0x51, offset 0x2b9 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, - // Block 0x53, offset 0x2d8 + // Block 0x52, offset 0x2bd {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, {value: 0x0018, lo: 0x98, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbc}, {value: 0x0018, lo: 0xbd, hi: 0xbf}, - // Block 0x54, offset 0x2de + // Block 0x53, offset 0x2c3 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, - {value: 0x0018, lo: 0x8a, hi: 0x91}, - {value: 0x0040, lo: 0x92, hi: 0xab}, + {value: 0x0018, lo: 0x8a, hi: 0x92}, + {value: 0x0040, lo: 0x93, hi: 0xab}, {value: 0x0018, lo: 0xac, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, - // Block 0x55, offset 0x2e5 + // Block 0x54, offset 0x2ca {value: 0x0000, lo: 0x05}, {value: 0xe185, lo: 0x80, hi: 0x8f}, {value: 0x03f5, lo: 0x90, hi: 0x9f}, {value: 0x0ea5, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x56, offset 0x2eb + // Block 0x55, offset 0x2d0 {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xa6}, @@ -3184,15 +3189,15 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x57, offset 0x2f3 + // Block 0x56, offset 0x2d8 {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xae}, {value: 0xe075, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb0}, {value: 0x0040, lo: 0xb1, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0x58, offset 0x2fa + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0x57, offset 0x2df {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, @@ -3204,7 +3209,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xb7, hi: 0xb7}, {value: 0x0008, lo: 0xb8, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0x59, offset 0x305 + // Block 0x58, offset 0x2ea {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, @@ -3214,62 +3219,62 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x97, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, - {value: 0x1308, lo: 0xa0, hi: 0xbf}, - // Block 0x5a, offset 0x30f + {value: 0x3308, lo: 0xa0, hi: 0xbf}, + // Block 0x59, offset 0x2f4 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0008, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, - // Block 0x5b, offset 0x313 + // Block 0x5a, offset 0x2f8 {value: 0x0000, lo: 0x02}, - {value: 0x0018, lo: 0x80, hi: 0x84}, - {value: 0x0040, lo: 0x85, hi: 0xbf}, - // Block 0x5c, offset 0x316 + {value: 0x0018, lo: 0x80, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0xbf}, + // Block 0x5b, offset 0x2fb {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9e}, {value: 0x0edd, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, - // Block 0x5d, offset 0x31c + // Block 0x5c, offset 0x301 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xb2}, {value: 0x0efd, lo: 0xb3, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, - // Block 0x5e, offset 0x320 + // Block 0x5d, offset 0x305 {value: 0x0020, lo: 0x01}, {value: 0x0f1d, lo: 0x80, hi: 0xbf}, - // Block 0x5f, offset 0x322 + // Block 0x5e, offset 0x307 {value: 0x0020, lo: 0x02}, {value: 0x171d, lo: 0x80, hi: 0x8f}, {value: 0x18fd, lo: 0x90, hi: 0xbf}, - // Block 0x60, offset 0x325 + // Block 0x5f, offset 0x30a {value: 0x0020, lo: 0x01}, {value: 0x1efd, lo: 0x80, hi: 0xbf}, - // Block 0x61, offset 0x327 + // Block 0x60, offset 0x30c {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0xbf}, - // Block 0x62, offset 0x32a + // Block 0x61, offset 0x30f {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x98}, - {value: 0x1308, lo: 0x99, hi: 0x9a}, + {value: 0x3308, lo: 0x99, hi: 0x9a}, {value: 0x29e2, lo: 0x9b, hi: 0x9b}, {value: 0x2a0a, lo: 0x9c, hi: 0x9c}, {value: 0x0008, lo: 0x9d, hi: 0x9e}, {value: 0x2a31, lo: 0x9f, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0008, lo: 0xa1, hi: 0xbf}, - // Block 0x63, offset 0x334 + // Block 0x62, offset 0x319 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xbe}, {value: 0x2a69, lo: 0xbf, hi: 0xbf}, - // Block 0x64, offset 0x337 + // Block 0x63, offset 0x31c {value: 0x0000, lo: 0x0e}, {value: 0x0040, lo: 0x80, hi: 0x84}, - {value: 0x0008, lo: 0x85, hi: 0xad}, - {value: 0x0040, lo: 0xae, hi: 0xb0}, + {value: 0x0008, lo: 0x85, hi: 0xae}, + {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x2a1d, lo: 0xb1, hi: 0xb1}, {value: 0x2a3d, lo: 0xb2, hi: 0xb2}, {value: 0x2a5d, lo: 0xb3, hi: 0xb3}, @@ -3281,150 +3286,150 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x2afd, lo: 0xba, hi: 0xbb}, {value: 0x2b1d, lo: 0xbc, hi: 0xbd}, {value: 0x2afd, lo: 0xbe, hi: 0xbf}, - // Block 0x65, offset 0x346 + // Block 0x64, offset 0x32b {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x66, offset 0x34a + // Block 0x65, offset 0x32f {value: 0x0030, lo: 0x04}, {value: 0x2aa2, lo: 0x80, hi: 0x9d}, {value: 0x305a, lo: 0x9e, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, {value: 0x30a2, lo: 0xa0, hi: 0xbf}, - // Block 0x67, offset 0x34f + // Block 0x66, offset 0x334 {value: 0x0000, lo: 0x02}, - {value: 0x0008, lo: 0x80, hi: 0x95}, - {value: 0x0040, lo: 0x96, hi: 0xbf}, - // Block 0x68, offset 0x352 + {value: 0x0008, lo: 0x80, hi: 0xaa}, + {value: 0x0040, lo: 0xab, hi: 0xbf}, + // Block 0x67, offset 0x337 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0040, lo: 0x8d, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, - // Block 0x69, offset 0x356 + // Block 0x68, offset 0x33b {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, - // Block 0x6a, offset 0x35b + // Block 0x69, offset 0x340 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xbf}, - // Block 0x6b, offset 0x360 + // Block 0x6a, offset 0x345 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb1}, + {value: 0x3308, lo: 0xb0, hi: 0xb1}, {value: 0x0018, lo: 0xb2, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, - // Block 0x6c, offset 0x366 + // Block 0x6b, offset 0x34b {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0xb6}, {value: 0x0008, lo: 0xb7, hi: 0xb7}, {value: 0x2009, lo: 0xb8, hi: 0xb8}, {value: 0x6e89, lo: 0xb9, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xbf}, - // Block 0x6d, offset 0x36c + // Block 0x6c, offset 0x351 {value: 0x0000, lo: 0x0e}, {value: 0x0008, lo: 0x80, hi: 0x81}, - {value: 0x1308, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0x85}, - {value: 0x1b08, lo: 0x86, hi: 0x86}, + {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, - {value: 0x1308, lo: 0x8b, hi: 0x8b}, + {value: 0x3308, lo: 0x8b, hi: 0x8b}, {value: 0x0008, lo: 0x8c, hi: 0xa2}, - {value: 0x1008, lo: 0xa3, hi: 0xa4}, - {value: 0x1308, lo: 0xa5, hi: 0xa6}, - {value: 0x1008, lo: 0xa7, hi: 0xa7}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa6}, + {value: 0x3008, lo: 0xa7, hi: 0xa7}, {value: 0x0018, lo: 0xa8, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0x6e, offset 0x37b + // Block 0x6d, offset 0x360 {value: 0x0000, lo: 0x05}, {value: 0x0208, lo: 0x80, hi: 0xb1}, {value: 0x0108, lo: 0xb2, hi: 0xb2}, {value: 0x0008, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, - // Block 0x6f, offset 0x381 + // Block 0x6e, offset 0x366 {value: 0x0000, lo: 0x03}, - {value: 0x1008, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x80, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0xb3}, - {value: 0x1008, lo: 0xb4, hi: 0xbf}, - // Block 0x70, offset 0x385 + {value: 0x3008, lo: 0xb4, hi: 0xbf}, + // Block 0x6f, offset 0x36a {value: 0x0000, lo: 0x0e}, - {value: 0x1008, lo: 0x80, hi: 0x83}, - {value: 0x1b08, lo: 0x84, hi: 0x84}, - {value: 0x1308, lo: 0x85, hi: 0x85}, + {value: 0x3008, lo: 0x80, hi: 0x83}, + {value: 0x3b08, lo: 0x84, hi: 0x84}, + {value: 0x3308, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x8d}, {value: 0x0018, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, - {value: 0x1308, lo: 0xa0, hi: 0xb1}, + {value: 0x3308, lo: 0xa0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xba}, {value: 0x0008, lo: 0xbb, hi: 0xbb}, {value: 0x0018, lo: 0xbc, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, - // Block 0x71, offset 0x394 + // Block 0x70, offset 0x379 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa5}, - {value: 0x1308, lo: 0xa6, hi: 0xad}, + {value: 0x3308, lo: 0xa6, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x72, offset 0x399 + // Block 0x71, offset 0x37e {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0x86}, - {value: 0x1308, lo: 0x87, hi: 0x91}, - {value: 0x1008, lo: 0x92, hi: 0x92}, - {value: 0x1808, lo: 0x93, hi: 0x93}, + {value: 0x3308, lo: 0x87, hi: 0x91}, + {value: 0x3008, lo: 0x92, hi: 0x92}, + {value: 0x3808, lo: 0x93, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, - // Block 0x73, offset 0x3a1 + // Block 0x72, offset 0x386 {value: 0x0000, lo: 0x09}, - {value: 0x1308, lo: 0x80, hi: 0x82}, - {value: 0x1008, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x80, hi: 0x82}, + {value: 0x3008, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xb3}, - {value: 0x1008, lo: 0xb4, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xb9}, - {value: 0x1008, lo: 0xba, hi: 0xbb}, - {value: 0x1308, lo: 0xbc, hi: 0xbc}, - {value: 0x1008, lo: 0xbd, hi: 0xbf}, - // Block 0x74, offset 0x3ab + {value: 0x3308, lo: 0xb3, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb9}, + {value: 0x3008, lo: 0xba, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbf}, + // Block 0x73, offset 0x390 {value: 0x0000, lo: 0x0a}, - {value: 0x1808, lo: 0x80, hi: 0x80}, + {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8e}, {value: 0x0008, lo: 0x8f, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa4}, - {value: 0x1308, lo: 0xa5, hi: 0xa5}, + {value: 0x3308, lo: 0xa5, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0x75, offset 0x3b6 + // Block 0x74, offset 0x39b {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xa8}, - {value: 0x1308, lo: 0xa9, hi: 0xae}, - {value: 0x1008, lo: 0xaf, hi: 0xb0}, - {value: 0x1308, lo: 0xb1, hi: 0xb2}, - {value: 0x1008, lo: 0xb3, hi: 0xb4}, - {value: 0x1308, lo: 0xb5, hi: 0xb6}, + {value: 0x3308, lo: 0xa9, hi: 0xae}, + {value: 0x3008, lo: 0xaf, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb2}, + {value: 0x3008, lo: 0xb3, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0x76, offset 0x3be + // Block 0x75, offset 0x3a3 {value: 0x0000, lo: 0x10}, {value: 0x0008, lo: 0x80, hi: 0x82}, - {value: 0x1308, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x8b}, - {value: 0x1308, lo: 0x8c, hi: 0x8c}, - {value: 0x1008, lo: 0x8d, hi: 0x8d}, + {value: 0x3308, lo: 0x8c, hi: 0x8c}, + {value: 0x3008, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, @@ -3432,38 +3437,38 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xa0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xb9}, {value: 0x0008, lo: 0xba, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbb}, - {value: 0x1308, lo: 0xbc, hi: 0xbc}, - {value: 0x1008, lo: 0xbd, hi: 0xbd}, + {value: 0x3008, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbc}, + {value: 0x3008, lo: 0xbd, hi: 0xbd}, {value: 0x0008, lo: 0xbe, hi: 0xbf}, - // Block 0x77, offset 0x3cf + // Block 0x76, offset 0x3b4 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb0}, + {value: 0x3308, lo: 0xb0, hi: 0xb0}, {value: 0x0008, lo: 0xb1, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb4}, + {value: 0x3308, lo: 0xb2, hi: 0xb4}, {value: 0x0008, lo: 0xb5, hi: 0xb6}, - {value: 0x1308, lo: 0xb7, hi: 0xb8}, + {value: 0x3308, lo: 0xb7, hi: 0xb8}, {value: 0x0008, lo: 0xb9, hi: 0xbd}, - {value: 0x1308, lo: 0xbe, hi: 0xbf}, - // Block 0x78, offset 0x3d8 + {value: 0x3308, lo: 0xbe, hi: 0xbf}, + // Block 0x77, offset 0x3bd {value: 0x0000, lo: 0x0f}, {value: 0x0008, lo: 0x80, hi: 0x80}, - {value: 0x1308, lo: 0x81, hi: 0x81}, + {value: 0x3308, lo: 0x81, hi: 0x81}, {value: 0x0008, lo: 0x82, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x9a}, {value: 0x0008, lo: 0x9b, hi: 0x9d}, {value: 0x0018, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xaa}, - {value: 0x1008, lo: 0xab, hi: 0xab}, - {value: 0x1308, lo: 0xac, hi: 0xad}, - {value: 0x1008, lo: 0xae, hi: 0xaf}, + {value: 0x3008, lo: 0xab, hi: 0xab}, + {value: 0x3308, lo: 0xac, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xb4}, - {value: 0x1008, lo: 0xb5, hi: 0xb5}, - {value: 0x1b08, lo: 0xb6, hi: 0xb6}, + {value: 0x3008, lo: 0xb5, hi: 0xb5}, + {value: 0x3b08, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0x79, offset 0x3e8 + // Block 0x78, offset 0x3cd {value: 0x0000, lo: 0x0c}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x86}, @@ -3477,7 +3482,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xa8, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x7a, offset 0x3f5 + // Block 0x79, offset 0x3da {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x9a}, {value: 0x0018, lo: 0x9b, hi: 0x9b}, @@ -3488,54 +3493,54 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xa0, hi: 0xa5}, {value: 0x0040, lo: 0xa6, hi: 0xaf}, {value: 0x4495, lo: 0xb0, hi: 0xbf}, - // Block 0x7b, offset 0x3ff + // Block 0x7a, offset 0x3e4 {value: 0x0000, lo: 0x04}, {value: 0x44b5, lo: 0x80, hi: 0x8f}, {value: 0x44d5, lo: 0x90, hi: 0x9f}, {value: 0x44f5, lo: 0xa0, hi: 0xaf}, {value: 0x44d5, lo: 0xb0, hi: 0xbf}, - // Block 0x7c, offset 0x404 + // Block 0x7b, offset 0x3e9 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0xa2}, - {value: 0x1008, lo: 0xa3, hi: 0xa4}, - {value: 0x1308, lo: 0xa5, hi: 0xa5}, - {value: 0x1008, lo: 0xa6, hi: 0xa7}, - {value: 0x1308, lo: 0xa8, hi: 0xa8}, - {value: 0x1008, lo: 0xa9, hi: 0xaa}, + {value: 0x3008, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa5, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa7}, + {value: 0x3308, lo: 0xa8, hi: 0xa8}, + {value: 0x3008, lo: 0xa9, hi: 0xaa}, {value: 0x0018, lo: 0xab, hi: 0xab}, - {value: 0x1008, lo: 0xac, hi: 0xac}, - {value: 0x1b08, lo: 0xad, hi: 0xad}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3b08, lo: 0xad, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0x7d, offset 0x411 + // Block 0x7c, offset 0x3f6 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, - // Block 0x7e, offset 0x415 + // Block 0x7d, offset 0x3fa {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, - // Block 0x7f, offset 0x41a + // Block 0x7e, offset 0x3ff {value: 0x0020, lo: 0x01}, {value: 0x4515, lo: 0x80, hi: 0xbf}, - // Block 0x80, offset 0x41c + // Block 0x7f, offset 0x401 {value: 0x0020, lo: 0x03}, {value: 0x4d15, lo: 0x80, hi: 0x94}, {value: 0x4ad5, lo: 0x95, hi: 0x95}, {value: 0x4fb5, lo: 0x96, hi: 0xbf}, - // Block 0x81, offset 0x420 + // Block 0x80, offset 0x405 {value: 0x0020, lo: 0x01}, {value: 0x54f5, lo: 0x80, hi: 0xbf}, - // Block 0x82, offset 0x422 + // Block 0x81, offset 0x407 {value: 0x0020, lo: 0x03}, {value: 0x5cf5, lo: 0x80, hi: 0x84}, {value: 0x5655, lo: 0x85, hi: 0x85}, {value: 0x5d95, lo: 0x86, hi: 0xbf}, - // Block 0x83, offset 0x426 + // Block 0x82, offset 0x40b {value: 0x0020, lo: 0x08}, {value: 0x6b55, lo: 0x80, hi: 0x8f}, {value: 0x6d15, lo: 0x90, hi: 0x90}, @@ -3545,19 +3550,19 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xae, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x70d5, lo: 0xb0, hi: 0xbf}, - // Block 0x84, offset 0x42f + // Block 0x83, offset 0x414 {value: 0x0020, lo: 0x05}, {value: 0x72d5, lo: 0x80, hi: 0xad}, {value: 0x6535, lo: 0xae, hi: 0xae}, {value: 0x7895, lo: 0xaf, hi: 0xb5}, {value: 0x6f55, lo: 0xb6, hi: 0xb6}, {value: 0x7975, lo: 0xb7, hi: 0xbf}, - // Block 0x85, offset 0x435 + // Block 0x84, offset 0x41a {value: 0x0028, lo: 0x03}, {value: 0x7c21, lo: 0x80, hi: 0x82}, {value: 0x7be1, lo: 0x83, hi: 0x83}, {value: 0x7c99, lo: 0x84, hi: 0xbf}, - // Block 0x86, offset 0x439 + // Block 0x85, offset 0x41e {value: 0x0038, lo: 0x0f}, {value: 0x9db1, lo: 0x80, hi: 0x83}, {value: 0x9e59, lo: 0x84, hi: 0x85}, @@ -3574,7 +3579,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0xa869, lo: 0xbc, hi: 0xbc}, {value: 0xa7f9, lo: 0xbd, hi: 0xbd}, {value: 0xa8d9, lo: 0xbe, hi: 0xbf}, - // Block 0x87, offset 0x449 + // Block 0x86, offset 0x42e {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8c}, @@ -3585,24 +3590,24 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xbc, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, - // Block 0x88, offset 0x453 + // Block 0x87, offset 0x438 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, - // Block 0x89, offset 0x458 + // Block 0x88, offset 0x43d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, - // Block 0x8a, offset 0x45b + // Block 0x89, offset 0x440 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x82}, {value: 0x0040, lo: 0x83, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, - // Block 0x8b, offset 0x461 + // Block 0x8a, offset 0x446 {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x8e}, {value: 0x0040, lo: 0x8f, hi: 0x8f}, @@ -3610,31 +3615,31 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x9c, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa0}, {value: 0x0040, lo: 0xa1, hi: 0xbf}, - // Block 0x8c, offset 0x468 + // Block 0x8b, offset 0x44d {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbc}, - {value: 0x1308, lo: 0xbd, hi: 0xbd}, + {value: 0x3308, lo: 0xbd, hi: 0xbd}, {value: 0x0040, lo: 0xbe, hi: 0xbf}, - // Block 0x8d, offset 0x46d + // Block 0x8c, offset 0x452 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9c}, {value: 0x0040, lo: 0x9d, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x8e, offset 0x471 + // Block 0x8d, offset 0x456 {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x90}, {value: 0x0040, lo: 0x91, hi: 0x9f}, - {value: 0x1308, lo: 0xa0, hi: 0xa0}, + {value: 0x3308, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, - // Block 0x8f, offset 0x477 + // Block 0x8e, offset 0x45c {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xa3}, - {value: 0x0040, lo: 0xa4, hi: 0xaf}, - {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x90, offset 0x47c + {value: 0x0040, lo: 0xa4, hi: 0xac}, + {value: 0x0008, lo: 0xad, hi: 0xbf}, + // Block 0x8f, offset 0x461 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x81}, @@ -3642,22 +3647,22 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0018, lo: 0x8a, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xba}, + {value: 0x3308, lo: 0xb6, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbf}, - // Block 0x91, offset 0x485 + // Block 0x90, offset 0x46a {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0x92, offset 0x48a + // Block 0x91, offset 0x46f {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x87}, {value: 0x0008, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0xbf}, - // Block 0x93, offset 0x490 + // Block 0x92, offset 0x475 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, @@ -3665,7 +3670,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x8ad5, lo: 0x98, hi: 0x9f}, {value: 0x8aed, lo: 0xa0, hi: 0xa7}, {value: 0x0008, lo: 0xa8, hi: 0xbf}, - // Block 0x94, offset 0x497 + // Block 0x93, offset 0x47c {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, @@ -3673,7 +3678,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x8aed, lo: 0xb0, hi: 0xb7}, {value: 0x8ad5, lo: 0xb8, hi: 0xbf}, - // Block 0x95, offset 0x49e + // Block 0x94, offset 0x483 {value: 0x0000, lo: 0x06}, {value: 0xe145, lo: 0x80, hi: 0x87}, {value: 0xe1c5, lo: 0x88, hi: 0x8f}, @@ -3681,173 +3686,176 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x94, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0xbb}, {value: 0x0040, lo: 0xbc, hi: 0xbf}, - // Block 0x96, offset 0x4a5 + // Block 0x95, offset 0x48a {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0x97, offset 0x4a9 + // Block 0x96, offset 0x48e {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xae}, {value: 0x0018, lo: 0xaf, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, - // Block 0x98, offset 0x4ae + // Block 0x97, offset 0x493 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0x99, offset 0x4b1 + // Block 0x98, offset 0x496 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xbf}, - // Block 0x9a, offset 0x4b6 + // Block 0x99, offset 0x49b {value: 0x0000, lo: 0x0b}, - {value: 0x0008, lo: 0x80, hi: 0x85}, + {value: 0x0808, lo: 0x80, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0x87}, - {value: 0x0008, lo: 0x88, hi: 0x88}, + {value: 0x0808, lo: 0x88, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, - {value: 0x0008, lo: 0x8a, hi: 0xb5}, + {value: 0x0808, lo: 0x8a, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb6}, - {value: 0x0008, lo: 0xb7, hi: 0xb8}, + {value: 0x0808, lo: 0xb7, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbb}, - {value: 0x0008, lo: 0xbc, hi: 0xbc}, + {value: 0x0808, lo: 0xbc, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbe}, - {value: 0x0008, lo: 0xbf, hi: 0xbf}, - // Block 0x9b, offset 0x4c2 + {value: 0x0808, lo: 0xbf, hi: 0xbf}, + // Block 0x9a, offset 0x4a7 {value: 0x0000, lo: 0x05}, - {value: 0x0008, lo: 0x80, hi: 0x95}, + {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x96}, - {value: 0x0018, lo: 0x97, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xb6}, - {value: 0x0018, lo: 0xb7, hi: 0xbf}, - // Block 0x9c, offset 0x4c8 + {value: 0x0818, lo: 0x97, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb6}, + {value: 0x0818, lo: 0xb7, hi: 0xbf}, + // Block 0x9b, offset 0x4ad {value: 0x0000, lo: 0x04}, - {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x0808, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0xa6}, - {value: 0x0018, lo: 0xa7, hi: 0xaf}, + {value: 0x0818, lo: 0xa7, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, - // Block 0x9d, offset 0x4cd + // Block 0x9c, offset 0x4b2 {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xb2}, + {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb3}, - {value: 0x0008, lo: 0xb4, hi: 0xb5}, + {value: 0x0808, lo: 0xb4, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xba}, - {value: 0x0018, lo: 0xbb, hi: 0xbf}, - // Block 0x9e, offset 0x4d4 + {value: 0x0818, lo: 0xbb, hi: 0xbf}, + // Block 0x9d, offset 0x4b9 {value: 0x0000, lo: 0x07}, - {value: 0x0008, lo: 0x80, hi: 0x95}, - {value: 0x0018, lo: 0x96, hi: 0x9b}, + {value: 0x0808, lo: 0x80, hi: 0x95}, + {value: 0x0818, lo: 0x96, hi: 0x9b}, {value: 0x0040, lo: 0x9c, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xb9}, + {value: 0x0808, lo: 0xa0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbe}, - {value: 0x0018, lo: 0xbf, hi: 0xbf}, - // Block 0x9f, offset 0x4dc + {value: 0x0818, lo: 0xbf, hi: 0xbf}, + // Block 0x9e, offset 0x4c1 {value: 0x0000, lo: 0x04}, - {value: 0x0008, lo: 0x80, hi: 0xb7}, + {value: 0x0808, lo: 0x80, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbb}, - {value: 0x0018, lo: 0xbc, hi: 0xbd}, - {value: 0x0008, lo: 0xbe, hi: 0xbf}, - // Block 0xa0, offset 0x4e1 + {value: 0x0818, lo: 0xbc, hi: 0xbd}, + {value: 0x0808, lo: 0xbe, hi: 0xbf}, + // Block 0x9f, offset 0x4c6 {value: 0x0000, lo: 0x03}, - {value: 0x0018, lo: 0x80, hi: 0x8f}, + {value: 0x0818, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, - {value: 0x0018, lo: 0x92, hi: 0xbf}, - // Block 0xa1, offset 0x4e5 + {value: 0x0818, lo: 0x92, hi: 0xbf}, + // Block 0xa0, offset 0x4ca {value: 0x0000, lo: 0x0f}, - {value: 0x0008, lo: 0x80, hi: 0x80}, - {value: 0x1308, lo: 0x81, hi: 0x83}, + {value: 0x0808, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x84}, - {value: 0x1308, lo: 0x85, hi: 0x86}, + {value: 0x3308, lo: 0x85, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x8b}, - {value: 0x1308, lo: 0x8c, hi: 0x8f}, - {value: 0x0008, lo: 0x90, hi: 0x93}, + {value: 0x3308, lo: 0x8c, hi: 0x8f}, + {value: 0x0808, lo: 0x90, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x94}, - {value: 0x0008, lo: 0x95, hi: 0x97}, + {value: 0x0808, lo: 0x95, hi: 0x97}, {value: 0x0040, lo: 0x98, hi: 0x98}, - {value: 0x0008, lo: 0x99, hi: 0xb3}, + {value: 0x0808, lo: 0x99, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xb7}, - {value: 0x1308, lo: 0xb8, hi: 0xba}, + {value: 0x3308, lo: 0xb8, hi: 0xba}, {value: 0x0040, lo: 0xbb, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0xa2, offset 0x4f5 + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xa1, offset 0x4da {value: 0x0000, lo: 0x06}, - {value: 0x0018, lo: 0x80, hi: 0x87}, + {value: 0x0818, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, - {value: 0x0018, lo: 0x90, hi: 0x98}, + {value: 0x0818, lo: 0x90, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xbc}, - {value: 0x0018, lo: 0xbd, hi: 0xbf}, - // Block 0xa3, offset 0x4fc + {value: 0x0808, lo: 0xa0, hi: 0xbc}, + {value: 0x0818, lo: 0xbd, hi: 0xbf}, + // Block 0xa2, offset 0x4e1 {value: 0x0000, lo: 0x03}, - {value: 0x0008, lo: 0x80, hi: 0x9c}, - {value: 0x0018, lo: 0x9d, hi: 0x9f}, + {value: 0x0808, lo: 0x80, hi: 0x9c}, + {value: 0x0818, lo: 0x9d, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, - // Block 0xa4, offset 0x500 + // Block 0xa3, offset 0x4e5 {value: 0x0000, lo: 0x03}, - {value: 0x0008, lo: 0x80, hi: 0xb5}, + {value: 0x0808, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb8}, {value: 0x0018, lo: 0xb9, hi: 0xbf}, - // Block 0xa5, offset 0x504 + // Block 0xa4, offset 0x4e9 {value: 0x0000, lo: 0x06}, - {value: 0x0008, lo: 0x80, hi: 0x95}, + {value: 0x0808, lo: 0x80, hi: 0x95}, {value: 0x0040, lo: 0x96, hi: 0x97}, - {value: 0x0018, lo: 0x98, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xb2}, + {value: 0x0818, lo: 0x98, hi: 0x9f}, + {value: 0x0808, lo: 0xa0, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb7}, - {value: 0x0018, lo: 0xb8, hi: 0xbf}, - // Block 0xa6, offset 0x50b + {value: 0x0818, lo: 0xb8, hi: 0xbf}, + // Block 0xa5, offset 0x4f0 + {value: 0x0000, lo: 0x01}, + {value: 0x0808, lo: 0x80, hi: 0xbf}, + // Block 0xa6, offset 0x4f2 {value: 0x0000, lo: 0x02}, - {value: 0x0008, lo: 0x80, hi: 0x88}, + {value: 0x0808, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0xbf}, - // Block 0xa7, offset 0x50e + // Block 0xa7, offset 0x4f5 {value: 0x0000, lo: 0x02}, {value: 0x03dd, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, - // Block 0xa8, offset 0x511 + // Block 0xa8, offset 0x4f8 {value: 0x0000, lo: 0x03}, - {value: 0x0008, lo: 0x80, hi: 0xb2}, + {value: 0x0808, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xb9}, - {value: 0x0018, lo: 0xba, hi: 0xbf}, - // Block 0xa9, offset 0x515 + {value: 0x0818, lo: 0xba, hi: 0xbf}, + // Block 0xa9, offset 0x4fc {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, - {value: 0x0018, lo: 0xa0, hi: 0xbe}, + {value: 0x0818, lo: 0xa0, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xaa, offset 0x519 + // Block 0xaa, offset 0x500 {value: 0x0000, lo: 0x05}, - {value: 0x1008, lo: 0x80, hi: 0x80}, - {value: 0x1308, lo: 0x81, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x82}, + {value: 0x3008, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb7}, - {value: 0x1308, lo: 0xb8, hi: 0xbf}, - // Block 0xab, offset 0x51f + {value: 0x3308, lo: 0xb8, hi: 0xbf}, + // Block 0xab, offset 0x506 {value: 0x0000, lo: 0x08}, - {value: 0x1308, lo: 0x80, hi: 0x85}, - {value: 0x1b08, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x80, hi: 0x85}, + {value: 0x3b08, lo: 0x86, hi: 0x86}, {value: 0x0018, lo: 0x87, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x91}, {value: 0x0018, lo: 0x92, hi: 0xa5}, {value: 0x0008, lo: 0xa6, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0xac, offset 0x528 + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xac, offset 0x50f {value: 0x0000, lo: 0x0b}, - {value: 0x1308, lo: 0x80, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xaf}, - {value: 0x1008, lo: 0xb0, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xb6}, - {value: 0x1008, lo: 0xb7, hi: 0xb8}, - {value: 0x1b08, lo: 0xb9, hi: 0xb9}, - {value: 0x1308, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb6}, + {value: 0x3008, lo: 0xb7, hi: 0xb8}, + {value: 0x3b08, lo: 0xb9, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, {value: 0x0018, lo: 0xbb, hi: 0xbc}, {value: 0x0340, lo: 0xbd, hi: 0xbd}, {value: 0x0018, lo: 0xbe, hi: 0xbf}, - // Block 0xad, offset 0x534 + // Block 0xad, offset 0x51b {value: 0x0000, lo: 0x06}, {value: 0x0018, lo: 0x80, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x8f}, @@ -3855,39 +3863,39 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xa9, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0xae, offset 0x53b + // Block 0xae, offset 0x522 {value: 0x0000, lo: 0x08}, - {value: 0x1308, lo: 0x80, hi: 0x82}, + {value: 0x3308, lo: 0x80, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xa6}, - {value: 0x1308, lo: 0xa7, hi: 0xab}, - {value: 0x1008, lo: 0xac, hi: 0xac}, - {value: 0x1308, lo: 0xad, hi: 0xb2}, - {value: 0x1b08, lo: 0xb3, hi: 0xb4}, + {value: 0x3308, lo: 0xa7, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xb2}, + {value: 0x3b08, lo: 0xb3, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xbf}, - // Block 0xaf, offset 0x544 + // Block 0xaf, offset 0x52b {value: 0x0000, lo: 0x07}, {value: 0x0018, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xb3}, + {value: 0x3308, lo: 0xb3, hi: 0xb3}, {value: 0x0018, lo: 0xb4, hi: 0xb5}, {value: 0x0008, lo: 0xb6, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0xb0, offset 0x54c + // Block 0xb0, offset 0x533 {value: 0x0000, lo: 0x06}, - {value: 0x1308, lo: 0x80, hi: 0x81}, - {value: 0x1008, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x80, hi: 0x81}, + {value: 0x3008, lo: 0x82, hi: 0x82}, {value: 0x0008, lo: 0x83, hi: 0xb2}, - {value: 0x1008, lo: 0xb3, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xbe}, - {value: 0x1008, lo: 0xbf, hi: 0xbf}, - // Block 0xb1, offset 0x553 + {value: 0x3008, lo: 0xb3, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xbe}, + {value: 0x3008, lo: 0xbf, hi: 0xbf}, + // Block 0xb1, offset 0x53a {value: 0x0000, lo: 0x0d}, - {value: 0x1808, lo: 0x80, hi: 0x80}, + {value: 0x3808, lo: 0x80, hi: 0x80}, {value: 0x0008, lo: 0x81, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x89}, - {value: 0x1308, lo: 0x8a, hi: 0x8c}, + {value: 0x3308, lo: 0x8a, hi: 0x8c}, {value: 0x0018, lo: 0x8d, hi: 0x8d}, {value: 0x0040, lo: 0x8e, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x9a}, @@ -3897,21 +3905,21 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xa0, hi: 0xa0}, {value: 0x0018, lo: 0xa1, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, - // Block 0xb2, offset 0x561 + // Block 0xb2, offset 0x548 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x91}, {value: 0x0040, lo: 0x92, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0xab}, - {value: 0x1008, lo: 0xac, hi: 0xae}, - {value: 0x1308, lo: 0xaf, hi: 0xb1}, - {value: 0x1008, lo: 0xb2, hi: 0xb3}, - {value: 0x1308, lo: 0xb4, hi: 0xb4}, - {value: 0x1808, lo: 0xb5, hi: 0xb5}, - {value: 0x1308, lo: 0xb6, hi: 0xb7}, + {value: 0x3008, lo: 0xac, hi: 0xae}, + {value: 0x3308, lo: 0xaf, hi: 0xb1}, + {value: 0x3008, lo: 0xb2, hi: 0xb3}, + {value: 0x3308, lo: 0xb4, hi: 0xb4}, + {value: 0x3808, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb6, hi: 0xb7}, {value: 0x0018, lo: 0xb8, hi: 0xbd}, - {value: 0x1308, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xbe, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xb3, offset 0x56e + // Block 0xb3, offset 0x555 {value: 0x0000, lo: 0x0c}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, @@ -3925,28 +3933,28 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0018, lo: 0xa9, hi: 0xa9}, {value: 0x0040, lo: 0xaa, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbf}, - // Block 0xb4, offset 0x57b + // Block 0xb4, offset 0x562 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x9e}, - {value: 0x1308, lo: 0x9f, hi: 0x9f}, - {value: 0x1008, lo: 0xa0, hi: 0xa2}, - {value: 0x1308, lo: 0xa3, hi: 0xa9}, - {value: 0x1b08, lo: 0xaa, hi: 0xaa}, + {value: 0x3308, lo: 0x9f, hi: 0x9f}, + {value: 0x3008, lo: 0xa0, hi: 0xa2}, + {value: 0x3308, lo: 0xa3, hi: 0xa9}, + {value: 0x3b08, lo: 0xaa, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0040, lo: 0xba, hi: 0xbf}, - // Block 0xb5, offset 0x584 + // Block 0xb5, offset 0x56b {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xb4}, - {value: 0x1008, lo: 0xb5, hi: 0xb7}, - {value: 0x1308, lo: 0xb8, hi: 0xbf}, - // Block 0xb6, offset 0x588 + {value: 0x3008, lo: 0xb5, hi: 0xb7}, + {value: 0x3308, lo: 0xb8, hi: 0xbf}, + // Block 0xb6, offset 0x56f {value: 0x0000, lo: 0x0d}, - {value: 0x1008, lo: 0x80, hi: 0x81}, - {value: 0x1b08, lo: 0x82, hi: 0x82}, - {value: 0x1308, lo: 0x83, hi: 0x84}, - {value: 0x1008, lo: 0x85, hi: 0x85}, - {value: 0x1308, lo: 0x86, hi: 0x86}, + {value: 0x3008, lo: 0x80, hi: 0x81}, + {value: 0x3b08, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x83, hi: 0x84}, + {value: 0x3008, lo: 0x85, hi: 0x85}, + {value: 0x3308, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x8a}, {value: 0x0018, lo: 0x8b, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, @@ -3955,56 +3963,56 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x9c, hi: 0x9c}, {value: 0x0018, lo: 0x9d, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, - // Block 0xb7, offset 0x596 + // Block 0xb7, offset 0x57d {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, - {value: 0x1008, lo: 0xb0, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xb8}, - {value: 0x1008, lo: 0xb9, hi: 0xb9}, - {value: 0x1308, lo: 0xba, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbe}, - {value: 0x1308, lo: 0xbf, hi: 0xbf}, - // Block 0xb8, offset 0x59e + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb8}, + {value: 0x3008, lo: 0xb9, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0xb8, offset 0x585 {value: 0x0000, lo: 0x0a}, - {value: 0x1308, lo: 0x80, hi: 0x80}, - {value: 0x1008, lo: 0x81, hi: 0x81}, - {value: 0x1b08, lo: 0x82, hi: 0x82}, - {value: 0x1308, lo: 0x83, hi: 0x83}, + {value: 0x3308, lo: 0x80, hi: 0x80}, + {value: 0x3008, lo: 0x81, hi: 0x81}, + {value: 0x3b08, lo: 0x82, hi: 0x82}, + {value: 0x3308, lo: 0x83, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x85}, {value: 0x0018, lo: 0x86, hi: 0x86}, {value: 0x0008, lo: 0x87, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, - // Block 0xb9, offset 0x5a9 + // Block 0xb9, offset 0x590 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0xae}, - {value: 0x1008, lo: 0xaf, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb5}, + {value: 0x3008, lo: 0xaf, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xb7}, - {value: 0x1008, lo: 0xb8, hi: 0xbb}, - {value: 0x1308, lo: 0xbc, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0xba, offset 0x5b2 + {value: 0x3008, lo: 0xb8, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xba, offset 0x599 {value: 0x0000, lo: 0x05}, - {value: 0x1308, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x97}, {value: 0x0008, lo: 0x98, hi: 0x9b}, - {value: 0x1308, lo: 0x9c, hi: 0x9d}, + {value: 0x3308, lo: 0x9c, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0xbf}, - // Block 0xbb, offset 0x5b8 + // Block 0xbb, offset 0x59f {value: 0x0000, lo: 0x07}, {value: 0x0008, lo: 0x80, hi: 0xaf}, - {value: 0x1008, lo: 0xb0, hi: 0xb2}, - {value: 0x1308, lo: 0xb3, hi: 0xba}, - {value: 0x1008, lo: 0xbb, hi: 0xbc}, - {value: 0x1308, lo: 0xbd, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0xbc, offset 0x5c0 + {value: 0x3008, lo: 0xb0, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xba}, + {value: 0x3008, lo: 0xbb, hi: 0xbc}, + {value: 0x3308, lo: 0xbd, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xbc, offset 0x5a7 {value: 0x0000, lo: 0x08}, - {value: 0x1308, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x83}, {value: 0x0008, lo: 0x84, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, @@ -4012,60 +4020,97 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, - // Block 0xbd, offset 0x5c9 + // Block 0xbd, offset 0x5b0 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0xaa}, - {value: 0x1308, lo: 0xab, hi: 0xab}, - {value: 0x1008, lo: 0xac, hi: 0xac}, - {value: 0x1308, lo: 0xad, hi: 0xad}, - {value: 0x1008, lo: 0xae, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb5}, - {value: 0x1808, lo: 0xb6, hi: 0xb6}, - {value: 0x1308, lo: 0xb7, hi: 0xb7}, + {value: 0x3308, lo: 0xab, hi: 0xab}, + {value: 0x3008, lo: 0xac, hi: 0xac}, + {value: 0x3308, lo: 0xad, hi: 0xad}, + {value: 0x3008, lo: 0xae, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb5}, + {value: 0x3808, lo: 0xb6, hi: 0xb6}, + {value: 0x3308, lo: 0xb7, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbf}, - // Block 0xbe, offset 0x5d3 + // Block 0xbe, offset 0x5ba {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x89}, {value: 0x0040, lo: 0x8a, hi: 0xbf}, - // Block 0xbf, offset 0x5d6 + // Block 0xbf, offset 0x5bd {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9c}, - {value: 0x1308, lo: 0x9d, hi: 0x9f}, - {value: 0x1008, lo: 0xa0, hi: 0xa1}, - {value: 0x1308, lo: 0xa2, hi: 0xa5}, - {value: 0x1008, lo: 0xa6, hi: 0xa6}, - {value: 0x1308, lo: 0xa7, hi: 0xaa}, - {value: 0x1b08, lo: 0xab, hi: 0xab}, + {value: 0x3308, lo: 0x9d, hi: 0x9f}, + {value: 0x3008, lo: 0xa0, hi: 0xa1}, + {value: 0x3308, lo: 0xa2, hi: 0xa5}, + {value: 0x3008, lo: 0xa6, hi: 0xa6}, + {value: 0x3308, lo: 0xa7, hi: 0xaa}, + {value: 0x3b08, lo: 0xab, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xb9}, {value: 0x0018, lo: 0xba, hi: 0xbf}, - // Block 0xc0, offset 0x5e2 + // Block 0xc0, offset 0x5c9 {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0x9f}, {value: 0x049d, lo: 0xa0, hi: 0xbf}, - // Block 0xc1, offset 0x5e5 + // Block 0xc1, offset 0x5cc {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbe}, {value: 0x0008, lo: 0xbf, hi: 0xbf}, - // Block 0xc2, offset 0x5ea + // Block 0xc2, offset 0x5d1 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x80}, + {value: 0x3308, lo: 0x81, hi: 0x86}, + {value: 0x3008, lo: 0x87, hi: 0x88}, + {value: 0x3308, lo: 0x89, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0xb2}, + {value: 0x3308, lo: 0xb3, hi: 0xb3}, + {value: 0x3b08, lo: 0xb4, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb8}, + {value: 0x3008, lo: 0xb9, hi: 0xb9}, + {value: 0x0008, lo: 0xba, hi: 0xba}, + {value: 0x3308, lo: 0xbb, hi: 0xbe}, + {value: 0x0018, lo: 0xbf, hi: 0xbf}, + // Block 0xc3, offset 0x5de + {value: 0x0000, lo: 0x08}, + {value: 0x0018, lo: 0x80, hi: 0x86}, + {value: 0x3b08, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x90}, + {value: 0x3308, lo: 0x91, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x98}, + {value: 0x3308, lo: 0x99, hi: 0x9b}, + {value: 0x0008, lo: 0x9c, hi: 0xbf}, + // Block 0xc4, offset 0x5e7 + {value: 0x0000, lo: 0x0b}, + {value: 0x0008, lo: 0x80, hi: 0x83}, + {value: 0x0040, lo: 0x84, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0x89}, + {value: 0x3308, lo: 0x8a, hi: 0x96}, + {value: 0x3008, lo: 0x97, hi: 0x97}, + {value: 0x3308, lo: 0x98, hi: 0x98}, + {value: 0x3b08, lo: 0x99, hi: 0x99}, + {value: 0x0018, lo: 0x9a, hi: 0x9c}, + {value: 0x0040, lo: 0x9d, hi: 0x9d}, + {value: 0x0018, lo: 0x9e, hi: 0xa2}, + {value: 0x0040, lo: 0xa3, hi: 0xbf}, + // Block 0xc5, offset 0x5f3 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb8}, {value: 0x0040, lo: 0xb9, hi: 0xbf}, - // Block 0xc3, offset 0x5ed + // Block 0xc6, offset 0x5f6 {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x89}, {value: 0x0008, lo: 0x8a, hi: 0xae}, - {value: 0x1008, lo: 0xaf, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb6}, + {value: 0x3008, lo: 0xaf, hi: 0xaf}, + {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xb7}, - {value: 0x1308, lo: 0xb8, hi: 0xbd}, - {value: 0x1008, lo: 0xbe, hi: 0xbe}, - {value: 0x1b08, lo: 0xbf, hi: 0xbf}, - // Block 0xc4, offset 0x5f7 + {value: 0x3308, lo: 0xb8, hi: 0xbd}, + {value: 0x3008, lo: 0xbe, hi: 0xbe}, + {value: 0x3b08, lo: 0xbf, hi: 0xbf}, + // Block 0xc7, offset 0x600 {value: 0x0000, lo: 0x08}, {value: 0x0008, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x85}, @@ -4075,42 +4120,65 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xad, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0008, lo: 0xb2, hi: 0xbf}, - // Block 0xc5, offset 0x600 + // Block 0xc8, offset 0x609 {value: 0x0000, lo: 0x0b}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x91}, - {value: 0x1308, lo: 0x92, hi: 0xa7}, + {value: 0x3308, lo: 0x92, hi: 0xa7}, {value: 0x0040, lo: 0xa8, hi: 0xa8}, - {value: 0x1008, lo: 0xa9, hi: 0xa9}, - {value: 0x1308, lo: 0xaa, hi: 0xb0}, - {value: 0x1008, lo: 0xb1, hi: 0xb1}, - {value: 0x1308, lo: 0xb2, hi: 0xb3}, - {value: 0x1008, lo: 0xb4, hi: 0xb4}, - {value: 0x1308, lo: 0xb5, hi: 0xb6}, + {value: 0x3008, lo: 0xa9, hi: 0xa9}, + {value: 0x3308, lo: 0xaa, hi: 0xb0}, + {value: 0x3008, lo: 0xb1, hi: 0xb1}, + {value: 0x3308, lo: 0xb2, hi: 0xb3}, + {value: 0x3008, lo: 0xb4, hi: 0xb4}, + {value: 0x3308, lo: 0xb5, hi: 0xb6}, {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0xc6, offset 0x60c + // Block 0xc9, offset 0x615 + {value: 0x0000, lo: 0x0c}, + {value: 0x0008, lo: 0x80, hi: 0x86}, + {value: 0x0040, lo: 0x87, hi: 0x87}, + {value: 0x0008, lo: 0x88, hi: 0x89}, + {value: 0x0040, lo: 0x8a, hi: 0x8a}, + {value: 0x0008, lo: 0x8b, hi: 0xb0}, + {value: 0x3308, lo: 0xb1, hi: 0xb6}, + {value: 0x0040, lo: 0xb7, hi: 0xb9}, + {value: 0x3308, lo: 0xba, hi: 0xba}, + {value: 0x0040, lo: 0xbb, hi: 0xbb}, + {value: 0x3308, lo: 0xbc, hi: 0xbd}, + {value: 0x0040, lo: 0xbe, hi: 0xbe}, + {value: 0x3308, lo: 0xbf, hi: 0xbf}, + // Block 0xca, offset 0x622 + {value: 0x0000, lo: 0x07}, + {value: 0x3308, lo: 0x80, hi: 0x83}, + {value: 0x3b08, lo: 0x84, hi: 0x85}, + {value: 0x0008, lo: 0x86, hi: 0x86}, + {value: 0x3308, lo: 0x87, hi: 0x87}, + {value: 0x0040, lo: 0x88, hi: 0x8f}, + {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0040, lo: 0x9a, hi: 0xbf}, + // Block 0xcb, offset 0x62a {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0xbf}, - // Block 0xc7, offset 0x60f + // Block 0xcc, offset 0x62d {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, - // Block 0xc8, offset 0x614 + // Block 0xcd, offset 0x632 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0040, lo: 0x84, hi: 0xbf}, - // Block 0xc9, offset 0x617 + // Block 0xce, offset 0x635 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xbf}, - // Block 0xca, offset 0x61a + // Block 0xcf, offset 0x638 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0xbf}, - // Block 0xcb, offset 0x61d + // Block 0xd0, offset 0x63b {value: 0x0000, lo: 0x06}, {value: 0x0008, lo: 0x80, hi: 0x9e}, {value: 0x0040, lo: 0x9f, hi: 0x9f}, @@ -4118,20 +4186,20 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, - // Block 0xcc, offset 0x624 + // Block 0xd1, offset 0x642 {value: 0x0000, lo: 0x06}, {value: 0x0040, lo: 0x80, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb4}, + {value: 0x3308, lo: 0xb0, hi: 0xb4}, {value: 0x0018, lo: 0xb5, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, - // Block 0xcd, offset 0x62b + // Block 0xd2, offset 0x649 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xaf}, - {value: 0x1308, lo: 0xb0, hi: 0xb6}, + {value: 0x3308, lo: 0xb0, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xbf}, - // Block 0xce, offset 0x62f + // Block 0xd3, offset 0x64d {value: 0x0000, lo: 0x0a}, {value: 0x0008, lo: 0x80, hi: 0x83}, {value: 0x0018, lo: 0x84, hi: 0x85}, @@ -4143,67 +4211,75 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0008, lo: 0xa3, hi: 0xb7}, {value: 0x0040, lo: 0xb8, hi: 0xbc}, {value: 0x0008, lo: 0xbd, hi: 0xbf}, - // Block 0xcf, offset 0x63a + // Block 0xd4, offset 0x658 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0xbf}, - // Block 0xd0, offset 0x63d + // Block 0xd5, offset 0x65b {value: 0x0000, lo: 0x05}, {value: 0x0008, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x90}, - {value: 0x1008, lo: 0x91, hi: 0xbe}, + {value: 0x3008, lo: 0x91, hi: 0xbe}, {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xd1, offset 0x643 + // Block 0xd6, offset 0x661 {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x8e}, - {value: 0x1308, lo: 0x8f, hi: 0x92}, + {value: 0x3308, lo: 0x8f, hi: 0x92}, {value: 0x0008, lo: 0x93, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, - // Block 0xd2, offset 0x648 + // Block 0xd7, offset 0x666 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0x9f}, - {value: 0x0008, lo: 0xa0, hi: 0xa0}, - {value: 0x0040, lo: 0xa1, hi: 0xbf}, - // Block 0xd3, offset 0x64c + {value: 0x0008, lo: 0xa0, hi: 0xa1}, + {value: 0x0040, lo: 0xa2, hi: 0xbf}, + // Block 0xd8, offset 0x66a {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, - // Block 0xd4, offset 0x64f + // Block 0xd9, offset 0x66d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb2}, {value: 0x0040, lo: 0xb3, hi: 0xbf}, - // Block 0xd5, offset 0x652 + // Block 0xda, offset 0x670 {value: 0x0000, lo: 0x02}, - {value: 0x0008, lo: 0x80, hi: 0x81}, - {value: 0x0040, lo: 0x82, hi: 0xbf}, - // Block 0xd6, offset 0x655 + {value: 0x0008, lo: 0x80, hi: 0x9e}, + {value: 0x0040, lo: 0x9f, hi: 0xbf}, + // Block 0xdb, offset 0x673 + {value: 0x0000, lo: 0x02}, + {value: 0x0040, lo: 0x80, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0xdc, offset 0x676 + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xbb}, + {value: 0x0040, lo: 0xbc, hi: 0xbf}, + // Block 0xdd, offset 0x679 {value: 0x0000, lo: 0x04}, {value: 0x0008, lo: 0x80, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xaf}, {value: 0x0008, lo: 0xb0, hi: 0xbc}, {value: 0x0040, lo: 0xbd, hi: 0xbf}, - // Block 0xd7, offset 0x65a + // Block 0xde, offset 0x67e {value: 0x0000, lo: 0x09}, {value: 0x0008, lo: 0x80, hi: 0x88}, {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0x0008, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9b}, {value: 0x0018, lo: 0x9c, hi: 0x9c}, - {value: 0x1308, lo: 0x9d, hi: 0x9e}, + {value: 0x3308, lo: 0x9d, hi: 0x9e}, {value: 0x0018, lo: 0x9f, hi: 0x9f}, {value: 0x03c0, lo: 0xa0, hi: 0xa3}, {value: 0x0040, lo: 0xa4, hi: 0xbf}, - // Block 0xd8, offset 0x664 + // Block 0xdf, offset 0x688 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, - // Block 0xd9, offset 0x667 + // Block 0xe0, offset 0x68b {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xa6}, {value: 0x0040, lo: 0xa7, hi: 0xa8}, {value: 0x0018, lo: 0xa9, hi: 0xbf}, - // Block 0xda, offset 0x66b + // Block 0xe1, offset 0x68f {value: 0x0000, lo: 0x0e}, {value: 0x0018, lo: 0x80, hi: 0x9d}, {value: 0xb5b9, lo: 0x9e, hi: 0x9e}, @@ -4213,127 +4289,127 @@ var idnaSparseValues = [1876]valueRange{ {value: 0xb719, lo: 0xa2, hi: 0xa2}, {value: 0xb781, lo: 0xa3, hi: 0xa3}, {value: 0xb7e9, lo: 0xa4, hi: 0xa4}, - {value: 0x1018, lo: 0xa5, hi: 0xa6}, - {value: 0x1318, lo: 0xa7, hi: 0xa9}, + {value: 0x3018, lo: 0xa5, hi: 0xa6}, + {value: 0x3318, lo: 0xa7, hi: 0xa9}, {value: 0x0018, lo: 0xaa, hi: 0xac}, - {value: 0x1018, lo: 0xad, hi: 0xb2}, + {value: 0x3018, lo: 0xad, hi: 0xb2}, {value: 0x0340, lo: 0xb3, hi: 0xba}, - {value: 0x1318, lo: 0xbb, hi: 0xbf}, - // Block 0xdb, offset 0x67a + {value: 0x3318, lo: 0xbb, hi: 0xbf}, + // Block 0xe2, offset 0x69e {value: 0x0000, lo: 0x0b}, - {value: 0x1318, lo: 0x80, hi: 0x82}, + {value: 0x3318, lo: 0x80, hi: 0x82}, {value: 0x0018, lo: 0x83, hi: 0x84}, - {value: 0x1318, lo: 0x85, hi: 0x8b}, + {value: 0x3318, lo: 0x85, hi: 0x8b}, {value: 0x0018, lo: 0x8c, hi: 0xa9}, - {value: 0x1318, lo: 0xaa, hi: 0xad}, + {value: 0x3318, lo: 0xaa, hi: 0xad}, {value: 0x0018, lo: 0xae, hi: 0xba}, {value: 0xb851, lo: 0xbb, hi: 0xbb}, {value: 0xb899, lo: 0xbc, hi: 0xbc}, {value: 0xb8e1, lo: 0xbd, hi: 0xbd}, {value: 0xb949, lo: 0xbe, hi: 0xbe}, {value: 0xb9b1, lo: 0xbf, hi: 0xbf}, - // Block 0xdc, offset 0x686 + // Block 0xe3, offset 0x6aa {value: 0x0000, lo: 0x03}, {value: 0xba19, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0xa8}, {value: 0x0040, lo: 0xa9, hi: 0xbf}, - // Block 0xdd, offset 0x68a + // Block 0xe4, offset 0x6ae {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x81}, - {value: 0x1318, lo: 0x82, hi: 0x84}, + {value: 0x3318, lo: 0x82, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x85}, {value: 0x0040, lo: 0x86, hi: 0xbf}, - // Block 0xde, offset 0x68f + // Block 0xe5, offset 0x6b3 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, - // Block 0xdf, offset 0x694 + // Block 0xe6, offset 0x6b8 {value: 0x0000, lo: 0x03}, - {value: 0x1308, lo: 0x80, hi: 0xb6}, + {value: 0x3308, lo: 0x80, hi: 0xb6}, {value: 0x0018, lo: 0xb7, hi: 0xba}, - {value: 0x1308, lo: 0xbb, hi: 0xbf}, - // Block 0xe0, offset 0x698 + {value: 0x3308, lo: 0xbb, hi: 0xbf}, + // Block 0xe7, offset 0x6bc {value: 0x0000, lo: 0x04}, - {value: 0x1308, lo: 0x80, hi: 0xac}, + {value: 0x3308, lo: 0x80, hi: 0xac}, {value: 0x0018, lo: 0xad, hi: 0xb4}, - {value: 0x1308, lo: 0xb5, hi: 0xb5}, + {value: 0x3308, lo: 0xb5, hi: 0xb5}, {value: 0x0018, lo: 0xb6, hi: 0xbf}, - // Block 0xe1, offset 0x69d + // Block 0xe8, offset 0x6c1 {value: 0x0000, lo: 0x08}, {value: 0x0018, lo: 0x80, hi: 0x83}, - {value: 0x1308, lo: 0x84, hi: 0x84}, + {value: 0x3308, lo: 0x84, hi: 0x84}, {value: 0x0018, lo: 0x85, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x9a}, - {value: 0x1308, lo: 0x9b, hi: 0x9f}, + {value: 0x3308, lo: 0x9b, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xa0}, - {value: 0x1308, lo: 0xa1, hi: 0xaf}, + {value: 0x3308, lo: 0xa1, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, - // Block 0xe2, offset 0x6a6 + // Block 0xe9, offset 0x6ca {value: 0x0000, lo: 0x0a}, - {value: 0x1308, lo: 0x80, hi: 0x86}, + {value: 0x3308, lo: 0x80, hi: 0x86}, {value: 0x0040, lo: 0x87, hi: 0x87}, - {value: 0x1308, lo: 0x88, hi: 0x98}, + {value: 0x3308, lo: 0x88, hi: 0x98}, {value: 0x0040, lo: 0x99, hi: 0x9a}, - {value: 0x1308, lo: 0x9b, hi: 0xa1}, + {value: 0x3308, lo: 0x9b, hi: 0xa1}, {value: 0x0040, lo: 0xa2, hi: 0xa2}, - {value: 0x1308, lo: 0xa3, hi: 0xa4}, + {value: 0x3308, lo: 0xa3, hi: 0xa4}, {value: 0x0040, lo: 0xa5, hi: 0xa5}, - {value: 0x1308, lo: 0xa6, hi: 0xaa}, + {value: 0x3308, lo: 0xa6, hi: 0xaa}, {value: 0x0040, lo: 0xab, hi: 0xbf}, - // Block 0xe3, offset 0x6b1 + // Block 0xea, offset 0x6d5 {value: 0x0000, lo: 0x05}, - {value: 0x0008, lo: 0x80, hi: 0x84}, + {value: 0x0808, lo: 0x80, hi: 0x84}, {value: 0x0040, lo: 0x85, hi: 0x86}, - {value: 0x0018, lo: 0x87, hi: 0x8f}, - {value: 0x1308, lo: 0x90, hi: 0x96}, + {value: 0x0818, lo: 0x87, hi: 0x8f}, + {value: 0x3308, lo: 0x90, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, - // Block 0xe4, offset 0x6b7 + // Block 0xeb, offset 0x6db {value: 0x0000, lo: 0x07}, - {value: 0x0208, lo: 0x80, hi: 0x83}, - {value: 0x1308, lo: 0x84, hi: 0x8a}, + {value: 0x0a08, lo: 0x80, hi: 0x83}, + {value: 0x3308, lo: 0x84, hi: 0x8a}, {value: 0x0040, lo: 0x8b, hi: 0x8f}, - {value: 0x0008, lo: 0x90, hi: 0x99}, + {value: 0x0808, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9d}, - {value: 0x0018, lo: 0x9e, hi: 0x9f}, + {value: 0x0818, lo: 0x9e, hi: 0x9f}, {value: 0x0040, lo: 0xa0, hi: 0xbf}, - // Block 0xe5, offset 0x6bf + // Block 0xec, offset 0x6e3 {value: 0x0000, lo: 0x03}, {value: 0x0040, lo: 0x80, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xb1}, {value: 0x0040, lo: 0xb2, hi: 0xbf}, - // Block 0xe6, offset 0x6c3 + // Block 0xed, offset 0x6e7 {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0xab}, {value: 0x0040, lo: 0xac, hi: 0xaf}, {value: 0x0018, lo: 0xb0, hi: 0xbf}, - // Block 0xe7, offset 0x6c7 + // Block 0xee, offset 0x6eb {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x93}, {value: 0x0040, lo: 0x94, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xae}, {value: 0x0040, lo: 0xaf, hi: 0xb0}, {value: 0x0018, lo: 0xb1, hi: 0xbf}, - // Block 0xe8, offset 0x6cd + // Block 0xef, offset 0x6f1 {value: 0x0000, lo: 0x05}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0018, lo: 0x81, hi: 0x8f}, {value: 0x0040, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xb5}, {value: 0x0040, lo: 0xb6, hi: 0xbf}, - // Block 0xe9, offset 0x6d3 + // Block 0xf0, offset 0x6f7 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8f}, {value: 0xc1c1, lo: 0x90, hi: 0x90}, {value: 0x0018, lo: 0x91, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xbf}, - // Block 0xea, offset 0x6d8 + // Block 0xf1, offset 0x6fc {value: 0x0000, lo: 0x02}, {value: 0x0040, lo: 0x80, hi: 0xa5}, {value: 0x0018, lo: 0xa6, hi: 0xbf}, - // Block 0xeb, offset 0x6db - {value: 0x0000, lo: 0x0d}, + // Block 0xf2, offset 0x6ff + {value: 0x0000, lo: 0x0f}, {value: 0xc7e9, lo: 0x80, hi: 0x80}, {value: 0xc839, lo: 0x81, hi: 0x81}, {value: 0xc889, lo: 0x82, hi: 0x82}, @@ -4346,84 +4422,88 @@ var idnaSparseValues = [1876]valueRange{ {value: 0x0040, lo: 0x89, hi: 0x8f}, {value: 0xcab9, lo: 0x90, hi: 0x90}, {value: 0xcad9, lo: 0x91, hi: 0x91}, - {value: 0x0040, lo: 0x92, hi: 0xbf}, - // Block 0xec, offset 0x6e9 + {value: 0x0040, lo: 0x92, hi: 0x9f}, + {value: 0x0018, lo: 0xa0, hi: 0xa5}, + {value: 0x0040, lo: 0xa6, hi: 0xbf}, + // Block 0xf3, offset 0x70f {value: 0x0000, lo: 0x06}, - {value: 0x0018, lo: 0x80, hi: 0x92}, - {value: 0x0040, lo: 0x93, hi: 0x9f}, + {value: 0x0018, lo: 0x80, hi: 0x94}, + {value: 0x0040, lo: 0x95, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xac}, {value: 0x0040, lo: 0xad, hi: 0xaf}, - {value: 0x0018, lo: 0xb0, hi: 0xb6}, - {value: 0x0040, lo: 0xb7, hi: 0xbf}, - // Block 0xed, offset 0x6f0 + {value: 0x0018, lo: 0xb0, hi: 0xb8}, + {value: 0x0040, lo: 0xb9, hi: 0xbf}, + // Block 0xf4, offset 0x716 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0xb3}, {value: 0x0040, lo: 0xb4, hi: 0xbf}, - // Block 0xee, offset 0x6f3 + // Block 0xf5, offset 0x719 {value: 0x0000, lo: 0x02}, {value: 0x0018, lo: 0x80, hi: 0x94}, {value: 0x0040, lo: 0x95, hi: 0xbf}, - // Block 0xef, offset 0x6f6 + // Block 0xf6, offset 0x71c {value: 0x0000, lo: 0x03}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xbf}, - // Block 0xf0, offset 0x6fa + // Block 0xf7, offset 0x720 {value: 0x0000, lo: 0x05}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0x99}, {value: 0x0040, lo: 0x9a, hi: 0x9f}, {value: 0x0018, lo: 0xa0, hi: 0xbf}, - // Block 0xf1, offset 0x700 + // Block 0xf8, offset 0x726 {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x87}, {value: 0x0040, lo: 0x88, hi: 0x8f}, {value: 0x0018, lo: 0x90, hi: 0xad}, {value: 0x0040, lo: 0xae, hi: 0xbf}, - // Block 0xf2, offset 0x705 - {value: 0x0000, lo: 0x09}, - {value: 0x0040, lo: 0x80, hi: 0x8f}, - {value: 0x0018, lo: 0x90, hi: 0x9e}, - {value: 0x0040, lo: 0x9f, hi: 0x9f}, - {value: 0x0018, lo: 0xa0, hi: 0xa7}, - {value: 0x0040, lo: 0xa8, hi: 0xaf}, - {value: 0x0018, lo: 0xb0, hi: 0xb0}, - {value: 0x0040, lo: 0xb1, hi: 0xb2}, - {value: 0x0018, lo: 0xb3, hi: 0xbe}, - {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xf3, offset 0x70f + // Block 0xf9, offset 0x72b {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x8b}, {value: 0x0040, lo: 0x8c, hi: 0x8f}, - {value: 0x0018, lo: 0x90, hi: 0x9e}, - {value: 0x0040, lo: 0x9f, hi: 0xbf}, - // Block 0xf4, offset 0x714 - {value: 0x0000, lo: 0x02}, - {value: 0x0018, lo: 0x80, hi: 0x91}, - {value: 0x0040, lo: 0x92, hi: 0xbf}, - // Block 0xf5, offset 0x717 + {value: 0x0018, lo: 0x90, hi: 0xbe}, + {value: 0x0040, lo: 0xbf, hi: 0xbf}, + // Block 0xfa, offset 0x730 + {value: 0x0000, lo: 0x04}, + {value: 0x0018, lo: 0x80, hi: 0x8c}, + {value: 0x0040, lo: 0x8d, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xab}, + {value: 0x0040, lo: 0xac, hi: 0xbf}, + // Block 0xfb, offset 0x735 {value: 0x0000, lo: 0x02}, + {value: 0x0018, lo: 0x80, hi: 0x97}, + {value: 0x0040, lo: 0x98, hi: 0xbf}, + // Block 0xfc, offset 0x738 + {value: 0x0000, lo: 0x04}, {value: 0x0018, lo: 0x80, hi: 0x80}, - {value: 0x0040, lo: 0x81, hi: 0xbf}, - // Block 0xf6, offset 0x71a + {value: 0x0040, lo: 0x81, hi: 0x8f}, + {value: 0x0018, lo: 0x90, hi: 0xa6}, + {value: 0x0040, lo: 0xa7, hi: 0xbf}, + // Block 0xfd, offset 0x73d {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0x96}, {value: 0x0040, lo: 0x97, hi: 0xbf}, - // Block 0xf7, offset 0x71d + // Block 0xfe, offset 0x740 {value: 0x0000, lo: 0x02}, {value: 0x0008, lo: 0x80, hi: 0xb4}, {value: 0x0040, lo: 0xb5, hi: 0xbf}, - // Block 0xf8, offset 0x720 + // Block 0xff, offset 0x743 {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0x9d}, {value: 0x0040, lo: 0x9e, hi: 0x9f}, {value: 0x0008, lo: 0xa0, hi: 0xbf}, - // Block 0xf9, offset 0x724 - {value: 0x0000, lo: 0x02}, + // Block 0x100, offset 0x747 + {value: 0x0000, lo: 0x03}, {value: 0x0008, lo: 0x80, hi: 0xa1}, - {value: 0x0040, lo: 0xa2, hi: 0xbf}, - // Block 0xfa, offset 0x727 + {value: 0x0040, lo: 0xa2, hi: 0xaf}, + {value: 0x0008, lo: 0xb0, hi: 0xbf}, + // Block 0x101, offset 0x74b + {value: 0x0000, lo: 0x02}, + {value: 0x0008, lo: 0x80, hi: 0xa0}, + {value: 0x0040, lo: 0xa1, hi: 0xbf}, + // Block 0x102, offset 0x74e {value: 0x0020, lo: 0x0f}, {value: 0xdeb9, lo: 0x80, hi: 0x89}, {value: 0x8dfd, lo: 0x8a, hi: 0x8a}, @@ -4440,7 +4520,7 @@ var idnaSparseValues = [1876]valueRange{ {value: 0xe4f9, lo: 0xba, hi: 0xba}, {value: 0x8edd, lo: 0xbb, hi: 0xbb}, {value: 0xe519, lo: 0xbc, hi: 0xbf}, - // Block 0xfb, offset 0x737 + // Block 0x103, offset 0x75e {value: 0x0020, lo: 0x10}, {value: 0x937d, lo: 0x80, hi: 0x80}, {value: 0xf099, lo: 0x81, hi: 0x86}, @@ -4457,23 +4537,23 @@ var idnaSparseValues = [1876]valueRange{ {value: 0xf4d9, lo: 0xae, hi: 0xaf}, {value: 0x94dd, lo: 0xb0, hi: 0xb1}, {value: 0xf519, lo: 0xb2, hi: 0xbe}, - {value: 0x0040, lo: 0xbf, hi: 0xbf}, - // Block 0xfc, offset 0x748 + {value: 0x2040, lo: 0xbf, hi: 0xbf}, + // Block 0x104, offset 0x76f {value: 0x0000, lo: 0x04}, {value: 0x0040, lo: 0x80, hi: 0x80}, {value: 0x0340, lo: 0x81, hi: 0x81}, {value: 0x0040, lo: 0x82, hi: 0x9f}, {value: 0x0340, lo: 0xa0, hi: 0xbf}, - // Block 0xfd, offset 0x74d + // Block 0x105, offset 0x774 {value: 0x0000, lo: 0x01}, {value: 0x0340, lo: 0x80, hi: 0xbf}, - // Block 0xfe, offset 0x74f + // Block 0x106, offset 0x776 {value: 0x0000, lo: 0x01}, - {value: 0x13c0, lo: 0x80, hi: 0xbf}, - // Block 0xff, offset 0x751 + {value: 0x33c0, lo: 0x80, hi: 0xbf}, + // Block 0x107, offset 0x778 {value: 0x0000, lo: 0x02}, - {value: 0x13c0, lo: 0x80, hi: 0xaf}, + {value: 0x33c0, lo: 0x80, hi: 0xaf}, {value: 0x0040, lo: 0xb0, hi: 0xbf}, } -// Total table size 41559 bytes (40KiB); checksum: F4A1FA4E +// Total table size 42115 bytes (41KiB); checksum: F4A1FA4E diff --git a/libgo/go/golang_org/x/net/idna/trie.go b/libgo/go/golang_org/x/net/idna/trie.go index 000fb979a0b..c4ef847e7a3 100644 --- a/libgo/go/golang_org/x/net/idna/trie.go +++ b/libgo/go/golang_org/x/net/idna/trie.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/net/idna/trieval.go b/libgo/go/golang_org/x/net/idna/trieval.go index cd88e4d6bda..5f4e5f2e745 100644 --- a/libgo/go/golang_org/x/net/idna/trieval.go +++ b/libgo/go/golang_org/x/net/idna/trieval.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT. @@ -28,9 +28,9 @@ package idna // 15..3 index into xor or mapping table // } // } else { -// 15..13 unused -// 12 modifier (including virama) -// 11 virama modifier +// 15..14 unused +// 13 mayNeedNorm +// 12..11 attributes // 10..8 joining type // 7..3 category type // } @@ -51,15 +51,20 @@ const ( joinShift = 8 joinMask = 0x07 - viramaModifier = 0x0800 + // Attributes + attributesMask = 0x1800 + viramaModifier = 0x1800 modifier = 0x1000 + rtl = 0x0800 + + mayNeedNorm = 0x2000 ) // A category corresponds to a category defined in the IDNA mapping table. type category uint16 const ( - unknown category = 0 // not defined currently in unicode. + unknown category = 0 // not currently defined in unicode. mapped category = 1 disallowedSTD3Mapped category = 2 deviation category = 3 @@ -112,5 +117,5 @@ func (c info) isModifier() bool { } func (c info) isViramaModifier() bool { - return c&(viramaModifier|catSmallMask) == viramaModifier + return c&(attributesMask|catSmallMask) == viramaModifier } diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_bsd.go b/libgo/go/golang_org/x/net/internal/nettest/helper_bsd.go new file mode 100644 index 00000000000..a6e433b58c1 --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_bsd.go @@ -0,0 +1,53 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package nettest + +import ( + "runtime" + "strconv" + "strings" + "syscall" +) + +var darwinVersion int + +func init() { + if runtime.GOOS == "darwin" { + // See http://support.apple.com/kb/HT1633. + s, err := syscall.Sysctl("kern.osrelease") + if err != nil { + return + } + ss := strings.Split(s, ".") + if len(ss) == 0 { + return + } + darwinVersion, _ = strconv.Atoi(ss[0]) + } +} + +func supportsIPv6MulticastDeliveryOnLoopback() bool { + switch runtime.GOOS { + case "freebsd": + // See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065. + // Even after the fix, it looks like the latest + // kernels don't deliver link-local scoped multicast + // packets correctly. + return false + case "darwin": + return !causesIPv6Crash() + default: + return true + } +} + +func causesIPv6Crash() bool { + // We see some kernel crash when running IPv6 with IP-level + // options on Darwin kernel version 12 or below. + // See golang.org/issues/17015. + return darwinVersion < 13 +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_nobsd.go b/libgo/go/golang_org/x/net/internal/nettest/helper_nobsd.go new file mode 100644 index 00000000000..bc7da5e0d57 --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_nobsd.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Go 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 solaris + +package nettest + +func supportsIPv6MulticastDeliveryOnLoopback() bool { + return true +} + +func causesIPv6Crash() bool { + return false +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_posix.go b/libgo/go/golang_org/x/net/internal/nettest/helper_posix.go new file mode 100644 index 00000000000..963ed99655b --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_posix.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. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows + +package nettest + +import ( + "os" + "syscall" +) + +func protocolNotSupported(err error) bool { + switch err := err.(type) { + case syscall.Errno: + switch err { + case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT: + return true + } + case *os.SyscallError: + switch err := err.Err.(type) { + case syscall.Errno: + switch err { + case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT: + return true + } + } + } + return false +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_stub.go b/libgo/go/golang_org/x/net/internal/nettest/helper_stub.go new file mode 100644 index 00000000000..ea61b6f3992 --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_stub.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. + +// +build nacl plan9 + +package nettest + +import ( + "fmt" + "runtime" +) + +func maxOpenFiles() int { + return defaultMaxOpenFiles +} + +func supportsRawIPSocket() (string, bool) { + return fmt.Sprintf("not supported on %s", runtime.GOOS), false +} + +func supportsIPv6MulticastDeliveryOnLoopback() bool { + return false +} + +func causesIPv6Crash() bool { + return false +} + +func protocolNotSupported(err error) bool { + return false +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_unix.go b/libgo/go/golang_org/x/net/internal/nettest/helper_unix.go new file mode 100644 index 00000000000..ed13e448b7b --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_unix.go @@ -0,0 +1,29 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package nettest + +import ( + "fmt" + "os" + "runtime" + "syscall" +) + +func maxOpenFiles() int { + var rlim syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { + return defaultMaxOpenFiles + } + return int(rlim.Cur) +} + +func supportsRawIPSocket() (string, bool) { + if os.Getuid() != 0 { + return fmt.Sprintf("must be root on %s", runtime.GOOS), false + } + return "", true +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/helper_windows.go b/libgo/go/golang_org/x/net/internal/nettest/helper_windows.go new file mode 100644 index 00000000000..3dcb727c95c --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/helper_windows.go @@ -0,0 +1,42 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package nettest + +import ( + "fmt" + "runtime" + "syscall" +) + +func maxOpenFiles() int { + return 4 * defaultMaxOpenFiles /* actually it's 16581375 */ +} + +func supportsRawIPSocket() (string, bool) { + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx: + // Note: To use a socket of type SOCK_RAW requires administrative privileges. + // Users running Winsock applications that use raw sockets must be a member of + // the Administrators group on the local computer, otherwise raw socket calls + // will fail with an error code of WSAEACCES. On Windows Vista and later, access + // for raw sockets is enforced at socket creation. In earlier versions of Windows, + // access for raw sockets is enforced during other socket operations. + s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0) + if err == syscall.WSAEACCES { + return fmt.Sprintf("no access to raw socket allowed on %s", runtime.GOOS), false + } + if err != nil { + return err.Error(), false + } + syscall.Closesocket(s) + return "", true +} + +func supportsIPv6MulticastDeliveryOnLoopback() bool { + return true +} + +func causesIPv6Crash() bool { + return false +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/interface.go b/libgo/go/golang_org/x/net/internal/nettest/interface.go new file mode 100644 index 00000000000..8e6333afe1a --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/interface.go @@ -0,0 +1,94 @@ +// 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 nettest + +import "net" + +// IsMulticastCapable reports whether ifi is an IP multicast-capable +// network interface. Network must be "ip", "ip4" or "ip6". +func IsMulticastCapable(network string, ifi *net.Interface) (net.IP, bool) { + switch network { + case "ip", "ip4", "ip6": + default: + return nil, false + } + if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 { + return nil, false + } + return hasRoutableIP(network, ifi) +} + +// RoutedInterface returns a network interface that can route IP +// traffic and satisfies flags. It returns nil when an appropriate +// network interface is not found. Network must be "ip", "ip4" or +// "ip6". +func RoutedInterface(network string, flags net.Flags) *net.Interface { + switch network { + case "ip", "ip4", "ip6": + default: + return nil + } + ift, err := net.Interfaces() + if err != nil { + return nil + } + for _, ifi := range ift { + if ifi.Flags&flags != flags { + continue + } + if _, ok := hasRoutableIP(network, &ifi); !ok { + continue + } + return &ifi + } + return nil +} + +func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) { + ifat, err := ifi.Addrs() + if err != nil { + return nil, false + } + for _, ifa := range ifat { + switch ifa := ifa.(type) { + case *net.IPAddr: + if ip := routableIP(network, ifa.IP); ip != nil { + return ip, true + } + case *net.IPNet: + if ip := routableIP(network, ifa.IP); ip != nil { + return ip, true + } + } + } + return nil, false +} + +func routableIP(network string, ip net.IP) net.IP { + if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() { + return nil + } + switch network { + case "ip4": + if ip := ip.To4(); ip != nil { + return ip + } + case "ip6": + if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation + return nil + } + if ip := ip.To16(); ip != nil && ip.To4() == nil { + return ip + } + default: + if ip := ip.To4(); ip != nil { + return ip + } + if ip := ip.To16(); ip != nil { + return ip + } + } + return nil +} diff --git a/libgo/go/golang_org/x/net/internal/nettest/rlimit.go b/libgo/go/golang_org/x/net/internal/nettest/rlimit.go new file mode 100644 index 00000000000..bb34aec0bba --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/rlimit.go @@ -0,0 +1,11 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package nettest + +const defaultMaxOpenFiles = 256 + +// MaxOpenFiles returns the maximum number of open files for the +// caller's process. +func MaxOpenFiles() int { return maxOpenFiles() } diff --git a/libgo/go/golang_org/x/net/internal/nettest/stack.go b/libgo/go/golang_org/x/net/internal/nettest/stack.go new file mode 100644 index 00000000000..06f4e09ef85 --- /dev/null +++ b/libgo/go/golang_org/x/net/internal/nettest/stack.go @@ -0,0 +1,152 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package nettest provides utilities for network testing. +package nettest // import "golang.org/x/net/internal/nettest" + +import ( + "fmt" + "io/ioutil" + "net" + "os" + "runtime" +) + +var ( + supportsIPv4 bool + supportsIPv6 bool +) + +func init() { + if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil { + ln.Close() + supportsIPv4 = true + } + if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil { + ln.Close() + supportsIPv6 = true + } +} + +// SupportsIPv4 reports whether the platform supports IPv4 networking +// functionality. +func SupportsIPv4() bool { return supportsIPv4 } + +// SupportsIPv6 reports whether the platform supports IPv6 networking +// functionality. +func SupportsIPv6() bool { return supportsIPv6 } + +// SupportsRawIPSocket reports whether the platform supports raw IP +// sockets. +func SupportsRawIPSocket() (string, bool) { + return supportsRawIPSocket() +} + +// SupportsIPv6MulticastDeliveryOnLoopback reports whether the +// platform supports IPv6 multicast packet delivery on software +// loopback interface. +func SupportsIPv6MulticastDeliveryOnLoopback() bool { + return supportsIPv6MulticastDeliveryOnLoopback() +} + +// ProtocolNotSupported reports whether err is a protocol not +// supported error. +func ProtocolNotSupported(err error) bool { + return protocolNotSupported(err) +} + +// TestableNetwork reports whether network is testable on the current +// platform configuration. +func TestableNetwork(network string) bool { + // This is based on logic from standard library's + // net/platform_test.go. + switch network { + case "unix", "unixgram": + switch runtime.GOOS { + case "android", "nacl", "plan9", "windows": + return false + } + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + return false + } + case "unixpacket": + switch runtime.GOOS { + case "android", "darwin", "freebsd", "nacl", "plan9", "windows": + return false + case "netbsd": + // It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown. + if runtime.GOARCH == "386" { + return false + } + } + } + return true +} + +// NewLocalListener returns a listener which listens to a loopback IP +// address or local file system path. +// Network must be "tcp", "tcp4", "tcp6", "unix" or "unixpacket". +func NewLocalListener(network string) (net.Listener, error) { + switch network { + case "tcp": + if supportsIPv4 { + if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil { + return ln, nil + } + } + if supportsIPv6 { + return net.Listen("tcp6", "[::1]:0") + } + case "tcp4": + if supportsIPv4 { + return net.Listen("tcp4", "127.0.0.1:0") + } + case "tcp6": + if supportsIPv6 { + return net.Listen("tcp6", "[::1]:0") + } + case "unix", "unixpacket": + return net.Listen(network, localPath()) + } + return nil, fmt.Errorf("%s is not supported", network) +} + +// NewLocalPacketListener returns a packet listener which listens to a +// loopback IP address or local file system path. +// Network must be "udp", "udp4", "udp6" or "unixgram". +func NewLocalPacketListener(network string) (net.PacketConn, error) { + switch network { + case "udp": + if supportsIPv4 { + if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil { + return c, nil + } + } + if supportsIPv6 { + return net.ListenPacket("udp6", "[::1]:0") + } + case "udp4": + if supportsIPv4 { + return net.ListenPacket("udp4", "127.0.0.1:0") + } + case "udp6": + if supportsIPv6 { + return net.ListenPacket("udp6", "[::1]:0") + } + case "unixgram": + return net.ListenPacket(network, localPath()) + } + return nil, fmt.Errorf("%s is not supported", network) +} + +func localPath() string { + f, err := ioutil.TempFile("", "nettest") + if err != nil { + panic(err) + } + path := f.Name() + f.Close() + os.Remove(path) + return path +} diff --git a/libgo/go/golang_org/x/net/nettest/conntest_test.go b/libgo/go/golang_org/x/net/nettest/conntest_test.go index 23bd69fc630..ae8426a05c2 100644 --- a/libgo/go/golang_org/x/net/nettest/conntest_test.go +++ b/libgo/go/golang_org/x/net/nettest/conntest_test.go @@ -7,63 +7,13 @@ package nettest import ( - "fmt" - "io/ioutil" "net" "os" "runtime" "testing" -) - -// testUnixAddr uses ioutil.TempFile to get a name that is unique. -// It also uses /tmp directory in case it is prohibited to create UNIX -// sockets in TMPDIR. -func testUnixAddr() string { - f, err := ioutil.TempFile("", "go-nettest") - if err != nil { - panic(err) - } - addr := f.Name() - f.Close() - os.Remove(addr) - return addr -} - -// testableNetwork reports whether network is testable on the current -// platform configuration. -// This is based on logic from standard library's net/platform_test.go. -func testableNetwork(network string) bool { - switch network { - case "unix": - switch runtime.GOOS { - case "android", "nacl", "plan9", "windows": - return false - } - if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { - return false - } - case "unixpacket": - switch runtime.GOOS { - case "android", "darwin", "nacl", "plan9", "windows", "freebsd": - return false - } - } - return true -} -func newLocalListener(network string) (net.Listener, error) { - switch network { - case "tcp": - ln, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - ln, err = net.Listen("tcp6", "[::1]:0") - } - return ln, err - case "unix", "unixpacket": - return net.Listen(network, testUnixAddr()) - } - return nil, fmt.Errorf("%s is not supported", network) -} + "golang_org/x/net/internal/nettest" +) func TestTestConn(t *testing.T) { tests := []struct{ name, network string }{ @@ -74,12 +24,12 @@ func TestTestConn(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if !testableNetwork(tt.network) { + if !nettest.TestableNetwork(tt.network) { t.Skipf("not supported on %s", runtime.GOOS) } mp := func() (c1, c2 net.Conn, stop func(), err error) { - ln, err := newLocalListener(tt.network) + ln, err := nettest.NewLocalListener(tt.network) if err != nil { return nil, nil, nil, err } diff --git a/libgo/go/golang_org/x/net/route/defs_openbsd.go b/libgo/go/golang_org/x/net/route/defs_openbsd.go index 0f66d3619c7..173bb5d5138 100644 --- a/libgo/go/golang_org/x/net/route/defs_openbsd.go +++ b/libgo/go/golang_org/x/net/route/defs_openbsd.go @@ -69,6 +69,9 @@ const ( sysRTM_IFINFO = C.RTM_IFINFO sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE sysRTM_DESYNC = C.RTM_DESYNC + sysRTM_INVALIDATE = C.RTM_INVALIDATE + sysRTM_BFD = C.RTM_BFD + sysRTM_PROPOSAL = C.RTM_PROPOSAL sysRTA_DST = C.RTA_DST sysRTA_GATEWAY = C.RTA_GATEWAY @@ -81,6 +84,10 @@ const ( sysRTA_SRC = C.RTA_SRC sysRTA_SRCMASK = C.RTA_SRCMASK sysRTA_LABEL = C.RTA_LABEL + sysRTA_BFD = C.RTA_BFD + sysRTA_DNS = C.RTA_DNS + sysRTA_STATIC = C.RTA_STATIC + sysRTA_SEARCH = C.RTA_SEARCH sysRTAX_DST = C.RTAX_DST sysRTAX_GATEWAY = C.RTAX_GATEWAY @@ -93,6 +100,10 @@ const ( sysRTAX_SRC = C.RTAX_SRC sysRTAX_SRCMASK = C.RTAX_SRCMASK sysRTAX_LABEL = C.RTAX_LABEL + sysRTAX_BFD = C.RTAX_BFD + sysRTAX_DNS = C.RTAX_DNS + sysRTAX_STATIC = C.RTAX_STATIC + sysRTAX_SEARCH = C.RTAX_SEARCH sysRTAX_MAX = C.RTAX_MAX ) diff --git a/libgo/go/golang_org/x/net/route/route_classic.go b/libgo/go/golang_org/x/net/route/route_classic.go index 61b2bb4add0..02fa688309c 100644 --- a/libgo/go/golang_org/x/net/route/route_classic.go +++ b/libgo/go/golang_org/x/net/route/route_classic.go @@ -6,7 +6,10 @@ package route -import "syscall" +import ( + "runtime" + "syscall" +) func (m *RouteMessage) marshal() ([]byte, error) { w, ok := wireFormats[m.Type] @@ -14,6 +17,11 @@ func (m *RouteMessage) marshal() ([]byte, error) { return nil, errUnsupportedMessage } l := w.bodyOff + addrsSpace(m.Addrs) + if runtime.GOOS == "darwin" { + // Fix stray pointer writes on macOS. + // See golang.org/issue/22456. + l += 1024 + } b := make([]byte, l) nativeEndian.PutUint16(b[:2], uint16(l)) if m.Version == 0 { diff --git a/libgo/go/golang_org/x/net/route/route_test.go b/libgo/go/golang_org/x/net/route/route_test.go index 63fd8c5618a..61bd1745431 100644 --- a/libgo/go/golang_org/x/net/route/route_test.go +++ b/libgo/go/golang_org/x/net/route/route_test.go @@ -74,6 +74,10 @@ var addrAttrNames = [...]string{ "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd + "o:bfd", // bfd for openbsd + "o:dns", // dns for openbsd + "o:static", // static for openbsd + "o:search", // search for openbsd } func (attrs addrAttrs) String() string { diff --git a/libgo/go/golang_org/x/net/route/sys_darwin.go b/libgo/go/golang_org/x/net/route/sys_darwin.go index e742c919db8..d2daf5c05aa 100644 --- a/libgo/go/golang_org/x/net/route/sys_darwin.go +++ b/libgo/go/golang_org/x/net/route/sys_darwin.go @@ -13,7 +13,7 @@ func (typ RIBType) parseable() bool { } } -// A RouteMetrics represents route metrics. +// RouteMetrics represents route metrics. type RouteMetrics struct { PathMTU int // path maximum transmission unit } @@ -30,7 +30,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// A InterfaceMetrics represents interface metrics. +// InterfaceMetrics represents interface metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit diff --git a/libgo/go/golang_org/x/net/route/sys_dragonfly.go b/libgo/go/golang_org/x/net/route/sys_dragonfly.go index b175cb18cee..0c14bc2b4d4 100644 --- a/libgo/go/golang_org/x/net/route/sys_dragonfly.go +++ b/libgo/go/golang_org/x/net/route/sys_dragonfly.go @@ -8,7 +8,7 @@ import "unsafe" func (typ RIBType) parseable() bool { return true } -// A RouteMetrics represents route metrics. +// RouteMetrics represents route metrics. type RouteMetrics struct { PathMTU int // path maximum transmission unit } @@ -25,7 +25,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// A InterfaceMetrics represents interface metrics. +// InterfaceMetrics represents interface metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit diff --git a/libgo/go/golang_org/x/net/route/sys_freebsd.go b/libgo/go/golang_org/x/net/route/sys_freebsd.go index 010d4ae7827..89ba1c4e262 100644 --- a/libgo/go/golang_org/x/net/route/sys_freebsd.go +++ b/libgo/go/golang_org/x/net/route/sys_freebsd.go @@ -11,7 +11,7 @@ import ( func (typ RIBType) parseable() bool { return true } -// A RouteMetrics represents route metrics. +// RouteMetrics represents route metrics. type RouteMetrics struct { PathMTU int // path maximum transmission unit } @@ -35,7 +35,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// A InterfaceMetrics represents interface metrics. +// InterfaceMetrics represents interface metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit diff --git a/libgo/go/golang_org/x/net/route/sys_netbsd.go b/libgo/go/golang_org/x/net/route/sys_netbsd.go index b4e33014031..02f71d54bbd 100644 --- a/libgo/go/golang_org/x/net/route/sys_netbsd.go +++ b/libgo/go/golang_org/x/net/route/sys_netbsd.go @@ -6,7 +6,7 @@ package route func (typ RIBType) parseable() bool { return true } -// A RouteMetrics represents route metrics. +// RouteMetrics represents route metrics. type RouteMetrics struct { PathMTU int // path maximum transmission unit } @@ -23,7 +23,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// A InterfaceMetrics represents interface metrics. +// RouteMetrics represents route metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit diff --git a/libgo/go/golang_org/x/net/route/sys_openbsd.go b/libgo/go/golang_org/x/net/route/sys_openbsd.go index 8798dc4ca37..c5674e83d01 100644 --- a/libgo/go/golang_org/x/net/route/sys_openbsd.go +++ b/libgo/go/golang_org/x/net/route/sys_openbsd.go @@ -15,7 +15,7 @@ func (typ RIBType) parseable() bool { } } -// A RouteMetrics represents route metrics. +// RouteMetrics represents route metrics. type RouteMetrics struct { PathMTU int // path maximum transmission unit } @@ -32,7 +32,7 @@ func (m *RouteMessage) Sys() []Sys { } } -// A InterfaceMetrics represents interface metrics. +// InterfaceMetrics represents interface metrics. type InterfaceMetrics struct { Type int // interface type MTU int // maximum transmission unit @@ -75,5 +75,6 @@ func probeRoutingStack() (int, map[int]*wireFormat) { sysRTM_DELADDR: ifam, sysRTM_IFINFO: ifm, sysRTM_IFANNOUNCE: ifanm, + sysRTM_DESYNC: rtm, } } diff --git a/libgo/go/golang_org/x/net/route/zsys_openbsd.go b/libgo/go/golang_org/x/net/route/zsys_openbsd.go index f5a1ff96731..db8c8efb49b 100644 --- a/libgo/go/golang_org/x/net/route/zsys_openbsd.go +++ b/libgo/go/golang_org/x/net/route/zsys_openbsd.go @@ -54,6 +54,9 @@ const ( sysRTM_IFINFO = 0xe sysRTM_IFANNOUNCE = 0xf sysRTM_DESYNC = 0x10 + sysRTM_INVALIDATE = 0x11 + sysRTM_BFD = 0x12 + sysRTM_PROPOSAL = 0x13 sysRTA_DST = 0x1 sysRTA_GATEWAY = 0x2 @@ -66,6 +69,10 @@ const ( sysRTA_SRC = 0x100 sysRTA_SRCMASK = 0x200 sysRTA_LABEL = 0x400 + sysRTA_BFD = 0x800 + sysRTA_DNS = 0x1000 + sysRTA_STATIC = 0x2000 + sysRTA_SEARCH = 0x4000 sysRTAX_DST = 0x0 sysRTAX_GATEWAY = 0x1 @@ -78,7 +85,11 @@ const ( sysRTAX_SRC = 0x8 sysRTAX_SRCMASK = 0x9 sysRTAX_LABEL = 0xa - sysRTAX_MAX = 0xb + sysRTAX_BFD = 0xb + sysRTAX_DNS = 0xc + sysRTAX_STATIC = 0xd + sysRTAX_SEARCH = 0xe + sysRTAX_MAX = 0xf ) const ( diff --git a/libgo/go/golang_org/x/text/secure/bidirule/bidirule.go b/libgo/go/golang_org/x/text/secure/bidirule/bidirule.go index 9f9594e6179..c3ca2bc6fed 100644 --- a/libgo/go/golang_org/x/text/secure/bidirule/bidirule.go +++ b/libgo/go/golang_org/x/text/secure/bidirule/bidirule.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -157,6 +157,7 @@ func DirectionString(s string) bidi.Direction { e, sz := bidi.LookupString(s[i:]) if sz == 0 { i++ + continue } c := e.Class() if c == bidi.R || c == bidi.AL || c == bidi.AN { @@ -205,9 +206,6 @@ func (t *Transformer) isRTL() bool { } func (t *Transformer) isFinal() bool { - if !t.isRTL() { - return true - } return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial } diff --git a/libgo/go/golang_org/x/text/secure/doc.go b/libgo/go/golang_org/x/text/secure/doc.go index 4912b9b9a76..5eb60b94bf2 100644 --- a/libgo/go/golang_org/x/text/secure/doc.go +++ b/libgo/go/golang_org/x/text/secure/doc.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/transform/transform.go b/libgo/go/golang_org/x/text/transform/transform.go index 2a1b190b0d7..9ddfa80cf3e 100644 --- a/libgo/go/golang_org/x/text/transform/transform.go +++ b/libgo/go/golang_org/x/text/transform/transform.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/bidi/bidi.go b/libgo/go/golang_org/x/text/unicode/bidi/bidi.go index 4c9735ef0b0..e691ae86942 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/bidi.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/bidi.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/bidi/bracket.go b/libgo/go/golang_org/x/text/unicode/bidi/bracket.go index f08a93d9bee..0784e797b72 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/bracket.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/bracket.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/bidi/core.go b/libgo/go/golang_org/x/text/unicode/bidi/core.go index a352ad622a9..9a934b8430d 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/core.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/core.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/bidi/prop.go b/libgo/go/golang_org/x/text/unicode/bidi/prop.go index ed191c220d3..878b8c41b94 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/prop.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/prop.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/bidi/tables.go b/libgo/go/golang_org/x/text/unicode/bidi/tables.go index 124531574c3..fb2229efa87 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/tables.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/tables.go @@ -1,11 +1,11 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT. package bidi // UnicodeVersion is the Unicode version from which the tables in this package are derived. -const UnicodeVersion = "9.0.0" +const UnicodeVersion = "10.0.0" // xorMasks contains masks to be xor-ed with brackets to get the reverse // version. @@ -183,7 +183,7 @@ func (t *bidiTrie) lookupStringUnsafe(s string) uint8 { return 0 } -// bidiTrie. Total size: 15744 bytes (15.38 KiB). Checksum: b4c3b70954803b86. +// bidiTrie. Total size: 16128 bytes (15.75 KiB). Checksum: 8122d83e461996f. type bidiTrie struct{} func newBidiTrie(i int) *bidiTrie { @@ -198,9 +198,9 @@ func (t *bidiTrie) lookupValue(n uint32, b byte) uint8 { } } -// bidiValues: 222 blocks, 14208 entries, 14208 bytes +// bidiValues: 228 blocks, 14592 entries, 14592 bytes // The third block is the zero block. -var bidiValues = [14208]uint8{ +var bidiValues = [14592]uint8{ // Block 0x0, offset 0x0 0x00: 0x000b, 0x01: 0x000b, 0x02: 0x000b, 0x03: 0x000b, 0x04: 0x000b, 0x05: 0x000b, 0x06: 0x000b, 0x07: 0x000b, 0x08: 0x000b, 0x09: 0x0008, 0x0a: 0x0007, 0x0b: 0x0008, @@ -417,9 +417,9 @@ var bidiValues = [14208]uint8{ 0x5cc: 0x0001, 0x5cd: 0x0001, 0x5ce: 0x0001, 0x5cf: 0x0001, 0x5d0: 0x0001, 0x5d1: 0x0001, 0x5d2: 0x0001, 0x5d3: 0x0001, 0x5d4: 0x0001, 0x5d5: 0x0001, 0x5d6: 0x0001, 0x5d7: 0x0001, 0x5d8: 0x0001, 0x5d9: 0x000c, 0x5da: 0x000c, 0x5db: 0x000c, 0x5dc: 0x0001, 0x5dd: 0x0001, - 0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x0001, 0x5e1: 0x0001, 0x5e2: 0x0001, 0x5e3: 0x0001, - 0x5e4: 0x0001, 0x5e5: 0x0001, 0x5e6: 0x0001, 0x5e7: 0x0001, 0x5e8: 0x0001, 0x5e9: 0x0001, - 0x5ea: 0x0001, 0x5eb: 0x0001, 0x5ec: 0x0001, 0x5ed: 0x0001, 0x5ee: 0x0001, 0x5ef: 0x0001, + 0x5de: 0x0001, 0x5df: 0x0001, 0x5e0: 0x000d, 0x5e1: 0x000d, 0x5e2: 0x000d, 0x5e3: 0x000d, + 0x5e4: 0x000d, 0x5e5: 0x000d, 0x5e6: 0x000d, 0x5e7: 0x000d, 0x5e8: 0x000d, 0x5e9: 0x000d, + 0x5ea: 0x000d, 0x5eb: 0x000d, 0x5ec: 0x000d, 0x5ed: 0x000d, 0x5ee: 0x000d, 0x5ef: 0x000d, 0x5f0: 0x0001, 0x5f1: 0x0001, 0x5f2: 0x0001, 0x5f3: 0x0001, 0x5f4: 0x0001, 0x5f5: 0x0001, 0x5f6: 0x0001, 0x5f7: 0x0001, 0x5f8: 0x0001, 0x5f9: 0x0001, 0x5fa: 0x0001, 0x5fb: 0x0001, 0x5fc: 0x0001, 0x5fd: 0x0001, 0x5fe: 0x0001, 0x5ff: 0x0001, @@ -480,6 +480,8 @@ var bidiValues = [14208]uint8{ 0x80d: 0x000c, 0x822: 0x000c, 0x823: 0x000c, 0x831: 0x0004, + 0x83a: 0x000c, 0x83b: 0x000c, + 0x83c: 0x000c, 0x83d: 0x000c, 0x83e: 0x000c, 0x83f: 0x000c, // Block 0x21, offset 0x840 0x841: 0x000c, 0x87c: 0x000c, 0x87f: 0x000c, @@ -510,7 +512,9 @@ var bidiValues = [14208]uint8{ 0x9cc: 0x000c, 0x9cd: 0x000c, 0x9e2: 0x000c, 0x9e3: 0x000c, // Block 0x28, offset 0xa00 - 0xa01: 0x000c, + 0xa00: 0x000c, 0xa01: 0x000c, + 0xa3b: 0x000c, + 0xa3c: 0x000c, // Block 0x29, offset 0xa40 0xa41: 0x000c, 0xa42: 0x000c, 0xa43: 0x000c, 0xa44: 0x000c, 0xa4d: 0x000c, @@ -677,7 +681,7 @@ var bidiValues = [14208]uint8{ 0x1324: 0x000c, 0x1325: 0x000c, 0x1326: 0x000c, 0x1327: 0x000c, 0x1328: 0x000c, 0x1329: 0x000c, 0x132a: 0x000c, 0x132b: 0x000c, 0x132c: 0x000c, 0x132d: 0x000c, 0x132e: 0x000c, 0x132f: 0x000c, 0x1330: 0x000c, 0x1331: 0x000c, 0x1332: 0x000c, 0x1333: 0x000c, 0x1334: 0x000c, 0x1335: 0x000c, - 0x133b: 0x000c, + 0x1336: 0x000c, 0x1337: 0x000c, 0x1338: 0x000c, 0x1339: 0x000c, 0x133b: 0x000c, 0x133c: 0x000c, 0x133d: 0x000c, 0x133e: 0x000c, 0x133f: 0x000c, // Block 0x4d, offset 0x1340 0x137d: 0x000a, 0x137f: 0x000a, @@ -815,36 +819,36 @@ var bidiValues = [14208]uint8{ 0x16d2: 0x000a, 0x16d3: 0x000a, 0x16d4: 0x000a, 0x16d5: 0x000a, 0x16d6: 0x000a, 0x16d7: 0x000a, 0x16d8: 0x000a, 0x16d9: 0x000a, 0x16da: 0x000a, 0x16db: 0x000a, 0x16dc: 0x000a, 0x16dd: 0x000a, 0x16de: 0x000a, 0x16df: 0x000a, 0x16e0: 0x000a, 0x16e1: 0x000a, 0x16e2: 0x000a, 0x16e3: 0x000a, - 0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, 0x16e7: 0x000a, 0x16e8: 0x000a, 0x16e9: 0x000a, - 0x16ea: 0x000a, 0x16eb: 0x000a, 0x16ec: 0x000a, 0x16ed: 0x000a, 0x16ee: 0x000a, 0x16ef: 0x000a, - 0x16f0: 0x000a, 0x16f1: 0x000a, 0x16f2: 0x000a, 0x16f3: 0x000a, 0x16f4: 0x000a, 0x16f5: 0x000a, - 0x16f6: 0x000a, 0x16f7: 0x000a, 0x16f8: 0x000a, 0x16f9: 0x000a, 0x16fa: 0x000a, 0x16fb: 0x000a, - 0x16fc: 0x000a, 0x16fd: 0x000a, 0x16fe: 0x000a, + 0x16e4: 0x000a, 0x16e5: 0x000a, 0x16e6: 0x000a, // Block 0x5c, offset 0x1700 0x1700: 0x000a, 0x1701: 0x000a, 0x1702: 0x000a, 0x1703: 0x000a, 0x1704: 0x000a, 0x1705: 0x000a, - 0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, 0x170b: 0x000a, - 0x170c: 0x000a, 0x170d: 0x000a, 0x170e: 0x000a, 0x170f: 0x000a, 0x1710: 0x000a, 0x1711: 0x000a, - 0x1712: 0x000a, 0x1713: 0x000a, 0x1714: 0x000a, 0x1715: 0x000a, 0x1716: 0x000a, 0x1717: 0x000a, - 0x1718: 0x000a, 0x1719: 0x000a, 0x171a: 0x000a, 0x171b: 0x000a, 0x171c: 0x000a, 0x171d: 0x000a, - 0x171e: 0x000a, 0x171f: 0x000a, 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a, - 0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a, + 0x1706: 0x000a, 0x1707: 0x000a, 0x1708: 0x000a, 0x1709: 0x000a, 0x170a: 0x000a, + 0x1720: 0x000a, 0x1721: 0x000a, 0x1722: 0x000a, 0x1723: 0x000a, + 0x1724: 0x000a, 0x1725: 0x000a, 0x1726: 0x000a, 0x1727: 0x000a, 0x1728: 0x000a, 0x1729: 0x000a, + 0x172a: 0x000a, 0x172b: 0x000a, 0x172c: 0x000a, 0x172d: 0x000a, 0x172e: 0x000a, 0x172f: 0x000a, + 0x1730: 0x000a, 0x1731: 0x000a, 0x1732: 0x000a, 0x1733: 0x000a, 0x1734: 0x000a, 0x1735: 0x000a, + 0x1736: 0x000a, 0x1737: 0x000a, 0x1738: 0x000a, 0x1739: 0x000a, 0x173a: 0x000a, 0x173b: 0x000a, + 0x173c: 0x000a, 0x173d: 0x000a, 0x173e: 0x000a, 0x173f: 0x000a, // Block 0x5d, offset 0x1740 0x1740: 0x000a, 0x1741: 0x000a, 0x1742: 0x000a, 0x1743: 0x000a, 0x1744: 0x000a, 0x1745: 0x000a, - 0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x000a, 0x1749: 0x000a, 0x174a: 0x000a, - 0x1760: 0x000a, 0x1761: 0x000a, 0x1762: 0x000a, 0x1763: 0x000a, - 0x1764: 0x000a, 0x1765: 0x000a, 0x1766: 0x000a, 0x1767: 0x000a, 0x1768: 0x000a, 0x1769: 0x000a, - 0x176a: 0x000a, 0x176b: 0x000a, 0x176c: 0x000a, 0x176d: 0x000a, 0x176e: 0x000a, 0x176f: 0x000a, - 0x1770: 0x000a, 0x1771: 0x000a, 0x1772: 0x000a, 0x1773: 0x000a, 0x1774: 0x000a, 0x1775: 0x000a, - 0x1776: 0x000a, 0x1777: 0x000a, 0x1778: 0x000a, 0x1779: 0x000a, 0x177a: 0x000a, 0x177b: 0x000a, - 0x177c: 0x000a, 0x177d: 0x000a, 0x177e: 0x000a, 0x177f: 0x000a, + 0x1746: 0x000a, 0x1747: 0x000a, 0x1748: 0x0002, 0x1749: 0x0002, 0x174a: 0x0002, 0x174b: 0x0002, + 0x174c: 0x0002, 0x174d: 0x0002, 0x174e: 0x0002, 0x174f: 0x0002, 0x1750: 0x0002, 0x1751: 0x0002, + 0x1752: 0x0002, 0x1753: 0x0002, 0x1754: 0x0002, 0x1755: 0x0002, 0x1756: 0x0002, 0x1757: 0x0002, + 0x1758: 0x0002, 0x1759: 0x0002, 0x175a: 0x0002, 0x175b: 0x0002, // Block 0x5e, offset 0x1780 - 0x1780: 0x000a, 0x1781: 0x000a, 0x1782: 0x000a, 0x1783: 0x000a, 0x1784: 0x000a, 0x1785: 0x000a, - 0x1786: 0x000a, 0x1787: 0x000a, 0x1788: 0x0002, 0x1789: 0x0002, 0x178a: 0x0002, 0x178b: 0x0002, - 0x178c: 0x0002, 0x178d: 0x0002, 0x178e: 0x0002, 0x178f: 0x0002, 0x1790: 0x0002, 0x1791: 0x0002, - 0x1792: 0x0002, 0x1793: 0x0002, 0x1794: 0x0002, 0x1795: 0x0002, 0x1796: 0x0002, 0x1797: 0x0002, - 0x1798: 0x0002, 0x1799: 0x0002, 0x179a: 0x0002, 0x179b: 0x0002, + 0x17aa: 0x000a, 0x17ab: 0x000a, 0x17ac: 0x000a, 0x17ad: 0x000a, 0x17ae: 0x000a, 0x17af: 0x000a, + 0x17b0: 0x000a, 0x17b1: 0x000a, 0x17b2: 0x000a, 0x17b3: 0x000a, 0x17b4: 0x000a, 0x17b5: 0x000a, + 0x17b6: 0x000a, 0x17b7: 0x000a, 0x17b8: 0x000a, 0x17b9: 0x000a, 0x17ba: 0x000a, 0x17bb: 0x000a, + 0x17bc: 0x000a, 0x17bd: 0x000a, 0x17be: 0x000a, 0x17bf: 0x000a, // Block 0x5f, offset 0x17c0 - 0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ec: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a, + 0x17c0: 0x000a, 0x17c1: 0x000a, 0x17c2: 0x000a, 0x17c3: 0x000a, 0x17c4: 0x000a, 0x17c5: 0x000a, + 0x17c6: 0x000a, 0x17c7: 0x000a, 0x17c8: 0x000a, 0x17c9: 0x000a, 0x17ca: 0x000a, 0x17cb: 0x000a, + 0x17cc: 0x000a, 0x17cd: 0x000a, 0x17ce: 0x000a, 0x17cf: 0x000a, 0x17d0: 0x000a, 0x17d1: 0x000a, + 0x17d2: 0x000a, 0x17d3: 0x000a, 0x17d4: 0x000a, 0x17d5: 0x000a, 0x17d6: 0x000a, 0x17d7: 0x000a, + 0x17d8: 0x000a, 0x17d9: 0x000a, 0x17da: 0x000a, 0x17db: 0x000a, 0x17dc: 0x000a, 0x17dd: 0x000a, + 0x17de: 0x000a, 0x17df: 0x000a, 0x17e0: 0x000a, 0x17e1: 0x000a, 0x17e2: 0x000a, 0x17e3: 0x000a, + 0x17e4: 0x000a, 0x17e5: 0x000a, 0x17e6: 0x000a, 0x17e7: 0x000a, 0x17e8: 0x000a, 0x17e9: 0x000a, + 0x17ea: 0x000a, 0x17eb: 0x000a, 0x17ed: 0x000a, 0x17ee: 0x000a, 0x17ef: 0x000a, 0x17f0: 0x000a, 0x17f1: 0x000a, 0x17f2: 0x000a, 0x17f3: 0x000a, 0x17f4: 0x000a, 0x17f5: 0x000a, 0x17f6: 0x000a, 0x17f7: 0x000a, 0x17f8: 0x000a, 0x17f9: 0x000a, 0x17fa: 0x000a, 0x17fb: 0x000a, 0x17fc: 0x000a, 0x17fd: 0x000a, 0x17fe: 0x000a, 0x17ff: 0x000a, @@ -855,282 +859,284 @@ var bidiValues = [14208]uint8{ 0x1812: 0x000a, 0x1813: 0x000a, 0x1814: 0x000a, 0x1815: 0x000a, 0x1816: 0x000a, 0x1817: 0x000a, 0x1818: 0x000a, 0x1819: 0x000a, 0x181a: 0x000a, 0x181b: 0x000a, 0x181c: 0x000a, 0x181d: 0x000a, 0x181e: 0x000a, 0x181f: 0x000a, 0x1820: 0x000a, 0x1821: 0x000a, 0x1822: 0x000a, 0x1823: 0x000a, - 0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x000a, 0x1829: 0x000a, - 0x182a: 0x000a, 0x182b: 0x000a, 0x182d: 0x000a, 0x182e: 0x000a, 0x182f: 0x000a, - 0x1830: 0x000a, 0x1831: 0x000a, 0x1832: 0x000a, 0x1833: 0x000a, 0x1834: 0x000a, 0x1835: 0x000a, + 0x1824: 0x000a, 0x1825: 0x000a, 0x1826: 0x000a, 0x1827: 0x000a, 0x1828: 0x003a, 0x1829: 0x002a, + 0x182a: 0x003a, 0x182b: 0x002a, 0x182c: 0x003a, 0x182d: 0x002a, 0x182e: 0x003a, 0x182f: 0x002a, + 0x1830: 0x003a, 0x1831: 0x002a, 0x1832: 0x003a, 0x1833: 0x002a, 0x1834: 0x003a, 0x1835: 0x002a, 0x1836: 0x000a, 0x1837: 0x000a, 0x1838: 0x000a, 0x1839: 0x000a, 0x183a: 0x000a, 0x183b: 0x000a, 0x183c: 0x000a, 0x183d: 0x000a, 0x183e: 0x000a, 0x183f: 0x000a, // Block 0x61, offset 0x1840 - 0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x000a, - 0x1846: 0x000a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a, + 0x1840: 0x000a, 0x1841: 0x000a, 0x1842: 0x000a, 0x1843: 0x000a, 0x1844: 0x000a, 0x1845: 0x009a, + 0x1846: 0x008a, 0x1847: 0x000a, 0x1848: 0x000a, 0x1849: 0x000a, 0x184a: 0x000a, 0x184b: 0x000a, 0x184c: 0x000a, 0x184d: 0x000a, 0x184e: 0x000a, 0x184f: 0x000a, 0x1850: 0x000a, 0x1851: 0x000a, 0x1852: 0x000a, 0x1853: 0x000a, 0x1854: 0x000a, 0x1855: 0x000a, 0x1856: 0x000a, 0x1857: 0x000a, 0x1858: 0x000a, 0x1859: 0x000a, 0x185a: 0x000a, 0x185b: 0x000a, 0x185c: 0x000a, 0x185d: 0x000a, 0x185e: 0x000a, 0x185f: 0x000a, 0x1860: 0x000a, 0x1861: 0x000a, 0x1862: 0x000a, 0x1863: 0x000a, - 0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x000a, 0x1867: 0x000a, 0x1868: 0x003a, 0x1869: 0x002a, + 0x1864: 0x000a, 0x1865: 0x000a, 0x1866: 0x003a, 0x1867: 0x002a, 0x1868: 0x003a, 0x1869: 0x002a, 0x186a: 0x003a, 0x186b: 0x002a, 0x186c: 0x003a, 0x186d: 0x002a, 0x186e: 0x003a, 0x186f: 0x002a, - 0x1870: 0x003a, 0x1871: 0x002a, 0x1872: 0x003a, 0x1873: 0x002a, 0x1874: 0x003a, 0x1875: 0x002a, + 0x1870: 0x000a, 0x1871: 0x000a, 0x1872: 0x000a, 0x1873: 0x000a, 0x1874: 0x000a, 0x1875: 0x000a, 0x1876: 0x000a, 0x1877: 0x000a, 0x1878: 0x000a, 0x1879: 0x000a, 0x187a: 0x000a, 0x187b: 0x000a, 0x187c: 0x000a, 0x187d: 0x000a, 0x187e: 0x000a, 0x187f: 0x000a, // Block 0x62, offset 0x1880 - 0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x000a, 0x1884: 0x000a, 0x1885: 0x009a, - 0x1886: 0x008a, 0x1887: 0x000a, 0x1888: 0x000a, 0x1889: 0x000a, 0x188a: 0x000a, 0x188b: 0x000a, - 0x188c: 0x000a, 0x188d: 0x000a, 0x188e: 0x000a, 0x188f: 0x000a, 0x1890: 0x000a, 0x1891: 0x000a, - 0x1892: 0x000a, 0x1893: 0x000a, 0x1894: 0x000a, 0x1895: 0x000a, 0x1896: 0x000a, 0x1897: 0x000a, - 0x1898: 0x000a, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a, + 0x1880: 0x000a, 0x1881: 0x000a, 0x1882: 0x000a, 0x1883: 0x007a, 0x1884: 0x006a, 0x1885: 0x009a, + 0x1886: 0x008a, 0x1887: 0x00ba, 0x1888: 0x00aa, 0x1889: 0x009a, 0x188a: 0x008a, 0x188b: 0x007a, + 0x188c: 0x006a, 0x188d: 0x00da, 0x188e: 0x002a, 0x188f: 0x003a, 0x1890: 0x00ca, 0x1891: 0x009a, + 0x1892: 0x008a, 0x1893: 0x007a, 0x1894: 0x006a, 0x1895: 0x009a, 0x1896: 0x008a, 0x1897: 0x00ba, + 0x1898: 0x00aa, 0x1899: 0x000a, 0x189a: 0x000a, 0x189b: 0x000a, 0x189c: 0x000a, 0x189d: 0x000a, 0x189e: 0x000a, 0x189f: 0x000a, 0x18a0: 0x000a, 0x18a1: 0x000a, 0x18a2: 0x000a, 0x18a3: 0x000a, - 0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x003a, 0x18a7: 0x002a, 0x18a8: 0x003a, 0x18a9: 0x002a, - 0x18aa: 0x003a, 0x18ab: 0x002a, 0x18ac: 0x003a, 0x18ad: 0x002a, 0x18ae: 0x003a, 0x18af: 0x002a, + 0x18a4: 0x000a, 0x18a5: 0x000a, 0x18a6: 0x000a, 0x18a7: 0x000a, 0x18a8: 0x000a, 0x18a9: 0x000a, + 0x18aa: 0x000a, 0x18ab: 0x000a, 0x18ac: 0x000a, 0x18ad: 0x000a, 0x18ae: 0x000a, 0x18af: 0x000a, 0x18b0: 0x000a, 0x18b1: 0x000a, 0x18b2: 0x000a, 0x18b3: 0x000a, 0x18b4: 0x000a, 0x18b5: 0x000a, 0x18b6: 0x000a, 0x18b7: 0x000a, 0x18b8: 0x000a, 0x18b9: 0x000a, 0x18ba: 0x000a, 0x18bb: 0x000a, 0x18bc: 0x000a, 0x18bd: 0x000a, 0x18be: 0x000a, 0x18bf: 0x000a, // Block 0x63, offset 0x18c0 - 0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x007a, 0x18c4: 0x006a, 0x18c5: 0x009a, - 0x18c6: 0x008a, 0x18c7: 0x00ba, 0x18c8: 0x00aa, 0x18c9: 0x009a, 0x18ca: 0x008a, 0x18cb: 0x007a, - 0x18cc: 0x006a, 0x18cd: 0x00da, 0x18ce: 0x002a, 0x18cf: 0x003a, 0x18d0: 0x00ca, 0x18d1: 0x009a, - 0x18d2: 0x008a, 0x18d3: 0x007a, 0x18d4: 0x006a, 0x18d5: 0x009a, 0x18d6: 0x008a, 0x18d7: 0x00ba, - 0x18d8: 0x00aa, 0x18d9: 0x000a, 0x18da: 0x000a, 0x18db: 0x000a, 0x18dc: 0x000a, 0x18dd: 0x000a, + 0x18c0: 0x000a, 0x18c1: 0x000a, 0x18c2: 0x000a, 0x18c3: 0x000a, 0x18c4: 0x000a, 0x18c5: 0x000a, + 0x18c6: 0x000a, 0x18c7: 0x000a, 0x18c8: 0x000a, 0x18c9: 0x000a, 0x18ca: 0x000a, 0x18cb: 0x000a, + 0x18cc: 0x000a, 0x18cd: 0x000a, 0x18ce: 0x000a, 0x18cf: 0x000a, 0x18d0: 0x000a, 0x18d1: 0x000a, + 0x18d2: 0x000a, 0x18d3: 0x000a, 0x18d4: 0x000a, 0x18d5: 0x000a, 0x18d6: 0x000a, 0x18d7: 0x000a, + 0x18d8: 0x003a, 0x18d9: 0x002a, 0x18da: 0x003a, 0x18db: 0x002a, 0x18dc: 0x000a, 0x18dd: 0x000a, 0x18de: 0x000a, 0x18df: 0x000a, 0x18e0: 0x000a, 0x18e1: 0x000a, 0x18e2: 0x000a, 0x18e3: 0x000a, 0x18e4: 0x000a, 0x18e5: 0x000a, 0x18e6: 0x000a, 0x18e7: 0x000a, 0x18e8: 0x000a, 0x18e9: 0x000a, 0x18ea: 0x000a, 0x18eb: 0x000a, 0x18ec: 0x000a, 0x18ed: 0x000a, 0x18ee: 0x000a, 0x18ef: 0x000a, 0x18f0: 0x000a, 0x18f1: 0x000a, 0x18f2: 0x000a, 0x18f3: 0x000a, 0x18f4: 0x000a, 0x18f5: 0x000a, 0x18f6: 0x000a, 0x18f7: 0x000a, 0x18f8: 0x000a, 0x18f9: 0x000a, 0x18fa: 0x000a, 0x18fb: 0x000a, - 0x18fc: 0x000a, 0x18fd: 0x000a, 0x18fe: 0x000a, 0x18ff: 0x000a, + 0x18fc: 0x003a, 0x18fd: 0x002a, 0x18fe: 0x000a, 0x18ff: 0x000a, // Block 0x64, offset 0x1900 0x1900: 0x000a, 0x1901: 0x000a, 0x1902: 0x000a, 0x1903: 0x000a, 0x1904: 0x000a, 0x1905: 0x000a, 0x1906: 0x000a, 0x1907: 0x000a, 0x1908: 0x000a, 0x1909: 0x000a, 0x190a: 0x000a, 0x190b: 0x000a, 0x190c: 0x000a, 0x190d: 0x000a, 0x190e: 0x000a, 0x190f: 0x000a, 0x1910: 0x000a, 0x1911: 0x000a, 0x1912: 0x000a, 0x1913: 0x000a, 0x1914: 0x000a, 0x1915: 0x000a, 0x1916: 0x000a, 0x1917: 0x000a, - 0x1918: 0x003a, 0x1919: 0x002a, 0x191a: 0x003a, 0x191b: 0x002a, 0x191c: 0x000a, 0x191d: 0x000a, + 0x1918: 0x000a, 0x1919: 0x000a, 0x191a: 0x000a, 0x191b: 0x000a, 0x191c: 0x000a, 0x191d: 0x000a, 0x191e: 0x000a, 0x191f: 0x000a, 0x1920: 0x000a, 0x1921: 0x000a, 0x1922: 0x000a, 0x1923: 0x000a, 0x1924: 0x000a, 0x1925: 0x000a, 0x1926: 0x000a, 0x1927: 0x000a, 0x1928: 0x000a, 0x1929: 0x000a, 0x192a: 0x000a, 0x192b: 0x000a, 0x192c: 0x000a, 0x192d: 0x000a, 0x192e: 0x000a, 0x192f: 0x000a, - 0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, 0x1934: 0x000a, 0x1935: 0x000a, + 0x1930: 0x000a, 0x1931: 0x000a, 0x1932: 0x000a, 0x1933: 0x000a, 0x1936: 0x000a, 0x1937: 0x000a, 0x1938: 0x000a, 0x1939: 0x000a, 0x193a: 0x000a, 0x193b: 0x000a, - 0x193c: 0x003a, 0x193d: 0x002a, 0x193e: 0x000a, 0x193f: 0x000a, + 0x193c: 0x000a, 0x193d: 0x000a, 0x193e: 0x000a, 0x193f: 0x000a, // Block 0x65, offset 0x1940 0x1940: 0x000a, 0x1941: 0x000a, 0x1942: 0x000a, 0x1943: 0x000a, 0x1944: 0x000a, 0x1945: 0x000a, 0x1946: 0x000a, 0x1947: 0x000a, 0x1948: 0x000a, 0x1949: 0x000a, 0x194a: 0x000a, 0x194b: 0x000a, 0x194c: 0x000a, 0x194d: 0x000a, 0x194e: 0x000a, 0x194f: 0x000a, 0x1950: 0x000a, 0x1951: 0x000a, - 0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, 0x1956: 0x000a, 0x1957: 0x000a, + 0x1952: 0x000a, 0x1953: 0x000a, 0x1954: 0x000a, 0x1955: 0x000a, 0x1958: 0x000a, 0x1959: 0x000a, 0x195a: 0x000a, 0x195b: 0x000a, 0x195c: 0x000a, 0x195d: 0x000a, 0x195e: 0x000a, 0x195f: 0x000a, 0x1960: 0x000a, 0x1961: 0x000a, 0x1962: 0x000a, 0x1963: 0x000a, 0x1964: 0x000a, 0x1965: 0x000a, 0x1966: 0x000a, 0x1967: 0x000a, 0x1968: 0x000a, 0x1969: 0x000a, 0x196a: 0x000a, 0x196b: 0x000a, 0x196c: 0x000a, 0x196d: 0x000a, 0x196e: 0x000a, 0x196f: 0x000a, - 0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a, - 0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, 0x197a: 0x000a, 0x197b: 0x000a, - 0x197c: 0x000a, 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a, + 0x1970: 0x000a, 0x1971: 0x000a, 0x1972: 0x000a, 0x1973: 0x000a, 0x1974: 0x000a, 0x1975: 0x000a, + 0x1976: 0x000a, 0x1977: 0x000a, 0x1978: 0x000a, 0x1979: 0x000a, + 0x197d: 0x000a, 0x197e: 0x000a, 0x197f: 0x000a, // Block 0x66, offset 0x1980 0x1980: 0x000a, 0x1981: 0x000a, 0x1982: 0x000a, 0x1983: 0x000a, 0x1984: 0x000a, 0x1985: 0x000a, - 0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x1989: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a, + 0x1986: 0x000a, 0x1987: 0x000a, 0x1988: 0x000a, 0x198a: 0x000a, 0x198b: 0x000a, 0x198c: 0x000a, 0x198d: 0x000a, 0x198e: 0x000a, 0x198f: 0x000a, 0x1990: 0x000a, 0x1991: 0x000a, - 0x1992: 0x000a, 0x1993: 0x000a, 0x1994: 0x000a, 0x1995: 0x000a, - 0x1998: 0x000a, 0x1999: 0x000a, 0x199a: 0x000a, 0x199b: 0x000a, 0x199c: 0x000a, 0x199d: 0x000a, - 0x199e: 0x000a, 0x199f: 0x000a, 0x19a0: 0x000a, 0x19a1: 0x000a, 0x19a2: 0x000a, 0x19a3: 0x000a, - 0x19a4: 0x000a, 0x19a5: 0x000a, 0x19a6: 0x000a, 0x19a7: 0x000a, 0x19a8: 0x000a, 0x19a9: 0x000a, - 0x19aa: 0x000a, 0x19ab: 0x000a, 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a, - 0x19b0: 0x000a, 0x19b1: 0x000a, 0x19b2: 0x000a, 0x19b3: 0x000a, 0x19b4: 0x000a, 0x19b5: 0x000a, - 0x19b6: 0x000a, 0x19b7: 0x000a, 0x19b8: 0x000a, 0x19b9: 0x000a, - 0x19bd: 0x000a, 0x19be: 0x000a, 0x19bf: 0x000a, + 0x1992: 0x000a, + 0x19ac: 0x000a, 0x19ad: 0x000a, 0x19ae: 0x000a, 0x19af: 0x000a, // Block 0x67, offset 0x19c0 - 0x19c0: 0x000a, 0x19c1: 0x000a, 0x19c2: 0x000a, 0x19c3: 0x000a, 0x19c4: 0x000a, 0x19c5: 0x000a, - 0x19c6: 0x000a, 0x19c7: 0x000a, 0x19c8: 0x000a, 0x19ca: 0x000a, 0x19cb: 0x000a, - 0x19cc: 0x000a, 0x19cd: 0x000a, 0x19ce: 0x000a, 0x19cf: 0x000a, 0x19d0: 0x000a, 0x19d1: 0x000a, - 0x19ec: 0x000a, 0x19ed: 0x000a, 0x19ee: 0x000a, 0x19ef: 0x000a, + 0x19e5: 0x000a, 0x19e6: 0x000a, 0x19e7: 0x000a, 0x19e8: 0x000a, 0x19e9: 0x000a, + 0x19ea: 0x000a, 0x19ef: 0x000c, + 0x19f0: 0x000c, 0x19f1: 0x000c, + 0x19f9: 0x000a, 0x19fa: 0x000a, 0x19fb: 0x000a, + 0x19fc: 0x000a, 0x19fd: 0x000a, 0x19fe: 0x000a, 0x19ff: 0x000a, // Block 0x68, offset 0x1a00 - 0x1a25: 0x000a, 0x1a26: 0x000a, 0x1a27: 0x000a, 0x1a28: 0x000a, 0x1a29: 0x000a, - 0x1a2a: 0x000a, 0x1a2f: 0x000c, - 0x1a30: 0x000c, 0x1a31: 0x000c, - 0x1a39: 0x000a, 0x1a3a: 0x000a, 0x1a3b: 0x000a, - 0x1a3c: 0x000a, 0x1a3d: 0x000a, 0x1a3e: 0x000a, 0x1a3f: 0x000a, + 0x1a3f: 0x000c, // Block 0x69, offset 0x1a40 - 0x1a7f: 0x000c, + 0x1a60: 0x000c, 0x1a61: 0x000c, 0x1a62: 0x000c, 0x1a63: 0x000c, + 0x1a64: 0x000c, 0x1a65: 0x000c, 0x1a66: 0x000c, 0x1a67: 0x000c, 0x1a68: 0x000c, 0x1a69: 0x000c, + 0x1a6a: 0x000c, 0x1a6b: 0x000c, 0x1a6c: 0x000c, 0x1a6d: 0x000c, 0x1a6e: 0x000c, 0x1a6f: 0x000c, + 0x1a70: 0x000c, 0x1a71: 0x000c, 0x1a72: 0x000c, 0x1a73: 0x000c, 0x1a74: 0x000c, 0x1a75: 0x000c, + 0x1a76: 0x000c, 0x1a77: 0x000c, 0x1a78: 0x000c, 0x1a79: 0x000c, 0x1a7a: 0x000c, 0x1a7b: 0x000c, + 0x1a7c: 0x000c, 0x1a7d: 0x000c, 0x1a7e: 0x000c, 0x1a7f: 0x000c, // Block 0x6a, offset 0x1a80 - 0x1aa0: 0x000c, 0x1aa1: 0x000c, 0x1aa2: 0x000c, 0x1aa3: 0x000c, - 0x1aa4: 0x000c, 0x1aa5: 0x000c, 0x1aa6: 0x000c, 0x1aa7: 0x000c, 0x1aa8: 0x000c, 0x1aa9: 0x000c, - 0x1aaa: 0x000c, 0x1aab: 0x000c, 0x1aac: 0x000c, 0x1aad: 0x000c, 0x1aae: 0x000c, 0x1aaf: 0x000c, - 0x1ab0: 0x000c, 0x1ab1: 0x000c, 0x1ab2: 0x000c, 0x1ab3: 0x000c, 0x1ab4: 0x000c, 0x1ab5: 0x000c, - 0x1ab6: 0x000c, 0x1ab7: 0x000c, 0x1ab8: 0x000c, 0x1ab9: 0x000c, 0x1aba: 0x000c, 0x1abb: 0x000c, - 0x1abc: 0x000c, 0x1abd: 0x000c, 0x1abe: 0x000c, 0x1abf: 0x000c, + 0x1a80: 0x000a, 0x1a81: 0x000a, 0x1a82: 0x000a, 0x1a83: 0x000a, 0x1a84: 0x000a, 0x1a85: 0x000a, + 0x1a86: 0x000a, 0x1a87: 0x000a, 0x1a88: 0x000a, 0x1a89: 0x000a, 0x1a8a: 0x000a, 0x1a8b: 0x000a, + 0x1a8c: 0x000a, 0x1a8d: 0x000a, 0x1a8e: 0x000a, 0x1a8f: 0x000a, 0x1a90: 0x000a, 0x1a91: 0x000a, + 0x1a92: 0x000a, 0x1a93: 0x000a, 0x1a94: 0x000a, 0x1a95: 0x000a, 0x1a96: 0x000a, 0x1a97: 0x000a, + 0x1a98: 0x000a, 0x1a99: 0x000a, 0x1a9a: 0x000a, 0x1a9b: 0x000a, 0x1a9c: 0x000a, 0x1a9d: 0x000a, + 0x1a9e: 0x000a, 0x1a9f: 0x000a, 0x1aa0: 0x000a, 0x1aa1: 0x000a, 0x1aa2: 0x003a, 0x1aa3: 0x002a, + 0x1aa4: 0x003a, 0x1aa5: 0x002a, 0x1aa6: 0x003a, 0x1aa7: 0x002a, 0x1aa8: 0x003a, 0x1aa9: 0x002a, + 0x1aaa: 0x000a, 0x1aab: 0x000a, 0x1aac: 0x000a, 0x1aad: 0x000a, 0x1aae: 0x000a, 0x1aaf: 0x000a, + 0x1ab0: 0x000a, 0x1ab1: 0x000a, 0x1ab2: 0x000a, 0x1ab3: 0x000a, 0x1ab4: 0x000a, 0x1ab5: 0x000a, + 0x1ab6: 0x000a, 0x1ab7: 0x000a, 0x1ab8: 0x000a, 0x1ab9: 0x000a, 0x1aba: 0x000a, 0x1abb: 0x000a, + 0x1abc: 0x000a, 0x1abd: 0x000a, 0x1abe: 0x000a, 0x1abf: 0x000a, // Block 0x6b, offset 0x1ac0 0x1ac0: 0x000a, 0x1ac1: 0x000a, 0x1ac2: 0x000a, 0x1ac3: 0x000a, 0x1ac4: 0x000a, 0x1ac5: 0x000a, - 0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, 0x1aca: 0x000a, 0x1acb: 0x000a, - 0x1acc: 0x000a, 0x1acd: 0x000a, 0x1ace: 0x000a, 0x1acf: 0x000a, 0x1ad0: 0x000a, 0x1ad1: 0x000a, - 0x1ad2: 0x000a, 0x1ad3: 0x000a, 0x1ad4: 0x000a, 0x1ad5: 0x000a, 0x1ad6: 0x000a, 0x1ad7: 0x000a, - 0x1ad8: 0x000a, 0x1ad9: 0x000a, 0x1ada: 0x000a, 0x1adb: 0x000a, 0x1adc: 0x000a, 0x1add: 0x000a, - 0x1ade: 0x000a, 0x1adf: 0x000a, 0x1ae0: 0x000a, 0x1ae1: 0x000a, 0x1ae2: 0x003a, 0x1ae3: 0x002a, - 0x1ae4: 0x003a, 0x1ae5: 0x002a, 0x1ae6: 0x003a, 0x1ae7: 0x002a, 0x1ae8: 0x003a, 0x1ae9: 0x002a, - 0x1aea: 0x000a, 0x1aeb: 0x000a, 0x1aec: 0x000a, 0x1aed: 0x000a, 0x1aee: 0x000a, 0x1aef: 0x000a, - 0x1af0: 0x000a, 0x1af1: 0x000a, 0x1af2: 0x000a, 0x1af3: 0x000a, 0x1af4: 0x000a, 0x1af5: 0x000a, - 0x1af6: 0x000a, 0x1af7: 0x000a, 0x1af8: 0x000a, 0x1af9: 0x000a, 0x1afa: 0x000a, 0x1afb: 0x000a, - 0x1afc: 0x000a, 0x1afd: 0x000a, 0x1afe: 0x000a, 0x1aff: 0x000a, + 0x1ac6: 0x000a, 0x1ac7: 0x000a, 0x1ac8: 0x000a, 0x1ac9: 0x000a, // Block 0x6c, offset 0x1b00 - 0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a, + 0x1b00: 0x000a, 0x1b01: 0x000a, 0x1b02: 0x000a, 0x1b03: 0x000a, 0x1b04: 0x000a, 0x1b05: 0x000a, + 0x1b06: 0x000a, 0x1b07: 0x000a, 0x1b08: 0x000a, 0x1b09: 0x000a, 0x1b0a: 0x000a, 0x1b0b: 0x000a, + 0x1b0c: 0x000a, 0x1b0d: 0x000a, 0x1b0e: 0x000a, 0x1b0f: 0x000a, 0x1b10: 0x000a, 0x1b11: 0x000a, + 0x1b12: 0x000a, 0x1b13: 0x000a, 0x1b14: 0x000a, 0x1b15: 0x000a, 0x1b16: 0x000a, 0x1b17: 0x000a, + 0x1b18: 0x000a, 0x1b19: 0x000a, 0x1b1b: 0x000a, 0x1b1c: 0x000a, 0x1b1d: 0x000a, + 0x1b1e: 0x000a, 0x1b1f: 0x000a, 0x1b20: 0x000a, 0x1b21: 0x000a, 0x1b22: 0x000a, 0x1b23: 0x000a, + 0x1b24: 0x000a, 0x1b25: 0x000a, 0x1b26: 0x000a, 0x1b27: 0x000a, 0x1b28: 0x000a, 0x1b29: 0x000a, + 0x1b2a: 0x000a, 0x1b2b: 0x000a, 0x1b2c: 0x000a, 0x1b2d: 0x000a, 0x1b2e: 0x000a, 0x1b2f: 0x000a, + 0x1b30: 0x000a, 0x1b31: 0x000a, 0x1b32: 0x000a, 0x1b33: 0x000a, 0x1b34: 0x000a, 0x1b35: 0x000a, + 0x1b36: 0x000a, 0x1b37: 0x000a, 0x1b38: 0x000a, 0x1b39: 0x000a, 0x1b3a: 0x000a, 0x1b3b: 0x000a, + 0x1b3c: 0x000a, 0x1b3d: 0x000a, 0x1b3e: 0x000a, 0x1b3f: 0x000a, // Block 0x6d, offset 0x1b40 0x1b40: 0x000a, 0x1b41: 0x000a, 0x1b42: 0x000a, 0x1b43: 0x000a, 0x1b44: 0x000a, 0x1b45: 0x000a, 0x1b46: 0x000a, 0x1b47: 0x000a, 0x1b48: 0x000a, 0x1b49: 0x000a, 0x1b4a: 0x000a, 0x1b4b: 0x000a, 0x1b4c: 0x000a, 0x1b4d: 0x000a, 0x1b4e: 0x000a, 0x1b4f: 0x000a, 0x1b50: 0x000a, 0x1b51: 0x000a, 0x1b52: 0x000a, 0x1b53: 0x000a, 0x1b54: 0x000a, 0x1b55: 0x000a, 0x1b56: 0x000a, 0x1b57: 0x000a, - 0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a, + 0x1b58: 0x000a, 0x1b59: 0x000a, 0x1b5a: 0x000a, 0x1b5b: 0x000a, 0x1b5c: 0x000a, 0x1b5d: 0x000a, 0x1b5e: 0x000a, 0x1b5f: 0x000a, 0x1b60: 0x000a, 0x1b61: 0x000a, 0x1b62: 0x000a, 0x1b63: 0x000a, 0x1b64: 0x000a, 0x1b65: 0x000a, 0x1b66: 0x000a, 0x1b67: 0x000a, 0x1b68: 0x000a, 0x1b69: 0x000a, 0x1b6a: 0x000a, 0x1b6b: 0x000a, 0x1b6c: 0x000a, 0x1b6d: 0x000a, 0x1b6e: 0x000a, 0x1b6f: 0x000a, - 0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, 0x1b74: 0x000a, 0x1b75: 0x000a, - 0x1b76: 0x000a, 0x1b77: 0x000a, 0x1b78: 0x000a, 0x1b79: 0x000a, 0x1b7a: 0x000a, 0x1b7b: 0x000a, - 0x1b7c: 0x000a, 0x1b7d: 0x000a, 0x1b7e: 0x000a, 0x1b7f: 0x000a, + 0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, // Block 0x6e, offset 0x1b80 0x1b80: 0x000a, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a, 0x1b85: 0x000a, 0x1b86: 0x000a, 0x1b87: 0x000a, 0x1b88: 0x000a, 0x1b89: 0x000a, 0x1b8a: 0x000a, 0x1b8b: 0x000a, 0x1b8c: 0x000a, 0x1b8d: 0x000a, 0x1b8e: 0x000a, 0x1b8f: 0x000a, 0x1b90: 0x000a, 0x1b91: 0x000a, - 0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a, 0x1b96: 0x000a, 0x1b97: 0x000a, - 0x1b98: 0x000a, 0x1b99: 0x000a, 0x1b9a: 0x000a, 0x1b9b: 0x000a, 0x1b9c: 0x000a, 0x1b9d: 0x000a, - 0x1b9e: 0x000a, 0x1b9f: 0x000a, 0x1ba0: 0x000a, 0x1ba1: 0x000a, 0x1ba2: 0x000a, 0x1ba3: 0x000a, - 0x1ba4: 0x000a, 0x1ba5: 0x000a, 0x1ba6: 0x000a, 0x1ba7: 0x000a, 0x1ba8: 0x000a, 0x1ba9: 0x000a, - 0x1baa: 0x000a, 0x1bab: 0x000a, 0x1bac: 0x000a, 0x1bad: 0x000a, 0x1bae: 0x000a, 0x1baf: 0x000a, - 0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a, + 0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x000a, 0x1b95: 0x000a, + 0x1bb0: 0x000a, 0x1bb1: 0x000a, 0x1bb2: 0x000a, 0x1bb3: 0x000a, 0x1bb4: 0x000a, 0x1bb5: 0x000a, + 0x1bb6: 0x000a, 0x1bb7: 0x000a, 0x1bb8: 0x000a, 0x1bb9: 0x000a, 0x1bba: 0x000a, 0x1bbb: 0x000a, // Block 0x6f, offset 0x1bc0 - 0x1bc0: 0x000a, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a, 0x1bc5: 0x000a, - 0x1bc6: 0x000a, 0x1bc7: 0x000a, 0x1bc8: 0x000a, 0x1bc9: 0x000a, 0x1bca: 0x000a, 0x1bcb: 0x000a, - 0x1bcc: 0x000a, 0x1bcd: 0x000a, 0x1bce: 0x000a, 0x1bcf: 0x000a, 0x1bd0: 0x000a, 0x1bd1: 0x000a, - 0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x000a, 0x1bd5: 0x000a, - 0x1bf0: 0x000a, 0x1bf1: 0x000a, 0x1bf2: 0x000a, 0x1bf3: 0x000a, 0x1bf4: 0x000a, 0x1bf5: 0x000a, - 0x1bf6: 0x000a, 0x1bf7: 0x000a, 0x1bf8: 0x000a, 0x1bf9: 0x000a, 0x1bfa: 0x000a, 0x1bfb: 0x000a, + 0x1bc0: 0x0009, 0x1bc1: 0x000a, 0x1bc2: 0x000a, 0x1bc3: 0x000a, 0x1bc4: 0x000a, + 0x1bc8: 0x003a, 0x1bc9: 0x002a, 0x1bca: 0x003a, 0x1bcb: 0x002a, + 0x1bcc: 0x003a, 0x1bcd: 0x002a, 0x1bce: 0x003a, 0x1bcf: 0x002a, 0x1bd0: 0x003a, 0x1bd1: 0x002a, + 0x1bd2: 0x000a, 0x1bd3: 0x000a, 0x1bd4: 0x003a, 0x1bd5: 0x002a, 0x1bd6: 0x003a, 0x1bd7: 0x002a, + 0x1bd8: 0x003a, 0x1bd9: 0x002a, 0x1bda: 0x003a, 0x1bdb: 0x002a, 0x1bdc: 0x000a, 0x1bdd: 0x000a, + 0x1bde: 0x000a, 0x1bdf: 0x000a, 0x1be0: 0x000a, + 0x1bea: 0x000c, 0x1beb: 0x000c, 0x1bec: 0x000c, 0x1bed: 0x000c, + 0x1bf0: 0x000a, + 0x1bf6: 0x000a, 0x1bf7: 0x000a, + 0x1bfd: 0x000a, 0x1bfe: 0x000a, 0x1bff: 0x000a, // Block 0x70, offset 0x1c00 - 0x1c00: 0x0009, 0x1c01: 0x000a, 0x1c02: 0x000a, 0x1c03: 0x000a, 0x1c04: 0x000a, - 0x1c08: 0x003a, 0x1c09: 0x002a, 0x1c0a: 0x003a, 0x1c0b: 0x002a, - 0x1c0c: 0x003a, 0x1c0d: 0x002a, 0x1c0e: 0x003a, 0x1c0f: 0x002a, 0x1c10: 0x003a, 0x1c11: 0x002a, - 0x1c12: 0x000a, 0x1c13: 0x000a, 0x1c14: 0x003a, 0x1c15: 0x002a, 0x1c16: 0x003a, 0x1c17: 0x002a, - 0x1c18: 0x003a, 0x1c19: 0x002a, 0x1c1a: 0x003a, 0x1c1b: 0x002a, 0x1c1c: 0x000a, 0x1c1d: 0x000a, - 0x1c1e: 0x000a, 0x1c1f: 0x000a, 0x1c20: 0x000a, - 0x1c2a: 0x000c, 0x1c2b: 0x000c, 0x1c2c: 0x000c, 0x1c2d: 0x000c, - 0x1c30: 0x000a, - 0x1c36: 0x000a, 0x1c37: 0x000a, - 0x1c3d: 0x000a, 0x1c3e: 0x000a, 0x1c3f: 0x000a, + 0x1c19: 0x000c, 0x1c1a: 0x000c, 0x1c1b: 0x000a, 0x1c1c: 0x000a, + 0x1c20: 0x000a, // Block 0x71, offset 0x1c40 - 0x1c59: 0x000c, 0x1c5a: 0x000c, 0x1c5b: 0x000a, 0x1c5c: 0x000a, - 0x1c60: 0x000a, + 0x1c7b: 0x000a, // Block 0x72, offset 0x1c80 - 0x1cbb: 0x000a, + 0x1c80: 0x000a, 0x1c81: 0x000a, 0x1c82: 0x000a, 0x1c83: 0x000a, 0x1c84: 0x000a, 0x1c85: 0x000a, + 0x1c86: 0x000a, 0x1c87: 0x000a, 0x1c88: 0x000a, 0x1c89: 0x000a, 0x1c8a: 0x000a, 0x1c8b: 0x000a, + 0x1c8c: 0x000a, 0x1c8d: 0x000a, 0x1c8e: 0x000a, 0x1c8f: 0x000a, 0x1c90: 0x000a, 0x1c91: 0x000a, + 0x1c92: 0x000a, 0x1c93: 0x000a, 0x1c94: 0x000a, 0x1c95: 0x000a, 0x1c96: 0x000a, 0x1c97: 0x000a, + 0x1c98: 0x000a, 0x1c99: 0x000a, 0x1c9a: 0x000a, 0x1c9b: 0x000a, 0x1c9c: 0x000a, 0x1c9d: 0x000a, + 0x1c9e: 0x000a, 0x1c9f: 0x000a, 0x1ca0: 0x000a, 0x1ca1: 0x000a, 0x1ca2: 0x000a, 0x1ca3: 0x000a, // Block 0x73, offset 0x1cc0 - 0x1cc0: 0x000a, 0x1cc1: 0x000a, 0x1cc2: 0x000a, 0x1cc3: 0x000a, 0x1cc4: 0x000a, 0x1cc5: 0x000a, - 0x1cc6: 0x000a, 0x1cc7: 0x000a, 0x1cc8: 0x000a, 0x1cc9: 0x000a, 0x1cca: 0x000a, 0x1ccb: 0x000a, - 0x1ccc: 0x000a, 0x1ccd: 0x000a, 0x1cce: 0x000a, 0x1ccf: 0x000a, 0x1cd0: 0x000a, 0x1cd1: 0x000a, - 0x1cd2: 0x000a, 0x1cd3: 0x000a, 0x1cd4: 0x000a, 0x1cd5: 0x000a, 0x1cd6: 0x000a, 0x1cd7: 0x000a, - 0x1cd8: 0x000a, 0x1cd9: 0x000a, 0x1cda: 0x000a, 0x1cdb: 0x000a, 0x1cdc: 0x000a, 0x1cdd: 0x000a, - 0x1cde: 0x000a, 0x1cdf: 0x000a, 0x1ce0: 0x000a, 0x1ce1: 0x000a, 0x1ce2: 0x000a, 0x1ce3: 0x000a, + 0x1cdd: 0x000a, + 0x1cde: 0x000a, // Block 0x74, offset 0x1d00 - 0x1d1d: 0x000a, - 0x1d1e: 0x000a, + 0x1d10: 0x000a, 0x1d11: 0x000a, + 0x1d12: 0x000a, 0x1d13: 0x000a, 0x1d14: 0x000a, 0x1d15: 0x000a, 0x1d16: 0x000a, 0x1d17: 0x000a, + 0x1d18: 0x000a, 0x1d19: 0x000a, 0x1d1a: 0x000a, 0x1d1b: 0x000a, 0x1d1c: 0x000a, 0x1d1d: 0x000a, + 0x1d1e: 0x000a, 0x1d1f: 0x000a, + 0x1d3c: 0x000a, 0x1d3d: 0x000a, 0x1d3e: 0x000a, // Block 0x75, offset 0x1d40 - 0x1d50: 0x000a, 0x1d51: 0x000a, - 0x1d52: 0x000a, 0x1d53: 0x000a, 0x1d54: 0x000a, 0x1d55: 0x000a, 0x1d56: 0x000a, 0x1d57: 0x000a, - 0x1d58: 0x000a, 0x1d59: 0x000a, 0x1d5a: 0x000a, 0x1d5b: 0x000a, 0x1d5c: 0x000a, 0x1d5d: 0x000a, - 0x1d5e: 0x000a, 0x1d5f: 0x000a, - 0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a, + 0x1d71: 0x000a, 0x1d72: 0x000a, 0x1d73: 0x000a, 0x1d74: 0x000a, 0x1d75: 0x000a, + 0x1d76: 0x000a, 0x1d77: 0x000a, 0x1d78: 0x000a, 0x1d79: 0x000a, 0x1d7a: 0x000a, 0x1d7b: 0x000a, + 0x1d7c: 0x000a, 0x1d7d: 0x000a, 0x1d7e: 0x000a, 0x1d7f: 0x000a, // Block 0x76, offset 0x1d80 - 0x1db1: 0x000a, 0x1db2: 0x000a, 0x1db3: 0x000a, 0x1db4: 0x000a, 0x1db5: 0x000a, - 0x1db6: 0x000a, 0x1db7: 0x000a, 0x1db8: 0x000a, 0x1db9: 0x000a, 0x1dba: 0x000a, 0x1dbb: 0x000a, - 0x1dbc: 0x000a, 0x1dbd: 0x000a, 0x1dbe: 0x000a, 0x1dbf: 0x000a, + 0x1d8c: 0x000a, 0x1d8d: 0x000a, 0x1d8e: 0x000a, 0x1d8f: 0x000a, // Block 0x77, offset 0x1dc0 - 0x1dcc: 0x000a, 0x1dcd: 0x000a, 0x1dce: 0x000a, 0x1dcf: 0x000a, + 0x1df7: 0x000a, 0x1df8: 0x000a, 0x1df9: 0x000a, 0x1dfa: 0x000a, // Block 0x78, offset 0x1e00 - 0x1e37: 0x000a, 0x1e38: 0x000a, 0x1e39: 0x000a, 0x1e3a: 0x000a, + 0x1e1e: 0x000a, 0x1e1f: 0x000a, + 0x1e3f: 0x000a, // Block 0x79, offset 0x1e40 - 0x1e5e: 0x000a, 0x1e5f: 0x000a, - 0x1e7f: 0x000a, + 0x1e50: 0x000a, 0x1e51: 0x000a, + 0x1e52: 0x000a, 0x1e53: 0x000a, 0x1e54: 0x000a, 0x1e55: 0x000a, 0x1e56: 0x000a, 0x1e57: 0x000a, + 0x1e58: 0x000a, 0x1e59: 0x000a, 0x1e5a: 0x000a, 0x1e5b: 0x000a, 0x1e5c: 0x000a, 0x1e5d: 0x000a, + 0x1e5e: 0x000a, 0x1e5f: 0x000a, 0x1e60: 0x000a, 0x1e61: 0x000a, 0x1e62: 0x000a, 0x1e63: 0x000a, + 0x1e64: 0x000a, 0x1e65: 0x000a, 0x1e66: 0x000a, 0x1e67: 0x000a, 0x1e68: 0x000a, 0x1e69: 0x000a, + 0x1e6a: 0x000a, 0x1e6b: 0x000a, 0x1e6c: 0x000a, 0x1e6d: 0x000a, 0x1e6e: 0x000a, 0x1e6f: 0x000a, + 0x1e70: 0x000a, 0x1e71: 0x000a, 0x1e72: 0x000a, 0x1e73: 0x000a, 0x1e74: 0x000a, 0x1e75: 0x000a, + 0x1e76: 0x000a, 0x1e77: 0x000a, 0x1e78: 0x000a, 0x1e79: 0x000a, 0x1e7a: 0x000a, 0x1e7b: 0x000a, + 0x1e7c: 0x000a, 0x1e7d: 0x000a, 0x1e7e: 0x000a, 0x1e7f: 0x000a, // Block 0x7a, offset 0x1e80 - 0x1e90: 0x000a, 0x1e91: 0x000a, - 0x1e92: 0x000a, 0x1e93: 0x000a, 0x1e94: 0x000a, 0x1e95: 0x000a, 0x1e96: 0x000a, 0x1e97: 0x000a, - 0x1e98: 0x000a, 0x1e99: 0x000a, 0x1e9a: 0x000a, 0x1e9b: 0x000a, 0x1e9c: 0x000a, 0x1e9d: 0x000a, - 0x1e9e: 0x000a, 0x1e9f: 0x000a, 0x1ea0: 0x000a, 0x1ea1: 0x000a, 0x1ea2: 0x000a, 0x1ea3: 0x000a, - 0x1ea4: 0x000a, 0x1ea5: 0x000a, 0x1ea6: 0x000a, 0x1ea7: 0x000a, 0x1ea8: 0x000a, 0x1ea9: 0x000a, - 0x1eaa: 0x000a, 0x1eab: 0x000a, 0x1eac: 0x000a, 0x1ead: 0x000a, 0x1eae: 0x000a, 0x1eaf: 0x000a, - 0x1eb0: 0x000a, 0x1eb1: 0x000a, 0x1eb2: 0x000a, 0x1eb3: 0x000a, 0x1eb4: 0x000a, 0x1eb5: 0x000a, - 0x1eb6: 0x000a, 0x1eb7: 0x000a, 0x1eb8: 0x000a, 0x1eb9: 0x000a, 0x1eba: 0x000a, 0x1ebb: 0x000a, - 0x1ebc: 0x000a, 0x1ebd: 0x000a, 0x1ebe: 0x000a, 0x1ebf: 0x000a, + 0x1e80: 0x000a, 0x1e81: 0x000a, 0x1e82: 0x000a, 0x1e83: 0x000a, 0x1e84: 0x000a, 0x1e85: 0x000a, + 0x1e86: 0x000a, // Block 0x7b, offset 0x1ec0 - 0x1ec0: 0x000a, 0x1ec1: 0x000a, 0x1ec2: 0x000a, 0x1ec3: 0x000a, 0x1ec4: 0x000a, 0x1ec5: 0x000a, - 0x1ec6: 0x000a, + 0x1ecd: 0x000a, 0x1ece: 0x000a, 0x1ecf: 0x000a, // Block 0x7c, offset 0x1f00 - 0x1f0d: 0x000a, 0x1f0e: 0x000a, 0x1f0f: 0x000a, + 0x1f2f: 0x000c, + 0x1f30: 0x000c, 0x1f31: 0x000c, 0x1f32: 0x000c, 0x1f33: 0x000a, 0x1f34: 0x000c, 0x1f35: 0x000c, + 0x1f36: 0x000c, 0x1f37: 0x000c, 0x1f38: 0x000c, 0x1f39: 0x000c, 0x1f3a: 0x000c, 0x1f3b: 0x000c, + 0x1f3c: 0x000c, 0x1f3d: 0x000c, 0x1f3e: 0x000a, 0x1f3f: 0x000a, // Block 0x7d, offset 0x1f40 - 0x1f6f: 0x000c, - 0x1f70: 0x000c, 0x1f71: 0x000c, 0x1f72: 0x000c, 0x1f73: 0x000a, 0x1f74: 0x000c, 0x1f75: 0x000c, - 0x1f76: 0x000c, 0x1f77: 0x000c, 0x1f78: 0x000c, 0x1f79: 0x000c, 0x1f7a: 0x000c, 0x1f7b: 0x000c, - 0x1f7c: 0x000c, 0x1f7d: 0x000c, 0x1f7e: 0x000a, 0x1f7f: 0x000a, + 0x1f5e: 0x000c, 0x1f5f: 0x000c, // Block 0x7e, offset 0x1f80 - 0x1f9e: 0x000c, 0x1f9f: 0x000c, + 0x1fb0: 0x000c, 0x1fb1: 0x000c, // Block 0x7f, offset 0x1fc0 - 0x1ff0: 0x000c, 0x1ff1: 0x000c, + 0x1fc0: 0x000a, 0x1fc1: 0x000a, 0x1fc2: 0x000a, 0x1fc3: 0x000a, 0x1fc4: 0x000a, 0x1fc5: 0x000a, + 0x1fc6: 0x000a, 0x1fc7: 0x000a, 0x1fc8: 0x000a, 0x1fc9: 0x000a, 0x1fca: 0x000a, 0x1fcb: 0x000a, + 0x1fcc: 0x000a, 0x1fcd: 0x000a, 0x1fce: 0x000a, 0x1fcf: 0x000a, 0x1fd0: 0x000a, 0x1fd1: 0x000a, + 0x1fd2: 0x000a, 0x1fd3: 0x000a, 0x1fd4: 0x000a, 0x1fd5: 0x000a, 0x1fd6: 0x000a, 0x1fd7: 0x000a, + 0x1fd8: 0x000a, 0x1fd9: 0x000a, 0x1fda: 0x000a, 0x1fdb: 0x000a, 0x1fdc: 0x000a, 0x1fdd: 0x000a, + 0x1fde: 0x000a, 0x1fdf: 0x000a, 0x1fe0: 0x000a, 0x1fe1: 0x000a, // Block 0x80, offset 0x2000 - 0x2000: 0x000a, 0x2001: 0x000a, 0x2002: 0x000a, 0x2003: 0x000a, 0x2004: 0x000a, 0x2005: 0x000a, - 0x2006: 0x000a, 0x2007: 0x000a, 0x2008: 0x000a, 0x2009: 0x000a, 0x200a: 0x000a, 0x200b: 0x000a, - 0x200c: 0x000a, 0x200d: 0x000a, 0x200e: 0x000a, 0x200f: 0x000a, 0x2010: 0x000a, 0x2011: 0x000a, - 0x2012: 0x000a, 0x2013: 0x000a, 0x2014: 0x000a, 0x2015: 0x000a, 0x2016: 0x000a, 0x2017: 0x000a, - 0x2018: 0x000a, 0x2019: 0x000a, 0x201a: 0x000a, 0x201b: 0x000a, 0x201c: 0x000a, 0x201d: 0x000a, - 0x201e: 0x000a, 0x201f: 0x000a, 0x2020: 0x000a, 0x2021: 0x000a, + 0x2008: 0x000a, // Block 0x81, offset 0x2040 - 0x2048: 0x000a, + 0x2042: 0x000c, + 0x2046: 0x000c, 0x204b: 0x000c, + 0x2065: 0x000c, 0x2066: 0x000c, 0x2068: 0x000a, 0x2069: 0x000a, + 0x206a: 0x000a, 0x206b: 0x000a, + 0x2078: 0x0004, 0x2079: 0x0004, // Block 0x82, offset 0x2080 - 0x2082: 0x000c, - 0x2086: 0x000c, 0x208b: 0x000c, - 0x20a5: 0x000c, 0x20a6: 0x000c, 0x20a8: 0x000a, 0x20a9: 0x000a, - 0x20aa: 0x000a, 0x20ab: 0x000a, - 0x20b8: 0x0004, 0x20b9: 0x0004, + 0x20b4: 0x000a, 0x20b5: 0x000a, + 0x20b6: 0x000a, 0x20b7: 0x000a, // Block 0x83, offset 0x20c0 - 0x20f4: 0x000a, 0x20f5: 0x000a, - 0x20f6: 0x000a, 0x20f7: 0x000a, + 0x20c4: 0x000c, 0x20c5: 0x000c, + 0x20e0: 0x000c, 0x20e1: 0x000c, 0x20e2: 0x000c, 0x20e3: 0x000c, + 0x20e4: 0x000c, 0x20e5: 0x000c, 0x20e6: 0x000c, 0x20e7: 0x000c, 0x20e8: 0x000c, 0x20e9: 0x000c, + 0x20ea: 0x000c, 0x20eb: 0x000c, 0x20ec: 0x000c, 0x20ed: 0x000c, 0x20ee: 0x000c, 0x20ef: 0x000c, + 0x20f0: 0x000c, 0x20f1: 0x000c, // Block 0x84, offset 0x2100 - 0x2104: 0x000c, 0x2105: 0x000c, - 0x2120: 0x000c, 0x2121: 0x000c, 0x2122: 0x000c, 0x2123: 0x000c, - 0x2124: 0x000c, 0x2125: 0x000c, 0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c, - 0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c, 0x212e: 0x000c, 0x212f: 0x000c, - 0x2130: 0x000c, 0x2131: 0x000c, + 0x2126: 0x000c, 0x2127: 0x000c, 0x2128: 0x000c, 0x2129: 0x000c, + 0x212a: 0x000c, 0x212b: 0x000c, 0x212c: 0x000c, 0x212d: 0x000c, // Block 0x85, offset 0x2140 - 0x2166: 0x000c, 0x2167: 0x000c, 0x2168: 0x000c, 0x2169: 0x000c, - 0x216a: 0x000c, 0x216b: 0x000c, 0x216c: 0x000c, 0x216d: 0x000c, + 0x2147: 0x000c, 0x2148: 0x000c, 0x2149: 0x000c, 0x214a: 0x000c, 0x214b: 0x000c, + 0x214c: 0x000c, 0x214d: 0x000c, 0x214e: 0x000c, 0x214f: 0x000c, 0x2150: 0x000c, 0x2151: 0x000c, // Block 0x86, offset 0x2180 - 0x2187: 0x000c, 0x2188: 0x000c, 0x2189: 0x000c, 0x218a: 0x000c, 0x218b: 0x000c, - 0x218c: 0x000c, 0x218d: 0x000c, 0x218e: 0x000c, 0x218f: 0x000c, 0x2190: 0x000c, 0x2191: 0x000c, + 0x2180: 0x000c, 0x2181: 0x000c, 0x2182: 0x000c, + 0x21b3: 0x000c, + 0x21b6: 0x000c, 0x21b7: 0x000c, 0x21b8: 0x000c, 0x21b9: 0x000c, + 0x21bc: 0x000c, // Block 0x87, offset 0x21c0 - 0x21c0: 0x000c, 0x21c1: 0x000c, 0x21c2: 0x000c, - 0x21f3: 0x000c, - 0x21f6: 0x000c, 0x21f7: 0x000c, 0x21f8: 0x000c, 0x21f9: 0x000c, - 0x21fc: 0x000c, + 0x21e5: 0x000c, // Block 0x88, offset 0x2200 - 0x2225: 0x000c, + 0x2229: 0x000c, + 0x222a: 0x000c, 0x222b: 0x000c, 0x222c: 0x000c, 0x222d: 0x000c, 0x222e: 0x000c, + 0x2231: 0x000c, 0x2232: 0x000c, 0x2235: 0x000c, + 0x2236: 0x000c, // Block 0x89, offset 0x2240 - 0x2269: 0x000c, - 0x226a: 0x000c, 0x226b: 0x000c, 0x226c: 0x000c, 0x226d: 0x000c, 0x226e: 0x000c, - 0x2271: 0x000c, 0x2272: 0x000c, 0x2275: 0x000c, - 0x2276: 0x000c, + 0x2243: 0x000c, + 0x224c: 0x000c, + 0x227c: 0x000c, // Block 0x8a, offset 0x2280 - 0x2283: 0x000c, - 0x228c: 0x000c, - 0x22bc: 0x000c, + 0x22b0: 0x000c, 0x22b2: 0x000c, 0x22b3: 0x000c, 0x22b4: 0x000c, + 0x22b7: 0x000c, 0x22b8: 0x000c, + 0x22be: 0x000c, 0x22bf: 0x000c, // Block 0x8b, offset 0x22c0 - 0x22f0: 0x000c, 0x22f2: 0x000c, 0x22f3: 0x000c, 0x22f4: 0x000c, - 0x22f7: 0x000c, 0x22f8: 0x000c, - 0x22fe: 0x000c, 0x22ff: 0x000c, + 0x22c1: 0x000c, + 0x22ec: 0x000c, 0x22ed: 0x000c, + 0x22f6: 0x000c, // Block 0x8c, offset 0x2300 - 0x2301: 0x000c, - 0x232c: 0x000c, 0x232d: 0x000c, - 0x2336: 0x000c, + 0x2325: 0x000c, 0x2328: 0x000c, + 0x232d: 0x000c, // Block 0x8d, offset 0x2340 - 0x2365: 0x000c, 0x2368: 0x000c, - 0x236d: 0x000c, + 0x235d: 0x0001, + 0x235e: 0x000c, 0x235f: 0x0001, 0x2360: 0x0001, 0x2361: 0x0001, 0x2362: 0x0001, 0x2363: 0x0001, + 0x2364: 0x0001, 0x2365: 0x0001, 0x2366: 0x0001, 0x2367: 0x0001, 0x2368: 0x0001, 0x2369: 0x0003, + 0x236a: 0x0001, 0x236b: 0x0001, 0x236c: 0x0001, 0x236d: 0x0001, 0x236e: 0x0001, 0x236f: 0x0001, + 0x2370: 0x0001, 0x2371: 0x0001, 0x2372: 0x0001, 0x2373: 0x0001, 0x2374: 0x0001, 0x2375: 0x0001, + 0x2376: 0x0001, 0x2377: 0x0001, 0x2378: 0x0001, 0x2379: 0x0001, 0x237a: 0x0001, 0x237b: 0x0001, + 0x237c: 0x0001, 0x237d: 0x0001, 0x237e: 0x0001, 0x237f: 0x0001, // Block 0x8e, offset 0x2380 - 0x239d: 0x0001, - 0x239e: 0x000c, 0x239f: 0x0001, 0x23a0: 0x0001, 0x23a1: 0x0001, 0x23a2: 0x0001, 0x23a3: 0x0001, - 0x23a4: 0x0001, 0x23a5: 0x0001, 0x23a6: 0x0001, 0x23a7: 0x0001, 0x23a8: 0x0001, 0x23a9: 0x0003, - 0x23aa: 0x0001, 0x23ab: 0x0001, 0x23ac: 0x0001, 0x23ad: 0x0001, 0x23ae: 0x0001, 0x23af: 0x0001, - 0x23b0: 0x0001, 0x23b1: 0x0001, 0x23b2: 0x0001, 0x23b3: 0x0001, 0x23b4: 0x0001, 0x23b5: 0x0001, - 0x23b6: 0x0001, 0x23b7: 0x0001, 0x23b8: 0x0001, 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001, - 0x23bc: 0x0001, 0x23bd: 0x0001, 0x23be: 0x0001, 0x23bf: 0x0001, + 0x2380: 0x0001, 0x2381: 0x0001, 0x2382: 0x0001, 0x2383: 0x0001, 0x2384: 0x0001, 0x2385: 0x0001, + 0x2386: 0x0001, 0x2387: 0x0001, 0x2388: 0x0001, 0x2389: 0x0001, 0x238a: 0x0001, 0x238b: 0x0001, + 0x238c: 0x0001, 0x238d: 0x0001, 0x238e: 0x0001, 0x238f: 0x0001, 0x2390: 0x000d, 0x2391: 0x000d, + 0x2392: 0x000d, 0x2393: 0x000d, 0x2394: 0x000d, 0x2395: 0x000d, 0x2396: 0x000d, 0x2397: 0x000d, + 0x2398: 0x000d, 0x2399: 0x000d, 0x239a: 0x000d, 0x239b: 0x000d, 0x239c: 0x000d, 0x239d: 0x000d, + 0x239e: 0x000d, 0x239f: 0x000d, 0x23a0: 0x000d, 0x23a1: 0x000d, 0x23a2: 0x000d, 0x23a3: 0x000d, + 0x23a4: 0x000d, 0x23a5: 0x000d, 0x23a6: 0x000d, 0x23a7: 0x000d, 0x23a8: 0x000d, 0x23a9: 0x000d, + 0x23aa: 0x000d, 0x23ab: 0x000d, 0x23ac: 0x000d, 0x23ad: 0x000d, 0x23ae: 0x000d, 0x23af: 0x000d, + 0x23b0: 0x000d, 0x23b1: 0x000d, 0x23b2: 0x000d, 0x23b3: 0x000d, 0x23b4: 0x000d, 0x23b5: 0x000d, + 0x23b6: 0x000d, 0x23b7: 0x000d, 0x23b8: 0x000d, 0x23b9: 0x000d, 0x23ba: 0x000d, 0x23bb: 0x000d, + 0x23bc: 0x000d, 0x23bd: 0x000d, 0x23be: 0x000d, 0x23bf: 0x000d, // Block 0x8f, offset 0x23c0 - 0x23c0: 0x0001, 0x23c1: 0x0001, 0x23c2: 0x0001, 0x23c3: 0x0001, 0x23c4: 0x0001, 0x23c5: 0x0001, - 0x23c6: 0x0001, 0x23c7: 0x0001, 0x23c8: 0x0001, 0x23c9: 0x0001, 0x23ca: 0x0001, 0x23cb: 0x0001, - 0x23cc: 0x0001, 0x23cd: 0x0001, 0x23ce: 0x0001, 0x23cf: 0x0001, 0x23d0: 0x000d, 0x23d1: 0x000d, + 0x23c0: 0x000d, 0x23c1: 0x000d, 0x23c2: 0x000d, 0x23c3: 0x000d, 0x23c4: 0x000d, 0x23c5: 0x000d, + 0x23c6: 0x000d, 0x23c7: 0x000d, 0x23c8: 0x000d, 0x23c9: 0x000d, 0x23ca: 0x000d, 0x23cb: 0x000d, + 0x23cc: 0x000d, 0x23cd: 0x000d, 0x23ce: 0x000d, 0x23cf: 0x000d, 0x23d0: 0x000d, 0x23d1: 0x000d, 0x23d2: 0x000d, 0x23d3: 0x000d, 0x23d4: 0x000d, 0x23d5: 0x000d, 0x23d6: 0x000d, 0x23d7: 0x000d, 0x23d8: 0x000d, 0x23d9: 0x000d, 0x23da: 0x000d, 0x23db: 0x000d, 0x23dc: 0x000d, 0x23dd: 0x000d, 0x23de: 0x000d, 0x23df: 0x000d, 0x23e0: 0x000d, 0x23e1: 0x000d, 0x23e2: 0x000d, 0x23e3: 0x000d, @@ -1138,143 +1144,143 @@ var bidiValues = [14208]uint8{ 0x23ea: 0x000d, 0x23eb: 0x000d, 0x23ec: 0x000d, 0x23ed: 0x000d, 0x23ee: 0x000d, 0x23ef: 0x000d, 0x23f0: 0x000d, 0x23f1: 0x000d, 0x23f2: 0x000d, 0x23f3: 0x000d, 0x23f4: 0x000d, 0x23f5: 0x000d, 0x23f6: 0x000d, 0x23f7: 0x000d, 0x23f8: 0x000d, 0x23f9: 0x000d, 0x23fa: 0x000d, 0x23fb: 0x000d, - 0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000d, 0x23ff: 0x000d, + 0x23fc: 0x000d, 0x23fd: 0x000d, 0x23fe: 0x000a, 0x23ff: 0x000a, // Block 0x90, offset 0x2400 0x2400: 0x000d, 0x2401: 0x000d, 0x2402: 0x000d, 0x2403: 0x000d, 0x2404: 0x000d, 0x2405: 0x000d, 0x2406: 0x000d, 0x2407: 0x000d, 0x2408: 0x000d, 0x2409: 0x000d, 0x240a: 0x000d, 0x240b: 0x000d, - 0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000d, 0x2411: 0x000d, - 0x2412: 0x000d, 0x2413: 0x000d, 0x2414: 0x000d, 0x2415: 0x000d, 0x2416: 0x000d, 0x2417: 0x000d, - 0x2418: 0x000d, 0x2419: 0x000d, 0x241a: 0x000d, 0x241b: 0x000d, 0x241c: 0x000d, 0x241d: 0x000d, - 0x241e: 0x000d, 0x241f: 0x000d, 0x2420: 0x000d, 0x2421: 0x000d, 0x2422: 0x000d, 0x2423: 0x000d, - 0x2424: 0x000d, 0x2425: 0x000d, 0x2426: 0x000d, 0x2427: 0x000d, 0x2428: 0x000d, 0x2429: 0x000d, - 0x242a: 0x000d, 0x242b: 0x000d, 0x242c: 0x000d, 0x242d: 0x000d, 0x242e: 0x000d, 0x242f: 0x000d, + 0x240c: 0x000d, 0x240d: 0x000d, 0x240e: 0x000d, 0x240f: 0x000d, 0x2410: 0x000b, 0x2411: 0x000b, + 0x2412: 0x000b, 0x2413: 0x000b, 0x2414: 0x000b, 0x2415: 0x000b, 0x2416: 0x000b, 0x2417: 0x000b, + 0x2418: 0x000b, 0x2419: 0x000b, 0x241a: 0x000b, 0x241b: 0x000b, 0x241c: 0x000b, 0x241d: 0x000b, + 0x241e: 0x000b, 0x241f: 0x000b, 0x2420: 0x000b, 0x2421: 0x000b, 0x2422: 0x000b, 0x2423: 0x000b, + 0x2424: 0x000b, 0x2425: 0x000b, 0x2426: 0x000b, 0x2427: 0x000b, 0x2428: 0x000b, 0x2429: 0x000b, + 0x242a: 0x000b, 0x242b: 0x000b, 0x242c: 0x000b, 0x242d: 0x000b, 0x242e: 0x000b, 0x242f: 0x000b, 0x2430: 0x000d, 0x2431: 0x000d, 0x2432: 0x000d, 0x2433: 0x000d, 0x2434: 0x000d, 0x2435: 0x000d, 0x2436: 0x000d, 0x2437: 0x000d, 0x2438: 0x000d, 0x2439: 0x000d, 0x243a: 0x000d, 0x243b: 0x000d, - 0x243c: 0x000d, 0x243d: 0x000d, 0x243e: 0x000a, 0x243f: 0x000a, + 0x243c: 0x000d, 0x243d: 0x000a, 0x243e: 0x000d, 0x243f: 0x000d, // Block 0x91, offset 0x2440 - 0x2440: 0x000d, 0x2441: 0x000d, 0x2442: 0x000d, 0x2443: 0x000d, 0x2444: 0x000d, 0x2445: 0x000d, - 0x2446: 0x000d, 0x2447: 0x000d, 0x2448: 0x000d, 0x2449: 0x000d, 0x244a: 0x000d, 0x244b: 0x000d, - 0x244c: 0x000d, 0x244d: 0x000d, 0x244e: 0x000d, 0x244f: 0x000d, 0x2450: 0x000b, 0x2451: 0x000b, - 0x2452: 0x000b, 0x2453: 0x000b, 0x2454: 0x000b, 0x2455: 0x000b, 0x2456: 0x000b, 0x2457: 0x000b, - 0x2458: 0x000b, 0x2459: 0x000b, 0x245a: 0x000b, 0x245b: 0x000b, 0x245c: 0x000b, 0x245d: 0x000b, - 0x245e: 0x000b, 0x245f: 0x000b, 0x2460: 0x000b, 0x2461: 0x000b, 0x2462: 0x000b, 0x2463: 0x000b, - 0x2464: 0x000b, 0x2465: 0x000b, 0x2466: 0x000b, 0x2467: 0x000b, 0x2468: 0x000b, 0x2469: 0x000b, - 0x246a: 0x000b, 0x246b: 0x000b, 0x246c: 0x000b, 0x246d: 0x000b, 0x246e: 0x000b, 0x246f: 0x000b, - 0x2470: 0x000d, 0x2471: 0x000d, 0x2472: 0x000d, 0x2473: 0x000d, 0x2474: 0x000d, 0x2475: 0x000d, - 0x2476: 0x000d, 0x2477: 0x000d, 0x2478: 0x000d, 0x2479: 0x000d, 0x247a: 0x000d, 0x247b: 0x000d, - 0x247c: 0x000d, 0x247d: 0x000a, 0x247e: 0x000d, 0x247f: 0x000d, + 0x2440: 0x000c, 0x2441: 0x000c, 0x2442: 0x000c, 0x2443: 0x000c, 0x2444: 0x000c, 0x2445: 0x000c, + 0x2446: 0x000c, 0x2447: 0x000c, 0x2448: 0x000c, 0x2449: 0x000c, 0x244a: 0x000c, 0x244b: 0x000c, + 0x244c: 0x000c, 0x244d: 0x000c, 0x244e: 0x000c, 0x244f: 0x000c, 0x2450: 0x000a, 0x2451: 0x000a, + 0x2452: 0x000a, 0x2453: 0x000a, 0x2454: 0x000a, 0x2455: 0x000a, 0x2456: 0x000a, 0x2457: 0x000a, + 0x2458: 0x000a, 0x2459: 0x000a, + 0x2460: 0x000c, 0x2461: 0x000c, 0x2462: 0x000c, 0x2463: 0x000c, + 0x2464: 0x000c, 0x2465: 0x000c, 0x2466: 0x000c, 0x2467: 0x000c, 0x2468: 0x000c, 0x2469: 0x000c, + 0x246a: 0x000c, 0x246b: 0x000c, 0x246c: 0x000c, 0x246d: 0x000c, 0x246e: 0x000c, 0x246f: 0x000c, + 0x2470: 0x000a, 0x2471: 0x000a, 0x2472: 0x000a, 0x2473: 0x000a, 0x2474: 0x000a, 0x2475: 0x000a, + 0x2476: 0x000a, 0x2477: 0x000a, 0x2478: 0x000a, 0x2479: 0x000a, 0x247a: 0x000a, 0x247b: 0x000a, + 0x247c: 0x000a, 0x247d: 0x000a, 0x247e: 0x000a, 0x247f: 0x000a, // Block 0x92, offset 0x2480 - 0x2480: 0x000c, 0x2481: 0x000c, 0x2482: 0x000c, 0x2483: 0x000c, 0x2484: 0x000c, 0x2485: 0x000c, - 0x2486: 0x000c, 0x2487: 0x000c, 0x2488: 0x000c, 0x2489: 0x000c, 0x248a: 0x000c, 0x248b: 0x000c, - 0x248c: 0x000c, 0x248d: 0x000c, 0x248e: 0x000c, 0x248f: 0x000c, 0x2490: 0x000a, 0x2491: 0x000a, - 0x2492: 0x000a, 0x2493: 0x000a, 0x2494: 0x000a, 0x2495: 0x000a, 0x2496: 0x000a, 0x2497: 0x000a, - 0x2498: 0x000a, 0x2499: 0x000a, - 0x24a0: 0x000c, 0x24a1: 0x000c, 0x24a2: 0x000c, 0x24a3: 0x000c, - 0x24a4: 0x000c, 0x24a5: 0x000c, 0x24a6: 0x000c, 0x24a7: 0x000c, 0x24a8: 0x000c, 0x24a9: 0x000c, - 0x24aa: 0x000c, 0x24ab: 0x000c, 0x24ac: 0x000c, 0x24ad: 0x000c, 0x24ae: 0x000c, 0x24af: 0x000c, - 0x24b0: 0x000a, 0x24b1: 0x000a, 0x24b2: 0x000a, 0x24b3: 0x000a, 0x24b4: 0x000a, 0x24b5: 0x000a, - 0x24b6: 0x000a, 0x24b7: 0x000a, 0x24b8: 0x000a, 0x24b9: 0x000a, 0x24ba: 0x000a, 0x24bb: 0x000a, - 0x24bc: 0x000a, 0x24bd: 0x000a, 0x24be: 0x000a, 0x24bf: 0x000a, + 0x2480: 0x000a, 0x2481: 0x000a, 0x2482: 0x000a, 0x2483: 0x000a, 0x2484: 0x000a, 0x2485: 0x000a, + 0x2486: 0x000a, 0x2487: 0x000a, 0x2488: 0x000a, 0x2489: 0x000a, 0x248a: 0x000a, 0x248b: 0x000a, + 0x248c: 0x000a, 0x248d: 0x000a, 0x248e: 0x000a, 0x248f: 0x000a, 0x2490: 0x0006, 0x2491: 0x000a, + 0x2492: 0x0006, 0x2494: 0x000a, 0x2495: 0x0006, 0x2496: 0x000a, 0x2497: 0x000a, + 0x2498: 0x000a, 0x2499: 0x009a, 0x249a: 0x008a, 0x249b: 0x007a, 0x249c: 0x006a, 0x249d: 0x009a, + 0x249e: 0x008a, 0x249f: 0x0004, 0x24a0: 0x000a, 0x24a1: 0x000a, 0x24a2: 0x0003, 0x24a3: 0x0003, + 0x24a4: 0x000a, 0x24a5: 0x000a, 0x24a6: 0x000a, 0x24a8: 0x000a, 0x24a9: 0x0004, + 0x24aa: 0x0004, 0x24ab: 0x000a, + 0x24b0: 0x000d, 0x24b1: 0x000d, 0x24b2: 0x000d, 0x24b3: 0x000d, 0x24b4: 0x000d, 0x24b5: 0x000d, + 0x24b6: 0x000d, 0x24b7: 0x000d, 0x24b8: 0x000d, 0x24b9: 0x000d, 0x24ba: 0x000d, 0x24bb: 0x000d, + 0x24bc: 0x000d, 0x24bd: 0x000d, 0x24be: 0x000d, 0x24bf: 0x000d, // Block 0x93, offset 0x24c0 - 0x24c0: 0x000a, 0x24c1: 0x000a, 0x24c2: 0x000a, 0x24c3: 0x000a, 0x24c4: 0x000a, 0x24c5: 0x000a, - 0x24c6: 0x000a, 0x24c7: 0x000a, 0x24c8: 0x000a, 0x24c9: 0x000a, 0x24ca: 0x000a, 0x24cb: 0x000a, - 0x24cc: 0x000a, 0x24cd: 0x000a, 0x24ce: 0x000a, 0x24cf: 0x000a, 0x24d0: 0x0006, 0x24d1: 0x000a, - 0x24d2: 0x0006, 0x24d4: 0x000a, 0x24d5: 0x0006, 0x24d6: 0x000a, 0x24d7: 0x000a, - 0x24d8: 0x000a, 0x24d9: 0x009a, 0x24da: 0x008a, 0x24db: 0x007a, 0x24dc: 0x006a, 0x24dd: 0x009a, - 0x24de: 0x008a, 0x24df: 0x0004, 0x24e0: 0x000a, 0x24e1: 0x000a, 0x24e2: 0x0003, 0x24e3: 0x0003, - 0x24e4: 0x000a, 0x24e5: 0x000a, 0x24e6: 0x000a, 0x24e8: 0x000a, 0x24e9: 0x0004, - 0x24ea: 0x0004, 0x24eb: 0x000a, + 0x24c0: 0x000d, 0x24c1: 0x000d, 0x24c2: 0x000d, 0x24c3: 0x000d, 0x24c4: 0x000d, 0x24c5: 0x000d, + 0x24c6: 0x000d, 0x24c7: 0x000d, 0x24c8: 0x000d, 0x24c9: 0x000d, 0x24ca: 0x000d, 0x24cb: 0x000d, + 0x24cc: 0x000d, 0x24cd: 0x000d, 0x24ce: 0x000d, 0x24cf: 0x000d, 0x24d0: 0x000d, 0x24d1: 0x000d, + 0x24d2: 0x000d, 0x24d3: 0x000d, 0x24d4: 0x000d, 0x24d5: 0x000d, 0x24d6: 0x000d, 0x24d7: 0x000d, + 0x24d8: 0x000d, 0x24d9: 0x000d, 0x24da: 0x000d, 0x24db: 0x000d, 0x24dc: 0x000d, 0x24dd: 0x000d, + 0x24de: 0x000d, 0x24df: 0x000d, 0x24e0: 0x000d, 0x24e1: 0x000d, 0x24e2: 0x000d, 0x24e3: 0x000d, + 0x24e4: 0x000d, 0x24e5: 0x000d, 0x24e6: 0x000d, 0x24e7: 0x000d, 0x24e8: 0x000d, 0x24e9: 0x000d, + 0x24ea: 0x000d, 0x24eb: 0x000d, 0x24ec: 0x000d, 0x24ed: 0x000d, 0x24ee: 0x000d, 0x24ef: 0x000d, 0x24f0: 0x000d, 0x24f1: 0x000d, 0x24f2: 0x000d, 0x24f3: 0x000d, 0x24f4: 0x000d, 0x24f5: 0x000d, 0x24f6: 0x000d, 0x24f7: 0x000d, 0x24f8: 0x000d, 0x24f9: 0x000d, 0x24fa: 0x000d, 0x24fb: 0x000d, - 0x24fc: 0x000d, 0x24fd: 0x000d, 0x24fe: 0x000d, 0x24ff: 0x000d, + 0x24fc: 0x000d, 0x24fd: 0x000d, 0x24fe: 0x000d, 0x24ff: 0x000b, // Block 0x94, offset 0x2500 - 0x2500: 0x000d, 0x2501: 0x000d, 0x2502: 0x000d, 0x2503: 0x000d, 0x2504: 0x000d, 0x2505: 0x000d, - 0x2506: 0x000d, 0x2507: 0x000d, 0x2508: 0x000d, 0x2509: 0x000d, 0x250a: 0x000d, 0x250b: 0x000d, - 0x250c: 0x000d, 0x250d: 0x000d, 0x250e: 0x000d, 0x250f: 0x000d, 0x2510: 0x000d, 0x2511: 0x000d, - 0x2512: 0x000d, 0x2513: 0x000d, 0x2514: 0x000d, 0x2515: 0x000d, 0x2516: 0x000d, 0x2517: 0x000d, - 0x2518: 0x000d, 0x2519: 0x000d, 0x251a: 0x000d, 0x251b: 0x000d, 0x251c: 0x000d, 0x251d: 0x000d, - 0x251e: 0x000d, 0x251f: 0x000d, 0x2520: 0x000d, 0x2521: 0x000d, 0x2522: 0x000d, 0x2523: 0x000d, - 0x2524: 0x000d, 0x2525: 0x000d, 0x2526: 0x000d, 0x2527: 0x000d, 0x2528: 0x000d, 0x2529: 0x000d, - 0x252a: 0x000d, 0x252b: 0x000d, 0x252c: 0x000d, 0x252d: 0x000d, 0x252e: 0x000d, 0x252f: 0x000d, - 0x2530: 0x000d, 0x2531: 0x000d, 0x2532: 0x000d, 0x2533: 0x000d, 0x2534: 0x000d, 0x2535: 0x000d, - 0x2536: 0x000d, 0x2537: 0x000d, 0x2538: 0x000d, 0x2539: 0x000d, 0x253a: 0x000d, 0x253b: 0x000d, - 0x253c: 0x000d, 0x253d: 0x000d, 0x253e: 0x000d, 0x253f: 0x000b, + 0x2501: 0x000a, 0x2502: 0x000a, 0x2503: 0x0004, 0x2504: 0x0004, 0x2505: 0x0004, + 0x2506: 0x000a, 0x2507: 0x000a, 0x2508: 0x003a, 0x2509: 0x002a, 0x250a: 0x000a, 0x250b: 0x0003, + 0x250c: 0x0006, 0x250d: 0x0003, 0x250e: 0x0006, 0x250f: 0x0006, 0x2510: 0x0002, 0x2511: 0x0002, + 0x2512: 0x0002, 0x2513: 0x0002, 0x2514: 0x0002, 0x2515: 0x0002, 0x2516: 0x0002, 0x2517: 0x0002, + 0x2518: 0x0002, 0x2519: 0x0002, 0x251a: 0x0006, 0x251b: 0x000a, 0x251c: 0x000a, 0x251d: 0x000a, + 0x251e: 0x000a, 0x251f: 0x000a, 0x2520: 0x000a, + 0x253b: 0x005a, + 0x253c: 0x000a, 0x253d: 0x004a, 0x253e: 0x000a, 0x253f: 0x000a, // Block 0x95, offset 0x2540 - 0x2541: 0x000a, 0x2542: 0x000a, 0x2543: 0x0004, 0x2544: 0x0004, 0x2545: 0x0004, - 0x2546: 0x000a, 0x2547: 0x000a, 0x2548: 0x003a, 0x2549: 0x002a, 0x254a: 0x000a, 0x254b: 0x0003, - 0x254c: 0x0006, 0x254d: 0x0003, 0x254e: 0x0006, 0x254f: 0x0006, 0x2550: 0x0002, 0x2551: 0x0002, - 0x2552: 0x0002, 0x2553: 0x0002, 0x2554: 0x0002, 0x2555: 0x0002, 0x2556: 0x0002, 0x2557: 0x0002, - 0x2558: 0x0002, 0x2559: 0x0002, 0x255a: 0x0006, 0x255b: 0x000a, 0x255c: 0x000a, 0x255d: 0x000a, - 0x255e: 0x000a, 0x255f: 0x000a, 0x2560: 0x000a, - 0x257b: 0x005a, - 0x257c: 0x000a, 0x257d: 0x004a, 0x257e: 0x000a, 0x257f: 0x000a, + 0x2540: 0x000a, + 0x255b: 0x005a, 0x255c: 0x000a, 0x255d: 0x004a, + 0x255e: 0x000a, 0x255f: 0x00fa, 0x2560: 0x00ea, 0x2561: 0x000a, 0x2562: 0x003a, 0x2563: 0x002a, + 0x2564: 0x000a, 0x2565: 0x000a, // Block 0x96, offset 0x2580 - 0x2580: 0x000a, - 0x259b: 0x005a, 0x259c: 0x000a, 0x259d: 0x004a, - 0x259e: 0x000a, 0x259f: 0x00fa, 0x25a0: 0x00ea, 0x25a1: 0x000a, 0x25a2: 0x003a, 0x25a3: 0x002a, - 0x25a4: 0x000a, 0x25a5: 0x000a, + 0x25a0: 0x0004, 0x25a1: 0x0004, 0x25a2: 0x000a, 0x25a3: 0x000a, + 0x25a4: 0x000a, 0x25a5: 0x0004, 0x25a6: 0x0004, 0x25a8: 0x000a, 0x25a9: 0x000a, + 0x25aa: 0x000a, 0x25ab: 0x000a, 0x25ac: 0x000a, 0x25ad: 0x000a, 0x25ae: 0x000a, + 0x25b0: 0x000b, 0x25b1: 0x000b, 0x25b2: 0x000b, 0x25b3: 0x000b, 0x25b4: 0x000b, 0x25b5: 0x000b, + 0x25b6: 0x000b, 0x25b7: 0x000b, 0x25b8: 0x000b, 0x25b9: 0x000a, 0x25ba: 0x000a, 0x25bb: 0x000a, + 0x25bc: 0x000a, 0x25bd: 0x000a, 0x25be: 0x000b, 0x25bf: 0x000b, // Block 0x97, offset 0x25c0 - 0x25e0: 0x0004, 0x25e1: 0x0004, 0x25e2: 0x000a, 0x25e3: 0x000a, - 0x25e4: 0x000a, 0x25e5: 0x0004, 0x25e6: 0x0004, 0x25e8: 0x000a, 0x25e9: 0x000a, - 0x25ea: 0x000a, 0x25eb: 0x000a, 0x25ec: 0x000a, 0x25ed: 0x000a, 0x25ee: 0x000a, - 0x25f0: 0x000b, 0x25f1: 0x000b, 0x25f2: 0x000b, 0x25f3: 0x000b, 0x25f4: 0x000b, 0x25f5: 0x000b, - 0x25f6: 0x000b, 0x25f7: 0x000b, 0x25f8: 0x000b, 0x25f9: 0x000a, 0x25fa: 0x000a, 0x25fb: 0x000a, - 0x25fc: 0x000a, 0x25fd: 0x000a, 0x25fe: 0x000b, 0x25ff: 0x000b, + 0x25c1: 0x000a, // Block 0x98, offset 0x2600 - 0x2601: 0x000a, + 0x2600: 0x000a, 0x2601: 0x000a, 0x2602: 0x000a, 0x2603: 0x000a, 0x2604: 0x000a, 0x2605: 0x000a, + 0x2606: 0x000a, 0x2607: 0x000a, 0x2608: 0x000a, 0x2609: 0x000a, 0x260a: 0x000a, 0x260b: 0x000a, + 0x260c: 0x000a, 0x2610: 0x000a, 0x2611: 0x000a, + 0x2612: 0x000a, 0x2613: 0x000a, 0x2614: 0x000a, 0x2615: 0x000a, 0x2616: 0x000a, 0x2617: 0x000a, + 0x2618: 0x000a, 0x2619: 0x000a, 0x261a: 0x000a, 0x261b: 0x000a, + 0x2620: 0x000a, // Block 0x99, offset 0x2640 - 0x2640: 0x000a, 0x2641: 0x000a, 0x2642: 0x000a, 0x2643: 0x000a, 0x2644: 0x000a, 0x2645: 0x000a, - 0x2646: 0x000a, 0x2647: 0x000a, 0x2648: 0x000a, 0x2649: 0x000a, 0x264a: 0x000a, 0x264b: 0x000a, - 0x264c: 0x000a, 0x2650: 0x000a, 0x2651: 0x000a, - 0x2652: 0x000a, 0x2653: 0x000a, 0x2654: 0x000a, 0x2655: 0x000a, 0x2656: 0x000a, 0x2657: 0x000a, - 0x2658: 0x000a, 0x2659: 0x000a, 0x265a: 0x000a, 0x265b: 0x000a, - 0x2660: 0x000a, + 0x267d: 0x000c, // Block 0x9a, offset 0x2680 - 0x26bd: 0x000c, + 0x26a0: 0x000c, 0x26a1: 0x0002, 0x26a2: 0x0002, 0x26a3: 0x0002, + 0x26a4: 0x0002, 0x26a5: 0x0002, 0x26a6: 0x0002, 0x26a7: 0x0002, 0x26a8: 0x0002, 0x26a9: 0x0002, + 0x26aa: 0x0002, 0x26ab: 0x0002, 0x26ac: 0x0002, 0x26ad: 0x0002, 0x26ae: 0x0002, 0x26af: 0x0002, + 0x26b0: 0x0002, 0x26b1: 0x0002, 0x26b2: 0x0002, 0x26b3: 0x0002, 0x26b4: 0x0002, 0x26b5: 0x0002, + 0x26b6: 0x0002, 0x26b7: 0x0002, 0x26b8: 0x0002, 0x26b9: 0x0002, 0x26ba: 0x0002, 0x26bb: 0x0002, // Block 0x9b, offset 0x26c0 - 0x26e0: 0x000c, 0x26e1: 0x0002, 0x26e2: 0x0002, 0x26e3: 0x0002, - 0x26e4: 0x0002, 0x26e5: 0x0002, 0x26e6: 0x0002, 0x26e7: 0x0002, 0x26e8: 0x0002, 0x26e9: 0x0002, - 0x26ea: 0x0002, 0x26eb: 0x0002, 0x26ec: 0x0002, 0x26ed: 0x0002, 0x26ee: 0x0002, 0x26ef: 0x0002, - 0x26f0: 0x0002, 0x26f1: 0x0002, 0x26f2: 0x0002, 0x26f3: 0x0002, 0x26f4: 0x0002, 0x26f5: 0x0002, - 0x26f6: 0x0002, 0x26f7: 0x0002, 0x26f8: 0x0002, 0x26f9: 0x0002, 0x26fa: 0x0002, 0x26fb: 0x0002, + 0x26f6: 0x000c, 0x26f7: 0x000c, 0x26f8: 0x000c, 0x26f9: 0x000c, 0x26fa: 0x000c, // Block 0x9c, offset 0x2700 - 0x2736: 0x000c, 0x2737: 0x000c, 0x2738: 0x000c, 0x2739: 0x000c, 0x273a: 0x000c, + 0x2700: 0x0001, 0x2701: 0x0001, 0x2702: 0x0001, 0x2703: 0x0001, 0x2704: 0x0001, 0x2705: 0x0001, + 0x2706: 0x0001, 0x2707: 0x0001, 0x2708: 0x0001, 0x2709: 0x0001, 0x270a: 0x0001, 0x270b: 0x0001, + 0x270c: 0x0001, 0x270d: 0x0001, 0x270e: 0x0001, 0x270f: 0x0001, 0x2710: 0x0001, 0x2711: 0x0001, + 0x2712: 0x0001, 0x2713: 0x0001, 0x2714: 0x0001, 0x2715: 0x0001, 0x2716: 0x0001, 0x2717: 0x0001, + 0x2718: 0x0001, 0x2719: 0x0001, 0x271a: 0x0001, 0x271b: 0x0001, 0x271c: 0x0001, 0x271d: 0x0001, + 0x271e: 0x0001, 0x271f: 0x0001, 0x2720: 0x0001, 0x2721: 0x0001, 0x2722: 0x0001, 0x2723: 0x0001, + 0x2724: 0x0001, 0x2725: 0x0001, 0x2726: 0x0001, 0x2727: 0x0001, 0x2728: 0x0001, 0x2729: 0x0001, + 0x272a: 0x0001, 0x272b: 0x0001, 0x272c: 0x0001, 0x272d: 0x0001, 0x272e: 0x0001, 0x272f: 0x0001, + 0x2730: 0x0001, 0x2731: 0x0001, 0x2732: 0x0001, 0x2733: 0x0001, 0x2734: 0x0001, 0x2735: 0x0001, + 0x2736: 0x0001, 0x2737: 0x0001, 0x2738: 0x0001, 0x2739: 0x0001, 0x273a: 0x0001, 0x273b: 0x0001, + 0x273c: 0x0001, 0x273d: 0x0001, 0x273e: 0x0001, 0x273f: 0x0001, // Block 0x9d, offset 0x2740 0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, 0x2743: 0x0001, 0x2744: 0x0001, 0x2745: 0x0001, 0x2746: 0x0001, 0x2747: 0x0001, 0x2748: 0x0001, 0x2749: 0x0001, 0x274a: 0x0001, 0x274b: 0x0001, 0x274c: 0x0001, 0x274d: 0x0001, 0x274e: 0x0001, 0x274f: 0x0001, 0x2750: 0x0001, 0x2751: 0x0001, 0x2752: 0x0001, 0x2753: 0x0001, 0x2754: 0x0001, 0x2755: 0x0001, 0x2756: 0x0001, 0x2757: 0x0001, 0x2758: 0x0001, 0x2759: 0x0001, 0x275a: 0x0001, 0x275b: 0x0001, 0x275c: 0x0001, 0x275d: 0x0001, - 0x275e: 0x0001, 0x275f: 0x0001, 0x2760: 0x0001, 0x2761: 0x0001, 0x2762: 0x0001, 0x2763: 0x0001, + 0x275e: 0x0001, 0x275f: 0x000a, 0x2760: 0x0001, 0x2761: 0x0001, 0x2762: 0x0001, 0x2763: 0x0001, 0x2764: 0x0001, 0x2765: 0x0001, 0x2766: 0x0001, 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001, 0x276a: 0x0001, 0x276b: 0x0001, 0x276c: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001, 0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, 0x2775: 0x0001, 0x2776: 0x0001, 0x2777: 0x0001, 0x2778: 0x0001, 0x2779: 0x0001, 0x277a: 0x0001, 0x277b: 0x0001, 0x277c: 0x0001, 0x277d: 0x0001, 0x277e: 0x0001, 0x277f: 0x0001, // Block 0x9e, offset 0x2780 - 0x2780: 0x0001, 0x2781: 0x0001, 0x2782: 0x0001, 0x2783: 0x0001, 0x2784: 0x0001, 0x2785: 0x0001, - 0x2786: 0x0001, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001, - 0x278c: 0x0001, 0x278d: 0x0001, 0x278e: 0x0001, 0x278f: 0x0001, 0x2790: 0x0001, 0x2791: 0x0001, + 0x2780: 0x0001, 0x2781: 0x000c, 0x2782: 0x000c, 0x2783: 0x000c, 0x2784: 0x0001, 0x2785: 0x000c, + 0x2786: 0x000c, 0x2787: 0x0001, 0x2788: 0x0001, 0x2789: 0x0001, 0x278a: 0x0001, 0x278b: 0x0001, + 0x278c: 0x000c, 0x278d: 0x000c, 0x278e: 0x000c, 0x278f: 0x000c, 0x2790: 0x0001, 0x2791: 0x0001, 0x2792: 0x0001, 0x2793: 0x0001, 0x2794: 0x0001, 0x2795: 0x0001, 0x2796: 0x0001, 0x2797: 0x0001, 0x2798: 0x0001, 0x2799: 0x0001, 0x279a: 0x0001, 0x279b: 0x0001, 0x279c: 0x0001, 0x279d: 0x0001, - 0x279e: 0x0001, 0x279f: 0x000a, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001, + 0x279e: 0x0001, 0x279f: 0x0001, 0x27a0: 0x0001, 0x27a1: 0x0001, 0x27a2: 0x0001, 0x27a3: 0x0001, 0x27a4: 0x0001, 0x27a5: 0x0001, 0x27a6: 0x0001, 0x27a7: 0x0001, 0x27a8: 0x0001, 0x27a9: 0x0001, 0x27aa: 0x0001, 0x27ab: 0x0001, 0x27ac: 0x0001, 0x27ad: 0x0001, 0x27ae: 0x0001, 0x27af: 0x0001, 0x27b0: 0x0001, 0x27b1: 0x0001, 0x27b2: 0x0001, 0x27b3: 0x0001, 0x27b4: 0x0001, 0x27b5: 0x0001, - 0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x0001, 0x27b9: 0x0001, 0x27ba: 0x0001, 0x27bb: 0x0001, - 0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x0001, + 0x27b6: 0x0001, 0x27b7: 0x0001, 0x27b8: 0x000c, 0x27b9: 0x000c, 0x27ba: 0x000c, 0x27bb: 0x0001, + 0x27bc: 0x0001, 0x27bd: 0x0001, 0x27be: 0x0001, 0x27bf: 0x000c, // Block 0x9f, offset 0x27c0 - 0x27c0: 0x0001, 0x27c1: 0x000c, 0x27c2: 0x000c, 0x27c3: 0x000c, 0x27c4: 0x0001, 0x27c5: 0x000c, - 0x27c6: 0x000c, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001, - 0x27cc: 0x000c, 0x27cd: 0x000c, 0x27ce: 0x000c, 0x27cf: 0x000c, 0x27d0: 0x0001, 0x27d1: 0x0001, + 0x27c0: 0x0001, 0x27c1: 0x0001, 0x27c2: 0x0001, 0x27c3: 0x0001, 0x27c4: 0x0001, 0x27c5: 0x0001, + 0x27c6: 0x0001, 0x27c7: 0x0001, 0x27c8: 0x0001, 0x27c9: 0x0001, 0x27ca: 0x0001, 0x27cb: 0x0001, + 0x27cc: 0x0001, 0x27cd: 0x0001, 0x27ce: 0x0001, 0x27cf: 0x0001, 0x27d0: 0x0001, 0x27d1: 0x0001, 0x27d2: 0x0001, 0x27d3: 0x0001, 0x27d4: 0x0001, 0x27d5: 0x0001, 0x27d6: 0x0001, 0x27d7: 0x0001, 0x27d8: 0x0001, 0x27d9: 0x0001, 0x27da: 0x0001, 0x27db: 0x0001, 0x27dc: 0x0001, 0x27dd: 0x0001, 0x27de: 0x0001, 0x27df: 0x0001, 0x27e0: 0x0001, 0x27e1: 0x0001, 0x27e2: 0x0001, 0x27e3: 0x0001, - 0x27e4: 0x0001, 0x27e5: 0x0001, 0x27e6: 0x0001, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001, + 0x27e4: 0x0001, 0x27e5: 0x000c, 0x27e6: 0x000c, 0x27e7: 0x0001, 0x27e8: 0x0001, 0x27e9: 0x0001, 0x27ea: 0x0001, 0x27eb: 0x0001, 0x27ec: 0x0001, 0x27ed: 0x0001, 0x27ee: 0x0001, 0x27ef: 0x0001, 0x27f0: 0x0001, 0x27f1: 0x0001, 0x27f2: 0x0001, 0x27f3: 0x0001, 0x27f4: 0x0001, 0x27f5: 0x0001, - 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x000c, 0x27f9: 0x000c, 0x27fa: 0x000c, 0x27fb: 0x0001, - 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x000c, + 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x0001, 0x27f9: 0x0001, 0x27fa: 0x0001, 0x27fb: 0x0001, + 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, 0x27ff: 0x0001, // Block 0xa0, offset 0x2800 0x2800: 0x0001, 0x2801: 0x0001, 0x2802: 0x0001, 0x2803: 0x0001, 0x2804: 0x0001, 0x2805: 0x0001, 0x2806: 0x0001, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001, @@ -1282,382 +1288,409 @@ var bidiValues = [14208]uint8{ 0x2812: 0x0001, 0x2813: 0x0001, 0x2814: 0x0001, 0x2815: 0x0001, 0x2816: 0x0001, 0x2817: 0x0001, 0x2818: 0x0001, 0x2819: 0x0001, 0x281a: 0x0001, 0x281b: 0x0001, 0x281c: 0x0001, 0x281d: 0x0001, 0x281e: 0x0001, 0x281f: 0x0001, 0x2820: 0x0001, 0x2821: 0x0001, 0x2822: 0x0001, 0x2823: 0x0001, - 0x2824: 0x0001, 0x2825: 0x000c, 0x2826: 0x000c, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001, + 0x2824: 0x0001, 0x2825: 0x0001, 0x2826: 0x0001, 0x2827: 0x0001, 0x2828: 0x0001, 0x2829: 0x0001, 0x282a: 0x0001, 0x282b: 0x0001, 0x282c: 0x0001, 0x282d: 0x0001, 0x282e: 0x0001, 0x282f: 0x0001, 0x2830: 0x0001, 0x2831: 0x0001, 0x2832: 0x0001, 0x2833: 0x0001, 0x2834: 0x0001, 0x2835: 0x0001, - 0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x0001, 0x2839: 0x0001, 0x283a: 0x0001, 0x283b: 0x0001, - 0x283c: 0x0001, 0x283d: 0x0001, 0x283e: 0x0001, 0x283f: 0x0001, + 0x2836: 0x0001, 0x2837: 0x0001, 0x2838: 0x0001, 0x2839: 0x000a, 0x283a: 0x000a, 0x283b: 0x000a, + 0x283c: 0x000a, 0x283d: 0x000a, 0x283e: 0x000a, 0x283f: 0x000a, // Block 0xa1, offset 0x2840 0x2840: 0x0001, 0x2841: 0x0001, 0x2842: 0x0001, 0x2843: 0x0001, 0x2844: 0x0001, 0x2845: 0x0001, 0x2846: 0x0001, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001, 0x284c: 0x0001, 0x284d: 0x0001, 0x284e: 0x0001, 0x284f: 0x0001, 0x2850: 0x0001, 0x2851: 0x0001, 0x2852: 0x0001, 0x2853: 0x0001, 0x2854: 0x0001, 0x2855: 0x0001, 0x2856: 0x0001, 0x2857: 0x0001, 0x2858: 0x0001, 0x2859: 0x0001, 0x285a: 0x0001, 0x285b: 0x0001, 0x285c: 0x0001, 0x285d: 0x0001, - 0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0001, 0x2861: 0x0001, 0x2862: 0x0001, 0x2863: 0x0001, - 0x2864: 0x0001, 0x2865: 0x0001, 0x2866: 0x0001, 0x2867: 0x0001, 0x2868: 0x0001, 0x2869: 0x0001, - 0x286a: 0x0001, 0x286b: 0x0001, 0x286c: 0x0001, 0x286d: 0x0001, 0x286e: 0x0001, 0x286f: 0x0001, - 0x2870: 0x0001, 0x2871: 0x0001, 0x2872: 0x0001, 0x2873: 0x0001, 0x2874: 0x0001, 0x2875: 0x0001, - 0x2876: 0x0001, 0x2877: 0x0001, 0x2878: 0x0001, 0x2879: 0x000a, 0x287a: 0x000a, 0x287b: 0x000a, - 0x287c: 0x000a, 0x287d: 0x000a, 0x287e: 0x000a, 0x287f: 0x000a, + 0x285e: 0x0001, 0x285f: 0x0001, 0x2860: 0x0005, 0x2861: 0x0005, 0x2862: 0x0005, 0x2863: 0x0005, + 0x2864: 0x0005, 0x2865: 0x0005, 0x2866: 0x0005, 0x2867: 0x0005, 0x2868: 0x0005, 0x2869: 0x0005, + 0x286a: 0x0005, 0x286b: 0x0005, 0x286c: 0x0005, 0x286d: 0x0005, 0x286e: 0x0005, 0x286f: 0x0005, + 0x2870: 0x0005, 0x2871: 0x0005, 0x2872: 0x0005, 0x2873: 0x0005, 0x2874: 0x0005, 0x2875: 0x0005, + 0x2876: 0x0005, 0x2877: 0x0005, 0x2878: 0x0005, 0x2879: 0x0005, 0x287a: 0x0005, 0x287b: 0x0005, + 0x287c: 0x0005, 0x287d: 0x0005, 0x287e: 0x0005, 0x287f: 0x0001, // Block 0xa2, offset 0x2880 - 0x2880: 0x0001, 0x2881: 0x0001, 0x2882: 0x0001, 0x2883: 0x0001, 0x2884: 0x0001, 0x2885: 0x0001, - 0x2886: 0x0001, 0x2887: 0x0001, 0x2888: 0x0001, 0x2889: 0x0001, 0x288a: 0x0001, 0x288b: 0x0001, - 0x288c: 0x0001, 0x288d: 0x0001, 0x288e: 0x0001, 0x288f: 0x0001, 0x2890: 0x0001, 0x2891: 0x0001, - 0x2892: 0x0001, 0x2893: 0x0001, 0x2894: 0x0001, 0x2895: 0x0001, 0x2896: 0x0001, 0x2897: 0x0001, - 0x2898: 0x0001, 0x2899: 0x0001, 0x289a: 0x0001, 0x289b: 0x0001, 0x289c: 0x0001, 0x289d: 0x0001, - 0x289e: 0x0001, 0x289f: 0x0001, 0x28a0: 0x0005, 0x28a1: 0x0005, 0x28a2: 0x0005, 0x28a3: 0x0005, - 0x28a4: 0x0005, 0x28a5: 0x0005, 0x28a6: 0x0005, 0x28a7: 0x0005, 0x28a8: 0x0005, 0x28a9: 0x0005, - 0x28aa: 0x0005, 0x28ab: 0x0005, 0x28ac: 0x0005, 0x28ad: 0x0005, 0x28ae: 0x0005, 0x28af: 0x0005, - 0x28b0: 0x0005, 0x28b1: 0x0005, 0x28b2: 0x0005, 0x28b3: 0x0005, 0x28b4: 0x0005, 0x28b5: 0x0005, - 0x28b6: 0x0005, 0x28b7: 0x0005, 0x28b8: 0x0005, 0x28b9: 0x0005, 0x28ba: 0x0005, 0x28bb: 0x0005, - 0x28bc: 0x0005, 0x28bd: 0x0005, 0x28be: 0x0005, 0x28bf: 0x0001, + 0x2881: 0x000c, + 0x28b8: 0x000c, 0x28b9: 0x000c, 0x28ba: 0x000c, 0x28bb: 0x000c, + 0x28bc: 0x000c, 0x28bd: 0x000c, 0x28be: 0x000c, 0x28bf: 0x000c, // Block 0xa3, offset 0x28c0 - 0x28c1: 0x000c, - 0x28f8: 0x000c, 0x28f9: 0x000c, 0x28fa: 0x000c, 0x28fb: 0x000c, - 0x28fc: 0x000c, 0x28fd: 0x000c, 0x28fe: 0x000c, 0x28ff: 0x000c, + 0x28c0: 0x000c, 0x28c1: 0x000c, 0x28c2: 0x000c, 0x28c3: 0x000c, 0x28c4: 0x000c, 0x28c5: 0x000c, + 0x28c6: 0x000c, + 0x28d2: 0x000a, 0x28d3: 0x000a, 0x28d4: 0x000a, 0x28d5: 0x000a, 0x28d6: 0x000a, 0x28d7: 0x000a, + 0x28d8: 0x000a, 0x28d9: 0x000a, 0x28da: 0x000a, 0x28db: 0x000a, 0x28dc: 0x000a, 0x28dd: 0x000a, + 0x28de: 0x000a, 0x28df: 0x000a, 0x28e0: 0x000a, 0x28e1: 0x000a, 0x28e2: 0x000a, 0x28e3: 0x000a, + 0x28e4: 0x000a, 0x28e5: 0x000a, + 0x28ff: 0x000c, // Block 0xa4, offset 0x2900 - 0x2900: 0x000c, 0x2901: 0x000c, 0x2902: 0x000c, 0x2903: 0x000c, 0x2904: 0x000c, 0x2905: 0x000c, - 0x2906: 0x000c, - 0x2912: 0x000a, 0x2913: 0x000a, 0x2914: 0x000a, 0x2915: 0x000a, 0x2916: 0x000a, 0x2917: 0x000a, - 0x2918: 0x000a, 0x2919: 0x000a, 0x291a: 0x000a, 0x291b: 0x000a, 0x291c: 0x000a, 0x291d: 0x000a, - 0x291e: 0x000a, 0x291f: 0x000a, 0x2920: 0x000a, 0x2921: 0x000a, 0x2922: 0x000a, 0x2923: 0x000a, - 0x2924: 0x000a, 0x2925: 0x000a, - 0x293f: 0x000c, + 0x2900: 0x000c, 0x2901: 0x000c, + 0x2933: 0x000c, 0x2934: 0x000c, 0x2935: 0x000c, + 0x2936: 0x000c, 0x2939: 0x000c, 0x293a: 0x000c, // Block 0xa5, offset 0x2940 - 0x2940: 0x000c, 0x2941: 0x000c, - 0x2973: 0x000c, 0x2974: 0x000c, 0x2975: 0x000c, - 0x2976: 0x000c, 0x2979: 0x000c, 0x297a: 0x000c, + 0x2940: 0x000c, 0x2941: 0x000c, 0x2942: 0x000c, + 0x2967: 0x000c, 0x2968: 0x000c, 0x2969: 0x000c, + 0x296a: 0x000c, 0x296b: 0x000c, 0x296d: 0x000c, 0x296e: 0x000c, 0x296f: 0x000c, + 0x2970: 0x000c, 0x2971: 0x000c, 0x2972: 0x000c, 0x2973: 0x000c, 0x2974: 0x000c, // Block 0xa6, offset 0x2980 - 0x2980: 0x000c, 0x2981: 0x000c, 0x2982: 0x000c, - 0x29a7: 0x000c, 0x29a8: 0x000c, 0x29a9: 0x000c, - 0x29aa: 0x000c, 0x29ab: 0x000c, 0x29ad: 0x000c, 0x29ae: 0x000c, 0x29af: 0x000c, - 0x29b0: 0x000c, 0x29b1: 0x000c, 0x29b2: 0x000c, 0x29b3: 0x000c, 0x29b4: 0x000c, + 0x29b3: 0x000c, // Block 0xa7, offset 0x29c0 - 0x29f3: 0x000c, + 0x29c0: 0x000c, 0x29c1: 0x000c, + 0x29f6: 0x000c, 0x29f7: 0x000c, 0x29f8: 0x000c, 0x29f9: 0x000c, 0x29fa: 0x000c, 0x29fb: 0x000c, + 0x29fc: 0x000c, 0x29fd: 0x000c, 0x29fe: 0x000c, // Block 0xa8, offset 0x2a00 - 0x2a00: 0x000c, 0x2a01: 0x000c, - 0x2a36: 0x000c, 0x2a37: 0x000c, 0x2a38: 0x000c, 0x2a39: 0x000c, 0x2a3a: 0x000c, 0x2a3b: 0x000c, - 0x2a3c: 0x000c, 0x2a3d: 0x000c, 0x2a3e: 0x000c, + 0x2a0a: 0x000c, 0x2a0b: 0x000c, + 0x2a0c: 0x000c, // Block 0xa9, offset 0x2a40 - 0x2a4a: 0x000c, 0x2a4b: 0x000c, - 0x2a4c: 0x000c, + 0x2a6f: 0x000c, + 0x2a70: 0x000c, 0x2a71: 0x000c, 0x2a74: 0x000c, + 0x2a76: 0x000c, 0x2a77: 0x000c, + 0x2a7e: 0x000c, // Block 0xaa, offset 0x2a80 - 0x2aaf: 0x000c, - 0x2ab0: 0x000c, 0x2ab1: 0x000c, 0x2ab4: 0x000c, - 0x2ab6: 0x000c, 0x2ab7: 0x000c, - 0x2abe: 0x000c, + 0x2a9f: 0x000c, 0x2aa3: 0x000c, + 0x2aa4: 0x000c, 0x2aa5: 0x000c, 0x2aa6: 0x000c, 0x2aa7: 0x000c, 0x2aa8: 0x000c, 0x2aa9: 0x000c, + 0x2aaa: 0x000c, // Block 0xab, offset 0x2ac0 - 0x2adf: 0x000c, 0x2ae3: 0x000c, - 0x2ae4: 0x000c, 0x2ae5: 0x000c, 0x2ae6: 0x000c, 0x2ae7: 0x000c, 0x2ae8: 0x000c, 0x2ae9: 0x000c, - 0x2aea: 0x000c, + 0x2ac0: 0x000c, 0x2ac1: 0x000c, + 0x2afc: 0x000c, // Block 0xac, offset 0x2b00 - 0x2b00: 0x000c, 0x2b01: 0x000c, - 0x2b3c: 0x000c, + 0x2b00: 0x000c, + 0x2b26: 0x000c, 0x2b27: 0x000c, 0x2b28: 0x000c, 0x2b29: 0x000c, + 0x2b2a: 0x000c, 0x2b2b: 0x000c, 0x2b2c: 0x000c, + 0x2b30: 0x000c, 0x2b31: 0x000c, 0x2b32: 0x000c, 0x2b33: 0x000c, 0x2b34: 0x000c, // Block 0xad, offset 0x2b40 - 0x2b40: 0x000c, - 0x2b66: 0x000c, 0x2b67: 0x000c, 0x2b68: 0x000c, 0x2b69: 0x000c, - 0x2b6a: 0x000c, 0x2b6b: 0x000c, 0x2b6c: 0x000c, - 0x2b70: 0x000c, 0x2b71: 0x000c, 0x2b72: 0x000c, 0x2b73: 0x000c, 0x2b74: 0x000c, + 0x2b78: 0x000c, 0x2b79: 0x000c, 0x2b7a: 0x000c, 0x2b7b: 0x000c, + 0x2b7c: 0x000c, 0x2b7d: 0x000c, 0x2b7e: 0x000c, 0x2b7f: 0x000c, // Block 0xae, offset 0x2b80 - 0x2bb8: 0x000c, 0x2bb9: 0x000c, 0x2bba: 0x000c, 0x2bbb: 0x000c, - 0x2bbc: 0x000c, 0x2bbd: 0x000c, 0x2bbe: 0x000c, 0x2bbf: 0x000c, + 0x2b82: 0x000c, 0x2b83: 0x000c, 0x2b84: 0x000c, + 0x2b86: 0x000c, // Block 0xaf, offset 0x2bc0 - 0x2bc2: 0x000c, 0x2bc3: 0x000c, 0x2bc4: 0x000c, - 0x2bc6: 0x000c, + 0x2bf3: 0x000c, 0x2bf4: 0x000c, 0x2bf5: 0x000c, + 0x2bf6: 0x000c, 0x2bf7: 0x000c, 0x2bf8: 0x000c, 0x2bfa: 0x000c, + 0x2bff: 0x000c, // Block 0xb0, offset 0x2c00 - 0x2c33: 0x000c, 0x2c34: 0x000c, 0x2c35: 0x000c, - 0x2c36: 0x000c, 0x2c37: 0x000c, 0x2c38: 0x000c, 0x2c3a: 0x000c, - 0x2c3f: 0x000c, + 0x2c00: 0x000c, 0x2c02: 0x000c, 0x2c03: 0x000c, // Block 0xb1, offset 0x2c40 - 0x2c40: 0x000c, 0x2c42: 0x000c, 0x2c43: 0x000c, + 0x2c72: 0x000c, 0x2c73: 0x000c, 0x2c74: 0x000c, 0x2c75: 0x000c, + 0x2c7c: 0x000c, 0x2c7d: 0x000c, 0x2c7f: 0x000c, // Block 0xb2, offset 0x2c80 - 0x2cb2: 0x000c, 0x2cb3: 0x000c, 0x2cb4: 0x000c, 0x2cb5: 0x000c, - 0x2cbc: 0x000c, 0x2cbd: 0x000c, 0x2cbf: 0x000c, + 0x2c80: 0x000c, + 0x2c9c: 0x000c, 0x2c9d: 0x000c, // Block 0xb3, offset 0x2cc0 - 0x2cc0: 0x000c, - 0x2cdc: 0x000c, 0x2cdd: 0x000c, + 0x2cf3: 0x000c, 0x2cf4: 0x000c, 0x2cf5: 0x000c, + 0x2cf6: 0x000c, 0x2cf7: 0x000c, 0x2cf8: 0x000c, 0x2cf9: 0x000c, 0x2cfa: 0x000c, + 0x2cfd: 0x000c, 0x2cff: 0x000c, // Block 0xb4, offset 0x2d00 - 0x2d33: 0x000c, 0x2d34: 0x000c, 0x2d35: 0x000c, - 0x2d36: 0x000c, 0x2d37: 0x000c, 0x2d38: 0x000c, 0x2d39: 0x000c, 0x2d3a: 0x000c, - 0x2d3d: 0x000c, 0x2d3f: 0x000c, + 0x2d00: 0x000c, + 0x2d20: 0x000a, 0x2d21: 0x000a, 0x2d22: 0x000a, 0x2d23: 0x000a, + 0x2d24: 0x000a, 0x2d25: 0x000a, 0x2d26: 0x000a, 0x2d27: 0x000a, 0x2d28: 0x000a, 0x2d29: 0x000a, + 0x2d2a: 0x000a, 0x2d2b: 0x000a, 0x2d2c: 0x000a, // Block 0xb5, offset 0x2d40 - 0x2d40: 0x000c, - 0x2d60: 0x000a, 0x2d61: 0x000a, 0x2d62: 0x000a, 0x2d63: 0x000a, - 0x2d64: 0x000a, 0x2d65: 0x000a, 0x2d66: 0x000a, 0x2d67: 0x000a, 0x2d68: 0x000a, 0x2d69: 0x000a, - 0x2d6a: 0x000a, 0x2d6b: 0x000a, 0x2d6c: 0x000a, + 0x2d6b: 0x000c, 0x2d6d: 0x000c, + 0x2d70: 0x000c, 0x2d71: 0x000c, 0x2d72: 0x000c, 0x2d73: 0x000c, 0x2d74: 0x000c, 0x2d75: 0x000c, + 0x2d77: 0x000c, // Block 0xb6, offset 0x2d80 - 0x2dab: 0x000c, 0x2dad: 0x000c, - 0x2db0: 0x000c, 0x2db1: 0x000c, 0x2db2: 0x000c, 0x2db3: 0x000c, 0x2db4: 0x000c, 0x2db5: 0x000c, - 0x2db7: 0x000c, + 0x2d9d: 0x000c, + 0x2d9e: 0x000c, 0x2d9f: 0x000c, 0x2da2: 0x000c, 0x2da3: 0x000c, + 0x2da4: 0x000c, 0x2da5: 0x000c, 0x2da7: 0x000c, 0x2da8: 0x000c, 0x2da9: 0x000c, + 0x2daa: 0x000c, 0x2dab: 0x000c, // Block 0xb7, offset 0x2dc0 - 0x2ddd: 0x000c, - 0x2dde: 0x000c, 0x2ddf: 0x000c, 0x2de2: 0x000c, 0x2de3: 0x000c, - 0x2de4: 0x000c, 0x2de5: 0x000c, 0x2de7: 0x000c, 0x2de8: 0x000c, 0x2de9: 0x000c, - 0x2dea: 0x000c, 0x2deb: 0x000c, + 0x2dc1: 0x000c, 0x2dc2: 0x000c, 0x2dc3: 0x000c, 0x2dc4: 0x000c, 0x2dc5: 0x000c, + 0x2dc6: 0x000c, 0x2dc9: 0x000c, 0x2dca: 0x000c, + 0x2df3: 0x000c, 0x2df4: 0x000c, 0x2df5: 0x000c, + 0x2df6: 0x000c, 0x2df7: 0x000c, 0x2df8: 0x000c, 0x2dfb: 0x000c, + 0x2dfc: 0x000c, 0x2dfd: 0x000c, 0x2dfe: 0x000c, // Block 0xb8, offset 0x2e00 - 0x2e30: 0x000c, 0x2e31: 0x000c, 0x2e32: 0x000c, 0x2e33: 0x000c, 0x2e34: 0x000c, 0x2e35: 0x000c, - 0x2e36: 0x000c, 0x2e38: 0x000c, 0x2e39: 0x000c, 0x2e3a: 0x000c, 0x2e3b: 0x000c, - 0x2e3c: 0x000c, 0x2e3d: 0x000c, + 0x2e07: 0x000c, + 0x2e11: 0x000c, + 0x2e12: 0x000c, 0x2e13: 0x000c, 0x2e14: 0x000c, 0x2e15: 0x000c, 0x2e16: 0x000c, + 0x2e19: 0x000c, 0x2e1a: 0x000c, 0x2e1b: 0x000c, // Block 0xb9, offset 0x2e40 - 0x2e52: 0x000c, 0x2e53: 0x000c, 0x2e54: 0x000c, 0x2e55: 0x000c, 0x2e56: 0x000c, 0x2e57: 0x000c, - 0x2e58: 0x000c, 0x2e59: 0x000c, 0x2e5a: 0x000c, 0x2e5b: 0x000c, 0x2e5c: 0x000c, 0x2e5d: 0x000c, - 0x2e5e: 0x000c, 0x2e5f: 0x000c, 0x2e60: 0x000c, 0x2e61: 0x000c, 0x2e62: 0x000c, 0x2e63: 0x000c, - 0x2e64: 0x000c, 0x2e65: 0x000c, 0x2e66: 0x000c, 0x2e67: 0x000c, - 0x2e6a: 0x000c, 0x2e6b: 0x000c, 0x2e6c: 0x000c, 0x2e6d: 0x000c, 0x2e6e: 0x000c, 0x2e6f: 0x000c, - 0x2e70: 0x000c, 0x2e72: 0x000c, 0x2e73: 0x000c, 0x2e75: 0x000c, - 0x2e76: 0x000c, + 0x2e4a: 0x000c, 0x2e4b: 0x000c, + 0x2e4c: 0x000c, 0x2e4d: 0x000c, 0x2e4e: 0x000c, 0x2e4f: 0x000c, 0x2e50: 0x000c, 0x2e51: 0x000c, + 0x2e52: 0x000c, 0x2e53: 0x000c, 0x2e54: 0x000c, 0x2e55: 0x000c, 0x2e56: 0x000c, + 0x2e58: 0x000c, 0x2e59: 0x000c, // Block 0xba, offset 0x2e80 - 0x2eb0: 0x000c, 0x2eb1: 0x000c, 0x2eb2: 0x000c, 0x2eb3: 0x000c, 0x2eb4: 0x000c, + 0x2eb0: 0x000c, 0x2eb1: 0x000c, 0x2eb2: 0x000c, 0x2eb3: 0x000c, 0x2eb4: 0x000c, 0x2eb5: 0x000c, + 0x2eb6: 0x000c, 0x2eb8: 0x000c, 0x2eb9: 0x000c, 0x2eba: 0x000c, 0x2ebb: 0x000c, + 0x2ebc: 0x000c, 0x2ebd: 0x000c, // Block 0xbb, offset 0x2ec0 - 0x2ef0: 0x000c, 0x2ef1: 0x000c, 0x2ef2: 0x000c, 0x2ef3: 0x000c, 0x2ef4: 0x000c, 0x2ef5: 0x000c, + 0x2ed2: 0x000c, 0x2ed3: 0x000c, 0x2ed4: 0x000c, 0x2ed5: 0x000c, 0x2ed6: 0x000c, 0x2ed7: 0x000c, + 0x2ed8: 0x000c, 0x2ed9: 0x000c, 0x2eda: 0x000c, 0x2edb: 0x000c, 0x2edc: 0x000c, 0x2edd: 0x000c, + 0x2ede: 0x000c, 0x2edf: 0x000c, 0x2ee0: 0x000c, 0x2ee1: 0x000c, 0x2ee2: 0x000c, 0x2ee3: 0x000c, + 0x2ee4: 0x000c, 0x2ee5: 0x000c, 0x2ee6: 0x000c, 0x2ee7: 0x000c, + 0x2eea: 0x000c, 0x2eeb: 0x000c, 0x2eec: 0x000c, 0x2eed: 0x000c, 0x2eee: 0x000c, 0x2eef: 0x000c, + 0x2ef0: 0x000c, 0x2ef2: 0x000c, 0x2ef3: 0x000c, 0x2ef5: 0x000c, 0x2ef6: 0x000c, // Block 0xbc, offset 0x2f00 - 0x2f0f: 0x000c, 0x2f10: 0x000c, 0x2f11: 0x000c, - 0x2f12: 0x000c, + 0x2f31: 0x000c, 0x2f32: 0x000c, 0x2f33: 0x000c, 0x2f34: 0x000c, 0x2f35: 0x000c, + 0x2f36: 0x000c, 0x2f3a: 0x000c, + 0x2f3c: 0x000c, 0x2f3d: 0x000c, 0x2f3f: 0x000c, // Block 0xbd, offset 0x2f40 - 0x2f5d: 0x000c, - 0x2f5e: 0x000c, 0x2f60: 0x000b, 0x2f61: 0x000b, 0x2f62: 0x000b, 0x2f63: 0x000b, + 0x2f40: 0x000c, 0x2f41: 0x000c, 0x2f42: 0x000c, 0x2f43: 0x000c, 0x2f44: 0x000c, 0x2f45: 0x000c, + 0x2f47: 0x000c, // Block 0xbe, offset 0x2f80 - 0x2fa7: 0x000c, 0x2fa8: 0x000c, 0x2fa9: 0x000c, - 0x2fb3: 0x000b, 0x2fb4: 0x000b, 0x2fb5: 0x000b, - 0x2fb6: 0x000b, 0x2fb7: 0x000b, 0x2fb8: 0x000b, 0x2fb9: 0x000b, 0x2fba: 0x000b, 0x2fbb: 0x000c, - 0x2fbc: 0x000c, 0x2fbd: 0x000c, 0x2fbe: 0x000c, 0x2fbf: 0x000c, + 0x2fb0: 0x000c, 0x2fb1: 0x000c, 0x2fb2: 0x000c, 0x2fb3: 0x000c, 0x2fb4: 0x000c, // Block 0xbf, offset 0x2fc0 - 0x2fc0: 0x000c, 0x2fc1: 0x000c, 0x2fc2: 0x000c, 0x2fc5: 0x000c, - 0x2fc6: 0x000c, 0x2fc7: 0x000c, 0x2fc8: 0x000c, 0x2fc9: 0x000c, 0x2fca: 0x000c, 0x2fcb: 0x000c, - 0x2fea: 0x000c, 0x2feb: 0x000c, 0x2fec: 0x000c, 0x2fed: 0x000c, + 0x2ff0: 0x000c, 0x2ff1: 0x000c, 0x2ff2: 0x000c, 0x2ff3: 0x000c, 0x2ff4: 0x000c, 0x2ff5: 0x000c, + 0x2ff6: 0x000c, // Block 0xc0, offset 0x3000 - 0x3000: 0x000a, 0x3001: 0x000a, 0x3002: 0x000c, 0x3003: 0x000c, 0x3004: 0x000c, 0x3005: 0x000a, + 0x300f: 0x000c, 0x3010: 0x000c, 0x3011: 0x000c, + 0x3012: 0x000c, // Block 0xc1, offset 0x3040 - 0x3040: 0x000a, 0x3041: 0x000a, 0x3042: 0x000a, 0x3043: 0x000a, 0x3044: 0x000a, 0x3045: 0x000a, - 0x3046: 0x000a, 0x3047: 0x000a, 0x3048: 0x000a, 0x3049: 0x000a, 0x304a: 0x000a, 0x304b: 0x000a, - 0x304c: 0x000a, 0x304d: 0x000a, 0x304e: 0x000a, 0x304f: 0x000a, 0x3050: 0x000a, 0x3051: 0x000a, - 0x3052: 0x000a, 0x3053: 0x000a, 0x3054: 0x000a, 0x3055: 0x000a, 0x3056: 0x000a, + 0x305d: 0x000c, + 0x305e: 0x000c, 0x3060: 0x000b, 0x3061: 0x000b, 0x3062: 0x000b, 0x3063: 0x000b, // Block 0xc2, offset 0x3080 - 0x309b: 0x000a, + 0x30a7: 0x000c, 0x30a8: 0x000c, 0x30a9: 0x000c, + 0x30b3: 0x000b, 0x30b4: 0x000b, 0x30b5: 0x000b, + 0x30b6: 0x000b, 0x30b7: 0x000b, 0x30b8: 0x000b, 0x30b9: 0x000b, 0x30ba: 0x000b, 0x30bb: 0x000c, + 0x30bc: 0x000c, 0x30bd: 0x000c, 0x30be: 0x000c, 0x30bf: 0x000c, // Block 0xc3, offset 0x30c0 - 0x30d5: 0x000a, + 0x30c0: 0x000c, 0x30c1: 0x000c, 0x30c2: 0x000c, 0x30c5: 0x000c, + 0x30c6: 0x000c, 0x30c7: 0x000c, 0x30c8: 0x000c, 0x30c9: 0x000c, 0x30ca: 0x000c, 0x30cb: 0x000c, + 0x30ea: 0x000c, 0x30eb: 0x000c, 0x30ec: 0x000c, 0x30ed: 0x000c, // Block 0xc4, offset 0x3100 - 0x310f: 0x000a, + 0x3100: 0x000a, 0x3101: 0x000a, 0x3102: 0x000c, 0x3103: 0x000c, 0x3104: 0x000c, 0x3105: 0x000a, // Block 0xc5, offset 0x3140 - 0x3149: 0x000a, + 0x3140: 0x000a, 0x3141: 0x000a, 0x3142: 0x000a, 0x3143: 0x000a, 0x3144: 0x000a, 0x3145: 0x000a, + 0x3146: 0x000a, 0x3147: 0x000a, 0x3148: 0x000a, 0x3149: 0x000a, 0x314a: 0x000a, 0x314b: 0x000a, + 0x314c: 0x000a, 0x314d: 0x000a, 0x314e: 0x000a, 0x314f: 0x000a, 0x3150: 0x000a, 0x3151: 0x000a, + 0x3152: 0x000a, 0x3153: 0x000a, 0x3154: 0x000a, 0x3155: 0x000a, 0x3156: 0x000a, // Block 0xc6, offset 0x3180 - 0x3183: 0x000a, - 0x318e: 0x0002, 0x318f: 0x0002, 0x3190: 0x0002, 0x3191: 0x0002, - 0x3192: 0x0002, 0x3193: 0x0002, 0x3194: 0x0002, 0x3195: 0x0002, 0x3196: 0x0002, 0x3197: 0x0002, - 0x3198: 0x0002, 0x3199: 0x0002, 0x319a: 0x0002, 0x319b: 0x0002, 0x319c: 0x0002, 0x319d: 0x0002, - 0x319e: 0x0002, 0x319f: 0x0002, 0x31a0: 0x0002, 0x31a1: 0x0002, 0x31a2: 0x0002, 0x31a3: 0x0002, - 0x31a4: 0x0002, 0x31a5: 0x0002, 0x31a6: 0x0002, 0x31a7: 0x0002, 0x31a8: 0x0002, 0x31a9: 0x0002, - 0x31aa: 0x0002, 0x31ab: 0x0002, 0x31ac: 0x0002, 0x31ad: 0x0002, 0x31ae: 0x0002, 0x31af: 0x0002, - 0x31b0: 0x0002, 0x31b1: 0x0002, 0x31b2: 0x0002, 0x31b3: 0x0002, 0x31b4: 0x0002, 0x31b5: 0x0002, - 0x31b6: 0x0002, 0x31b7: 0x0002, 0x31b8: 0x0002, 0x31b9: 0x0002, 0x31ba: 0x0002, 0x31bb: 0x0002, - 0x31bc: 0x0002, 0x31bd: 0x0002, 0x31be: 0x0002, 0x31bf: 0x0002, + 0x319b: 0x000a, // Block 0xc7, offset 0x31c0 - 0x31c0: 0x000c, 0x31c1: 0x000c, 0x31c2: 0x000c, 0x31c3: 0x000c, 0x31c4: 0x000c, 0x31c5: 0x000c, - 0x31c6: 0x000c, 0x31c7: 0x000c, 0x31c8: 0x000c, 0x31c9: 0x000c, 0x31ca: 0x000c, 0x31cb: 0x000c, - 0x31cc: 0x000c, 0x31cd: 0x000c, 0x31ce: 0x000c, 0x31cf: 0x000c, 0x31d0: 0x000c, 0x31d1: 0x000c, - 0x31d2: 0x000c, 0x31d3: 0x000c, 0x31d4: 0x000c, 0x31d5: 0x000c, 0x31d6: 0x000c, 0x31d7: 0x000c, - 0x31d8: 0x000c, 0x31d9: 0x000c, 0x31da: 0x000c, 0x31db: 0x000c, 0x31dc: 0x000c, 0x31dd: 0x000c, - 0x31de: 0x000c, 0x31df: 0x000c, 0x31e0: 0x000c, 0x31e1: 0x000c, 0x31e2: 0x000c, 0x31e3: 0x000c, - 0x31e4: 0x000c, 0x31e5: 0x000c, 0x31e6: 0x000c, 0x31e7: 0x000c, 0x31e8: 0x000c, 0x31e9: 0x000c, - 0x31ea: 0x000c, 0x31eb: 0x000c, 0x31ec: 0x000c, 0x31ed: 0x000c, 0x31ee: 0x000c, 0x31ef: 0x000c, - 0x31f0: 0x000c, 0x31f1: 0x000c, 0x31f2: 0x000c, 0x31f3: 0x000c, 0x31f4: 0x000c, 0x31f5: 0x000c, - 0x31f6: 0x000c, 0x31fb: 0x000c, - 0x31fc: 0x000c, 0x31fd: 0x000c, 0x31fe: 0x000c, 0x31ff: 0x000c, + 0x31d5: 0x000a, // Block 0xc8, offset 0x3200 - 0x3200: 0x000c, 0x3201: 0x000c, 0x3202: 0x000c, 0x3203: 0x000c, 0x3204: 0x000c, 0x3205: 0x000c, - 0x3206: 0x000c, 0x3207: 0x000c, 0x3208: 0x000c, 0x3209: 0x000c, 0x320a: 0x000c, 0x320b: 0x000c, - 0x320c: 0x000c, 0x320d: 0x000c, 0x320e: 0x000c, 0x320f: 0x000c, 0x3210: 0x000c, 0x3211: 0x000c, - 0x3212: 0x000c, 0x3213: 0x000c, 0x3214: 0x000c, 0x3215: 0x000c, 0x3216: 0x000c, 0x3217: 0x000c, - 0x3218: 0x000c, 0x3219: 0x000c, 0x321a: 0x000c, 0x321b: 0x000c, 0x321c: 0x000c, 0x321d: 0x000c, - 0x321e: 0x000c, 0x321f: 0x000c, 0x3220: 0x000c, 0x3221: 0x000c, 0x3222: 0x000c, 0x3223: 0x000c, - 0x3224: 0x000c, 0x3225: 0x000c, 0x3226: 0x000c, 0x3227: 0x000c, 0x3228: 0x000c, 0x3229: 0x000c, - 0x322a: 0x000c, 0x322b: 0x000c, 0x322c: 0x000c, - 0x3235: 0x000c, + 0x320f: 0x000a, // Block 0xc9, offset 0x3240 - 0x3244: 0x000c, - 0x325b: 0x000c, 0x325c: 0x000c, 0x325d: 0x000c, - 0x325e: 0x000c, 0x325f: 0x000c, 0x3261: 0x000c, 0x3262: 0x000c, 0x3263: 0x000c, - 0x3264: 0x000c, 0x3265: 0x000c, 0x3266: 0x000c, 0x3267: 0x000c, 0x3268: 0x000c, 0x3269: 0x000c, - 0x326a: 0x000c, 0x326b: 0x000c, 0x326c: 0x000c, 0x326d: 0x000c, 0x326e: 0x000c, 0x326f: 0x000c, + 0x3249: 0x000a, // Block 0xca, offset 0x3280 - 0x3280: 0x000c, 0x3281: 0x000c, 0x3282: 0x000c, 0x3283: 0x000c, 0x3284: 0x000c, 0x3285: 0x000c, - 0x3286: 0x000c, 0x3288: 0x000c, 0x3289: 0x000c, 0x328a: 0x000c, 0x328b: 0x000c, - 0x328c: 0x000c, 0x328d: 0x000c, 0x328e: 0x000c, 0x328f: 0x000c, 0x3290: 0x000c, 0x3291: 0x000c, - 0x3292: 0x000c, 0x3293: 0x000c, 0x3294: 0x000c, 0x3295: 0x000c, 0x3296: 0x000c, 0x3297: 0x000c, - 0x3298: 0x000c, 0x329b: 0x000c, 0x329c: 0x000c, 0x329d: 0x000c, - 0x329e: 0x000c, 0x329f: 0x000c, 0x32a0: 0x000c, 0x32a1: 0x000c, 0x32a3: 0x000c, - 0x32a4: 0x000c, 0x32a6: 0x000c, 0x32a7: 0x000c, 0x32a8: 0x000c, 0x32a9: 0x000c, - 0x32aa: 0x000c, + 0x3283: 0x000a, + 0x328e: 0x0002, 0x328f: 0x0002, 0x3290: 0x0002, 0x3291: 0x0002, + 0x3292: 0x0002, 0x3293: 0x0002, 0x3294: 0x0002, 0x3295: 0x0002, 0x3296: 0x0002, 0x3297: 0x0002, + 0x3298: 0x0002, 0x3299: 0x0002, 0x329a: 0x0002, 0x329b: 0x0002, 0x329c: 0x0002, 0x329d: 0x0002, + 0x329e: 0x0002, 0x329f: 0x0002, 0x32a0: 0x0002, 0x32a1: 0x0002, 0x32a2: 0x0002, 0x32a3: 0x0002, + 0x32a4: 0x0002, 0x32a5: 0x0002, 0x32a6: 0x0002, 0x32a7: 0x0002, 0x32a8: 0x0002, 0x32a9: 0x0002, + 0x32aa: 0x0002, 0x32ab: 0x0002, 0x32ac: 0x0002, 0x32ad: 0x0002, 0x32ae: 0x0002, 0x32af: 0x0002, + 0x32b0: 0x0002, 0x32b1: 0x0002, 0x32b2: 0x0002, 0x32b3: 0x0002, 0x32b4: 0x0002, 0x32b5: 0x0002, + 0x32b6: 0x0002, 0x32b7: 0x0002, 0x32b8: 0x0002, 0x32b9: 0x0002, 0x32ba: 0x0002, 0x32bb: 0x0002, + 0x32bc: 0x0002, 0x32bd: 0x0002, 0x32be: 0x0002, 0x32bf: 0x0002, // Block 0xcb, offset 0x32c0 - 0x32c0: 0x0001, 0x32c1: 0x0001, 0x32c2: 0x0001, 0x32c3: 0x0001, 0x32c4: 0x0001, 0x32c5: 0x0001, - 0x32c6: 0x0001, 0x32c7: 0x0001, 0x32c8: 0x0001, 0x32c9: 0x0001, 0x32ca: 0x0001, 0x32cb: 0x0001, - 0x32cc: 0x0001, 0x32cd: 0x0001, 0x32ce: 0x0001, 0x32cf: 0x0001, 0x32d0: 0x000c, 0x32d1: 0x000c, - 0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x0001, - 0x32d8: 0x0001, 0x32d9: 0x0001, 0x32da: 0x0001, 0x32db: 0x0001, 0x32dc: 0x0001, 0x32dd: 0x0001, - 0x32de: 0x0001, 0x32df: 0x0001, 0x32e0: 0x0001, 0x32e1: 0x0001, 0x32e2: 0x0001, 0x32e3: 0x0001, - 0x32e4: 0x0001, 0x32e5: 0x0001, 0x32e6: 0x0001, 0x32e7: 0x0001, 0x32e8: 0x0001, 0x32e9: 0x0001, - 0x32ea: 0x0001, 0x32eb: 0x0001, 0x32ec: 0x0001, 0x32ed: 0x0001, 0x32ee: 0x0001, 0x32ef: 0x0001, - 0x32f0: 0x0001, 0x32f1: 0x0001, 0x32f2: 0x0001, 0x32f3: 0x0001, 0x32f4: 0x0001, 0x32f5: 0x0001, - 0x32f6: 0x0001, 0x32f7: 0x0001, 0x32f8: 0x0001, 0x32f9: 0x0001, 0x32fa: 0x0001, 0x32fb: 0x0001, - 0x32fc: 0x0001, 0x32fd: 0x0001, 0x32fe: 0x0001, 0x32ff: 0x0001, + 0x32c0: 0x000c, 0x32c1: 0x000c, 0x32c2: 0x000c, 0x32c3: 0x000c, 0x32c4: 0x000c, 0x32c5: 0x000c, + 0x32c6: 0x000c, 0x32c7: 0x000c, 0x32c8: 0x000c, 0x32c9: 0x000c, 0x32ca: 0x000c, 0x32cb: 0x000c, + 0x32cc: 0x000c, 0x32cd: 0x000c, 0x32ce: 0x000c, 0x32cf: 0x000c, 0x32d0: 0x000c, 0x32d1: 0x000c, + 0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x000c, + 0x32d8: 0x000c, 0x32d9: 0x000c, 0x32da: 0x000c, 0x32db: 0x000c, 0x32dc: 0x000c, 0x32dd: 0x000c, + 0x32de: 0x000c, 0x32df: 0x000c, 0x32e0: 0x000c, 0x32e1: 0x000c, 0x32e2: 0x000c, 0x32e3: 0x000c, + 0x32e4: 0x000c, 0x32e5: 0x000c, 0x32e6: 0x000c, 0x32e7: 0x000c, 0x32e8: 0x000c, 0x32e9: 0x000c, + 0x32ea: 0x000c, 0x32eb: 0x000c, 0x32ec: 0x000c, 0x32ed: 0x000c, 0x32ee: 0x000c, 0x32ef: 0x000c, + 0x32f0: 0x000c, 0x32f1: 0x000c, 0x32f2: 0x000c, 0x32f3: 0x000c, 0x32f4: 0x000c, 0x32f5: 0x000c, + 0x32f6: 0x000c, 0x32fb: 0x000c, + 0x32fc: 0x000c, 0x32fd: 0x000c, 0x32fe: 0x000c, 0x32ff: 0x000c, // Block 0xcc, offset 0x3300 - 0x3300: 0x0001, 0x3301: 0x0001, 0x3302: 0x0001, 0x3303: 0x0001, 0x3304: 0x000c, 0x3305: 0x000c, - 0x3306: 0x000c, 0x3307: 0x000c, 0x3308: 0x000c, 0x3309: 0x000c, 0x330a: 0x000c, 0x330b: 0x0001, - 0x330c: 0x0001, 0x330d: 0x0001, 0x330e: 0x0001, 0x330f: 0x0001, 0x3310: 0x0001, 0x3311: 0x0001, - 0x3312: 0x0001, 0x3313: 0x0001, 0x3314: 0x0001, 0x3315: 0x0001, 0x3316: 0x0001, 0x3317: 0x0001, - 0x3318: 0x0001, 0x3319: 0x0001, 0x331a: 0x0001, 0x331b: 0x0001, 0x331c: 0x0001, 0x331d: 0x0001, - 0x331e: 0x0001, 0x331f: 0x0001, 0x3320: 0x0001, 0x3321: 0x0001, 0x3322: 0x0001, 0x3323: 0x0001, - 0x3324: 0x0001, 0x3325: 0x0001, 0x3326: 0x0001, 0x3327: 0x0001, 0x3328: 0x0001, 0x3329: 0x0001, - 0x332a: 0x0001, 0x332b: 0x0001, 0x332c: 0x0001, 0x332d: 0x0001, 0x332e: 0x0001, 0x332f: 0x0001, - 0x3330: 0x0001, 0x3331: 0x0001, 0x3332: 0x0001, 0x3333: 0x0001, 0x3334: 0x0001, 0x3335: 0x0001, - 0x3336: 0x0001, 0x3337: 0x0001, 0x3338: 0x0001, 0x3339: 0x0001, 0x333a: 0x0001, 0x333b: 0x0001, - 0x333c: 0x0001, 0x333d: 0x0001, 0x333e: 0x0001, 0x333f: 0x0001, + 0x3300: 0x000c, 0x3301: 0x000c, 0x3302: 0x000c, 0x3303: 0x000c, 0x3304: 0x000c, 0x3305: 0x000c, + 0x3306: 0x000c, 0x3307: 0x000c, 0x3308: 0x000c, 0x3309: 0x000c, 0x330a: 0x000c, 0x330b: 0x000c, + 0x330c: 0x000c, 0x330d: 0x000c, 0x330e: 0x000c, 0x330f: 0x000c, 0x3310: 0x000c, 0x3311: 0x000c, + 0x3312: 0x000c, 0x3313: 0x000c, 0x3314: 0x000c, 0x3315: 0x000c, 0x3316: 0x000c, 0x3317: 0x000c, + 0x3318: 0x000c, 0x3319: 0x000c, 0x331a: 0x000c, 0x331b: 0x000c, 0x331c: 0x000c, 0x331d: 0x000c, + 0x331e: 0x000c, 0x331f: 0x000c, 0x3320: 0x000c, 0x3321: 0x000c, 0x3322: 0x000c, 0x3323: 0x000c, + 0x3324: 0x000c, 0x3325: 0x000c, 0x3326: 0x000c, 0x3327: 0x000c, 0x3328: 0x000c, 0x3329: 0x000c, + 0x332a: 0x000c, 0x332b: 0x000c, 0x332c: 0x000c, + 0x3335: 0x000c, // Block 0xcd, offset 0x3340 - 0x3340: 0x000d, 0x3341: 0x000d, 0x3342: 0x000d, 0x3343: 0x000d, 0x3344: 0x000d, 0x3345: 0x000d, - 0x3346: 0x000d, 0x3347: 0x000d, 0x3348: 0x000d, 0x3349: 0x000d, 0x334a: 0x000d, 0x334b: 0x000d, - 0x334c: 0x000d, 0x334d: 0x000d, 0x334e: 0x000d, 0x334f: 0x000d, 0x3350: 0x000d, 0x3351: 0x000d, - 0x3352: 0x000d, 0x3353: 0x000d, 0x3354: 0x000d, 0x3355: 0x000d, 0x3356: 0x000d, 0x3357: 0x000d, - 0x3358: 0x000d, 0x3359: 0x000d, 0x335a: 0x000d, 0x335b: 0x000d, 0x335c: 0x000d, 0x335d: 0x000d, - 0x335e: 0x000d, 0x335f: 0x000d, 0x3360: 0x000d, 0x3361: 0x000d, 0x3362: 0x000d, 0x3363: 0x000d, - 0x3364: 0x000d, 0x3365: 0x000d, 0x3366: 0x000d, 0x3367: 0x000d, 0x3368: 0x000d, 0x3369: 0x000d, - 0x336a: 0x000d, 0x336b: 0x000d, 0x336c: 0x000d, 0x336d: 0x000d, 0x336e: 0x000d, 0x336f: 0x000d, - 0x3370: 0x000a, 0x3371: 0x000a, 0x3372: 0x000d, 0x3373: 0x000d, 0x3374: 0x000d, 0x3375: 0x000d, - 0x3376: 0x000d, 0x3377: 0x000d, 0x3378: 0x000d, 0x3379: 0x000d, 0x337a: 0x000d, 0x337b: 0x000d, - 0x337c: 0x000d, 0x337d: 0x000d, 0x337e: 0x000d, 0x337f: 0x000d, + 0x3344: 0x000c, + 0x335b: 0x000c, 0x335c: 0x000c, 0x335d: 0x000c, + 0x335e: 0x000c, 0x335f: 0x000c, 0x3361: 0x000c, 0x3362: 0x000c, 0x3363: 0x000c, + 0x3364: 0x000c, 0x3365: 0x000c, 0x3366: 0x000c, 0x3367: 0x000c, 0x3368: 0x000c, 0x3369: 0x000c, + 0x336a: 0x000c, 0x336b: 0x000c, 0x336c: 0x000c, 0x336d: 0x000c, 0x336e: 0x000c, 0x336f: 0x000c, // Block 0xce, offset 0x3380 - 0x3380: 0x000a, 0x3381: 0x000a, 0x3382: 0x000a, 0x3383: 0x000a, 0x3384: 0x000a, 0x3385: 0x000a, - 0x3386: 0x000a, 0x3387: 0x000a, 0x3388: 0x000a, 0x3389: 0x000a, 0x338a: 0x000a, 0x338b: 0x000a, - 0x338c: 0x000a, 0x338d: 0x000a, 0x338e: 0x000a, 0x338f: 0x000a, 0x3390: 0x000a, 0x3391: 0x000a, - 0x3392: 0x000a, 0x3393: 0x000a, 0x3394: 0x000a, 0x3395: 0x000a, 0x3396: 0x000a, 0x3397: 0x000a, - 0x3398: 0x000a, 0x3399: 0x000a, 0x339a: 0x000a, 0x339b: 0x000a, 0x339c: 0x000a, 0x339d: 0x000a, - 0x339e: 0x000a, 0x339f: 0x000a, 0x33a0: 0x000a, 0x33a1: 0x000a, 0x33a2: 0x000a, 0x33a3: 0x000a, - 0x33a4: 0x000a, 0x33a5: 0x000a, 0x33a6: 0x000a, 0x33a7: 0x000a, 0x33a8: 0x000a, 0x33a9: 0x000a, - 0x33aa: 0x000a, 0x33ab: 0x000a, - 0x33b0: 0x000a, 0x33b1: 0x000a, 0x33b2: 0x000a, 0x33b3: 0x000a, 0x33b4: 0x000a, 0x33b5: 0x000a, - 0x33b6: 0x000a, 0x33b7: 0x000a, 0x33b8: 0x000a, 0x33b9: 0x000a, 0x33ba: 0x000a, 0x33bb: 0x000a, - 0x33bc: 0x000a, 0x33bd: 0x000a, 0x33be: 0x000a, 0x33bf: 0x000a, + 0x3380: 0x000c, 0x3381: 0x000c, 0x3382: 0x000c, 0x3383: 0x000c, 0x3384: 0x000c, 0x3385: 0x000c, + 0x3386: 0x000c, 0x3388: 0x000c, 0x3389: 0x000c, 0x338a: 0x000c, 0x338b: 0x000c, + 0x338c: 0x000c, 0x338d: 0x000c, 0x338e: 0x000c, 0x338f: 0x000c, 0x3390: 0x000c, 0x3391: 0x000c, + 0x3392: 0x000c, 0x3393: 0x000c, 0x3394: 0x000c, 0x3395: 0x000c, 0x3396: 0x000c, 0x3397: 0x000c, + 0x3398: 0x000c, 0x339b: 0x000c, 0x339c: 0x000c, 0x339d: 0x000c, + 0x339e: 0x000c, 0x339f: 0x000c, 0x33a0: 0x000c, 0x33a1: 0x000c, 0x33a3: 0x000c, + 0x33a4: 0x000c, 0x33a6: 0x000c, 0x33a7: 0x000c, 0x33a8: 0x000c, 0x33a9: 0x000c, + 0x33aa: 0x000c, // Block 0xcf, offset 0x33c0 - 0x33c0: 0x000a, 0x33c1: 0x000a, 0x33c2: 0x000a, 0x33c3: 0x000a, 0x33c4: 0x000a, 0x33c5: 0x000a, - 0x33c6: 0x000a, 0x33c7: 0x000a, 0x33c8: 0x000a, 0x33c9: 0x000a, 0x33ca: 0x000a, 0x33cb: 0x000a, - 0x33cc: 0x000a, 0x33cd: 0x000a, 0x33ce: 0x000a, 0x33cf: 0x000a, 0x33d0: 0x000a, 0x33d1: 0x000a, - 0x33d2: 0x000a, 0x33d3: 0x000a, - 0x33e0: 0x000a, 0x33e1: 0x000a, 0x33e2: 0x000a, 0x33e3: 0x000a, - 0x33e4: 0x000a, 0x33e5: 0x000a, 0x33e6: 0x000a, 0x33e7: 0x000a, 0x33e8: 0x000a, 0x33e9: 0x000a, - 0x33ea: 0x000a, 0x33eb: 0x000a, 0x33ec: 0x000a, 0x33ed: 0x000a, 0x33ee: 0x000a, - 0x33f1: 0x000a, 0x33f2: 0x000a, 0x33f3: 0x000a, 0x33f4: 0x000a, 0x33f5: 0x000a, - 0x33f6: 0x000a, 0x33f7: 0x000a, 0x33f8: 0x000a, 0x33f9: 0x000a, 0x33fa: 0x000a, 0x33fb: 0x000a, - 0x33fc: 0x000a, 0x33fd: 0x000a, 0x33fe: 0x000a, 0x33ff: 0x000a, + 0x33c0: 0x0001, 0x33c1: 0x0001, 0x33c2: 0x0001, 0x33c3: 0x0001, 0x33c4: 0x0001, 0x33c5: 0x0001, + 0x33c6: 0x0001, 0x33c7: 0x0001, 0x33c8: 0x0001, 0x33c9: 0x0001, 0x33ca: 0x0001, 0x33cb: 0x0001, + 0x33cc: 0x0001, 0x33cd: 0x0001, 0x33ce: 0x0001, 0x33cf: 0x0001, 0x33d0: 0x000c, 0x33d1: 0x000c, + 0x33d2: 0x000c, 0x33d3: 0x000c, 0x33d4: 0x000c, 0x33d5: 0x000c, 0x33d6: 0x000c, 0x33d7: 0x0001, + 0x33d8: 0x0001, 0x33d9: 0x0001, 0x33da: 0x0001, 0x33db: 0x0001, 0x33dc: 0x0001, 0x33dd: 0x0001, + 0x33de: 0x0001, 0x33df: 0x0001, 0x33e0: 0x0001, 0x33e1: 0x0001, 0x33e2: 0x0001, 0x33e3: 0x0001, + 0x33e4: 0x0001, 0x33e5: 0x0001, 0x33e6: 0x0001, 0x33e7: 0x0001, 0x33e8: 0x0001, 0x33e9: 0x0001, + 0x33ea: 0x0001, 0x33eb: 0x0001, 0x33ec: 0x0001, 0x33ed: 0x0001, 0x33ee: 0x0001, 0x33ef: 0x0001, + 0x33f0: 0x0001, 0x33f1: 0x0001, 0x33f2: 0x0001, 0x33f3: 0x0001, 0x33f4: 0x0001, 0x33f5: 0x0001, + 0x33f6: 0x0001, 0x33f7: 0x0001, 0x33f8: 0x0001, 0x33f9: 0x0001, 0x33fa: 0x0001, 0x33fb: 0x0001, + 0x33fc: 0x0001, 0x33fd: 0x0001, 0x33fe: 0x0001, 0x33ff: 0x0001, // Block 0xd0, offset 0x3400 - 0x3401: 0x000a, 0x3402: 0x000a, 0x3403: 0x000a, 0x3404: 0x000a, 0x3405: 0x000a, - 0x3406: 0x000a, 0x3407: 0x000a, 0x3408: 0x000a, 0x3409: 0x000a, 0x340a: 0x000a, 0x340b: 0x000a, - 0x340c: 0x000a, 0x340d: 0x000a, 0x340e: 0x000a, 0x340f: 0x000a, 0x3411: 0x000a, - 0x3412: 0x000a, 0x3413: 0x000a, 0x3414: 0x000a, 0x3415: 0x000a, 0x3416: 0x000a, 0x3417: 0x000a, - 0x3418: 0x000a, 0x3419: 0x000a, 0x341a: 0x000a, 0x341b: 0x000a, 0x341c: 0x000a, 0x341d: 0x000a, - 0x341e: 0x000a, 0x341f: 0x000a, 0x3420: 0x000a, 0x3421: 0x000a, 0x3422: 0x000a, 0x3423: 0x000a, - 0x3424: 0x000a, 0x3425: 0x000a, 0x3426: 0x000a, 0x3427: 0x000a, 0x3428: 0x000a, 0x3429: 0x000a, - 0x342a: 0x000a, 0x342b: 0x000a, 0x342c: 0x000a, 0x342d: 0x000a, 0x342e: 0x000a, 0x342f: 0x000a, - 0x3430: 0x000a, 0x3431: 0x000a, 0x3432: 0x000a, 0x3433: 0x000a, 0x3434: 0x000a, 0x3435: 0x000a, + 0x3400: 0x0001, 0x3401: 0x0001, 0x3402: 0x0001, 0x3403: 0x0001, 0x3404: 0x000c, 0x3405: 0x000c, + 0x3406: 0x000c, 0x3407: 0x000c, 0x3408: 0x000c, 0x3409: 0x000c, 0x340a: 0x000c, 0x340b: 0x0001, + 0x340c: 0x0001, 0x340d: 0x0001, 0x340e: 0x0001, 0x340f: 0x0001, 0x3410: 0x0001, 0x3411: 0x0001, + 0x3412: 0x0001, 0x3413: 0x0001, 0x3414: 0x0001, 0x3415: 0x0001, 0x3416: 0x0001, 0x3417: 0x0001, + 0x3418: 0x0001, 0x3419: 0x0001, 0x341a: 0x0001, 0x341b: 0x0001, 0x341c: 0x0001, 0x341d: 0x0001, + 0x341e: 0x0001, 0x341f: 0x0001, 0x3420: 0x0001, 0x3421: 0x0001, 0x3422: 0x0001, 0x3423: 0x0001, + 0x3424: 0x0001, 0x3425: 0x0001, 0x3426: 0x0001, 0x3427: 0x0001, 0x3428: 0x0001, 0x3429: 0x0001, + 0x342a: 0x0001, 0x342b: 0x0001, 0x342c: 0x0001, 0x342d: 0x0001, 0x342e: 0x0001, 0x342f: 0x0001, + 0x3430: 0x0001, 0x3431: 0x0001, 0x3432: 0x0001, 0x3433: 0x0001, 0x3434: 0x0001, 0x3435: 0x0001, + 0x3436: 0x0001, 0x3437: 0x0001, 0x3438: 0x0001, 0x3439: 0x0001, 0x343a: 0x0001, 0x343b: 0x0001, + 0x343c: 0x0001, 0x343d: 0x0001, 0x343e: 0x0001, 0x343f: 0x0001, // Block 0xd1, offset 0x3440 - 0x3440: 0x0002, 0x3441: 0x0002, 0x3442: 0x0002, 0x3443: 0x0002, 0x3444: 0x0002, 0x3445: 0x0002, - 0x3446: 0x0002, 0x3447: 0x0002, 0x3448: 0x0002, 0x3449: 0x0002, 0x344a: 0x0002, 0x344b: 0x000a, - 0x344c: 0x000a, + 0x3440: 0x000d, 0x3441: 0x000d, 0x3442: 0x000d, 0x3443: 0x000d, 0x3444: 0x000d, 0x3445: 0x000d, + 0x3446: 0x000d, 0x3447: 0x000d, 0x3448: 0x000d, 0x3449: 0x000d, 0x344a: 0x000d, 0x344b: 0x000d, + 0x344c: 0x000d, 0x344d: 0x000d, 0x344e: 0x000d, 0x344f: 0x000d, 0x3450: 0x000d, 0x3451: 0x000d, + 0x3452: 0x000d, 0x3453: 0x000d, 0x3454: 0x000d, 0x3455: 0x000d, 0x3456: 0x000d, 0x3457: 0x000d, + 0x3458: 0x000d, 0x3459: 0x000d, 0x345a: 0x000d, 0x345b: 0x000d, 0x345c: 0x000d, 0x345d: 0x000d, + 0x345e: 0x000d, 0x345f: 0x000d, 0x3460: 0x000d, 0x3461: 0x000d, 0x3462: 0x000d, 0x3463: 0x000d, + 0x3464: 0x000d, 0x3465: 0x000d, 0x3466: 0x000d, 0x3467: 0x000d, 0x3468: 0x000d, 0x3469: 0x000d, + 0x346a: 0x000d, 0x346b: 0x000d, 0x346c: 0x000d, 0x346d: 0x000d, 0x346e: 0x000d, 0x346f: 0x000d, + 0x3470: 0x000a, 0x3471: 0x000a, 0x3472: 0x000d, 0x3473: 0x000d, 0x3474: 0x000d, 0x3475: 0x000d, + 0x3476: 0x000d, 0x3477: 0x000d, 0x3478: 0x000d, 0x3479: 0x000d, 0x347a: 0x000d, 0x347b: 0x000d, + 0x347c: 0x000d, 0x347d: 0x000d, 0x347e: 0x000d, 0x347f: 0x000d, // Block 0xd2, offset 0x3480 + 0x3480: 0x000a, 0x3481: 0x000a, 0x3482: 0x000a, 0x3483: 0x000a, 0x3484: 0x000a, 0x3485: 0x000a, + 0x3486: 0x000a, 0x3487: 0x000a, 0x3488: 0x000a, 0x3489: 0x000a, 0x348a: 0x000a, 0x348b: 0x000a, + 0x348c: 0x000a, 0x348d: 0x000a, 0x348e: 0x000a, 0x348f: 0x000a, 0x3490: 0x000a, 0x3491: 0x000a, + 0x3492: 0x000a, 0x3493: 0x000a, 0x3494: 0x000a, 0x3495: 0x000a, 0x3496: 0x000a, 0x3497: 0x000a, + 0x3498: 0x000a, 0x3499: 0x000a, 0x349a: 0x000a, 0x349b: 0x000a, 0x349c: 0x000a, 0x349d: 0x000a, + 0x349e: 0x000a, 0x349f: 0x000a, 0x34a0: 0x000a, 0x34a1: 0x000a, 0x34a2: 0x000a, 0x34a3: 0x000a, + 0x34a4: 0x000a, 0x34a5: 0x000a, 0x34a6: 0x000a, 0x34a7: 0x000a, 0x34a8: 0x000a, 0x34a9: 0x000a, 0x34aa: 0x000a, 0x34ab: 0x000a, + 0x34b0: 0x000a, 0x34b1: 0x000a, 0x34b2: 0x000a, 0x34b3: 0x000a, 0x34b4: 0x000a, 0x34b5: 0x000a, + 0x34b6: 0x000a, 0x34b7: 0x000a, 0x34b8: 0x000a, 0x34b9: 0x000a, 0x34ba: 0x000a, 0x34bb: 0x000a, + 0x34bc: 0x000a, 0x34bd: 0x000a, 0x34be: 0x000a, 0x34bf: 0x000a, // Block 0xd3, offset 0x34c0 0x34c0: 0x000a, 0x34c1: 0x000a, 0x34c2: 0x000a, 0x34c3: 0x000a, 0x34c4: 0x000a, 0x34c5: 0x000a, 0x34c6: 0x000a, 0x34c7: 0x000a, 0x34c8: 0x000a, 0x34c9: 0x000a, 0x34ca: 0x000a, 0x34cb: 0x000a, 0x34cc: 0x000a, 0x34cd: 0x000a, 0x34ce: 0x000a, 0x34cf: 0x000a, 0x34d0: 0x000a, 0x34d1: 0x000a, - 0x34d2: 0x000a, + 0x34d2: 0x000a, 0x34d3: 0x000a, 0x34e0: 0x000a, 0x34e1: 0x000a, 0x34e2: 0x000a, 0x34e3: 0x000a, 0x34e4: 0x000a, 0x34e5: 0x000a, 0x34e6: 0x000a, 0x34e7: 0x000a, 0x34e8: 0x000a, 0x34e9: 0x000a, - 0x34ea: 0x000a, 0x34eb: 0x000a, 0x34ec: 0x000a, - 0x34f0: 0x000a, 0x34f1: 0x000a, 0x34f2: 0x000a, 0x34f3: 0x000a, 0x34f4: 0x000a, 0x34f5: 0x000a, - 0x34f6: 0x000a, + 0x34ea: 0x000a, 0x34eb: 0x000a, 0x34ec: 0x000a, 0x34ed: 0x000a, 0x34ee: 0x000a, + 0x34f1: 0x000a, 0x34f2: 0x000a, 0x34f3: 0x000a, 0x34f4: 0x000a, 0x34f5: 0x000a, + 0x34f6: 0x000a, 0x34f7: 0x000a, 0x34f8: 0x000a, 0x34f9: 0x000a, 0x34fa: 0x000a, 0x34fb: 0x000a, + 0x34fc: 0x000a, 0x34fd: 0x000a, 0x34fe: 0x000a, 0x34ff: 0x000a, // Block 0xd4, offset 0x3500 - 0x3500: 0x000a, 0x3501: 0x000a, 0x3502: 0x000a, 0x3503: 0x000a, 0x3504: 0x000a, 0x3505: 0x000a, + 0x3501: 0x000a, 0x3502: 0x000a, 0x3503: 0x000a, 0x3504: 0x000a, 0x3505: 0x000a, 0x3506: 0x000a, 0x3507: 0x000a, 0x3508: 0x000a, 0x3509: 0x000a, 0x350a: 0x000a, 0x350b: 0x000a, - 0x350c: 0x000a, 0x350d: 0x000a, 0x350e: 0x000a, 0x350f: 0x000a, 0x3510: 0x000a, 0x3511: 0x000a, - 0x3512: 0x000a, 0x3513: 0x000a, 0x3514: 0x000a, + 0x350c: 0x000a, 0x350d: 0x000a, 0x350e: 0x000a, 0x350f: 0x000a, 0x3511: 0x000a, + 0x3512: 0x000a, 0x3513: 0x000a, 0x3514: 0x000a, 0x3515: 0x000a, 0x3516: 0x000a, 0x3517: 0x000a, + 0x3518: 0x000a, 0x3519: 0x000a, 0x351a: 0x000a, 0x351b: 0x000a, 0x351c: 0x000a, 0x351d: 0x000a, + 0x351e: 0x000a, 0x351f: 0x000a, 0x3520: 0x000a, 0x3521: 0x000a, 0x3522: 0x000a, 0x3523: 0x000a, + 0x3524: 0x000a, 0x3525: 0x000a, 0x3526: 0x000a, 0x3527: 0x000a, 0x3528: 0x000a, 0x3529: 0x000a, + 0x352a: 0x000a, 0x352b: 0x000a, 0x352c: 0x000a, 0x352d: 0x000a, 0x352e: 0x000a, 0x352f: 0x000a, + 0x3530: 0x000a, 0x3531: 0x000a, 0x3532: 0x000a, 0x3533: 0x000a, 0x3534: 0x000a, 0x3535: 0x000a, // Block 0xd5, offset 0x3540 - 0x3540: 0x000a, 0x3541: 0x000a, 0x3542: 0x000a, 0x3543: 0x000a, 0x3544: 0x000a, 0x3545: 0x000a, - 0x3546: 0x000a, 0x3547: 0x000a, 0x3548: 0x000a, 0x3549: 0x000a, 0x354a: 0x000a, 0x354b: 0x000a, - 0x3550: 0x000a, 0x3551: 0x000a, - 0x3552: 0x000a, 0x3553: 0x000a, 0x3554: 0x000a, 0x3555: 0x000a, 0x3556: 0x000a, 0x3557: 0x000a, - 0x3558: 0x000a, 0x3559: 0x000a, 0x355a: 0x000a, 0x355b: 0x000a, 0x355c: 0x000a, 0x355d: 0x000a, - 0x355e: 0x000a, 0x355f: 0x000a, 0x3560: 0x000a, 0x3561: 0x000a, 0x3562: 0x000a, 0x3563: 0x000a, - 0x3564: 0x000a, 0x3565: 0x000a, 0x3566: 0x000a, 0x3567: 0x000a, 0x3568: 0x000a, 0x3569: 0x000a, - 0x356a: 0x000a, 0x356b: 0x000a, 0x356c: 0x000a, 0x356d: 0x000a, 0x356e: 0x000a, 0x356f: 0x000a, - 0x3570: 0x000a, 0x3571: 0x000a, 0x3572: 0x000a, 0x3573: 0x000a, 0x3574: 0x000a, 0x3575: 0x000a, - 0x3576: 0x000a, 0x3577: 0x000a, 0x3578: 0x000a, 0x3579: 0x000a, 0x357a: 0x000a, 0x357b: 0x000a, - 0x357c: 0x000a, 0x357d: 0x000a, 0x357e: 0x000a, 0x357f: 0x000a, + 0x3540: 0x0002, 0x3541: 0x0002, 0x3542: 0x0002, 0x3543: 0x0002, 0x3544: 0x0002, 0x3545: 0x0002, + 0x3546: 0x0002, 0x3547: 0x0002, 0x3548: 0x0002, 0x3549: 0x0002, 0x354a: 0x0002, 0x354b: 0x000a, + 0x354c: 0x000a, // Block 0xd6, offset 0x3580 - 0x3580: 0x000a, 0x3581: 0x000a, 0x3582: 0x000a, 0x3583: 0x000a, 0x3584: 0x000a, 0x3585: 0x000a, - 0x3586: 0x000a, 0x3587: 0x000a, - 0x3590: 0x000a, 0x3591: 0x000a, - 0x3592: 0x000a, 0x3593: 0x000a, 0x3594: 0x000a, 0x3595: 0x000a, 0x3596: 0x000a, 0x3597: 0x000a, - 0x3598: 0x000a, 0x3599: 0x000a, - 0x35a0: 0x000a, 0x35a1: 0x000a, 0x35a2: 0x000a, 0x35a3: 0x000a, - 0x35a4: 0x000a, 0x35a5: 0x000a, 0x35a6: 0x000a, 0x35a7: 0x000a, 0x35a8: 0x000a, 0x35a9: 0x000a, - 0x35aa: 0x000a, 0x35ab: 0x000a, 0x35ac: 0x000a, 0x35ad: 0x000a, 0x35ae: 0x000a, 0x35af: 0x000a, - 0x35b0: 0x000a, 0x35b1: 0x000a, 0x35b2: 0x000a, 0x35b3: 0x000a, 0x35b4: 0x000a, 0x35b5: 0x000a, - 0x35b6: 0x000a, 0x35b7: 0x000a, 0x35b8: 0x000a, 0x35b9: 0x000a, 0x35ba: 0x000a, 0x35bb: 0x000a, - 0x35bc: 0x000a, 0x35bd: 0x000a, 0x35be: 0x000a, 0x35bf: 0x000a, + 0x35aa: 0x000a, 0x35ab: 0x000a, // Block 0xd7, offset 0x35c0 - 0x35c0: 0x000a, 0x35c1: 0x000a, 0x35c2: 0x000a, 0x35c3: 0x000a, 0x35c4: 0x000a, 0x35c5: 0x000a, - 0x35c6: 0x000a, 0x35c7: 0x000a, - 0x35d0: 0x000a, 0x35d1: 0x000a, - 0x35d2: 0x000a, 0x35d3: 0x000a, 0x35d4: 0x000a, 0x35d5: 0x000a, 0x35d6: 0x000a, 0x35d7: 0x000a, - 0x35d8: 0x000a, 0x35d9: 0x000a, 0x35da: 0x000a, 0x35db: 0x000a, 0x35dc: 0x000a, 0x35dd: 0x000a, - 0x35de: 0x000a, 0x35df: 0x000a, 0x35e0: 0x000a, 0x35e1: 0x000a, 0x35e2: 0x000a, 0x35e3: 0x000a, - 0x35e4: 0x000a, 0x35e5: 0x000a, 0x35e6: 0x000a, 0x35e7: 0x000a, 0x35e8: 0x000a, 0x35e9: 0x000a, - 0x35ea: 0x000a, 0x35eb: 0x000a, 0x35ec: 0x000a, 0x35ed: 0x000a, + 0x35e0: 0x000a, 0x35e1: 0x000a, 0x35e2: 0x000a, 0x35e3: 0x000a, + 0x35e4: 0x000a, 0x35e5: 0x000a, // Block 0xd8, offset 0x3600 - 0x3610: 0x000a, 0x3611: 0x000a, - 0x3612: 0x000a, 0x3613: 0x000a, 0x3614: 0x000a, 0x3615: 0x000a, 0x3616: 0x000a, 0x3617: 0x000a, - 0x3618: 0x000a, 0x3619: 0x000a, 0x361a: 0x000a, 0x361b: 0x000a, 0x361c: 0x000a, 0x361d: 0x000a, - 0x361e: 0x000a, 0x3620: 0x000a, 0x3621: 0x000a, 0x3622: 0x000a, 0x3623: 0x000a, - 0x3624: 0x000a, 0x3625: 0x000a, 0x3626: 0x000a, 0x3627: 0x000a, - 0x3630: 0x000a, 0x3633: 0x000a, 0x3634: 0x000a, 0x3635: 0x000a, - 0x3636: 0x000a, 0x3637: 0x000a, 0x3638: 0x000a, 0x3639: 0x000a, 0x363a: 0x000a, 0x363b: 0x000a, - 0x363c: 0x000a, 0x363d: 0x000a, 0x363e: 0x000a, + 0x3600: 0x000a, 0x3601: 0x000a, 0x3602: 0x000a, 0x3603: 0x000a, 0x3604: 0x000a, 0x3605: 0x000a, + 0x3606: 0x000a, 0x3607: 0x000a, 0x3608: 0x000a, 0x3609: 0x000a, 0x360a: 0x000a, 0x360b: 0x000a, + 0x360c: 0x000a, 0x360d: 0x000a, 0x360e: 0x000a, 0x360f: 0x000a, 0x3610: 0x000a, 0x3611: 0x000a, + 0x3612: 0x000a, 0x3613: 0x000a, 0x3614: 0x000a, + 0x3620: 0x000a, 0x3621: 0x000a, 0x3622: 0x000a, 0x3623: 0x000a, + 0x3624: 0x000a, 0x3625: 0x000a, 0x3626: 0x000a, 0x3627: 0x000a, 0x3628: 0x000a, 0x3629: 0x000a, + 0x362a: 0x000a, 0x362b: 0x000a, 0x362c: 0x000a, + 0x3630: 0x000a, 0x3631: 0x000a, 0x3632: 0x000a, 0x3633: 0x000a, 0x3634: 0x000a, 0x3635: 0x000a, + 0x3636: 0x000a, 0x3637: 0x000a, 0x3638: 0x000a, // Block 0xd9, offset 0x3640 0x3640: 0x000a, 0x3641: 0x000a, 0x3642: 0x000a, 0x3643: 0x000a, 0x3644: 0x000a, 0x3645: 0x000a, 0x3646: 0x000a, 0x3647: 0x000a, 0x3648: 0x000a, 0x3649: 0x000a, 0x364a: 0x000a, 0x364b: 0x000a, - 0x3650: 0x000a, 0x3651: 0x000a, - 0x3652: 0x000a, 0x3653: 0x000a, 0x3654: 0x000a, 0x3655: 0x000a, 0x3656: 0x000a, 0x3657: 0x000a, - 0x3658: 0x000a, 0x3659: 0x000a, 0x365a: 0x000a, 0x365b: 0x000a, 0x365c: 0x000a, 0x365d: 0x000a, - 0x365e: 0x000a, + 0x364c: 0x000a, 0x364d: 0x000a, 0x364e: 0x000a, 0x364f: 0x000a, 0x3650: 0x000a, 0x3651: 0x000a, + 0x3652: 0x000a, 0x3653: 0x000a, 0x3654: 0x000a, // Block 0xda, offset 0x3680 0x3680: 0x000a, 0x3681: 0x000a, 0x3682: 0x000a, 0x3683: 0x000a, 0x3684: 0x000a, 0x3685: 0x000a, 0x3686: 0x000a, 0x3687: 0x000a, 0x3688: 0x000a, 0x3689: 0x000a, 0x368a: 0x000a, 0x368b: 0x000a, - 0x368c: 0x000a, 0x368d: 0x000a, 0x368e: 0x000a, 0x368f: 0x000a, 0x3690: 0x000a, 0x3691: 0x000a, + 0x3690: 0x000a, 0x3691: 0x000a, + 0x3692: 0x000a, 0x3693: 0x000a, 0x3694: 0x000a, 0x3695: 0x000a, 0x3696: 0x000a, 0x3697: 0x000a, + 0x3698: 0x000a, 0x3699: 0x000a, 0x369a: 0x000a, 0x369b: 0x000a, 0x369c: 0x000a, 0x369d: 0x000a, + 0x369e: 0x000a, 0x369f: 0x000a, 0x36a0: 0x000a, 0x36a1: 0x000a, 0x36a2: 0x000a, 0x36a3: 0x000a, + 0x36a4: 0x000a, 0x36a5: 0x000a, 0x36a6: 0x000a, 0x36a7: 0x000a, 0x36a8: 0x000a, 0x36a9: 0x000a, + 0x36aa: 0x000a, 0x36ab: 0x000a, 0x36ac: 0x000a, 0x36ad: 0x000a, 0x36ae: 0x000a, 0x36af: 0x000a, + 0x36b0: 0x000a, 0x36b1: 0x000a, 0x36b2: 0x000a, 0x36b3: 0x000a, 0x36b4: 0x000a, 0x36b5: 0x000a, + 0x36b6: 0x000a, 0x36b7: 0x000a, 0x36b8: 0x000a, 0x36b9: 0x000a, 0x36ba: 0x000a, 0x36bb: 0x000a, + 0x36bc: 0x000a, 0x36bd: 0x000a, 0x36be: 0x000a, 0x36bf: 0x000a, // Block 0xdb, offset 0x36c0 - 0x36fe: 0x000b, 0x36ff: 0x000b, + 0x36c0: 0x000a, 0x36c1: 0x000a, 0x36c2: 0x000a, 0x36c3: 0x000a, 0x36c4: 0x000a, 0x36c5: 0x000a, + 0x36c6: 0x000a, 0x36c7: 0x000a, + 0x36d0: 0x000a, 0x36d1: 0x000a, + 0x36d2: 0x000a, 0x36d3: 0x000a, 0x36d4: 0x000a, 0x36d5: 0x000a, 0x36d6: 0x000a, 0x36d7: 0x000a, + 0x36d8: 0x000a, 0x36d9: 0x000a, + 0x36e0: 0x000a, 0x36e1: 0x000a, 0x36e2: 0x000a, 0x36e3: 0x000a, + 0x36e4: 0x000a, 0x36e5: 0x000a, 0x36e6: 0x000a, 0x36e7: 0x000a, 0x36e8: 0x000a, 0x36e9: 0x000a, + 0x36ea: 0x000a, 0x36eb: 0x000a, 0x36ec: 0x000a, 0x36ed: 0x000a, 0x36ee: 0x000a, 0x36ef: 0x000a, + 0x36f0: 0x000a, 0x36f1: 0x000a, 0x36f2: 0x000a, 0x36f3: 0x000a, 0x36f4: 0x000a, 0x36f5: 0x000a, + 0x36f6: 0x000a, 0x36f7: 0x000a, 0x36f8: 0x000a, 0x36f9: 0x000a, 0x36fa: 0x000a, 0x36fb: 0x000a, + 0x36fc: 0x000a, 0x36fd: 0x000a, 0x36fe: 0x000a, 0x36ff: 0x000a, // Block 0xdc, offset 0x3700 - 0x3700: 0x000b, 0x3701: 0x000b, 0x3702: 0x000b, 0x3703: 0x000b, 0x3704: 0x000b, 0x3705: 0x000b, - 0x3706: 0x000b, 0x3707: 0x000b, 0x3708: 0x000b, 0x3709: 0x000b, 0x370a: 0x000b, 0x370b: 0x000b, - 0x370c: 0x000b, 0x370d: 0x000b, 0x370e: 0x000b, 0x370f: 0x000b, 0x3710: 0x000b, 0x3711: 0x000b, - 0x3712: 0x000b, 0x3713: 0x000b, 0x3714: 0x000b, 0x3715: 0x000b, 0x3716: 0x000b, 0x3717: 0x000b, - 0x3718: 0x000b, 0x3719: 0x000b, 0x371a: 0x000b, 0x371b: 0x000b, 0x371c: 0x000b, 0x371d: 0x000b, - 0x371e: 0x000b, 0x371f: 0x000b, 0x3720: 0x000b, 0x3721: 0x000b, 0x3722: 0x000b, 0x3723: 0x000b, - 0x3724: 0x000b, 0x3725: 0x000b, 0x3726: 0x000b, 0x3727: 0x000b, 0x3728: 0x000b, 0x3729: 0x000b, - 0x372a: 0x000b, 0x372b: 0x000b, 0x372c: 0x000b, 0x372d: 0x000b, 0x372e: 0x000b, 0x372f: 0x000b, - 0x3730: 0x000b, 0x3731: 0x000b, 0x3732: 0x000b, 0x3733: 0x000b, 0x3734: 0x000b, 0x3735: 0x000b, - 0x3736: 0x000b, 0x3737: 0x000b, 0x3738: 0x000b, 0x3739: 0x000b, 0x373a: 0x000b, 0x373b: 0x000b, - 0x373c: 0x000b, 0x373d: 0x000b, 0x373e: 0x000b, 0x373f: 0x000b, + 0x3700: 0x000a, 0x3701: 0x000a, 0x3702: 0x000a, 0x3703: 0x000a, 0x3704: 0x000a, 0x3705: 0x000a, + 0x3706: 0x000a, 0x3707: 0x000a, + 0x3710: 0x000a, 0x3711: 0x000a, + 0x3712: 0x000a, 0x3713: 0x000a, 0x3714: 0x000a, 0x3715: 0x000a, 0x3716: 0x000a, 0x3717: 0x000a, + 0x3718: 0x000a, 0x3719: 0x000a, 0x371a: 0x000a, 0x371b: 0x000a, 0x371c: 0x000a, 0x371d: 0x000a, + 0x371e: 0x000a, 0x371f: 0x000a, 0x3720: 0x000a, 0x3721: 0x000a, 0x3722: 0x000a, 0x3723: 0x000a, + 0x3724: 0x000a, 0x3725: 0x000a, 0x3726: 0x000a, 0x3727: 0x000a, 0x3728: 0x000a, 0x3729: 0x000a, + 0x372a: 0x000a, 0x372b: 0x000a, 0x372c: 0x000a, 0x372d: 0x000a, // Block 0xdd, offset 0x3740 - 0x3740: 0x000c, 0x3741: 0x000c, 0x3742: 0x000c, 0x3743: 0x000c, 0x3744: 0x000c, 0x3745: 0x000c, - 0x3746: 0x000c, 0x3747: 0x000c, 0x3748: 0x000c, 0x3749: 0x000c, 0x374a: 0x000c, 0x374b: 0x000c, - 0x374c: 0x000c, 0x374d: 0x000c, 0x374e: 0x000c, 0x374f: 0x000c, 0x3750: 0x000c, 0x3751: 0x000c, - 0x3752: 0x000c, 0x3753: 0x000c, 0x3754: 0x000c, 0x3755: 0x000c, 0x3756: 0x000c, 0x3757: 0x000c, - 0x3758: 0x000c, 0x3759: 0x000c, 0x375a: 0x000c, 0x375b: 0x000c, 0x375c: 0x000c, 0x375d: 0x000c, - 0x375e: 0x000c, 0x375f: 0x000c, 0x3760: 0x000c, 0x3761: 0x000c, 0x3762: 0x000c, 0x3763: 0x000c, - 0x3764: 0x000c, 0x3765: 0x000c, 0x3766: 0x000c, 0x3767: 0x000c, 0x3768: 0x000c, 0x3769: 0x000c, - 0x376a: 0x000c, 0x376b: 0x000c, 0x376c: 0x000c, 0x376d: 0x000c, 0x376e: 0x000c, 0x376f: 0x000c, - 0x3770: 0x000b, 0x3771: 0x000b, 0x3772: 0x000b, 0x3773: 0x000b, 0x3774: 0x000b, 0x3775: 0x000b, - 0x3776: 0x000b, 0x3777: 0x000b, 0x3778: 0x000b, 0x3779: 0x000b, 0x377a: 0x000b, 0x377b: 0x000b, - 0x377c: 0x000b, 0x377d: 0x000b, 0x377e: 0x000b, 0x377f: 0x000b, + 0x3740: 0x000a, 0x3741: 0x000a, 0x3742: 0x000a, 0x3743: 0x000a, 0x3744: 0x000a, 0x3745: 0x000a, + 0x3746: 0x000a, 0x3747: 0x000a, 0x3748: 0x000a, 0x3749: 0x000a, 0x374a: 0x000a, 0x374b: 0x000a, + 0x3750: 0x000a, 0x3751: 0x000a, + 0x3752: 0x000a, 0x3753: 0x000a, 0x3754: 0x000a, 0x3755: 0x000a, 0x3756: 0x000a, 0x3757: 0x000a, + 0x3758: 0x000a, 0x3759: 0x000a, 0x375a: 0x000a, 0x375b: 0x000a, 0x375c: 0x000a, 0x375d: 0x000a, + 0x375e: 0x000a, 0x375f: 0x000a, 0x3760: 0x000a, 0x3761: 0x000a, 0x3762: 0x000a, 0x3763: 0x000a, + 0x3764: 0x000a, 0x3765: 0x000a, 0x3766: 0x000a, 0x3767: 0x000a, 0x3768: 0x000a, 0x3769: 0x000a, + 0x376a: 0x000a, 0x376b: 0x000a, 0x376c: 0x000a, 0x376d: 0x000a, 0x376e: 0x000a, 0x376f: 0x000a, + 0x3770: 0x000a, 0x3771: 0x000a, 0x3772: 0x000a, 0x3773: 0x000a, 0x3774: 0x000a, 0x3775: 0x000a, + 0x3776: 0x000a, 0x3777: 0x000a, 0x3778: 0x000a, 0x3779: 0x000a, 0x377a: 0x000a, 0x377b: 0x000a, + 0x377c: 0x000a, 0x377d: 0x000a, 0x377e: 0x000a, + // Block 0xde, offset 0x3780 + 0x3780: 0x000a, 0x3781: 0x000a, 0x3782: 0x000a, 0x3783: 0x000a, 0x3784: 0x000a, 0x3785: 0x000a, + 0x3786: 0x000a, 0x3787: 0x000a, 0x3788: 0x000a, 0x3789: 0x000a, 0x378a: 0x000a, 0x378b: 0x000a, + 0x378c: 0x000a, 0x3790: 0x000a, 0x3791: 0x000a, + 0x3792: 0x000a, 0x3793: 0x000a, 0x3794: 0x000a, 0x3795: 0x000a, 0x3796: 0x000a, 0x3797: 0x000a, + 0x3798: 0x000a, 0x3799: 0x000a, 0x379a: 0x000a, 0x379b: 0x000a, 0x379c: 0x000a, 0x379d: 0x000a, + 0x379e: 0x000a, 0x379f: 0x000a, 0x37a0: 0x000a, 0x37a1: 0x000a, 0x37a2: 0x000a, 0x37a3: 0x000a, + 0x37a4: 0x000a, 0x37a5: 0x000a, 0x37a6: 0x000a, 0x37a7: 0x000a, 0x37a8: 0x000a, 0x37a9: 0x000a, + 0x37aa: 0x000a, 0x37ab: 0x000a, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x000a, 0x37c1: 0x000a, 0x37c2: 0x000a, 0x37c3: 0x000a, 0x37c4: 0x000a, 0x37c5: 0x000a, + 0x37c6: 0x000a, 0x37c7: 0x000a, 0x37c8: 0x000a, 0x37c9: 0x000a, 0x37ca: 0x000a, 0x37cb: 0x000a, + 0x37cc: 0x000a, 0x37cd: 0x000a, 0x37ce: 0x000a, 0x37cf: 0x000a, 0x37d0: 0x000a, 0x37d1: 0x000a, + 0x37d2: 0x000a, 0x37d3: 0x000a, 0x37d4: 0x000a, 0x37d5: 0x000a, 0x37d6: 0x000a, 0x37d7: 0x000a, + // Block 0xe0, offset 0x3800 + 0x3800: 0x000a, + 0x3810: 0x000a, 0x3811: 0x000a, + 0x3812: 0x000a, 0x3813: 0x000a, 0x3814: 0x000a, 0x3815: 0x000a, 0x3816: 0x000a, 0x3817: 0x000a, + 0x3818: 0x000a, 0x3819: 0x000a, 0x381a: 0x000a, 0x381b: 0x000a, 0x381c: 0x000a, 0x381d: 0x000a, + 0x381e: 0x000a, 0x381f: 0x000a, 0x3820: 0x000a, 0x3821: 0x000a, 0x3822: 0x000a, 0x3823: 0x000a, + 0x3824: 0x000a, 0x3825: 0x000a, 0x3826: 0x000a, + // Block 0xe1, offset 0x3840 + 0x387e: 0x000b, 0x387f: 0x000b, + // Block 0xe2, offset 0x3880 + 0x3880: 0x000b, 0x3881: 0x000b, 0x3882: 0x000b, 0x3883: 0x000b, 0x3884: 0x000b, 0x3885: 0x000b, + 0x3886: 0x000b, 0x3887: 0x000b, 0x3888: 0x000b, 0x3889: 0x000b, 0x388a: 0x000b, 0x388b: 0x000b, + 0x388c: 0x000b, 0x388d: 0x000b, 0x388e: 0x000b, 0x388f: 0x000b, 0x3890: 0x000b, 0x3891: 0x000b, + 0x3892: 0x000b, 0x3893: 0x000b, 0x3894: 0x000b, 0x3895: 0x000b, 0x3896: 0x000b, 0x3897: 0x000b, + 0x3898: 0x000b, 0x3899: 0x000b, 0x389a: 0x000b, 0x389b: 0x000b, 0x389c: 0x000b, 0x389d: 0x000b, + 0x389e: 0x000b, 0x389f: 0x000b, 0x38a0: 0x000b, 0x38a1: 0x000b, 0x38a2: 0x000b, 0x38a3: 0x000b, + 0x38a4: 0x000b, 0x38a5: 0x000b, 0x38a6: 0x000b, 0x38a7: 0x000b, 0x38a8: 0x000b, 0x38a9: 0x000b, + 0x38aa: 0x000b, 0x38ab: 0x000b, 0x38ac: 0x000b, 0x38ad: 0x000b, 0x38ae: 0x000b, 0x38af: 0x000b, + 0x38b0: 0x000b, 0x38b1: 0x000b, 0x38b2: 0x000b, 0x38b3: 0x000b, 0x38b4: 0x000b, 0x38b5: 0x000b, + 0x38b6: 0x000b, 0x38b7: 0x000b, 0x38b8: 0x000b, 0x38b9: 0x000b, 0x38ba: 0x000b, 0x38bb: 0x000b, + 0x38bc: 0x000b, 0x38bd: 0x000b, 0x38be: 0x000b, 0x38bf: 0x000b, + // Block 0xe3, offset 0x38c0 + 0x38c0: 0x000c, 0x38c1: 0x000c, 0x38c2: 0x000c, 0x38c3: 0x000c, 0x38c4: 0x000c, 0x38c5: 0x000c, + 0x38c6: 0x000c, 0x38c7: 0x000c, 0x38c8: 0x000c, 0x38c9: 0x000c, 0x38ca: 0x000c, 0x38cb: 0x000c, + 0x38cc: 0x000c, 0x38cd: 0x000c, 0x38ce: 0x000c, 0x38cf: 0x000c, 0x38d0: 0x000c, 0x38d1: 0x000c, + 0x38d2: 0x000c, 0x38d3: 0x000c, 0x38d4: 0x000c, 0x38d5: 0x000c, 0x38d6: 0x000c, 0x38d7: 0x000c, + 0x38d8: 0x000c, 0x38d9: 0x000c, 0x38da: 0x000c, 0x38db: 0x000c, 0x38dc: 0x000c, 0x38dd: 0x000c, + 0x38de: 0x000c, 0x38df: 0x000c, 0x38e0: 0x000c, 0x38e1: 0x000c, 0x38e2: 0x000c, 0x38e3: 0x000c, + 0x38e4: 0x000c, 0x38e5: 0x000c, 0x38e6: 0x000c, 0x38e7: 0x000c, 0x38e8: 0x000c, 0x38e9: 0x000c, + 0x38ea: 0x000c, 0x38eb: 0x000c, 0x38ec: 0x000c, 0x38ed: 0x000c, 0x38ee: 0x000c, 0x38ef: 0x000c, + 0x38f0: 0x000b, 0x38f1: 0x000b, 0x38f2: 0x000b, 0x38f3: 0x000b, 0x38f4: 0x000b, 0x38f5: 0x000b, + 0x38f6: 0x000b, 0x38f7: 0x000b, 0x38f8: 0x000b, 0x38f9: 0x000b, 0x38fa: 0x000b, 0x38fb: 0x000b, + 0x38fc: 0x000b, 0x38fd: 0x000b, 0x38fe: 0x000b, 0x38ff: 0x000b, } // bidiIndex: 24 blocks, 1536 entries, 1536 bytes @@ -1690,65 +1723,66 @@ var bidiIndex = [1536]uint8{ 0x17e: 0x4b, 0x17f: 0x4c, // Block 0x6, offset 0x180 0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54, - 0x188: 0x55, 0x189: 0x54, 0x18a: 0x54, 0x18b: 0x54, 0x18c: 0x56, 0x18d: 0x57, 0x18e: 0x58, 0x18f: 0x59, - 0x190: 0x5a, 0x191: 0x5b, 0x192: 0x5c, 0x193: 0x5d, 0x194: 0x54, 0x195: 0x54, 0x196: 0x54, 0x197: 0x54, - 0x198: 0x54, 0x199: 0x54, 0x19a: 0x5e, 0x19b: 0x54, 0x19c: 0x54, 0x19d: 0x5f, 0x19e: 0x54, 0x19f: 0x60, - 0x1a4: 0x54, 0x1a5: 0x54, 0x1a6: 0x61, 0x1a7: 0x62, - 0x1a8: 0x54, 0x1a9: 0x54, 0x1aa: 0x54, 0x1ab: 0x54, 0x1ac: 0x54, 0x1ad: 0x63, 0x1ae: 0x64, 0x1af: 0x65, - 0x1b3: 0x66, 0x1b5: 0x67, 0x1b7: 0x68, - 0x1b8: 0x69, 0x1b9: 0x6a, 0x1ba: 0x6b, 0x1bb: 0x6c, 0x1bc: 0x54, 0x1bd: 0x54, 0x1be: 0x54, 0x1bf: 0x6d, + 0x188: 0x55, 0x189: 0x54, 0x18a: 0x54, 0x18b: 0x54, 0x18c: 0x56, 0x18d: 0x57, 0x18e: 0x58, 0x18f: 0x54, + 0x190: 0x59, 0x191: 0x5a, 0x192: 0x5b, 0x193: 0x5c, 0x194: 0x54, 0x195: 0x54, 0x196: 0x54, 0x197: 0x54, + 0x198: 0x54, 0x199: 0x54, 0x19a: 0x5d, 0x19b: 0x54, 0x19c: 0x54, 0x19d: 0x5e, 0x19e: 0x54, 0x19f: 0x5f, + 0x1a4: 0x54, 0x1a5: 0x54, 0x1a6: 0x60, 0x1a7: 0x61, + 0x1a8: 0x54, 0x1a9: 0x54, 0x1aa: 0x54, 0x1ab: 0x54, 0x1ac: 0x54, 0x1ad: 0x62, 0x1ae: 0x63, 0x1af: 0x64, + 0x1b3: 0x65, 0x1b5: 0x66, 0x1b7: 0x67, + 0x1b8: 0x68, 0x1b9: 0x69, 0x1ba: 0x6a, 0x1bb: 0x6b, 0x1bc: 0x54, 0x1bd: 0x54, 0x1be: 0x54, 0x1bf: 0x6c, // Block 0x7, offset 0x1c0 - 0x1c0: 0x6e, 0x1c2: 0x6f, 0x1c3: 0x70, 0x1c7: 0x71, - 0x1c8: 0x72, 0x1c9: 0x73, 0x1ca: 0x74, 0x1cb: 0x75, 0x1cd: 0x76, 0x1cf: 0x77, + 0x1c0: 0x6d, 0x1c2: 0x6e, 0x1c3: 0x6f, 0x1c7: 0x70, + 0x1c8: 0x71, 0x1c9: 0x72, 0x1ca: 0x73, 0x1cb: 0x74, 0x1cd: 0x75, 0x1cf: 0x76, // Block 0x8, offset 0x200 0x237: 0x54, // Block 0x9, offset 0x240 - 0x252: 0x78, 0x253: 0x79, - 0x258: 0x7a, 0x259: 0x7b, 0x25a: 0x7c, 0x25b: 0x7d, 0x25c: 0x7e, 0x25e: 0x7f, - 0x260: 0x80, 0x261: 0x81, 0x263: 0x82, 0x264: 0x83, 0x265: 0x84, 0x266: 0x85, 0x267: 0x86, - 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26f: 0x8b, + 0x252: 0x77, 0x253: 0x78, + 0x258: 0x79, 0x259: 0x7a, 0x25a: 0x7b, 0x25b: 0x7c, 0x25c: 0x7d, 0x25e: 0x7e, + 0x260: 0x7f, 0x261: 0x80, 0x263: 0x81, 0x264: 0x82, 0x265: 0x83, 0x266: 0x84, 0x267: 0x85, + 0x268: 0x86, 0x269: 0x87, 0x26a: 0x88, 0x26b: 0x89, 0x26f: 0x8a, // Block 0xa, offset 0x280 - 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x0e, 0x2af: 0x0e, - 0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8e, 0x2b5: 0x0e, 0x2b6: 0x0e, 0x2b7: 0x8f, - 0x2b8: 0x90, 0x2b9: 0x91, 0x2ba: 0x0e, 0x2bb: 0x92, 0x2bc: 0x93, 0x2bd: 0x94, 0x2bf: 0x95, + 0x2ac: 0x8b, 0x2ad: 0x8c, 0x2ae: 0x0e, 0x2af: 0x0e, + 0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8d, 0x2b5: 0x0e, 0x2b6: 0x0e, 0x2b7: 0x8e, + 0x2b8: 0x8f, 0x2b9: 0x90, 0x2ba: 0x0e, 0x2bb: 0x91, 0x2bc: 0x92, 0x2bd: 0x93, 0x2bf: 0x94, // Block 0xb, offset 0x2c0 - 0x2c4: 0x96, 0x2c5: 0x54, 0x2c6: 0x97, 0x2c7: 0x98, - 0x2cb: 0x99, 0x2cd: 0x9a, - 0x2e0: 0x9b, 0x2e1: 0x9b, 0x2e2: 0x9b, 0x2e3: 0x9b, 0x2e4: 0x9c, 0x2e5: 0x9b, 0x2e6: 0x9b, 0x2e7: 0x9b, - 0x2e8: 0x9d, 0x2e9: 0x9b, 0x2ea: 0x9b, 0x2eb: 0x9e, 0x2ec: 0x9f, 0x2ed: 0x9b, 0x2ee: 0x9b, 0x2ef: 0x9b, - 0x2f0: 0x9b, 0x2f1: 0x9b, 0x2f2: 0x9b, 0x2f3: 0x9b, 0x2f4: 0x9b, 0x2f5: 0x9b, 0x2f6: 0x9b, 0x2f7: 0x9b, - 0x2f8: 0x9b, 0x2f9: 0xa0, 0x2fa: 0x9b, 0x2fb: 0x9b, 0x2fc: 0x9b, 0x2fd: 0x9b, 0x2fe: 0x9b, 0x2ff: 0x9b, + 0x2c4: 0x95, 0x2c5: 0x54, 0x2c6: 0x96, 0x2c7: 0x97, + 0x2cb: 0x98, 0x2cd: 0x99, + 0x2e0: 0x9a, 0x2e1: 0x9a, 0x2e2: 0x9a, 0x2e3: 0x9a, 0x2e4: 0x9b, 0x2e5: 0x9a, 0x2e6: 0x9a, 0x2e7: 0x9a, + 0x2e8: 0x9c, 0x2e9: 0x9a, 0x2ea: 0x9a, 0x2eb: 0x9d, 0x2ec: 0x9e, 0x2ed: 0x9a, 0x2ee: 0x9a, 0x2ef: 0x9a, + 0x2f0: 0x9a, 0x2f1: 0x9a, 0x2f2: 0x9a, 0x2f3: 0x9a, 0x2f4: 0x9a, 0x2f5: 0x9a, 0x2f6: 0x9a, 0x2f7: 0x9a, + 0x2f8: 0x9a, 0x2f9: 0x9f, 0x2fa: 0x9a, 0x2fb: 0x9a, 0x2fc: 0x9a, 0x2fd: 0x9a, 0x2fe: 0x9a, 0x2ff: 0x9a, // Block 0xc, offset 0x300 - 0x300: 0xa1, 0x301: 0xa2, 0x302: 0xa3, 0x304: 0xa4, 0x305: 0xa5, 0x306: 0xa6, 0x307: 0xa7, - 0x308: 0xa8, 0x30b: 0xa9, 0x30c: 0xaa, 0x30d: 0xab, - 0x310: 0xac, 0x311: 0xad, 0x312: 0xae, 0x313: 0xaf, 0x316: 0xb0, 0x317: 0xb1, - 0x318: 0xb2, 0x319: 0xb3, 0x31a: 0xb4, 0x31c: 0xb5, - 0x330: 0xb6, 0x332: 0xb7, + 0x300: 0xa0, 0x301: 0xa1, 0x302: 0xa2, 0x304: 0xa3, 0x305: 0xa4, 0x306: 0xa5, 0x307: 0xa6, + 0x308: 0xa7, 0x30b: 0xa8, 0x30c: 0xa9, 0x30d: 0xaa, + 0x310: 0xab, 0x311: 0xac, 0x312: 0xad, 0x313: 0xae, 0x316: 0xaf, 0x317: 0xb0, + 0x318: 0xb1, 0x319: 0xb2, 0x31a: 0xb3, 0x31c: 0xb4, + 0x328: 0xb5, 0x329: 0xb6, 0x32a: 0xb7, + 0x330: 0xb8, 0x332: 0xb9, 0x334: 0xba, 0x335: 0xbb, // Block 0xd, offset 0x340 - 0x36b: 0xb8, 0x36c: 0xb9, - 0x37e: 0xba, + 0x36b: 0xbc, 0x36c: 0xbd, + 0x37e: 0xbe, // Block 0xe, offset 0x380 - 0x3b2: 0xbb, + 0x3b2: 0xbf, // Block 0xf, offset 0x3c0 - 0x3c5: 0xbc, 0x3c6: 0xbd, - 0x3c8: 0x54, 0x3c9: 0xbe, 0x3cc: 0x54, 0x3cd: 0xbf, - 0x3db: 0xc0, 0x3dc: 0xc1, 0x3dd: 0xc2, 0x3de: 0xc3, 0x3df: 0xc4, - 0x3e8: 0xc5, 0x3e9: 0xc6, 0x3ea: 0xc7, + 0x3c5: 0xc0, 0x3c6: 0xc1, + 0x3c8: 0x54, 0x3c9: 0xc2, 0x3cc: 0x54, 0x3cd: 0xc3, + 0x3db: 0xc4, 0x3dc: 0xc5, 0x3dd: 0xc6, 0x3de: 0xc7, 0x3df: 0xc8, + 0x3e8: 0xc9, 0x3e9: 0xca, 0x3ea: 0xcb, // Block 0x10, offset 0x400 - 0x400: 0xc8, - 0x420: 0x9b, 0x421: 0x9b, 0x422: 0x9b, 0x423: 0xc9, 0x424: 0x9b, 0x425: 0xca, 0x426: 0x9b, 0x427: 0x9b, - 0x428: 0x9b, 0x429: 0x9b, 0x42a: 0x9b, 0x42b: 0x9b, 0x42c: 0x9b, 0x42d: 0x9b, 0x42e: 0x9b, 0x42f: 0x9b, - 0x430: 0x9b, 0x431: 0x9b, 0x432: 0x9b, 0x433: 0x9b, 0x434: 0x9b, 0x435: 0x9b, 0x436: 0x9b, 0x437: 0x9b, - 0x438: 0x0e, 0x439: 0x0e, 0x43a: 0x0e, 0x43b: 0xcb, 0x43c: 0x9b, 0x43d: 0x9b, 0x43e: 0x9b, 0x43f: 0x9b, + 0x400: 0xcc, + 0x420: 0x9a, 0x421: 0x9a, 0x422: 0x9a, 0x423: 0xcd, 0x424: 0x9a, 0x425: 0xce, 0x426: 0x9a, 0x427: 0x9a, + 0x428: 0x9a, 0x429: 0x9a, 0x42a: 0x9a, 0x42b: 0x9a, 0x42c: 0x9a, 0x42d: 0x9a, 0x42e: 0x9a, 0x42f: 0x9a, + 0x430: 0x9a, 0x431: 0x9a, 0x432: 0x9a, 0x433: 0x9a, 0x434: 0x9a, 0x435: 0x9a, 0x436: 0x9a, 0x437: 0x9a, + 0x438: 0x0e, 0x439: 0x0e, 0x43a: 0x0e, 0x43b: 0xcf, 0x43c: 0x9a, 0x43d: 0x9a, 0x43e: 0x9a, 0x43f: 0x9a, // Block 0x11, offset 0x440 - 0x440: 0xcc, 0x441: 0x54, 0x442: 0xcd, 0x443: 0xce, 0x444: 0xcf, 0x445: 0xd0, - 0x44c: 0x54, 0x44d: 0x54, 0x44e: 0x54, 0x44f: 0x54, + 0x440: 0xd0, 0x441: 0x54, 0x442: 0xd1, 0x443: 0xd2, 0x444: 0xd3, 0x445: 0xd4, + 0x449: 0xd5, 0x44c: 0x54, 0x44d: 0x54, 0x44e: 0x54, 0x44f: 0x54, 0x450: 0x54, 0x451: 0x54, 0x452: 0x54, 0x453: 0x54, 0x454: 0x54, 0x455: 0x54, 0x456: 0x54, 0x457: 0x54, - 0x458: 0x54, 0x459: 0x54, 0x45a: 0x54, 0x45b: 0xd1, 0x45c: 0x54, 0x45d: 0x6c, 0x45e: 0x54, 0x45f: 0xd2, - 0x460: 0xd3, 0x461: 0xd4, 0x462: 0xd5, 0x464: 0xd6, 0x465: 0xd7, 0x466: 0xd8, 0x467: 0x36, - 0x47f: 0xd9, + 0x458: 0x54, 0x459: 0x54, 0x45a: 0x54, 0x45b: 0xd6, 0x45c: 0x54, 0x45d: 0x6b, 0x45e: 0x54, 0x45f: 0xd7, + 0x460: 0xd8, 0x461: 0xd9, 0x462: 0xda, 0x464: 0xdb, 0x465: 0xdc, 0x466: 0xdd, 0x467: 0xde, + 0x47f: 0xdf, // Block 0x12, offset 0x480 - 0x4bf: 0xd9, + 0x4bf: 0xdf, // Block 0x13, offset 0x4c0 0x4d0: 0x09, 0x4d1: 0x0a, 0x4d6: 0x0b, 0x4db: 0x0c, 0x4dd: 0x0d, 0x4de: 0x0e, 0x4df: 0x0f, @@ -1760,14 +1794,14 @@ var bidiIndex = [1536]uint8{ 0x52f: 0x10, 0x53f: 0x10, // Block 0x15, offset 0x540 - 0x540: 0xda, 0x541: 0xda, 0x542: 0xda, 0x543: 0xda, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0xdb, - 0x548: 0xda, 0x549: 0xda, 0x54a: 0xda, 0x54b: 0xda, 0x54c: 0xda, 0x54d: 0xda, 0x54e: 0xda, 0x54f: 0xda, - 0x550: 0xda, 0x551: 0xda, 0x552: 0xda, 0x553: 0xda, 0x554: 0xda, 0x555: 0xda, 0x556: 0xda, 0x557: 0xda, - 0x558: 0xda, 0x559: 0xda, 0x55a: 0xda, 0x55b: 0xda, 0x55c: 0xda, 0x55d: 0xda, 0x55e: 0xda, 0x55f: 0xda, - 0x560: 0xda, 0x561: 0xda, 0x562: 0xda, 0x563: 0xda, 0x564: 0xda, 0x565: 0xda, 0x566: 0xda, 0x567: 0xda, - 0x568: 0xda, 0x569: 0xda, 0x56a: 0xda, 0x56b: 0xda, 0x56c: 0xda, 0x56d: 0xda, 0x56e: 0xda, 0x56f: 0xda, - 0x570: 0xda, 0x571: 0xda, 0x572: 0xda, 0x573: 0xda, 0x574: 0xda, 0x575: 0xda, 0x576: 0xda, 0x577: 0xda, - 0x578: 0xda, 0x579: 0xda, 0x57a: 0xda, 0x57b: 0xda, 0x57c: 0xda, 0x57d: 0xda, 0x57e: 0xda, 0x57f: 0xda, + 0x540: 0xe0, 0x541: 0xe0, 0x542: 0xe0, 0x543: 0xe0, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0xe1, + 0x548: 0xe0, 0x549: 0xe0, 0x54a: 0xe0, 0x54b: 0xe0, 0x54c: 0xe0, 0x54d: 0xe0, 0x54e: 0xe0, 0x54f: 0xe0, + 0x550: 0xe0, 0x551: 0xe0, 0x552: 0xe0, 0x553: 0xe0, 0x554: 0xe0, 0x555: 0xe0, 0x556: 0xe0, 0x557: 0xe0, + 0x558: 0xe0, 0x559: 0xe0, 0x55a: 0xe0, 0x55b: 0xe0, 0x55c: 0xe0, 0x55d: 0xe0, 0x55e: 0xe0, 0x55f: 0xe0, + 0x560: 0xe0, 0x561: 0xe0, 0x562: 0xe0, 0x563: 0xe0, 0x564: 0xe0, 0x565: 0xe0, 0x566: 0xe0, 0x567: 0xe0, + 0x568: 0xe0, 0x569: 0xe0, 0x56a: 0xe0, 0x56b: 0xe0, 0x56c: 0xe0, 0x56d: 0xe0, 0x56e: 0xe0, 0x56f: 0xe0, + 0x570: 0xe0, 0x571: 0xe0, 0x572: 0xe0, 0x573: 0xe0, 0x574: 0xe0, 0x575: 0xe0, 0x576: 0xe0, 0x577: 0xe0, + 0x578: 0xe0, 0x579: 0xe0, 0x57a: 0xe0, 0x57b: 0xe0, 0x57c: 0xe0, 0x57d: 0xe0, 0x57e: 0xe0, 0x57f: 0xe0, // Block 0x16, offset 0x580 0x58f: 0x10, 0x59f: 0x10, @@ -1778,4 +1812,4 @@ var bidiIndex = [1536]uint8{ 0x5cf: 0x10, } -// Total table size 15800 bytes (15KiB); checksum: F50EF68C +// Total table size 16184 bytes (15KiB); checksum: F50EF68C diff --git a/libgo/go/golang_org/x/text/unicode/bidi/trieval.go b/libgo/go/golang_org/x/text/unicode/bidi/trieval.go index a825fdea4d0..c3f0e21f3e8 100644 --- a/libgo/go/golang_org/x/text/unicode/bidi/trieval.go +++ b/libgo/go/golang_org/x/text/unicode/bidi/trieval.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT. diff --git a/libgo/go/golang_org/x/text/unicode/doc.go b/libgo/go/golang_org/x/text/unicode/doc.go index 36b462a3e13..55a6775d59a 100644 --- a/libgo/go/golang_org/x/text/unicode/doc.go +++ b/libgo/go/golang_org/x/text/unicode/doc.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/norm/composition.go b/libgo/go/golang_org/x/text/unicode/norm/composition.go index 7380b0554e4..80287d2d5d3 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/composition.go +++ b/libgo/go/golang_org/x/text/unicode/norm/composition.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -35,17 +35,9 @@ const ( // streamSafe implements the policy of when a CGJ should be inserted. type streamSafe uint8 -// mkStreamSafe is a shorthand for declaring a streamSafe var and calling -// first on it. -func mkStreamSafe(p Properties) streamSafe { - return streamSafe(p.nTrailingNonStarters()) -} - -// first inserts the first rune of a segment. +// first inserts the first rune of a segment. It is a faster version of next if +// it is known p represents the first rune in a segment. func (ss *streamSafe) first(p Properties) { - if *ss != 0 { - panic("!= 0") - } *ss = streamSafe(p.nTrailingNonStarters()) } @@ -68,7 +60,7 @@ func (ss *streamSafe) next(p Properties) ssState { // be a non-starter. Note that it always hold that if nLead > 0 then // nLead == nTrail. if n == 0 { - *ss = 0 + *ss = streamSafe(p.nTrailingNonStarters()) return ssStarter } return ssSuccess @@ -144,7 +136,6 @@ func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) { func (rb *reorderBuffer) reset() { rb.nrune = 0 rb.nbyte = 0 - rb.ss = 0 } func (rb *reorderBuffer) doFlush() bool { @@ -259,6 +250,9 @@ func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) { // It flushes the buffer on each new segment start. func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr { rb.tmpBytes.setBytes(dcomp) + // As the streamSafe accounting already handles the counting for modifiers, + // we don't have to call next. However, we do need to keep the accounting + // intact when flushing the buffer. for i := 0; i < len(dcomp); { info := rb.f.info(rb.tmpBytes, i) if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() { diff --git a/libgo/go/golang_org/x/text/unicode/norm/forminfo.go b/libgo/go/golang_org/x/text/unicode/norm/forminfo.go index f3e2930daf2..64558400721 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/forminfo.go +++ b/libgo/go/golang_org/x/text/unicode/norm/forminfo.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/norm/input.go b/libgo/go/golang_org/x/text/unicode/norm/input.go index 202bde133ab..315f6fcaa1f 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/input.go +++ b/libgo/go/golang_org/x/text/unicode/norm/input.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -92,16 +92,20 @@ func (in *input) charinfoNFKC(p int) (uint16, int) { } func (in *input) hangul(p int) (r rune) { + var size int if in.bytes == nil { if !isHangulString(in.str[p:]) { return 0 } - r, _ = utf8.DecodeRuneInString(in.str[p:]) + r, size = utf8.DecodeRuneInString(in.str[p:]) } else { if !isHangul(in.bytes[p:]) { return 0 } - r, _ = utf8.DecodeRune(in.bytes[p:]) + r, size = utf8.DecodeRune(in.bytes[p:]) + } + if size != hangulUTF8Size { + return 0 } return r } diff --git a/libgo/go/golang_org/x/text/unicode/norm/iter.go b/libgo/go/golang_org/x/text/unicode/norm/iter.go index c0cf949435e..d0ae6cbc1ba 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/iter.go +++ b/libgo/go/golang_org/x/text/unicode/norm/iter.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -43,6 +43,7 @@ func (i *Iter) Init(f Form, src []byte) { i.next = i.rb.f.nextMain i.asciiF = nextASCIIBytes i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) } // InitString initializes i to iterate over src after normalizing it to Form f. @@ -58,11 +59,12 @@ func (i *Iter) InitString(f Form, src string) { i.next = i.rb.f.nextMain i.asciiF = nextASCIIString i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) } // Seek sets the segment to be returned by the next call to Next to start // at position p. It is the responsibility of the caller to set p to the -// start of a UTF8 rune. +// start of a segment. func (i *Iter) Seek(offset int64, whence int) (int64, error) { var abs int64 switch whence { @@ -86,6 +88,7 @@ func (i *Iter) Seek(offset int64, whence int) (int64, error) { i.multiSeg = nil i.next = i.rb.f.nextMain i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) return abs, nil } @@ -163,6 +166,7 @@ func nextHangul(i *Iter) []byte { if next >= i.rb.nsrc { i.setDone() } else if i.rb.src.hangul(next) == 0 { + i.rb.ss.next(i.info) i.info = i.rb.f.info(i.rb.src, i.p) i.next = i.rb.f.nextMain return i.next(i) @@ -206,12 +210,10 @@ func nextMultiNorm(i *Iter) []byte { if info.BoundaryBefore() { i.rb.compose() seg := i.buf[:i.rb.flushCopy(i.buf[:])] - i.rb.ss.first(info) i.rb.insertUnsafe(input{bytes: d}, j, info) i.multiSeg = d[j+int(info.size):] return seg } - i.rb.ss.next(info) i.rb.insertUnsafe(input{bytes: d}, j, info) j += int(info.size) } @@ -224,9 +226,9 @@ func nextMultiNorm(i *Iter) []byte { func nextDecomposed(i *Iter) (next []byte) { outp := 0 inCopyStart, outCopyStart := i.p, 0 - ss := mkStreamSafe(i.info) for { if sz := int(i.info.size); sz <= 1 { + i.rb.ss = 0 p := i.p i.p++ // ASCII or illegal byte. Either way, advance by 1. if i.p >= i.rb.nsrc { @@ -245,6 +247,8 @@ func nextDecomposed(i *Iter) (next []byte) { p := outp + len(d) if outp > 0 { i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p) + // TODO: this condition should not be possible, but we leave it + // in for defensive purposes. if p > len(i.buf) { return i.buf[:outp] } @@ -268,7 +272,7 @@ func nextDecomposed(i *Iter) (next []byte) { } else { i.info = i.rb.f.info(i.rb.src, i.p) } - switch ss.next(i.info) { + switch i.rb.ss.next(i.info) { case ssOverflow: i.next = nextCGJDecompose fallthrough @@ -311,7 +315,7 @@ func nextDecomposed(i *Iter) (next []byte) { } prevCC := i.info.tccc i.info = i.rb.f.info(i.rb.src, i.p) - if v := ss.next(i.info); v == ssStarter { + if v := i.rb.ss.next(i.info); v == ssStarter { break } else if v == ssOverflow { i.next = nextCGJDecompose @@ -337,10 +341,6 @@ doNorm: func doNormDecomposed(i *Iter) []byte { for { - if s := i.rb.ss.next(i.info); s == ssOverflow { - i.next = nextCGJDecompose - break - } i.rb.insertUnsafe(i.rb.src, i.p, i.info) if i.p += int(i.info.size); i.p >= i.rb.nsrc { i.setDone() @@ -350,6 +350,10 @@ func doNormDecomposed(i *Iter) []byte { if i.info.ccc == 0 { break } + if s := i.rb.ss.next(i.info); s == ssOverflow { + i.next = nextCGJDecompose + break + } } // new segment or too many combining characters: exit normalization return i.buf[:i.rb.flushCopy(i.buf[:])] @@ -359,6 +363,7 @@ func nextCGJDecompose(i *Iter) []byte { i.rb.ss = 0 i.rb.insertCGJ() i.next = nextDecomposed + i.rb.ss.first(i.info) buf := doNormDecomposed(i) return buf } @@ -367,7 +372,6 @@ func nextCGJDecompose(i *Iter) []byte { func nextComposed(i *Iter) []byte { outp, startp := 0, i.p var prevCC uint8 - ss := mkStreamSafe(i.info) for { if !i.info.isYesC() { goto doNorm @@ -387,11 +391,12 @@ func nextComposed(i *Iter) []byte { i.setDone() break } else if i.rb.src._byte(i.p) < utf8.RuneSelf { + i.rb.ss = 0 i.next = i.asciiF break } i.info = i.rb.f.info(i.rb.src, i.p) - if v := ss.next(i.info); v == ssStarter { + if v := i.rb.ss.next(i.info); v == ssStarter { break } else if v == ssOverflow { i.next = nextCGJCompose @@ -403,8 +408,10 @@ func nextComposed(i *Iter) []byte { } return i.returnSlice(startp, i.p) doNorm: + // reset to start position i.p = startp i.info = i.rb.f.info(i.rb.src, i.p) + i.rb.ss.first(i.info) if i.info.multiSegment() { d := i.info.Decomposition() info := i.rb.f.info(input{bytes: d}, 0) diff --git a/libgo/go/golang_org/x/text/unicode/norm/normalize.go b/libgo/go/golang_org/x/text/unicode/norm/normalize.go index 4427ee3177a..4de4ed6ed0f 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/normalize.go +++ b/libgo/go/golang_org/x/text/unicode/norm/normalize.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -324,7 +324,6 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) // have an overflow for runes that are starters (e.g. with U+FF9E). switch ss.next(info) { case ssStarter: - ss.first(info) lastSegStart = i case ssOverflow: return lastSegStart, false @@ -441,6 +440,8 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int { } return -1 } + // TODO: Using streamSafe to determine the boundary isn't the same as + // using BoundaryBefore. Determine which should be used. if s := ss.next(info); s != ssSuccess { return i } @@ -505,15 +506,14 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int { if info.size == 0 { return 0 } - if rb.nrune > 0 { - if s := rb.ss.next(info); s == ssStarter { - goto end - } else if s == ssOverflow { - rb.insertCGJ() + if s := rb.ss.next(info); s == ssStarter { + // TODO: this could be removed if we don't support merging. + if rb.nrune > 0 { goto end } - } else { - rb.ss.first(info) + } else if s == ssOverflow { + rb.insertCGJ() + goto end } if err := rb.insertFlush(rb.src, sp, info); err != iSuccess { return int(err) diff --git a/libgo/go/golang_org/x/text/unicode/norm/readwriter.go b/libgo/go/golang_org/x/text/unicode/norm/readwriter.go index 482ac85c745..068ab57153c 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/readwriter.go +++ b/libgo/go/golang_org/x/text/unicode/norm/readwriter.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/golang_org/x/text/unicode/norm/tables.go b/libgo/go/golang_org/x/text/unicode/norm/tables.go index ac99519efc5..d6466836cef 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/tables.go +++ b/libgo/go/golang_org/x/text/unicode/norm/tables.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang_org/x/text. DO NOT EDIT. @@ -6,7 +6,7 @@ package norm const ( // Version is the Unicode edition from which the tables are derived. - Version = "9.0.0" + Version = "10.0.0" // MaxTransformChunkSize indicates the maximum number of bytes that Transform // may need to write atomically for any Form. Making a destination buffer at @@ -2898,7 +2898,7 @@ func (t *nfcTrie) lookupStringUnsafe(s string) uint16 { return 0 } -// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: 51cc525b297fc970. +// nfcTrie. Total size: 10442 bytes (10.20 KiB). Checksum: 4ba400a9d8208e03. type nfcTrie struct{} func newNfcTrie(i int) *nfcTrie { @@ -2908,17 +2908,17 @@ func newNfcTrie(i int) *nfcTrie { // lookupValue determines the type of block n and looks up the value for b. func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 { switch { - case n < 44: + case n < 45: return uint16(nfcValues[n<<6+uint32(b)]) default: - n -= 44 + n -= 45 return uint16(nfcSparse.lookup(n, b)) } } -// nfcValues: 46 blocks, 2944 entries, 5888 bytes +// nfcValues: 47 blocks, 3008 entries, 6016 bytes // The third block is the zero block. -var nfcValues = [2944]uint16{ +var nfcValues = [3008]uint16{ // Block 0x0, offset 0x0 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, // Block 0x1, offset 0x40 @@ -3075,341 +3075,353 @@ var nfcValues = [2944]uint16{ 0x3fa: 0xa000, 0x3fb: 0x2d56, 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000, // Block 0x10, offset 0x400 - 0x400: 0x2f97, 0x401: 0x32a3, 0x402: 0x2fa1, 0x403: 0x32ad, 0x404: 0x2fa6, 0x405: 0x32b2, - 0x406: 0x2fab, 0x407: 0x32b7, 0x408: 0x38cc, 0x409: 0x3a5b, 0x40a: 0x2fc4, 0x40b: 0x32d0, - 0x40c: 0x2fce, 0x40d: 0x32da, 0x40e: 0x2fdd, 0x40f: 0x32e9, 0x410: 0x2fd3, 0x411: 0x32df, - 0x412: 0x2fd8, 0x413: 0x32e4, 0x414: 0x38ef, 0x415: 0x3a7e, 0x416: 0x38f6, 0x417: 0x3a85, - 0x418: 0x3019, 0x419: 0x3325, 0x41a: 0x301e, 0x41b: 0x332a, 0x41c: 0x3904, 0x41d: 0x3a93, - 0x41e: 0x3023, 0x41f: 0x332f, 0x420: 0x3032, 0x421: 0x333e, 0x422: 0x3050, 0x423: 0x335c, - 0x424: 0x305f, 0x425: 0x336b, 0x426: 0x3055, 0x427: 0x3361, 0x428: 0x3064, 0x429: 0x3370, - 0x42a: 0x3069, 0x42b: 0x3375, 0x42c: 0x30af, 0x42d: 0x33bb, 0x42e: 0x390b, 0x42f: 0x3a9a, - 0x430: 0x30b9, 0x431: 0x33ca, 0x432: 0x30c3, 0x433: 0x33d4, 0x434: 0x30cd, 0x435: 0x33de, - 0x436: 0x46c4, 0x437: 0x4755, 0x438: 0x3912, 0x439: 0x3aa1, 0x43a: 0x30e6, 0x43b: 0x33f7, - 0x43c: 0x30e1, 0x43d: 0x33f2, 0x43e: 0x30eb, 0x43f: 0x33fc, + 0x400: 0x8132, 0x401: 0x8132, 0x402: 0x812d, 0x403: 0x8132, 0x404: 0x8132, 0x405: 0x8132, + 0x406: 0x8132, 0x407: 0x8132, 0x408: 0x8132, 0x409: 0x8132, 0x40a: 0x812d, 0x40b: 0x8132, + 0x40c: 0x8132, 0x40d: 0x8135, 0x40e: 0x812a, 0x40f: 0x812d, 0x410: 0x8129, 0x411: 0x8132, + 0x412: 0x8132, 0x413: 0x8132, 0x414: 0x8132, 0x415: 0x8132, 0x416: 0x8132, 0x417: 0x8132, + 0x418: 0x8132, 0x419: 0x8132, 0x41a: 0x8132, 0x41b: 0x8132, 0x41c: 0x8132, 0x41d: 0x8132, + 0x41e: 0x8132, 0x41f: 0x8132, 0x420: 0x8132, 0x421: 0x8132, 0x422: 0x8132, 0x423: 0x8132, + 0x424: 0x8132, 0x425: 0x8132, 0x426: 0x8132, 0x427: 0x8132, 0x428: 0x8132, 0x429: 0x8132, + 0x42a: 0x8132, 0x42b: 0x8132, 0x42c: 0x8132, 0x42d: 0x8132, 0x42e: 0x8132, 0x42f: 0x8132, + 0x430: 0x8132, 0x431: 0x8132, 0x432: 0x8132, 0x433: 0x8132, 0x434: 0x8132, 0x435: 0x8132, + 0x436: 0x8133, 0x437: 0x8131, 0x438: 0x8131, 0x439: 0x812d, 0x43b: 0x8132, + 0x43c: 0x8134, 0x43d: 0x812d, 0x43e: 0x8132, 0x43f: 0x812d, // Block 0x11, offset 0x440 - 0x440: 0x30f0, 0x441: 0x3401, 0x442: 0x30f5, 0x443: 0x3406, 0x444: 0x3109, 0x445: 0x341a, - 0x446: 0x3113, 0x447: 0x3424, 0x448: 0x3122, 0x449: 0x3433, 0x44a: 0x311d, 0x44b: 0x342e, - 0x44c: 0x3935, 0x44d: 0x3ac4, 0x44e: 0x3943, 0x44f: 0x3ad2, 0x450: 0x394a, 0x451: 0x3ad9, - 0x452: 0x3951, 0x453: 0x3ae0, 0x454: 0x314f, 0x455: 0x3460, 0x456: 0x3154, 0x457: 0x3465, - 0x458: 0x315e, 0x459: 0x346f, 0x45a: 0x46f1, 0x45b: 0x4782, 0x45c: 0x3997, 0x45d: 0x3b26, - 0x45e: 0x3177, 0x45f: 0x3488, 0x460: 0x3181, 0x461: 0x3492, 0x462: 0x4700, 0x463: 0x4791, - 0x464: 0x399e, 0x465: 0x3b2d, 0x466: 0x39a5, 0x467: 0x3b34, 0x468: 0x39ac, 0x469: 0x3b3b, - 0x46a: 0x3190, 0x46b: 0x34a1, 0x46c: 0x319a, 0x46d: 0x34b0, 0x46e: 0x31ae, 0x46f: 0x34c4, - 0x470: 0x31a9, 0x471: 0x34bf, 0x472: 0x31ea, 0x473: 0x3500, 0x474: 0x31f9, 0x475: 0x350f, - 0x476: 0x31f4, 0x477: 0x350a, 0x478: 0x39b3, 0x479: 0x3b42, 0x47a: 0x39ba, 0x47b: 0x3b49, - 0x47c: 0x31fe, 0x47d: 0x3514, 0x47e: 0x3203, 0x47f: 0x3519, + 0x440: 0x2f97, 0x441: 0x32a3, 0x442: 0x2fa1, 0x443: 0x32ad, 0x444: 0x2fa6, 0x445: 0x32b2, + 0x446: 0x2fab, 0x447: 0x32b7, 0x448: 0x38cc, 0x449: 0x3a5b, 0x44a: 0x2fc4, 0x44b: 0x32d0, + 0x44c: 0x2fce, 0x44d: 0x32da, 0x44e: 0x2fdd, 0x44f: 0x32e9, 0x450: 0x2fd3, 0x451: 0x32df, + 0x452: 0x2fd8, 0x453: 0x32e4, 0x454: 0x38ef, 0x455: 0x3a7e, 0x456: 0x38f6, 0x457: 0x3a85, + 0x458: 0x3019, 0x459: 0x3325, 0x45a: 0x301e, 0x45b: 0x332a, 0x45c: 0x3904, 0x45d: 0x3a93, + 0x45e: 0x3023, 0x45f: 0x332f, 0x460: 0x3032, 0x461: 0x333e, 0x462: 0x3050, 0x463: 0x335c, + 0x464: 0x305f, 0x465: 0x336b, 0x466: 0x3055, 0x467: 0x3361, 0x468: 0x3064, 0x469: 0x3370, + 0x46a: 0x3069, 0x46b: 0x3375, 0x46c: 0x30af, 0x46d: 0x33bb, 0x46e: 0x390b, 0x46f: 0x3a9a, + 0x470: 0x30b9, 0x471: 0x33ca, 0x472: 0x30c3, 0x473: 0x33d4, 0x474: 0x30cd, 0x475: 0x33de, + 0x476: 0x46c4, 0x477: 0x4755, 0x478: 0x3912, 0x479: 0x3aa1, 0x47a: 0x30e6, 0x47b: 0x33f7, + 0x47c: 0x30e1, 0x47d: 0x33f2, 0x47e: 0x30eb, 0x47f: 0x33fc, // Block 0x12, offset 0x480 - 0x480: 0x3208, 0x481: 0x351e, 0x482: 0x320d, 0x483: 0x3523, 0x484: 0x321c, 0x485: 0x3532, - 0x486: 0x3217, 0x487: 0x352d, 0x488: 0x3221, 0x489: 0x353c, 0x48a: 0x3226, 0x48b: 0x3541, - 0x48c: 0x322b, 0x48d: 0x3546, 0x48e: 0x3249, 0x48f: 0x3564, 0x490: 0x3262, 0x491: 0x3582, - 0x492: 0x3271, 0x493: 0x3591, 0x494: 0x3276, 0x495: 0x3596, 0x496: 0x337a, 0x497: 0x34a6, - 0x498: 0x3537, 0x499: 0x3573, 0x49b: 0x35d1, - 0x4a0: 0x46a1, 0x4a1: 0x4732, 0x4a2: 0x2f83, 0x4a3: 0x328f, - 0x4a4: 0x3878, 0x4a5: 0x3a07, 0x4a6: 0x3871, 0x4a7: 0x3a00, 0x4a8: 0x3886, 0x4a9: 0x3a15, - 0x4aa: 0x387f, 0x4ab: 0x3a0e, 0x4ac: 0x38be, 0x4ad: 0x3a4d, 0x4ae: 0x3894, 0x4af: 0x3a23, - 0x4b0: 0x388d, 0x4b1: 0x3a1c, 0x4b2: 0x38a2, 0x4b3: 0x3a31, 0x4b4: 0x389b, 0x4b5: 0x3a2a, - 0x4b6: 0x38c5, 0x4b7: 0x3a54, 0x4b8: 0x46b5, 0x4b9: 0x4746, 0x4ba: 0x3000, 0x4bb: 0x330c, - 0x4bc: 0x2fec, 0x4bd: 0x32f8, 0x4be: 0x38da, 0x4bf: 0x3a69, + 0x480: 0x30f0, 0x481: 0x3401, 0x482: 0x30f5, 0x483: 0x3406, 0x484: 0x3109, 0x485: 0x341a, + 0x486: 0x3113, 0x487: 0x3424, 0x488: 0x3122, 0x489: 0x3433, 0x48a: 0x311d, 0x48b: 0x342e, + 0x48c: 0x3935, 0x48d: 0x3ac4, 0x48e: 0x3943, 0x48f: 0x3ad2, 0x490: 0x394a, 0x491: 0x3ad9, + 0x492: 0x3951, 0x493: 0x3ae0, 0x494: 0x314f, 0x495: 0x3460, 0x496: 0x3154, 0x497: 0x3465, + 0x498: 0x315e, 0x499: 0x346f, 0x49a: 0x46f1, 0x49b: 0x4782, 0x49c: 0x3997, 0x49d: 0x3b26, + 0x49e: 0x3177, 0x49f: 0x3488, 0x4a0: 0x3181, 0x4a1: 0x3492, 0x4a2: 0x4700, 0x4a3: 0x4791, + 0x4a4: 0x399e, 0x4a5: 0x3b2d, 0x4a6: 0x39a5, 0x4a7: 0x3b34, 0x4a8: 0x39ac, 0x4a9: 0x3b3b, + 0x4aa: 0x3190, 0x4ab: 0x34a1, 0x4ac: 0x319a, 0x4ad: 0x34b0, 0x4ae: 0x31ae, 0x4af: 0x34c4, + 0x4b0: 0x31a9, 0x4b1: 0x34bf, 0x4b2: 0x31ea, 0x4b3: 0x3500, 0x4b4: 0x31f9, 0x4b5: 0x350f, + 0x4b6: 0x31f4, 0x4b7: 0x350a, 0x4b8: 0x39b3, 0x4b9: 0x3b42, 0x4ba: 0x39ba, 0x4bb: 0x3b49, + 0x4bc: 0x31fe, 0x4bd: 0x3514, 0x4be: 0x3203, 0x4bf: 0x3519, // Block 0x13, offset 0x4c0 - 0x4c0: 0x38d3, 0x4c1: 0x3a62, 0x4c2: 0x38e8, 0x4c3: 0x3a77, 0x4c4: 0x38e1, 0x4c5: 0x3a70, - 0x4c6: 0x38fd, 0x4c7: 0x3a8c, 0x4c8: 0x3091, 0x4c9: 0x339d, 0x4ca: 0x30a5, 0x4cb: 0x33b1, - 0x4cc: 0x46e7, 0x4cd: 0x4778, 0x4ce: 0x3136, 0x4cf: 0x3447, 0x4d0: 0x3920, 0x4d1: 0x3aaf, - 0x4d2: 0x3919, 0x4d3: 0x3aa8, 0x4d4: 0x392e, 0x4d5: 0x3abd, 0x4d6: 0x3927, 0x4d7: 0x3ab6, - 0x4d8: 0x3989, 0x4d9: 0x3b18, 0x4da: 0x396d, 0x4db: 0x3afc, 0x4dc: 0x3966, 0x4dd: 0x3af5, - 0x4de: 0x397b, 0x4df: 0x3b0a, 0x4e0: 0x3974, 0x4e1: 0x3b03, 0x4e2: 0x3982, 0x4e3: 0x3b11, - 0x4e4: 0x31e5, 0x4e5: 0x34fb, 0x4e6: 0x31c7, 0x4e7: 0x34dd, 0x4e8: 0x39e4, 0x4e9: 0x3b73, - 0x4ea: 0x39dd, 0x4eb: 0x3b6c, 0x4ec: 0x39f2, 0x4ed: 0x3b81, 0x4ee: 0x39eb, 0x4ef: 0x3b7a, - 0x4f0: 0x39f9, 0x4f1: 0x3b88, 0x4f2: 0x3230, 0x4f3: 0x354b, 0x4f4: 0x3258, 0x4f5: 0x3578, - 0x4f6: 0x3253, 0x4f7: 0x356e, 0x4f8: 0x323f, 0x4f9: 0x355a, + 0x4c0: 0x3208, 0x4c1: 0x351e, 0x4c2: 0x320d, 0x4c3: 0x3523, 0x4c4: 0x321c, 0x4c5: 0x3532, + 0x4c6: 0x3217, 0x4c7: 0x352d, 0x4c8: 0x3221, 0x4c9: 0x353c, 0x4ca: 0x3226, 0x4cb: 0x3541, + 0x4cc: 0x322b, 0x4cd: 0x3546, 0x4ce: 0x3249, 0x4cf: 0x3564, 0x4d0: 0x3262, 0x4d1: 0x3582, + 0x4d2: 0x3271, 0x4d3: 0x3591, 0x4d4: 0x3276, 0x4d5: 0x3596, 0x4d6: 0x337a, 0x4d7: 0x34a6, + 0x4d8: 0x3537, 0x4d9: 0x3573, 0x4db: 0x35d1, + 0x4e0: 0x46a1, 0x4e1: 0x4732, 0x4e2: 0x2f83, 0x4e3: 0x328f, + 0x4e4: 0x3878, 0x4e5: 0x3a07, 0x4e6: 0x3871, 0x4e7: 0x3a00, 0x4e8: 0x3886, 0x4e9: 0x3a15, + 0x4ea: 0x387f, 0x4eb: 0x3a0e, 0x4ec: 0x38be, 0x4ed: 0x3a4d, 0x4ee: 0x3894, 0x4ef: 0x3a23, + 0x4f0: 0x388d, 0x4f1: 0x3a1c, 0x4f2: 0x38a2, 0x4f3: 0x3a31, 0x4f4: 0x389b, 0x4f5: 0x3a2a, + 0x4f6: 0x38c5, 0x4f7: 0x3a54, 0x4f8: 0x46b5, 0x4f9: 0x4746, 0x4fa: 0x3000, 0x4fb: 0x330c, + 0x4fc: 0x2fec, 0x4fd: 0x32f8, 0x4fe: 0x38da, 0x4ff: 0x3a69, // Block 0x14, offset 0x500 - 0x500: 0x4804, 0x501: 0x480a, 0x502: 0x491e, 0x503: 0x4936, 0x504: 0x4926, 0x505: 0x493e, - 0x506: 0x492e, 0x507: 0x4946, 0x508: 0x47aa, 0x509: 0x47b0, 0x50a: 0x488e, 0x50b: 0x48a6, - 0x50c: 0x4896, 0x50d: 0x48ae, 0x50e: 0x489e, 0x50f: 0x48b6, 0x510: 0x4816, 0x511: 0x481c, - 0x512: 0x3db8, 0x513: 0x3dc8, 0x514: 0x3dc0, 0x515: 0x3dd0, - 0x518: 0x47b6, 0x519: 0x47bc, 0x51a: 0x3ce8, 0x51b: 0x3cf8, 0x51c: 0x3cf0, 0x51d: 0x3d00, - 0x520: 0x482e, 0x521: 0x4834, 0x522: 0x494e, 0x523: 0x4966, - 0x524: 0x4956, 0x525: 0x496e, 0x526: 0x495e, 0x527: 0x4976, 0x528: 0x47c2, 0x529: 0x47c8, - 0x52a: 0x48be, 0x52b: 0x48d6, 0x52c: 0x48c6, 0x52d: 0x48de, 0x52e: 0x48ce, 0x52f: 0x48e6, - 0x530: 0x4846, 0x531: 0x484c, 0x532: 0x3e18, 0x533: 0x3e30, 0x534: 0x3e20, 0x535: 0x3e38, - 0x536: 0x3e28, 0x537: 0x3e40, 0x538: 0x47ce, 0x539: 0x47d4, 0x53a: 0x3d18, 0x53b: 0x3d30, - 0x53c: 0x3d20, 0x53d: 0x3d38, 0x53e: 0x3d28, 0x53f: 0x3d40, + 0x500: 0x38d3, 0x501: 0x3a62, 0x502: 0x38e8, 0x503: 0x3a77, 0x504: 0x38e1, 0x505: 0x3a70, + 0x506: 0x38fd, 0x507: 0x3a8c, 0x508: 0x3091, 0x509: 0x339d, 0x50a: 0x30a5, 0x50b: 0x33b1, + 0x50c: 0x46e7, 0x50d: 0x4778, 0x50e: 0x3136, 0x50f: 0x3447, 0x510: 0x3920, 0x511: 0x3aaf, + 0x512: 0x3919, 0x513: 0x3aa8, 0x514: 0x392e, 0x515: 0x3abd, 0x516: 0x3927, 0x517: 0x3ab6, + 0x518: 0x3989, 0x519: 0x3b18, 0x51a: 0x396d, 0x51b: 0x3afc, 0x51c: 0x3966, 0x51d: 0x3af5, + 0x51e: 0x397b, 0x51f: 0x3b0a, 0x520: 0x3974, 0x521: 0x3b03, 0x522: 0x3982, 0x523: 0x3b11, + 0x524: 0x31e5, 0x525: 0x34fb, 0x526: 0x31c7, 0x527: 0x34dd, 0x528: 0x39e4, 0x529: 0x3b73, + 0x52a: 0x39dd, 0x52b: 0x3b6c, 0x52c: 0x39f2, 0x52d: 0x3b81, 0x52e: 0x39eb, 0x52f: 0x3b7a, + 0x530: 0x39f9, 0x531: 0x3b88, 0x532: 0x3230, 0x533: 0x354b, 0x534: 0x3258, 0x535: 0x3578, + 0x536: 0x3253, 0x537: 0x356e, 0x538: 0x323f, 0x539: 0x355a, // Block 0x15, offset 0x540 - 0x540: 0x4852, 0x541: 0x4858, 0x542: 0x3e48, 0x543: 0x3e58, 0x544: 0x3e50, 0x545: 0x3e60, - 0x548: 0x47da, 0x549: 0x47e0, 0x54a: 0x3d48, 0x54b: 0x3d58, - 0x54c: 0x3d50, 0x54d: 0x3d60, 0x550: 0x4864, 0x551: 0x486a, - 0x552: 0x3e80, 0x553: 0x3e98, 0x554: 0x3e88, 0x555: 0x3ea0, 0x556: 0x3e90, 0x557: 0x3ea8, - 0x559: 0x47e6, 0x55b: 0x3d68, 0x55d: 0x3d70, - 0x55f: 0x3d78, 0x560: 0x487c, 0x561: 0x4882, 0x562: 0x497e, 0x563: 0x4996, - 0x564: 0x4986, 0x565: 0x499e, 0x566: 0x498e, 0x567: 0x49a6, 0x568: 0x47ec, 0x569: 0x47f2, - 0x56a: 0x48ee, 0x56b: 0x4906, 0x56c: 0x48f6, 0x56d: 0x490e, 0x56e: 0x48fe, 0x56f: 0x4916, - 0x570: 0x47f8, 0x571: 0x431e, 0x572: 0x3691, 0x573: 0x4324, 0x574: 0x4822, 0x575: 0x432a, - 0x576: 0x36a3, 0x577: 0x4330, 0x578: 0x36c1, 0x579: 0x4336, 0x57a: 0x36d9, 0x57b: 0x433c, - 0x57c: 0x4870, 0x57d: 0x4342, + 0x540: 0x4804, 0x541: 0x480a, 0x542: 0x491e, 0x543: 0x4936, 0x544: 0x4926, 0x545: 0x493e, + 0x546: 0x492e, 0x547: 0x4946, 0x548: 0x47aa, 0x549: 0x47b0, 0x54a: 0x488e, 0x54b: 0x48a6, + 0x54c: 0x4896, 0x54d: 0x48ae, 0x54e: 0x489e, 0x54f: 0x48b6, 0x550: 0x4816, 0x551: 0x481c, + 0x552: 0x3db8, 0x553: 0x3dc8, 0x554: 0x3dc0, 0x555: 0x3dd0, + 0x558: 0x47b6, 0x559: 0x47bc, 0x55a: 0x3ce8, 0x55b: 0x3cf8, 0x55c: 0x3cf0, 0x55d: 0x3d00, + 0x560: 0x482e, 0x561: 0x4834, 0x562: 0x494e, 0x563: 0x4966, + 0x564: 0x4956, 0x565: 0x496e, 0x566: 0x495e, 0x567: 0x4976, 0x568: 0x47c2, 0x569: 0x47c8, + 0x56a: 0x48be, 0x56b: 0x48d6, 0x56c: 0x48c6, 0x56d: 0x48de, 0x56e: 0x48ce, 0x56f: 0x48e6, + 0x570: 0x4846, 0x571: 0x484c, 0x572: 0x3e18, 0x573: 0x3e30, 0x574: 0x3e20, 0x575: 0x3e38, + 0x576: 0x3e28, 0x577: 0x3e40, 0x578: 0x47ce, 0x579: 0x47d4, 0x57a: 0x3d18, 0x57b: 0x3d30, + 0x57c: 0x3d20, 0x57d: 0x3d38, 0x57e: 0x3d28, 0x57f: 0x3d40, // Block 0x16, offset 0x580 - 0x580: 0x3da0, 0x581: 0x3da8, 0x582: 0x4184, 0x583: 0x41a2, 0x584: 0x418e, 0x585: 0x41ac, - 0x586: 0x4198, 0x587: 0x41b6, 0x588: 0x3cd8, 0x589: 0x3ce0, 0x58a: 0x40d0, 0x58b: 0x40ee, - 0x58c: 0x40da, 0x58d: 0x40f8, 0x58e: 0x40e4, 0x58f: 0x4102, 0x590: 0x3de8, 0x591: 0x3df0, - 0x592: 0x41c0, 0x593: 0x41de, 0x594: 0x41ca, 0x595: 0x41e8, 0x596: 0x41d4, 0x597: 0x41f2, - 0x598: 0x3d08, 0x599: 0x3d10, 0x59a: 0x410c, 0x59b: 0x412a, 0x59c: 0x4116, 0x59d: 0x4134, - 0x59e: 0x4120, 0x59f: 0x413e, 0x5a0: 0x3ec0, 0x5a1: 0x3ec8, 0x5a2: 0x41fc, 0x5a3: 0x421a, - 0x5a4: 0x4206, 0x5a5: 0x4224, 0x5a6: 0x4210, 0x5a7: 0x422e, 0x5a8: 0x3d80, 0x5a9: 0x3d88, - 0x5aa: 0x4148, 0x5ab: 0x4166, 0x5ac: 0x4152, 0x5ad: 0x4170, 0x5ae: 0x415c, 0x5af: 0x417a, - 0x5b0: 0x3685, 0x5b1: 0x367f, 0x5b2: 0x3d90, 0x5b3: 0x368b, 0x5b4: 0x3d98, - 0x5b6: 0x4810, 0x5b7: 0x3db0, 0x5b8: 0x35f5, 0x5b9: 0x35ef, 0x5ba: 0x35e3, 0x5bb: 0x42ee, - 0x5bc: 0x35fb, 0x5bd: 0x8100, 0x5be: 0x01d3, 0x5bf: 0xa100, + 0x580: 0x4852, 0x581: 0x4858, 0x582: 0x3e48, 0x583: 0x3e58, 0x584: 0x3e50, 0x585: 0x3e60, + 0x588: 0x47da, 0x589: 0x47e0, 0x58a: 0x3d48, 0x58b: 0x3d58, + 0x58c: 0x3d50, 0x58d: 0x3d60, 0x590: 0x4864, 0x591: 0x486a, + 0x592: 0x3e80, 0x593: 0x3e98, 0x594: 0x3e88, 0x595: 0x3ea0, 0x596: 0x3e90, 0x597: 0x3ea8, + 0x599: 0x47e6, 0x59b: 0x3d68, 0x59d: 0x3d70, + 0x59f: 0x3d78, 0x5a0: 0x487c, 0x5a1: 0x4882, 0x5a2: 0x497e, 0x5a3: 0x4996, + 0x5a4: 0x4986, 0x5a5: 0x499e, 0x5a6: 0x498e, 0x5a7: 0x49a6, 0x5a8: 0x47ec, 0x5a9: 0x47f2, + 0x5aa: 0x48ee, 0x5ab: 0x4906, 0x5ac: 0x48f6, 0x5ad: 0x490e, 0x5ae: 0x48fe, 0x5af: 0x4916, + 0x5b0: 0x47f8, 0x5b1: 0x431e, 0x5b2: 0x3691, 0x5b3: 0x4324, 0x5b4: 0x4822, 0x5b5: 0x432a, + 0x5b6: 0x36a3, 0x5b7: 0x4330, 0x5b8: 0x36c1, 0x5b9: 0x4336, 0x5ba: 0x36d9, 0x5bb: 0x433c, + 0x5bc: 0x4870, 0x5bd: 0x4342, // Block 0x17, offset 0x5c0 - 0x5c0: 0x8100, 0x5c1: 0x35a7, 0x5c2: 0x3dd8, 0x5c3: 0x369d, 0x5c4: 0x3de0, - 0x5c6: 0x483a, 0x5c7: 0x3df8, 0x5c8: 0x3601, 0x5c9: 0x42f4, 0x5ca: 0x360d, 0x5cb: 0x42fa, - 0x5cc: 0x3619, 0x5cd: 0x3b8f, 0x5ce: 0x3b96, 0x5cf: 0x3b9d, 0x5d0: 0x36b5, 0x5d1: 0x36af, - 0x5d2: 0x3e00, 0x5d3: 0x44e4, 0x5d6: 0x36bb, 0x5d7: 0x3e10, - 0x5d8: 0x3631, 0x5d9: 0x362b, 0x5da: 0x361f, 0x5db: 0x4300, 0x5dd: 0x3ba4, - 0x5de: 0x3bab, 0x5df: 0x3bb2, 0x5e0: 0x36eb, 0x5e1: 0x36e5, 0x5e2: 0x3e68, 0x5e3: 0x44ec, - 0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b, - 0x5ea: 0x364f, 0x5eb: 0x430c, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x42e8, 0x5ef: 0x0081, - 0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8, - 0x5f6: 0x4888, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x4306, 0x5fa: 0x366d, 0x5fb: 0x4318, - 0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100, + 0x5c0: 0x3da0, 0x5c1: 0x3da8, 0x5c2: 0x4184, 0x5c3: 0x41a2, 0x5c4: 0x418e, 0x5c5: 0x41ac, + 0x5c6: 0x4198, 0x5c7: 0x41b6, 0x5c8: 0x3cd8, 0x5c9: 0x3ce0, 0x5ca: 0x40d0, 0x5cb: 0x40ee, + 0x5cc: 0x40da, 0x5cd: 0x40f8, 0x5ce: 0x40e4, 0x5cf: 0x4102, 0x5d0: 0x3de8, 0x5d1: 0x3df0, + 0x5d2: 0x41c0, 0x5d3: 0x41de, 0x5d4: 0x41ca, 0x5d5: 0x41e8, 0x5d6: 0x41d4, 0x5d7: 0x41f2, + 0x5d8: 0x3d08, 0x5d9: 0x3d10, 0x5da: 0x410c, 0x5db: 0x412a, 0x5dc: 0x4116, 0x5dd: 0x4134, + 0x5de: 0x4120, 0x5df: 0x413e, 0x5e0: 0x3ec0, 0x5e1: 0x3ec8, 0x5e2: 0x41fc, 0x5e3: 0x421a, + 0x5e4: 0x4206, 0x5e5: 0x4224, 0x5e6: 0x4210, 0x5e7: 0x422e, 0x5e8: 0x3d80, 0x5e9: 0x3d88, + 0x5ea: 0x4148, 0x5eb: 0x4166, 0x5ec: 0x4152, 0x5ed: 0x4170, 0x5ee: 0x415c, 0x5ef: 0x417a, + 0x5f0: 0x3685, 0x5f1: 0x367f, 0x5f2: 0x3d90, 0x5f3: 0x368b, 0x5f4: 0x3d98, + 0x5f6: 0x4810, 0x5f7: 0x3db0, 0x5f8: 0x35f5, 0x5f9: 0x35ef, 0x5fa: 0x35e3, 0x5fb: 0x42ee, + 0x5fc: 0x35fb, 0x5fd: 0x8100, 0x5fe: 0x01d3, 0x5ff: 0xa100, // Block 0x18, offset 0x600 - 0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000, - 0x607: 0x3c14, 0x608: 0xa000, 0x609: 0x3c1b, - 0x60d: 0xa000, - 0x620: 0x2f65, 0x621: 0xa000, 0x622: 0x3c29, - 0x624: 0xa000, 0x625: 0xa000, - 0x62d: 0x3c22, 0x62e: 0x2f60, 0x62f: 0x2f6a, - 0x630: 0x3c30, 0x631: 0x3c37, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c3e, 0x635: 0x3c45, - 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c4c, 0x639: 0x3c53, 0x63a: 0xa000, 0x63b: 0xa000, - 0x63c: 0xa000, 0x63d: 0xa000, + 0x600: 0x8100, 0x601: 0x35a7, 0x602: 0x3dd8, 0x603: 0x369d, 0x604: 0x3de0, + 0x606: 0x483a, 0x607: 0x3df8, 0x608: 0x3601, 0x609: 0x42f4, 0x60a: 0x360d, 0x60b: 0x42fa, + 0x60c: 0x3619, 0x60d: 0x3b8f, 0x60e: 0x3b96, 0x60f: 0x3b9d, 0x610: 0x36b5, 0x611: 0x36af, + 0x612: 0x3e00, 0x613: 0x44e4, 0x616: 0x36bb, 0x617: 0x3e10, + 0x618: 0x3631, 0x619: 0x362b, 0x61a: 0x361f, 0x61b: 0x4300, 0x61d: 0x3ba4, + 0x61e: 0x3bab, 0x61f: 0x3bb2, 0x620: 0x36eb, 0x621: 0x36e5, 0x622: 0x3e68, 0x623: 0x44ec, + 0x624: 0x36cd, 0x625: 0x36d3, 0x626: 0x36f1, 0x627: 0x3e78, 0x628: 0x3661, 0x629: 0x365b, + 0x62a: 0x364f, 0x62b: 0x430c, 0x62c: 0x3649, 0x62d: 0x359b, 0x62e: 0x42e8, 0x62f: 0x0081, + 0x632: 0x3eb0, 0x633: 0x36f7, 0x634: 0x3eb8, + 0x636: 0x4888, 0x637: 0x3ed0, 0x638: 0x363d, 0x639: 0x4306, 0x63a: 0x366d, 0x63b: 0x4318, + 0x63c: 0x3679, 0x63d: 0x4256, 0x63e: 0xa100, // Block 0x19, offset 0x640 - 0x640: 0x3c5a, 0x641: 0x3c61, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3c76, 0x645: 0x3c7d, - 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3c84, 0x649: 0x3c8b, - 0x651: 0xa000, - 0x652: 0xa000, - 0x662: 0xa000, - 0x668: 0xa000, 0x669: 0xa000, - 0x66b: 0xa000, 0x66c: 0x3ca0, 0x66d: 0x3ca7, 0x66e: 0x3cae, 0x66f: 0x3cb5, - 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000, + 0x641: 0x3c06, 0x643: 0xa000, 0x644: 0x3c0d, 0x645: 0xa000, + 0x647: 0x3c14, 0x648: 0xa000, 0x649: 0x3c1b, + 0x64d: 0xa000, + 0x660: 0x2f65, 0x661: 0xa000, 0x662: 0x3c29, + 0x664: 0xa000, 0x665: 0xa000, + 0x66d: 0x3c22, 0x66e: 0x2f60, 0x66f: 0x2f6a, + 0x670: 0x3c30, 0x671: 0x3c37, 0x672: 0xa000, 0x673: 0xa000, 0x674: 0x3c3e, 0x675: 0x3c45, + 0x676: 0xa000, 0x677: 0xa000, 0x678: 0x3c4c, 0x679: 0x3c53, 0x67a: 0xa000, 0x67b: 0xa000, + 0x67c: 0xa000, 0x67d: 0xa000, // Block 0x1a, offset 0x680 - 0x686: 0xa000, 0x68b: 0xa000, - 0x68c: 0x3f08, 0x68d: 0xa000, 0x68e: 0x3f10, 0x68f: 0xa000, 0x690: 0x3f18, 0x691: 0xa000, - 0x692: 0x3f20, 0x693: 0xa000, 0x694: 0x3f28, 0x695: 0xa000, 0x696: 0x3f30, 0x697: 0xa000, - 0x698: 0x3f38, 0x699: 0xa000, 0x69a: 0x3f40, 0x69b: 0xa000, 0x69c: 0x3f48, 0x69d: 0xa000, - 0x69e: 0x3f50, 0x69f: 0xa000, 0x6a0: 0x3f58, 0x6a1: 0xa000, 0x6a2: 0x3f60, - 0x6a4: 0xa000, 0x6a5: 0x3f68, 0x6a6: 0xa000, 0x6a7: 0x3f70, 0x6a8: 0xa000, 0x6a9: 0x3f78, - 0x6af: 0xa000, - 0x6b0: 0x3f80, 0x6b1: 0x3f88, 0x6b2: 0xa000, 0x6b3: 0x3f90, 0x6b4: 0x3f98, 0x6b5: 0xa000, - 0x6b6: 0x3fa0, 0x6b7: 0x3fa8, 0x6b8: 0xa000, 0x6b9: 0x3fb0, 0x6ba: 0x3fb8, 0x6bb: 0xa000, - 0x6bc: 0x3fc0, 0x6bd: 0x3fc8, + 0x680: 0x3c5a, 0x681: 0x3c61, 0x682: 0xa000, 0x683: 0xa000, 0x684: 0x3c76, 0x685: 0x3c7d, + 0x686: 0xa000, 0x687: 0xa000, 0x688: 0x3c84, 0x689: 0x3c8b, + 0x691: 0xa000, + 0x692: 0xa000, + 0x6a2: 0xa000, + 0x6a8: 0xa000, 0x6a9: 0xa000, + 0x6ab: 0xa000, 0x6ac: 0x3ca0, 0x6ad: 0x3ca7, 0x6ae: 0x3cae, 0x6af: 0x3cb5, + 0x6b2: 0xa000, 0x6b3: 0xa000, 0x6b4: 0xa000, 0x6b5: 0xa000, // Block 0x1b, offset 0x6c0 - 0x6d4: 0x3f00, - 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000, - 0x6de: 0x3fd0, - 0x6e6: 0xa000, - 0x6eb: 0xa000, 0x6ec: 0x3fe0, 0x6ed: 0xa000, 0x6ee: 0x3fe8, 0x6ef: 0xa000, - 0x6f0: 0x3ff0, 0x6f1: 0xa000, 0x6f2: 0x3ff8, 0x6f3: 0xa000, 0x6f4: 0x4000, 0x6f5: 0xa000, - 0x6f6: 0x4008, 0x6f7: 0xa000, 0x6f8: 0x4010, 0x6f9: 0xa000, 0x6fa: 0x4018, 0x6fb: 0xa000, - 0x6fc: 0x4020, 0x6fd: 0xa000, 0x6fe: 0x4028, 0x6ff: 0xa000, + 0x6c6: 0xa000, 0x6cb: 0xa000, + 0x6cc: 0x3f08, 0x6cd: 0xa000, 0x6ce: 0x3f10, 0x6cf: 0xa000, 0x6d0: 0x3f18, 0x6d1: 0xa000, + 0x6d2: 0x3f20, 0x6d3: 0xa000, 0x6d4: 0x3f28, 0x6d5: 0xa000, 0x6d6: 0x3f30, 0x6d7: 0xa000, + 0x6d8: 0x3f38, 0x6d9: 0xa000, 0x6da: 0x3f40, 0x6db: 0xa000, 0x6dc: 0x3f48, 0x6dd: 0xa000, + 0x6de: 0x3f50, 0x6df: 0xa000, 0x6e0: 0x3f58, 0x6e1: 0xa000, 0x6e2: 0x3f60, + 0x6e4: 0xa000, 0x6e5: 0x3f68, 0x6e6: 0xa000, 0x6e7: 0x3f70, 0x6e8: 0xa000, 0x6e9: 0x3f78, + 0x6ef: 0xa000, + 0x6f0: 0x3f80, 0x6f1: 0x3f88, 0x6f2: 0xa000, 0x6f3: 0x3f90, 0x6f4: 0x3f98, 0x6f5: 0xa000, + 0x6f6: 0x3fa0, 0x6f7: 0x3fa8, 0x6f8: 0xa000, 0x6f9: 0x3fb0, 0x6fa: 0x3fb8, 0x6fb: 0xa000, + 0x6fc: 0x3fc0, 0x6fd: 0x3fc8, // Block 0x1c, offset 0x700 - 0x700: 0x4030, 0x701: 0xa000, 0x702: 0x4038, 0x704: 0xa000, 0x705: 0x4040, - 0x706: 0xa000, 0x707: 0x4048, 0x708: 0xa000, 0x709: 0x4050, - 0x70f: 0xa000, 0x710: 0x4058, 0x711: 0x4060, - 0x712: 0xa000, 0x713: 0x4068, 0x714: 0x4070, 0x715: 0xa000, 0x716: 0x4078, 0x717: 0x4080, - 0x718: 0xa000, 0x719: 0x4088, 0x71a: 0x4090, 0x71b: 0xa000, 0x71c: 0x4098, 0x71d: 0x40a0, - 0x72f: 0xa000, - 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x3fd8, - 0x737: 0x40a8, 0x738: 0x40b0, 0x739: 0x40b8, 0x73a: 0x40c0, - 0x73d: 0xa000, 0x73e: 0x40c8, + 0x714: 0x3f00, + 0x719: 0x9903, 0x71a: 0x9903, 0x71b: 0x8100, 0x71c: 0x8100, 0x71d: 0xa000, + 0x71e: 0x3fd0, + 0x726: 0xa000, + 0x72b: 0xa000, 0x72c: 0x3fe0, 0x72d: 0xa000, 0x72e: 0x3fe8, 0x72f: 0xa000, + 0x730: 0x3ff0, 0x731: 0xa000, 0x732: 0x3ff8, 0x733: 0xa000, 0x734: 0x4000, 0x735: 0xa000, + 0x736: 0x4008, 0x737: 0xa000, 0x738: 0x4010, 0x739: 0xa000, 0x73a: 0x4018, 0x73b: 0xa000, + 0x73c: 0x4020, 0x73d: 0xa000, 0x73e: 0x4028, 0x73f: 0xa000, // Block 0x1d, offset 0x740 - 0x740: 0x1377, 0x741: 0x0cfb, 0x742: 0x13d3, 0x743: 0x139f, 0x744: 0x0e57, 0x745: 0x06eb, - 0x746: 0x08df, 0x747: 0x162b, 0x748: 0x162b, 0x749: 0x0a0b, 0x74a: 0x145f, 0x74b: 0x0943, - 0x74c: 0x0a07, 0x74d: 0x0bef, 0x74e: 0x0fcf, 0x74f: 0x115f, 0x750: 0x1297, 0x751: 0x12d3, - 0x752: 0x1307, 0x753: 0x141b, 0x754: 0x0d73, 0x755: 0x0dff, 0x756: 0x0eab, 0x757: 0x0f43, - 0x758: 0x125f, 0x759: 0x1447, 0x75a: 0x1573, 0x75b: 0x070f, 0x75c: 0x08b3, 0x75d: 0x0d87, - 0x75e: 0x0ecf, 0x75f: 0x1293, 0x760: 0x15c3, 0x761: 0x0ab3, 0x762: 0x0e77, 0x763: 0x1283, - 0x764: 0x1317, 0x765: 0x0c23, 0x766: 0x11bb, 0x767: 0x12df, 0x768: 0x0b1f, 0x769: 0x0d0f, - 0x76a: 0x0e17, 0x76b: 0x0f1b, 0x76c: 0x1427, 0x76d: 0x074f, 0x76e: 0x07e7, 0x76f: 0x0853, - 0x770: 0x0c8b, 0x771: 0x0d7f, 0x772: 0x0ecb, 0x773: 0x0fef, 0x774: 0x1177, 0x775: 0x128b, - 0x776: 0x12a3, 0x777: 0x13c7, 0x778: 0x14ef, 0x779: 0x15a3, 0x77a: 0x15bf, 0x77b: 0x102b, - 0x77c: 0x106b, 0x77d: 0x1123, 0x77e: 0x1243, 0x77f: 0x147b, + 0x740: 0x4030, 0x741: 0xa000, 0x742: 0x4038, 0x744: 0xa000, 0x745: 0x4040, + 0x746: 0xa000, 0x747: 0x4048, 0x748: 0xa000, 0x749: 0x4050, + 0x74f: 0xa000, 0x750: 0x4058, 0x751: 0x4060, + 0x752: 0xa000, 0x753: 0x4068, 0x754: 0x4070, 0x755: 0xa000, 0x756: 0x4078, 0x757: 0x4080, + 0x758: 0xa000, 0x759: 0x4088, 0x75a: 0x4090, 0x75b: 0xa000, 0x75c: 0x4098, 0x75d: 0x40a0, + 0x76f: 0xa000, + 0x770: 0xa000, 0x771: 0xa000, 0x772: 0xa000, 0x774: 0x3fd8, + 0x777: 0x40a8, 0x778: 0x40b0, 0x779: 0x40b8, 0x77a: 0x40c0, + 0x77d: 0xa000, 0x77e: 0x40c8, // Block 0x1e, offset 0x780 - 0x780: 0x15cb, 0x781: 0x134b, 0x782: 0x09c7, 0x783: 0x0b3b, 0x784: 0x10db, 0x785: 0x119b, - 0x786: 0x0eff, 0x787: 0x1033, 0x788: 0x1397, 0x789: 0x14e7, 0x78a: 0x09c3, 0x78b: 0x0a8f, - 0x78c: 0x0d77, 0x78d: 0x0e2b, 0x78e: 0x0e5f, 0x78f: 0x1113, 0x790: 0x113b, 0x791: 0x14a7, - 0x792: 0x084f, 0x793: 0x11a7, 0x794: 0x07f3, 0x795: 0x07ef, 0x796: 0x1097, 0x797: 0x1127, - 0x798: 0x125b, 0x799: 0x14af, 0x79a: 0x1367, 0x79b: 0x0c27, 0x79c: 0x0d73, 0x79d: 0x1357, - 0x79e: 0x06f7, 0x79f: 0x0a63, 0x7a0: 0x0b93, 0x7a1: 0x0f2f, 0x7a2: 0x0faf, 0x7a3: 0x0873, - 0x7a4: 0x103b, 0x7a5: 0x075f, 0x7a6: 0x0b77, 0x7a7: 0x06d7, 0x7a8: 0x0deb, 0x7a9: 0x0ca3, - 0x7aa: 0x110f, 0x7ab: 0x08c7, 0x7ac: 0x09b3, 0x7ad: 0x0ffb, 0x7ae: 0x1263, 0x7af: 0x133b, - 0x7b0: 0x0db7, 0x7b1: 0x13f7, 0x7b2: 0x0de3, 0x7b3: 0x0c37, 0x7b4: 0x121b, 0x7b5: 0x0c57, - 0x7b6: 0x0fab, 0x7b7: 0x072b, 0x7b8: 0x07a7, 0x7b9: 0x07eb, 0x7ba: 0x0d53, 0x7bb: 0x10fb, - 0x7bc: 0x11f3, 0x7bd: 0x1347, 0x7be: 0x145b, 0x7bf: 0x085b, + 0x780: 0x1377, 0x781: 0x0cfb, 0x782: 0x13d3, 0x783: 0x139f, 0x784: 0x0e57, 0x785: 0x06eb, + 0x786: 0x08df, 0x787: 0x162b, 0x788: 0x162b, 0x789: 0x0a0b, 0x78a: 0x145f, 0x78b: 0x0943, + 0x78c: 0x0a07, 0x78d: 0x0bef, 0x78e: 0x0fcf, 0x78f: 0x115f, 0x790: 0x1297, 0x791: 0x12d3, + 0x792: 0x1307, 0x793: 0x141b, 0x794: 0x0d73, 0x795: 0x0dff, 0x796: 0x0eab, 0x797: 0x0f43, + 0x798: 0x125f, 0x799: 0x1447, 0x79a: 0x1573, 0x79b: 0x070f, 0x79c: 0x08b3, 0x79d: 0x0d87, + 0x79e: 0x0ecf, 0x79f: 0x1293, 0x7a0: 0x15c3, 0x7a1: 0x0ab3, 0x7a2: 0x0e77, 0x7a3: 0x1283, + 0x7a4: 0x1317, 0x7a5: 0x0c23, 0x7a6: 0x11bb, 0x7a7: 0x12df, 0x7a8: 0x0b1f, 0x7a9: 0x0d0f, + 0x7aa: 0x0e17, 0x7ab: 0x0f1b, 0x7ac: 0x1427, 0x7ad: 0x074f, 0x7ae: 0x07e7, 0x7af: 0x0853, + 0x7b0: 0x0c8b, 0x7b1: 0x0d7f, 0x7b2: 0x0ecb, 0x7b3: 0x0fef, 0x7b4: 0x1177, 0x7b5: 0x128b, + 0x7b6: 0x12a3, 0x7b7: 0x13c7, 0x7b8: 0x14ef, 0x7b9: 0x15a3, 0x7ba: 0x15bf, 0x7bb: 0x102b, + 0x7bc: 0x106b, 0x7bd: 0x1123, 0x7be: 0x1243, 0x7bf: 0x147b, // Block 0x1f, offset 0x7c0 - 0x7c0: 0x090f, 0x7c1: 0x0a17, 0x7c2: 0x0b2f, 0x7c3: 0x0cbf, 0x7c4: 0x0e7b, 0x7c5: 0x103f, - 0x7c6: 0x1497, 0x7c7: 0x157b, 0x7c8: 0x15cf, 0x7c9: 0x15e7, 0x7ca: 0x0837, 0x7cb: 0x0cf3, - 0x7cc: 0x0da3, 0x7cd: 0x13eb, 0x7ce: 0x0afb, 0x7cf: 0x0bd7, 0x7d0: 0x0bf3, 0x7d1: 0x0c83, - 0x7d2: 0x0e6b, 0x7d3: 0x0eb7, 0x7d4: 0x0f67, 0x7d5: 0x108b, 0x7d6: 0x112f, 0x7d7: 0x1193, - 0x7d8: 0x13db, 0x7d9: 0x126b, 0x7da: 0x1403, 0x7db: 0x147f, 0x7dc: 0x080f, 0x7dd: 0x083b, - 0x7de: 0x0923, 0x7df: 0x0ea7, 0x7e0: 0x12f3, 0x7e1: 0x133b, 0x7e2: 0x0b1b, 0x7e3: 0x0b8b, - 0x7e4: 0x0c4f, 0x7e5: 0x0daf, 0x7e6: 0x10d7, 0x7e7: 0x0f23, 0x7e8: 0x073b, 0x7e9: 0x097f, - 0x7ea: 0x0a63, 0x7eb: 0x0ac7, 0x7ec: 0x0b97, 0x7ed: 0x0f3f, 0x7ee: 0x0f5b, 0x7ef: 0x116b, - 0x7f0: 0x118b, 0x7f1: 0x1463, 0x7f2: 0x14e3, 0x7f3: 0x14f3, 0x7f4: 0x152f, 0x7f5: 0x0753, - 0x7f6: 0x107f, 0x7f7: 0x144f, 0x7f8: 0x14cb, 0x7f9: 0x0baf, 0x7fa: 0x0717, 0x7fb: 0x0777, - 0x7fc: 0x0a67, 0x7fd: 0x0a87, 0x7fe: 0x0caf, 0x7ff: 0x0d73, + 0x7c0: 0x15cb, 0x7c1: 0x134b, 0x7c2: 0x09c7, 0x7c3: 0x0b3b, 0x7c4: 0x10db, 0x7c5: 0x119b, + 0x7c6: 0x0eff, 0x7c7: 0x1033, 0x7c8: 0x1397, 0x7c9: 0x14e7, 0x7ca: 0x09c3, 0x7cb: 0x0a8f, + 0x7cc: 0x0d77, 0x7cd: 0x0e2b, 0x7ce: 0x0e5f, 0x7cf: 0x1113, 0x7d0: 0x113b, 0x7d1: 0x14a7, + 0x7d2: 0x084f, 0x7d3: 0x11a7, 0x7d4: 0x07f3, 0x7d5: 0x07ef, 0x7d6: 0x1097, 0x7d7: 0x1127, + 0x7d8: 0x125b, 0x7d9: 0x14af, 0x7da: 0x1367, 0x7db: 0x0c27, 0x7dc: 0x0d73, 0x7dd: 0x1357, + 0x7de: 0x06f7, 0x7df: 0x0a63, 0x7e0: 0x0b93, 0x7e1: 0x0f2f, 0x7e2: 0x0faf, 0x7e3: 0x0873, + 0x7e4: 0x103b, 0x7e5: 0x075f, 0x7e6: 0x0b77, 0x7e7: 0x06d7, 0x7e8: 0x0deb, 0x7e9: 0x0ca3, + 0x7ea: 0x110f, 0x7eb: 0x08c7, 0x7ec: 0x09b3, 0x7ed: 0x0ffb, 0x7ee: 0x1263, 0x7ef: 0x133b, + 0x7f0: 0x0db7, 0x7f1: 0x13f7, 0x7f2: 0x0de3, 0x7f3: 0x0c37, 0x7f4: 0x121b, 0x7f5: 0x0c57, + 0x7f6: 0x0fab, 0x7f7: 0x072b, 0x7f8: 0x07a7, 0x7f9: 0x07eb, 0x7fa: 0x0d53, 0x7fb: 0x10fb, + 0x7fc: 0x11f3, 0x7fd: 0x1347, 0x7fe: 0x145b, 0x7ff: 0x085b, // Block 0x20, offset 0x800 - 0x800: 0x0ec3, 0x801: 0x0fcb, 0x802: 0x1277, 0x803: 0x1417, 0x804: 0x1623, 0x805: 0x0ce3, - 0x806: 0x14a3, 0x807: 0x0833, 0x808: 0x0d2f, 0x809: 0x0d3b, 0x80a: 0x0e0f, 0x80b: 0x0e47, - 0x80c: 0x0f4b, 0x80d: 0x0fa7, 0x80e: 0x1027, 0x80f: 0x110b, 0x810: 0x153b, 0x811: 0x07af, - 0x812: 0x0c03, 0x813: 0x14b3, 0x814: 0x0767, 0x815: 0x0aab, 0x816: 0x0e2f, 0x817: 0x13df, - 0x818: 0x0b67, 0x819: 0x0bb7, 0x81a: 0x0d43, 0x81b: 0x0f2f, 0x81c: 0x14bb, 0x81d: 0x0817, - 0x81e: 0x08ff, 0x81f: 0x0a97, 0x820: 0x0cd3, 0x821: 0x0d1f, 0x822: 0x0d5f, 0x823: 0x0df3, - 0x824: 0x0f47, 0x825: 0x0fbb, 0x826: 0x1157, 0x827: 0x12f7, 0x828: 0x1303, 0x829: 0x1457, - 0x82a: 0x14d7, 0x82b: 0x0883, 0x82c: 0x0e4b, 0x82d: 0x0903, 0x82e: 0x0ec7, 0x82f: 0x0f6b, - 0x830: 0x1287, 0x831: 0x14bf, 0x832: 0x15ab, 0x833: 0x15d3, 0x834: 0x0d37, 0x835: 0x0e27, - 0x836: 0x11c3, 0x837: 0x10b7, 0x838: 0x10c3, 0x839: 0x10e7, 0x83a: 0x0f17, 0x83b: 0x0e9f, - 0x83c: 0x1363, 0x83d: 0x0733, 0x83e: 0x122b, 0x83f: 0x081b, + 0x800: 0x090f, 0x801: 0x0a17, 0x802: 0x0b2f, 0x803: 0x0cbf, 0x804: 0x0e7b, 0x805: 0x103f, + 0x806: 0x1497, 0x807: 0x157b, 0x808: 0x15cf, 0x809: 0x15e7, 0x80a: 0x0837, 0x80b: 0x0cf3, + 0x80c: 0x0da3, 0x80d: 0x13eb, 0x80e: 0x0afb, 0x80f: 0x0bd7, 0x810: 0x0bf3, 0x811: 0x0c83, + 0x812: 0x0e6b, 0x813: 0x0eb7, 0x814: 0x0f67, 0x815: 0x108b, 0x816: 0x112f, 0x817: 0x1193, + 0x818: 0x13db, 0x819: 0x126b, 0x81a: 0x1403, 0x81b: 0x147f, 0x81c: 0x080f, 0x81d: 0x083b, + 0x81e: 0x0923, 0x81f: 0x0ea7, 0x820: 0x12f3, 0x821: 0x133b, 0x822: 0x0b1b, 0x823: 0x0b8b, + 0x824: 0x0c4f, 0x825: 0x0daf, 0x826: 0x10d7, 0x827: 0x0f23, 0x828: 0x073b, 0x829: 0x097f, + 0x82a: 0x0a63, 0x82b: 0x0ac7, 0x82c: 0x0b97, 0x82d: 0x0f3f, 0x82e: 0x0f5b, 0x82f: 0x116b, + 0x830: 0x118b, 0x831: 0x1463, 0x832: 0x14e3, 0x833: 0x14f3, 0x834: 0x152f, 0x835: 0x0753, + 0x836: 0x107f, 0x837: 0x144f, 0x838: 0x14cb, 0x839: 0x0baf, 0x83a: 0x0717, 0x83b: 0x0777, + 0x83c: 0x0a67, 0x83d: 0x0a87, 0x83e: 0x0caf, 0x83f: 0x0d73, // Block 0x21, offset 0x840 - 0x840: 0x080b, 0x841: 0x0b0b, 0x842: 0x0c2b, 0x843: 0x10f3, 0x844: 0x0a53, 0x845: 0x0e03, - 0x846: 0x0cef, 0x847: 0x13e7, 0x848: 0x12e7, 0x849: 0x14ab, 0x84a: 0x1323, 0x84b: 0x0b27, - 0x84c: 0x0787, 0x84d: 0x095b, 0x850: 0x09af, - 0x852: 0x0cdf, 0x855: 0x07f7, 0x856: 0x0f1f, 0x857: 0x0fe3, - 0x858: 0x1047, 0x859: 0x1063, 0x85a: 0x1067, 0x85b: 0x107b, 0x85c: 0x14fb, 0x85d: 0x10eb, - 0x85e: 0x116f, 0x860: 0x128f, 0x862: 0x1353, - 0x865: 0x1407, 0x866: 0x1433, - 0x86a: 0x154f, 0x86b: 0x1553, 0x86c: 0x1557, 0x86d: 0x15bb, 0x86e: 0x142b, 0x86f: 0x14c7, - 0x870: 0x0757, 0x871: 0x077b, 0x872: 0x078f, 0x873: 0x084b, 0x874: 0x0857, 0x875: 0x0897, - 0x876: 0x094b, 0x877: 0x0967, 0x878: 0x096f, 0x879: 0x09ab, 0x87a: 0x09b7, 0x87b: 0x0a93, - 0x87c: 0x0a9b, 0x87d: 0x0ba3, 0x87e: 0x0bcb, 0x87f: 0x0bd3, + 0x840: 0x0ec3, 0x841: 0x0fcb, 0x842: 0x1277, 0x843: 0x1417, 0x844: 0x1623, 0x845: 0x0ce3, + 0x846: 0x14a3, 0x847: 0x0833, 0x848: 0x0d2f, 0x849: 0x0d3b, 0x84a: 0x0e0f, 0x84b: 0x0e47, + 0x84c: 0x0f4b, 0x84d: 0x0fa7, 0x84e: 0x1027, 0x84f: 0x110b, 0x850: 0x153b, 0x851: 0x07af, + 0x852: 0x0c03, 0x853: 0x14b3, 0x854: 0x0767, 0x855: 0x0aab, 0x856: 0x0e2f, 0x857: 0x13df, + 0x858: 0x0b67, 0x859: 0x0bb7, 0x85a: 0x0d43, 0x85b: 0x0f2f, 0x85c: 0x14bb, 0x85d: 0x0817, + 0x85e: 0x08ff, 0x85f: 0x0a97, 0x860: 0x0cd3, 0x861: 0x0d1f, 0x862: 0x0d5f, 0x863: 0x0df3, + 0x864: 0x0f47, 0x865: 0x0fbb, 0x866: 0x1157, 0x867: 0x12f7, 0x868: 0x1303, 0x869: 0x1457, + 0x86a: 0x14d7, 0x86b: 0x0883, 0x86c: 0x0e4b, 0x86d: 0x0903, 0x86e: 0x0ec7, 0x86f: 0x0f6b, + 0x870: 0x1287, 0x871: 0x14bf, 0x872: 0x15ab, 0x873: 0x15d3, 0x874: 0x0d37, 0x875: 0x0e27, + 0x876: 0x11c3, 0x877: 0x10b7, 0x878: 0x10c3, 0x879: 0x10e7, 0x87a: 0x0f17, 0x87b: 0x0e9f, + 0x87c: 0x1363, 0x87d: 0x0733, 0x87e: 0x122b, 0x87f: 0x081b, // Block 0x22, offset 0x880 - 0x880: 0x0beb, 0x881: 0x0c97, 0x882: 0x0cc7, 0x883: 0x0ce7, 0x884: 0x0d57, 0x885: 0x0e1b, - 0x886: 0x0e37, 0x887: 0x0e67, 0x888: 0x0ebb, 0x889: 0x0edb, 0x88a: 0x0f4f, 0x88b: 0x102f, - 0x88c: 0x104b, 0x88d: 0x1053, 0x88e: 0x104f, 0x88f: 0x1057, 0x890: 0x105b, 0x891: 0x105f, - 0x892: 0x1073, 0x893: 0x1077, 0x894: 0x109b, 0x895: 0x10af, 0x896: 0x10cb, 0x897: 0x112f, - 0x898: 0x1137, 0x899: 0x113f, 0x89a: 0x1153, 0x89b: 0x117b, 0x89c: 0x11cb, 0x89d: 0x11ff, - 0x89e: 0x11ff, 0x89f: 0x1267, 0x8a0: 0x130f, 0x8a1: 0x1327, 0x8a2: 0x135b, 0x8a3: 0x135f, - 0x8a4: 0x13a3, 0x8a5: 0x13a7, 0x8a6: 0x13ff, 0x8a7: 0x1407, 0x8a8: 0x14db, 0x8a9: 0x151f, - 0x8aa: 0x1537, 0x8ab: 0x0b9b, 0x8ac: 0x171e, 0x8ad: 0x11e3, - 0x8b0: 0x06df, 0x8b1: 0x07e3, 0x8b2: 0x07a3, 0x8b3: 0x074b, 0x8b4: 0x078b, 0x8b5: 0x07b7, - 0x8b6: 0x0847, 0x8b7: 0x0863, 0x8b8: 0x094b, 0x8b9: 0x0937, 0x8ba: 0x0947, 0x8bb: 0x0963, - 0x8bc: 0x09af, 0x8bd: 0x09bf, 0x8be: 0x0a03, 0x8bf: 0x0a0f, + 0x880: 0x080b, 0x881: 0x0b0b, 0x882: 0x0c2b, 0x883: 0x10f3, 0x884: 0x0a53, 0x885: 0x0e03, + 0x886: 0x0cef, 0x887: 0x13e7, 0x888: 0x12e7, 0x889: 0x14ab, 0x88a: 0x1323, 0x88b: 0x0b27, + 0x88c: 0x0787, 0x88d: 0x095b, 0x890: 0x09af, + 0x892: 0x0cdf, 0x895: 0x07f7, 0x896: 0x0f1f, 0x897: 0x0fe3, + 0x898: 0x1047, 0x899: 0x1063, 0x89a: 0x1067, 0x89b: 0x107b, 0x89c: 0x14fb, 0x89d: 0x10eb, + 0x89e: 0x116f, 0x8a0: 0x128f, 0x8a2: 0x1353, + 0x8a5: 0x1407, 0x8a6: 0x1433, + 0x8aa: 0x154f, 0x8ab: 0x1553, 0x8ac: 0x1557, 0x8ad: 0x15bb, 0x8ae: 0x142b, 0x8af: 0x14c7, + 0x8b0: 0x0757, 0x8b1: 0x077b, 0x8b2: 0x078f, 0x8b3: 0x084b, 0x8b4: 0x0857, 0x8b5: 0x0897, + 0x8b6: 0x094b, 0x8b7: 0x0967, 0x8b8: 0x096f, 0x8b9: 0x09ab, 0x8ba: 0x09b7, 0x8bb: 0x0a93, + 0x8bc: 0x0a9b, 0x8bd: 0x0ba3, 0x8be: 0x0bcb, 0x8bf: 0x0bd3, // Block 0x23, offset 0x8c0 - 0x8c0: 0x0a2b, 0x8c1: 0x0a3b, 0x8c2: 0x0b23, 0x8c3: 0x0b2b, 0x8c4: 0x0b5b, 0x8c5: 0x0b7b, - 0x8c6: 0x0bab, 0x8c7: 0x0bc3, 0x8c8: 0x0bb3, 0x8c9: 0x0bd3, 0x8ca: 0x0bc7, 0x8cb: 0x0beb, - 0x8cc: 0x0c07, 0x8cd: 0x0c5f, 0x8ce: 0x0c6b, 0x8cf: 0x0c73, 0x8d0: 0x0c9b, 0x8d1: 0x0cdf, - 0x8d2: 0x0d0f, 0x8d3: 0x0d13, 0x8d4: 0x0d27, 0x8d5: 0x0da7, 0x8d6: 0x0db7, 0x8d7: 0x0e0f, - 0x8d8: 0x0e5b, 0x8d9: 0x0e53, 0x8da: 0x0e67, 0x8db: 0x0e83, 0x8dc: 0x0ebb, 0x8dd: 0x1013, - 0x8de: 0x0edf, 0x8df: 0x0f13, 0x8e0: 0x0f1f, 0x8e1: 0x0f5f, 0x8e2: 0x0f7b, 0x8e3: 0x0f9f, - 0x8e4: 0x0fc3, 0x8e5: 0x0fc7, 0x8e6: 0x0fe3, 0x8e7: 0x0fe7, 0x8e8: 0x0ff7, 0x8e9: 0x100b, - 0x8ea: 0x1007, 0x8eb: 0x1037, 0x8ec: 0x10b3, 0x8ed: 0x10cb, 0x8ee: 0x10e3, 0x8ef: 0x111b, - 0x8f0: 0x112f, 0x8f1: 0x114b, 0x8f2: 0x117b, 0x8f3: 0x122f, 0x8f4: 0x1257, 0x8f5: 0x12cb, - 0x8f6: 0x1313, 0x8f7: 0x131f, 0x8f8: 0x1327, 0x8f9: 0x133f, 0x8fa: 0x1353, 0x8fb: 0x1343, - 0x8fc: 0x135b, 0x8fd: 0x1357, 0x8fe: 0x134f, 0x8ff: 0x135f, + 0x8c0: 0x0beb, 0x8c1: 0x0c97, 0x8c2: 0x0cc7, 0x8c3: 0x0ce7, 0x8c4: 0x0d57, 0x8c5: 0x0e1b, + 0x8c6: 0x0e37, 0x8c7: 0x0e67, 0x8c8: 0x0ebb, 0x8c9: 0x0edb, 0x8ca: 0x0f4f, 0x8cb: 0x102f, + 0x8cc: 0x104b, 0x8cd: 0x1053, 0x8ce: 0x104f, 0x8cf: 0x1057, 0x8d0: 0x105b, 0x8d1: 0x105f, + 0x8d2: 0x1073, 0x8d3: 0x1077, 0x8d4: 0x109b, 0x8d5: 0x10af, 0x8d6: 0x10cb, 0x8d7: 0x112f, + 0x8d8: 0x1137, 0x8d9: 0x113f, 0x8da: 0x1153, 0x8db: 0x117b, 0x8dc: 0x11cb, 0x8dd: 0x11ff, + 0x8de: 0x11ff, 0x8df: 0x1267, 0x8e0: 0x130f, 0x8e1: 0x1327, 0x8e2: 0x135b, 0x8e3: 0x135f, + 0x8e4: 0x13a3, 0x8e5: 0x13a7, 0x8e6: 0x13ff, 0x8e7: 0x1407, 0x8e8: 0x14db, 0x8e9: 0x151f, + 0x8ea: 0x1537, 0x8eb: 0x0b9b, 0x8ec: 0x171e, 0x8ed: 0x11e3, + 0x8f0: 0x06df, 0x8f1: 0x07e3, 0x8f2: 0x07a3, 0x8f3: 0x074b, 0x8f4: 0x078b, 0x8f5: 0x07b7, + 0x8f6: 0x0847, 0x8f7: 0x0863, 0x8f8: 0x094b, 0x8f9: 0x0937, 0x8fa: 0x0947, 0x8fb: 0x0963, + 0x8fc: 0x09af, 0x8fd: 0x09bf, 0x8fe: 0x0a03, 0x8ff: 0x0a0f, // Block 0x24, offset 0x900 - 0x900: 0x136b, 0x901: 0x13a7, 0x902: 0x13e3, 0x903: 0x1413, 0x904: 0x144b, 0x905: 0x146b, - 0x906: 0x14b7, 0x907: 0x14db, 0x908: 0x14fb, 0x909: 0x150f, 0x90a: 0x151f, 0x90b: 0x152b, - 0x90c: 0x1537, 0x90d: 0x158b, 0x90e: 0x162b, 0x90f: 0x16b5, 0x910: 0x16b0, 0x911: 0x16e2, - 0x912: 0x0607, 0x913: 0x062f, 0x914: 0x0633, 0x915: 0x1764, 0x916: 0x1791, 0x917: 0x1809, - 0x918: 0x1617, 0x919: 0x1627, + 0x900: 0x0a2b, 0x901: 0x0a3b, 0x902: 0x0b23, 0x903: 0x0b2b, 0x904: 0x0b5b, 0x905: 0x0b7b, + 0x906: 0x0bab, 0x907: 0x0bc3, 0x908: 0x0bb3, 0x909: 0x0bd3, 0x90a: 0x0bc7, 0x90b: 0x0beb, + 0x90c: 0x0c07, 0x90d: 0x0c5f, 0x90e: 0x0c6b, 0x90f: 0x0c73, 0x910: 0x0c9b, 0x911: 0x0cdf, + 0x912: 0x0d0f, 0x913: 0x0d13, 0x914: 0x0d27, 0x915: 0x0da7, 0x916: 0x0db7, 0x917: 0x0e0f, + 0x918: 0x0e5b, 0x919: 0x0e53, 0x91a: 0x0e67, 0x91b: 0x0e83, 0x91c: 0x0ebb, 0x91d: 0x1013, + 0x91e: 0x0edf, 0x91f: 0x0f13, 0x920: 0x0f1f, 0x921: 0x0f5f, 0x922: 0x0f7b, 0x923: 0x0f9f, + 0x924: 0x0fc3, 0x925: 0x0fc7, 0x926: 0x0fe3, 0x927: 0x0fe7, 0x928: 0x0ff7, 0x929: 0x100b, + 0x92a: 0x1007, 0x92b: 0x1037, 0x92c: 0x10b3, 0x92d: 0x10cb, 0x92e: 0x10e3, 0x92f: 0x111b, + 0x930: 0x112f, 0x931: 0x114b, 0x932: 0x117b, 0x933: 0x122f, 0x934: 0x1257, 0x935: 0x12cb, + 0x936: 0x1313, 0x937: 0x131f, 0x938: 0x1327, 0x939: 0x133f, 0x93a: 0x1353, 0x93b: 0x1343, + 0x93c: 0x135b, 0x93d: 0x1357, 0x93e: 0x134f, 0x93f: 0x135f, // Block 0x25, offset 0x940 - 0x940: 0x06fb, 0x941: 0x06f3, 0x942: 0x0703, 0x943: 0x1647, 0x944: 0x0747, 0x945: 0x0757, - 0x946: 0x075b, 0x947: 0x0763, 0x948: 0x076b, 0x949: 0x076f, 0x94a: 0x077b, 0x94b: 0x0773, - 0x94c: 0x05b3, 0x94d: 0x165b, 0x94e: 0x078f, 0x94f: 0x0793, 0x950: 0x0797, 0x951: 0x07b3, - 0x952: 0x164c, 0x953: 0x05b7, 0x954: 0x079f, 0x955: 0x07bf, 0x956: 0x1656, 0x957: 0x07cf, - 0x958: 0x07d7, 0x959: 0x0737, 0x95a: 0x07df, 0x95b: 0x07e3, 0x95c: 0x1831, 0x95d: 0x07ff, - 0x95e: 0x0807, 0x95f: 0x05bf, 0x960: 0x081f, 0x961: 0x0823, 0x962: 0x082b, 0x963: 0x082f, - 0x964: 0x05c3, 0x965: 0x0847, 0x966: 0x084b, 0x967: 0x0857, 0x968: 0x0863, 0x969: 0x0867, - 0x96a: 0x086b, 0x96b: 0x0873, 0x96c: 0x0893, 0x96d: 0x0897, 0x96e: 0x089f, 0x96f: 0x08af, - 0x970: 0x08b7, 0x971: 0x08bb, 0x972: 0x08bb, 0x973: 0x08bb, 0x974: 0x166a, 0x975: 0x0e93, - 0x976: 0x08cf, 0x977: 0x08d7, 0x978: 0x166f, 0x979: 0x08e3, 0x97a: 0x08eb, 0x97b: 0x08f3, - 0x97c: 0x091b, 0x97d: 0x0907, 0x97e: 0x0913, 0x97f: 0x0917, + 0x940: 0x136b, 0x941: 0x13a7, 0x942: 0x13e3, 0x943: 0x1413, 0x944: 0x144b, 0x945: 0x146b, + 0x946: 0x14b7, 0x947: 0x14db, 0x948: 0x14fb, 0x949: 0x150f, 0x94a: 0x151f, 0x94b: 0x152b, + 0x94c: 0x1537, 0x94d: 0x158b, 0x94e: 0x162b, 0x94f: 0x16b5, 0x950: 0x16b0, 0x951: 0x16e2, + 0x952: 0x0607, 0x953: 0x062f, 0x954: 0x0633, 0x955: 0x1764, 0x956: 0x1791, 0x957: 0x1809, + 0x958: 0x1617, 0x959: 0x1627, // Block 0x26, offset 0x980 - 0x980: 0x091f, 0x981: 0x0927, 0x982: 0x092b, 0x983: 0x0933, 0x984: 0x093b, 0x985: 0x093f, - 0x986: 0x093f, 0x987: 0x0947, 0x988: 0x094f, 0x989: 0x0953, 0x98a: 0x095f, 0x98b: 0x0983, - 0x98c: 0x0967, 0x98d: 0x0987, 0x98e: 0x096b, 0x98f: 0x0973, 0x990: 0x080b, 0x991: 0x09cf, - 0x992: 0x0997, 0x993: 0x099b, 0x994: 0x099f, 0x995: 0x0993, 0x996: 0x09a7, 0x997: 0x09a3, - 0x998: 0x09bb, 0x999: 0x1674, 0x99a: 0x09d7, 0x99b: 0x09db, 0x99c: 0x09e3, 0x99d: 0x09ef, - 0x99e: 0x09f7, 0x99f: 0x0a13, 0x9a0: 0x1679, 0x9a1: 0x167e, 0x9a2: 0x0a1f, 0x9a3: 0x0a23, - 0x9a4: 0x0a27, 0x9a5: 0x0a1b, 0x9a6: 0x0a2f, 0x9a7: 0x05c7, 0x9a8: 0x05cb, 0x9a9: 0x0a37, - 0x9aa: 0x0a3f, 0x9ab: 0x0a3f, 0x9ac: 0x1683, 0x9ad: 0x0a5b, 0x9ae: 0x0a5f, 0x9af: 0x0a63, - 0x9b0: 0x0a6b, 0x9b1: 0x1688, 0x9b2: 0x0a73, 0x9b3: 0x0a77, 0x9b4: 0x0b4f, 0x9b5: 0x0a7f, - 0x9b6: 0x05cf, 0x9b7: 0x0a8b, 0x9b8: 0x0a9b, 0x9b9: 0x0aa7, 0x9ba: 0x0aa3, 0x9bb: 0x1692, - 0x9bc: 0x0aaf, 0x9bd: 0x1697, 0x9be: 0x0abb, 0x9bf: 0x0ab7, + 0x980: 0x06fb, 0x981: 0x06f3, 0x982: 0x0703, 0x983: 0x1647, 0x984: 0x0747, 0x985: 0x0757, + 0x986: 0x075b, 0x987: 0x0763, 0x988: 0x076b, 0x989: 0x076f, 0x98a: 0x077b, 0x98b: 0x0773, + 0x98c: 0x05b3, 0x98d: 0x165b, 0x98e: 0x078f, 0x98f: 0x0793, 0x990: 0x0797, 0x991: 0x07b3, + 0x992: 0x164c, 0x993: 0x05b7, 0x994: 0x079f, 0x995: 0x07bf, 0x996: 0x1656, 0x997: 0x07cf, + 0x998: 0x07d7, 0x999: 0x0737, 0x99a: 0x07df, 0x99b: 0x07e3, 0x99c: 0x1831, 0x99d: 0x07ff, + 0x99e: 0x0807, 0x99f: 0x05bf, 0x9a0: 0x081f, 0x9a1: 0x0823, 0x9a2: 0x082b, 0x9a3: 0x082f, + 0x9a4: 0x05c3, 0x9a5: 0x0847, 0x9a6: 0x084b, 0x9a7: 0x0857, 0x9a8: 0x0863, 0x9a9: 0x0867, + 0x9aa: 0x086b, 0x9ab: 0x0873, 0x9ac: 0x0893, 0x9ad: 0x0897, 0x9ae: 0x089f, 0x9af: 0x08af, + 0x9b0: 0x08b7, 0x9b1: 0x08bb, 0x9b2: 0x08bb, 0x9b3: 0x08bb, 0x9b4: 0x166a, 0x9b5: 0x0e93, + 0x9b6: 0x08cf, 0x9b7: 0x08d7, 0x9b8: 0x166f, 0x9b9: 0x08e3, 0x9ba: 0x08eb, 0x9bb: 0x08f3, + 0x9bc: 0x091b, 0x9bd: 0x0907, 0x9be: 0x0913, 0x9bf: 0x0917, // Block 0x27, offset 0x9c0 - 0x9c0: 0x0abf, 0x9c1: 0x0acf, 0x9c2: 0x0ad3, 0x9c3: 0x05d3, 0x9c4: 0x0ae3, 0x9c5: 0x0aeb, - 0x9c6: 0x0aef, 0x9c7: 0x0af3, 0x9c8: 0x05d7, 0x9c9: 0x169c, 0x9ca: 0x05db, 0x9cb: 0x0b0f, - 0x9cc: 0x0b13, 0x9cd: 0x0b17, 0x9ce: 0x0b1f, 0x9cf: 0x1863, 0x9d0: 0x0b37, 0x9d1: 0x16a6, - 0x9d2: 0x16a6, 0x9d3: 0x11d7, 0x9d4: 0x0b47, 0x9d5: 0x0b47, 0x9d6: 0x05df, 0x9d7: 0x16c9, - 0x9d8: 0x179b, 0x9d9: 0x0b57, 0x9da: 0x0b5f, 0x9db: 0x05e3, 0x9dc: 0x0b73, 0x9dd: 0x0b83, - 0x9de: 0x0b87, 0x9df: 0x0b8f, 0x9e0: 0x0b9f, 0x9e1: 0x05eb, 0x9e2: 0x05e7, 0x9e3: 0x0ba3, - 0x9e4: 0x16ab, 0x9e5: 0x0ba7, 0x9e6: 0x0bbb, 0x9e7: 0x0bbf, 0x9e8: 0x0bc3, 0x9e9: 0x0bbf, - 0x9ea: 0x0bcf, 0x9eb: 0x0bd3, 0x9ec: 0x0be3, 0x9ed: 0x0bdb, 0x9ee: 0x0bdf, 0x9ef: 0x0be7, - 0x9f0: 0x0beb, 0x9f1: 0x0bef, 0x9f2: 0x0bfb, 0x9f3: 0x0bff, 0x9f4: 0x0c17, 0x9f5: 0x0c1f, - 0x9f6: 0x0c2f, 0x9f7: 0x0c43, 0x9f8: 0x16ba, 0x9f9: 0x0c3f, 0x9fa: 0x0c33, 0x9fb: 0x0c4b, - 0x9fc: 0x0c53, 0x9fd: 0x0c67, 0x9fe: 0x16bf, 0x9ff: 0x0c6f, + 0x9c0: 0x091f, 0x9c1: 0x0927, 0x9c2: 0x092b, 0x9c3: 0x0933, 0x9c4: 0x093b, 0x9c5: 0x093f, + 0x9c6: 0x093f, 0x9c7: 0x0947, 0x9c8: 0x094f, 0x9c9: 0x0953, 0x9ca: 0x095f, 0x9cb: 0x0983, + 0x9cc: 0x0967, 0x9cd: 0x0987, 0x9ce: 0x096b, 0x9cf: 0x0973, 0x9d0: 0x080b, 0x9d1: 0x09cf, + 0x9d2: 0x0997, 0x9d3: 0x099b, 0x9d4: 0x099f, 0x9d5: 0x0993, 0x9d6: 0x09a7, 0x9d7: 0x09a3, + 0x9d8: 0x09bb, 0x9d9: 0x1674, 0x9da: 0x09d7, 0x9db: 0x09db, 0x9dc: 0x09e3, 0x9dd: 0x09ef, + 0x9de: 0x09f7, 0x9df: 0x0a13, 0x9e0: 0x1679, 0x9e1: 0x167e, 0x9e2: 0x0a1f, 0x9e3: 0x0a23, + 0x9e4: 0x0a27, 0x9e5: 0x0a1b, 0x9e6: 0x0a2f, 0x9e7: 0x05c7, 0x9e8: 0x05cb, 0x9e9: 0x0a37, + 0x9ea: 0x0a3f, 0x9eb: 0x0a3f, 0x9ec: 0x1683, 0x9ed: 0x0a5b, 0x9ee: 0x0a5f, 0x9ef: 0x0a63, + 0x9f0: 0x0a6b, 0x9f1: 0x1688, 0x9f2: 0x0a73, 0x9f3: 0x0a77, 0x9f4: 0x0b4f, 0x9f5: 0x0a7f, + 0x9f6: 0x05cf, 0x9f7: 0x0a8b, 0x9f8: 0x0a9b, 0x9f9: 0x0aa7, 0x9fa: 0x0aa3, 0x9fb: 0x1692, + 0x9fc: 0x0aaf, 0x9fd: 0x1697, 0x9fe: 0x0abb, 0x9ff: 0x0ab7, // Block 0x28, offset 0xa00 - 0xa00: 0x0c63, 0xa01: 0x0c5b, 0xa02: 0x05ef, 0xa03: 0x0c77, 0xa04: 0x0c7f, 0xa05: 0x0c87, - 0xa06: 0x0c7b, 0xa07: 0x05f3, 0xa08: 0x0c97, 0xa09: 0x0c9f, 0xa0a: 0x16c4, 0xa0b: 0x0ccb, - 0xa0c: 0x0cff, 0xa0d: 0x0cdb, 0xa0e: 0x05ff, 0xa0f: 0x0ce7, 0xa10: 0x05fb, 0xa11: 0x05f7, - 0xa12: 0x07c3, 0xa13: 0x07c7, 0xa14: 0x0d03, 0xa15: 0x0ceb, 0xa16: 0x11ab, 0xa17: 0x0663, - 0xa18: 0x0d0f, 0xa19: 0x0d13, 0xa1a: 0x0d17, 0xa1b: 0x0d2b, 0xa1c: 0x0d23, 0xa1d: 0x16dd, - 0xa1e: 0x0603, 0xa1f: 0x0d3f, 0xa20: 0x0d33, 0xa21: 0x0d4f, 0xa22: 0x0d57, 0xa23: 0x16e7, - 0xa24: 0x0d5b, 0xa25: 0x0d47, 0xa26: 0x0d63, 0xa27: 0x0607, 0xa28: 0x0d67, 0xa29: 0x0d6b, - 0xa2a: 0x0d6f, 0xa2b: 0x0d7b, 0xa2c: 0x16ec, 0xa2d: 0x0d83, 0xa2e: 0x060b, 0xa2f: 0x0d8f, - 0xa30: 0x16f1, 0xa31: 0x0d93, 0xa32: 0x060f, 0xa33: 0x0d9f, 0xa34: 0x0dab, 0xa35: 0x0db7, - 0xa36: 0x0dbb, 0xa37: 0x16f6, 0xa38: 0x168d, 0xa39: 0x16fb, 0xa3a: 0x0ddb, 0xa3b: 0x1700, - 0xa3c: 0x0de7, 0xa3d: 0x0def, 0xa3e: 0x0ddf, 0xa3f: 0x0dfb, + 0xa00: 0x0abf, 0xa01: 0x0acf, 0xa02: 0x0ad3, 0xa03: 0x05d3, 0xa04: 0x0ae3, 0xa05: 0x0aeb, + 0xa06: 0x0aef, 0xa07: 0x0af3, 0xa08: 0x05d7, 0xa09: 0x169c, 0xa0a: 0x05db, 0xa0b: 0x0b0f, + 0xa0c: 0x0b13, 0xa0d: 0x0b17, 0xa0e: 0x0b1f, 0xa0f: 0x1863, 0xa10: 0x0b37, 0xa11: 0x16a6, + 0xa12: 0x16a6, 0xa13: 0x11d7, 0xa14: 0x0b47, 0xa15: 0x0b47, 0xa16: 0x05df, 0xa17: 0x16c9, + 0xa18: 0x179b, 0xa19: 0x0b57, 0xa1a: 0x0b5f, 0xa1b: 0x05e3, 0xa1c: 0x0b73, 0xa1d: 0x0b83, + 0xa1e: 0x0b87, 0xa1f: 0x0b8f, 0xa20: 0x0b9f, 0xa21: 0x05eb, 0xa22: 0x05e7, 0xa23: 0x0ba3, + 0xa24: 0x16ab, 0xa25: 0x0ba7, 0xa26: 0x0bbb, 0xa27: 0x0bbf, 0xa28: 0x0bc3, 0xa29: 0x0bbf, + 0xa2a: 0x0bcf, 0xa2b: 0x0bd3, 0xa2c: 0x0be3, 0xa2d: 0x0bdb, 0xa2e: 0x0bdf, 0xa2f: 0x0be7, + 0xa30: 0x0beb, 0xa31: 0x0bef, 0xa32: 0x0bfb, 0xa33: 0x0bff, 0xa34: 0x0c17, 0xa35: 0x0c1f, + 0xa36: 0x0c2f, 0xa37: 0x0c43, 0xa38: 0x16ba, 0xa39: 0x0c3f, 0xa3a: 0x0c33, 0xa3b: 0x0c4b, + 0xa3c: 0x0c53, 0xa3d: 0x0c67, 0xa3e: 0x16bf, 0xa3f: 0x0c6f, // Block 0x29, offset 0xa40 - 0xa40: 0x0e0b, 0xa41: 0x0e1b, 0xa42: 0x0e0f, 0xa43: 0x0e13, 0xa44: 0x0e1f, 0xa45: 0x0e23, - 0xa46: 0x1705, 0xa47: 0x0e07, 0xa48: 0x0e3b, 0xa49: 0x0e3f, 0xa4a: 0x0613, 0xa4b: 0x0e53, - 0xa4c: 0x0e4f, 0xa4d: 0x170a, 0xa4e: 0x0e33, 0xa4f: 0x0e6f, 0xa50: 0x170f, 0xa51: 0x1714, - 0xa52: 0x0e73, 0xa53: 0x0e87, 0xa54: 0x0e83, 0xa55: 0x0e7f, 0xa56: 0x0617, 0xa57: 0x0e8b, - 0xa58: 0x0e9b, 0xa59: 0x0e97, 0xa5a: 0x0ea3, 0xa5b: 0x1651, 0xa5c: 0x0eb3, 0xa5d: 0x1719, - 0xa5e: 0x0ebf, 0xa5f: 0x1723, 0xa60: 0x0ed3, 0xa61: 0x0edf, 0xa62: 0x0ef3, 0xa63: 0x1728, - 0xa64: 0x0f07, 0xa65: 0x0f0b, 0xa66: 0x172d, 0xa67: 0x1732, 0xa68: 0x0f27, 0xa69: 0x0f37, - 0xa6a: 0x061b, 0xa6b: 0x0f3b, 0xa6c: 0x061f, 0xa6d: 0x061f, 0xa6e: 0x0f53, 0xa6f: 0x0f57, - 0xa70: 0x0f5f, 0xa71: 0x0f63, 0xa72: 0x0f6f, 0xa73: 0x0623, 0xa74: 0x0f87, 0xa75: 0x1737, - 0xa76: 0x0fa3, 0xa77: 0x173c, 0xa78: 0x0faf, 0xa79: 0x16a1, 0xa7a: 0x0fbf, 0xa7b: 0x1741, - 0xa7c: 0x1746, 0xa7d: 0x174b, 0xa7e: 0x0627, 0xa7f: 0x062b, + 0xa40: 0x0c63, 0xa41: 0x0c5b, 0xa42: 0x05ef, 0xa43: 0x0c77, 0xa44: 0x0c7f, 0xa45: 0x0c87, + 0xa46: 0x0c7b, 0xa47: 0x05f3, 0xa48: 0x0c97, 0xa49: 0x0c9f, 0xa4a: 0x16c4, 0xa4b: 0x0ccb, + 0xa4c: 0x0cff, 0xa4d: 0x0cdb, 0xa4e: 0x05ff, 0xa4f: 0x0ce7, 0xa50: 0x05fb, 0xa51: 0x05f7, + 0xa52: 0x07c3, 0xa53: 0x07c7, 0xa54: 0x0d03, 0xa55: 0x0ceb, 0xa56: 0x11ab, 0xa57: 0x0663, + 0xa58: 0x0d0f, 0xa59: 0x0d13, 0xa5a: 0x0d17, 0xa5b: 0x0d2b, 0xa5c: 0x0d23, 0xa5d: 0x16dd, + 0xa5e: 0x0603, 0xa5f: 0x0d3f, 0xa60: 0x0d33, 0xa61: 0x0d4f, 0xa62: 0x0d57, 0xa63: 0x16e7, + 0xa64: 0x0d5b, 0xa65: 0x0d47, 0xa66: 0x0d63, 0xa67: 0x0607, 0xa68: 0x0d67, 0xa69: 0x0d6b, + 0xa6a: 0x0d6f, 0xa6b: 0x0d7b, 0xa6c: 0x16ec, 0xa6d: 0x0d83, 0xa6e: 0x060b, 0xa6f: 0x0d8f, + 0xa70: 0x16f1, 0xa71: 0x0d93, 0xa72: 0x060f, 0xa73: 0x0d9f, 0xa74: 0x0dab, 0xa75: 0x0db7, + 0xa76: 0x0dbb, 0xa77: 0x16f6, 0xa78: 0x168d, 0xa79: 0x16fb, 0xa7a: 0x0ddb, 0xa7b: 0x1700, + 0xa7c: 0x0de7, 0xa7d: 0x0def, 0xa7e: 0x0ddf, 0xa7f: 0x0dfb, // Block 0x2a, offset 0xa80 - 0xa80: 0x0ff7, 0xa81: 0x1755, 0xa82: 0x1750, 0xa83: 0x175a, 0xa84: 0x175f, 0xa85: 0x0fff, - 0xa86: 0x1003, 0xa87: 0x1003, 0xa88: 0x100b, 0xa89: 0x0633, 0xa8a: 0x100f, 0xa8b: 0x0637, - 0xa8c: 0x063b, 0xa8d: 0x1769, 0xa8e: 0x1023, 0xa8f: 0x102b, 0xa90: 0x1037, 0xa91: 0x063f, - 0xa92: 0x176e, 0xa93: 0x105b, 0xa94: 0x1773, 0xa95: 0x1778, 0xa96: 0x107b, 0xa97: 0x1093, - 0xa98: 0x0643, 0xa99: 0x109b, 0xa9a: 0x109f, 0xa9b: 0x10a3, 0xa9c: 0x177d, 0xa9d: 0x1782, - 0xa9e: 0x1782, 0xa9f: 0x10bb, 0xaa0: 0x0647, 0xaa1: 0x1787, 0xaa2: 0x10cf, 0xaa3: 0x10d3, - 0xaa4: 0x064b, 0xaa5: 0x178c, 0xaa6: 0x10ef, 0xaa7: 0x064f, 0xaa8: 0x10ff, 0xaa9: 0x10f7, - 0xaaa: 0x1107, 0xaab: 0x1796, 0xaac: 0x111f, 0xaad: 0x0653, 0xaae: 0x112b, 0xaaf: 0x1133, - 0xab0: 0x1143, 0xab1: 0x0657, 0xab2: 0x17a0, 0xab3: 0x17a5, 0xab4: 0x065b, 0xab5: 0x17aa, - 0xab6: 0x115b, 0xab7: 0x17af, 0xab8: 0x1167, 0xab9: 0x1173, 0xaba: 0x117b, 0xabb: 0x17b4, - 0xabc: 0x17b9, 0xabd: 0x118f, 0xabe: 0x17be, 0xabf: 0x1197, + 0xa80: 0x0e0b, 0xa81: 0x0e1b, 0xa82: 0x0e0f, 0xa83: 0x0e13, 0xa84: 0x0e1f, 0xa85: 0x0e23, + 0xa86: 0x1705, 0xa87: 0x0e07, 0xa88: 0x0e3b, 0xa89: 0x0e3f, 0xa8a: 0x0613, 0xa8b: 0x0e53, + 0xa8c: 0x0e4f, 0xa8d: 0x170a, 0xa8e: 0x0e33, 0xa8f: 0x0e6f, 0xa90: 0x170f, 0xa91: 0x1714, + 0xa92: 0x0e73, 0xa93: 0x0e87, 0xa94: 0x0e83, 0xa95: 0x0e7f, 0xa96: 0x0617, 0xa97: 0x0e8b, + 0xa98: 0x0e9b, 0xa99: 0x0e97, 0xa9a: 0x0ea3, 0xa9b: 0x1651, 0xa9c: 0x0eb3, 0xa9d: 0x1719, + 0xa9e: 0x0ebf, 0xa9f: 0x1723, 0xaa0: 0x0ed3, 0xaa1: 0x0edf, 0xaa2: 0x0ef3, 0xaa3: 0x1728, + 0xaa4: 0x0f07, 0xaa5: 0x0f0b, 0xaa6: 0x172d, 0xaa7: 0x1732, 0xaa8: 0x0f27, 0xaa9: 0x0f37, + 0xaaa: 0x061b, 0xaab: 0x0f3b, 0xaac: 0x061f, 0xaad: 0x061f, 0xaae: 0x0f53, 0xaaf: 0x0f57, + 0xab0: 0x0f5f, 0xab1: 0x0f63, 0xab2: 0x0f6f, 0xab3: 0x0623, 0xab4: 0x0f87, 0xab5: 0x1737, + 0xab6: 0x0fa3, 0xab7: 0x173c, 0xab8: 0x0faf, 0xab9: 0x16a1, 0xaba: 0x0fbf, 0xabb: 0x1741, + 0xabc: 0x1746, 0xabd: 0x174b, 0xabe: 0x0627, 0xabf: 0x062b, // Block 0x2b, offset 0xac0 - 0xac0: 0x16ce, 0xac1: 0x065f, 0xac2: 0x11af, 0xac3: 0x11b3, 0xac4: 0x0667, 0xac5: 0x11b7, - 0xac6: 0x0a33, 0xac7: 0x17c3, 0xac8: 0x17c8, 0xac9: 0x16d3, 0xaca: 0x16d8, 0xacb: 0x11d7, - 0xacc: 0x11db, 0xacd: 0x13f3, 0xace: 0x066b, 0xacf: 0x1207, 0xad0: 0x1203, 0xad1: 0x120b, - 0xad2: 0x083f, 0xad3: 0x120f, 0xad4: 0x1213, 0xad5: 0x1217, 0xad6: 0x121f, 0xad7: 0x17cd, - 0xad8: 0x121b, 0xad9: 0x1223, 0xada: 0x1237, 0xadb: 0x123b, 0xadc: 0x1227, 0xadd: 0x123f, - 0xade: 0x1253, 0xadf: 0x1267, 0xae0: 0x1233, 0xae1: 0x1247, 0xae2: 0x124b, 0xae3: 0x124f, - 0xae4: 0x17d2, 0xae5: 0x17dc, 0xae6: 0x17d7, 0xae7: 0x066f, 0xae8: 0x126f, 0xae9: 0x1273, - 0xaea: 0x127b, 0xaeb: 0x17f0, 0xaec: 0x127f, 0xaed: 0x17e1, 0xaee: 0x0673, 0xaef: 0x0677, - 0xaf0: 0x17e6, 0xaf1: 0x17eb, 0xaf2: 0x067b, 0xaf3: 0x129f, 0xaf4: 0x12a3, 0xaf5: 0x12a7, - 0xaf6: 0x12ab, 0xaf7: 0x12b7, 0xaf8: 0x12b3, 0xaf9: 0x12bf, 0xafa: 0x12bb, 0xafb: 0x12cb, - 0xafc: 0x12c3, 0xafd: 0x12c7, 0xafe: 0x12cf, 0xaff: 0x067f, + 0xac0: 0x0ff7, 0xac1: 0x1755, 0xac2: 0x1750, 0xac3: 0x175a, 0xac4: 0x175f, 0xac5: 0x0fff, + 0xac6: 0x1003, 0xac7: 0x1003, 0xac8: 0x100b, 0xac9: 0x0633, 0xaca: 0x100f, 0xacb: 0x0637, + 0xacc: 0x063b, 0xacd: 0x1769, 0xace: 0x1023, 0xacf: 0x102b, 0xad0: 0x1037, 0xad1: 0x063f, + 0xad2: 0x176e, 0xad3: 0x105b, 0xad4: 0x1773, 0xad5: 0x1778, 0xad6: 0x107b, 0xad7: 0x1093, + 0xad8: 0x0643, 0xad9: 0x109b, 0xada: 0x109f, 0xadb: 0x10a3, 0xadc: 0x177d, 0xadd: 0x1782, + 0xade: 0x1782, 0xadf: 0x10bb, 0xae0: 0x0647, 0xae1: 0x1787, 0xae2: 0x10cf, 0xae3: 0x10d3, + 0xae4: 0x064b, 0xae5: 0x178c, 0xae6: 0x10ef, 0xae7: 0x064f, 0xae8: 0x10ff, 0xae9: 0x10f7, + 0xaea: 0x1107, 0xaeb: 0x1796, 0xaec: 0x111f, 0xaed: 0x0653, 0xaee: 0x112b, 0xaef: 0x1133, + 0xaf0: 0x1143, 0xaf1: 0x0657, 0xaf2: 0x17a0, 0xaf3: 0x17a5, 0xaf4: 0x065b, 0xaf5: 0x17aa, + 0xaf6: 0x115b, 0xaf7: 0x17af, 0xaf8: 0x1167, 0xaf9: 0x1173, 0xafa: 0x117b, 0xafb: 0x17b4, + 0xafc: 0x17b9, 0xafd: 0x118f, 0xafe: 0x17be, 0xaff: 0x1197, // Block 0x2c, offset 0xb00 - 0xb00: 0x12d7, 0xb01: 0x12db, 0xb02: 0x0683, 0xb03: 0x12eb, 0xb04: 0x12ef, 0xb05: 0x17f5, - 0xb06: 0x12fb, 0xb07: 0x12ff, 0xb08: 0x0687, 0xb09: 0x130b, 0xb0a: 0x05bb, 0xb0b: 0x17fa, - 0xb0c: 0x17ff, 0xb0d: 0x068b, 0xb0e: 0x068f, 0xb0f: 0x1337, 0xb10: 0x134f, 0xb11: 0x136b, - 0xb12: 0x137b, 0xb13: 0x1804, 0xb14: 0x138f, 0xb15: 0x1393, 0xb16: 0x13ab, 0xb17: 0x13b7, - 0xb18: 0x180e, 0xb19: 0x1660, 0xb1a: 0x13c3, 0xb1b: 0x13bf, 0xb1c: 0x13cb, 0xb1d: 0x1665, - 0xb1e: 0x13d7, 0xb1f: 0x13e3, 0xb20: 0x1813, 0xb21: 0x1818, 0xb22: 0x1423, 0xb23: 0x142f, - 0xb24: 0x1437, 0xb25: 0x181d, 0xb26: 0x143b, 0xb27: 0x1467, 0xb28: 0x1473, 0xb29: 0x1477, - 0xb2a: 0x146f, 0xb2b: 0x1483, 0xb2c: 0x1487, 0xb2d: 0x1822, 0xb2e: 0x1493, 0xb2f: 0x0693, - 0xb30: 0x149b, 0xb31: 0x1827, 0xb32: 0x0697, 0xb33: 0x14d3, 0xb34: 0x0ac3, 0xb35: 0x14eb, - 0xb36: 0x182c, 0xb37: 0x1836, 0xb38: 0x069b, 0xb39: 0x069f, 0xb3a: 0x1513, 0xb3b: 0x183b, - 0xb3c: 0x06a3, 0xb3d: 0x1840, 0xb3e: 0x152b, 0xb3f: 0x152b, + 0xb00: 0x16ce, 0xb01: 0x065f, 0xb02: 0x11af, 0xb03: 0x11b3, 0xb04: 0x0667, 0xb05: 0x11b7, + 0xb06: 0x0a33, 0xb07: 0x17c3, 0xb08: 0x17c8, 0xb09: 0x16d3, 0xb0a: 0x16d8, 0xb0b: 0x11d7, + 0xb0c: 0x11db, 0xb0d: 0x13f3, 0xb0e: 0x066b, 0xb0f: 0x1207, 0xb10: 0x1203, 0xb11: 0x120b, + 0xb12: 0x083f, 0xb13: 0x120f, 0xb14: 0x1213, 0xb15: 0x1217, 0xb16: 0x121f, 0xb17: 0x17cd, + 0xb18: 0x121b, 0xb19: 0x1223, 0xb1a: 0x1237, 0xb1b: 0x123b, 0xb1c: 0x1227, 0xb1d: 0x123f, + 0xb1e: 0x1253, 0xb1f: 0x1267, 0xb20: 0x1233, 0xb21: 0x1247, 0xb22: 0x124b, 0xb23: 0x124f, + 0xb24: 0x17d2, 0xb25: 0x17dc, 0xb26: 0x17d7, 0xb27: 0x066f, 0xb28: 0x126f, 0xb29: 0x1273, + 0xb2a: 0x127b, 0xb2b: 0x17f0, 0xb2c: 0x127f, 0xb2d: 0x17e1, 0xb2e: 0x0673, 0xb2f: 0x0677, + 0xb30: 0x17e6, 0xb31: 0x17eb, 0xb32: 0x067b, 0xb33: 0x129f, 0xb34: 0x12a3, 0xb35: 0x12a7, + 0xb36: 0x12ab, 0xb37: 0x12b7, 0xb38: 0x12b3, 0xb39: 0x12bf, 0xb3a: 0x12bb, 0xb3b: 0x12cb, + 0xb3c: 0x12c3, 0xb3d: 0x12c7, 0xb3e: 0x12cf, 0xb3f: 0x067f, // Block 0x2d, offset 0xb40 - 0xb40: 0x1533, 0xb41: 0x1845, 0xb42: 0x154b, 0xb43: 0x06a7, 0xb44: 0x155b, 0xb45: 0x1567, - 0xb46: 0x156f, 0xb47: 0x1577, 0xb48: 0x06ab, 0xb49: 0x184a, 0xb4a: 0x158b, 0xb4b: 0x15a7, - 0xb4c: 0x15b3, 0xb4d: 0x06af, 0xb4e: 0x06b3, 0xb4f: 0x15b7, 0xb50: 0x184f, 0xb51: 0x06b7, - 0xb52: 0x1854, 0xb53: 0x1859, 0xb54: 0x185e, 0xb55: 0x15db, 0xb56: 0x06bb, 0xb57: 0x15ef, - 0xb58: 0x15f7, 0xb59: 0x15fb, 0xb5a: 0x1603, 0xb5b: 0x160b, 0xb5c: 0x1613, 0xb5d: 0x1868, + 0xb40: 0x12d7, 0xb41: 0x12db, 0xb42: 0x0683, 0xb43: 0x12eb, 0xb44: 0x12ef, 0xb45: 0x17f5, + 0xb46: 0x12fb, 0xb47: 0x12ff, 0xb48: 0x0687, 0xb49: 0x130b, 0xb4a: 0x05bb, 0xb4b: 0x17fa, + 0xb4c: 0x17ff, 0xb4d: 0x068b, 0xb4e: 0x068f, 0xb4f: 0x1337, 0xb50: 0x134f, 0xb51: 0x136b, + 0xb52: 0x137b, 0xb53: 0x1804, 0xb54: 0x138f, 0xb55: 0x1393, 0xb56: 0x13ab, 0xb57: 0x13b7, + 0xb58: 0x180e, 0xb59: 0x1660, 0xb5a: 0x13c3, 0xb5b: 0x13bf, 0xb5c: 0x13cb, 0xb5d: 0x1665, + 0xb5e: 0x13d7, 0xb5f: 0x13e3, 0xb60: 0x1813, 0xb61: 0x1818, 0xb62: 0x1423, 0xb63: 0x142f, + 0xb64: 0x1437, 0xb65: 0x181d, 0xb66: 0x143b, 0xb67: 0x1467, 0xb68: 0x1473, 0xb69: 0x1477, + 0xb6a: 0x146f, 0xb6b: 0x1483, 0xb6c: 0x1487, 0xb6d: 0x1822, 0xb6e: 0x1493, 0xb6f: 0x0693, + 0xb70: 0x149b, 0xb71: 0x1827, 0xb72: 0x0697, 0xb73: 0x14d3, 0xb74: 0x0ac3, 0xb75: 0x14eb, + 0xb76: 0x182c, 0xb77: 0x1836, 0xb78: 0x069b, 0xb79: 0x069f, 0xb7a: 0x1513, 0xb7b: 0x183b, + 0xb7c: 0x06a3, 0xb7d: 0x1840, 0xb7e: 0x152b, 0xb7f: 0x152b, + // Block 0x2e, offset 0xb80 + 0xb80: 0x1533, 0xb81: 0x1845, 0xb82: 0x154b, 0xb83: 0x06a7, 0xb84: 0x155b, 0xb85: 0x1567, + 0xb86: 0x156f, 0xb87: 0x1577, 0xb88: 0x06ab, 0xb89: 0x184a, 0xb8a: 0x158b, 0xb8b: 0x15a7, + 0xb8c: 0x15b3, 0xb8d: 0x06af, 0xb8e: 0x06b3, 0xb8f: 0x15b7, 0xb90: 0x184f, 0xb91: 0x06b7, + 0xb92: 0x1854, 0xb93: 0x1859, 0xb94: 0x185e, 0xb95: 0x15db, 0xb96: 0x06bb, 0xb97: 0x15ef, + 0xb98: 0x15f7, 0xb99: 0x15fb, 0xb9a: 0x1603, 0xb9b: 0x160b, 0xb9c: 0x1613, 0xb9d: 0x1868, } // nfcIndex: 22 blocks, 1408 entries, 1408 bytes @@ -3419,33 +3431,33 @@ var nfcIndex = [1408]uint8{ // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 - 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04, - 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30, - 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33, - 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38, + 0xc2: 0x2d, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2e, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x2f, 0xcb: 0x30, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x31, + 0xd0: 0x09, 0xd1: 0x32, 0xd2: 0x33, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x34, + 0xd8: 0x35, 0xd9: 0x0c, 0xdb: 0x36, 0xdc: 0x37, 0xdd: 0x38, 0xdf: 0x39, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, 0xf0: 0x13, // Block 0x4, offset 0x100 - 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f, - 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46, - 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c, - 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54, + 0x120: 0x3a, 0x121: 0x3b, 0x123: 0x3c, 0x124: 0x3d, 0x125: 0x3e, 0x126: 0x3f, 0x127: 0x40, + 0x128: 0x41, 0x129: 0x42, 0x12a: 0x43, 0x12b: 0x44, 0x12c: 0x3f, 0x12d: 0x45, 0x12e: 0x46, 0x12f: 0x47, + 0x131: 0x48, 0x132: 0x49, 0x133: 0x4a, 0x134: 0x4b, 0x135: 0x4c, 0x137: 0x4d, + 0x138: 0x4e, 0x139: 0x4f, 0x13a: 0x50, 0x13b: 0x51, 0x13c: 0x52, 0x13d: 0x53, 0x13e: 0x54, 0x13f: 0x55, // Block 0x5, offset 0x140 - 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a, - 0x14d: 0x5b, - 0x15c: 0x5c, 0x15f: 0x5d, - 0x162: 0x5e, 0x164: 0x5f, - 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65, - 0x170: 0x66, 0x173: 0x67, 0x177: 0x68, - 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15, + 0x140: 0x56, 0x142: 0x57, 0x144: 0x58, 0x145: 0x59, 0x146: 0x5a, 0x147: 0x5b, + 0x14d: 0x5c, + 0x15c: 0x5d, 0x15f: 0x5e, + 0x162: 0x5f, 0x164: 0x60, + 0x168: 0x61, 0x169: 0x62, 0x16a: 0x63, 0x16c: 0x0d, 0x16d: 0x64, 0x16e: 0x65, 0x16f: 0x66, + 0x170: 0x67, 0x173: 0x68, 0x177: 0x0e, + 0x178: 0x0f, 0x179: 0x10, 0x17a: 0x11, 0x17b: 0x12, 0x17c: 0x13, 0x17d: 0x14, 0x17e: 0x15, 0x17f: 0x16, // Block 0x6, offset 0x180 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d, - 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70, + 0x188: 0x6e, 0x189: 0x17, 0x18a: 0x18, 0x18b: 0x6f, 0x18c: 0x70, 0x1ab: 0x71, 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74, // Block 0x7, offset 0x1c0 - 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, 0x1c4: 0x76, 0x1c5: 0x77, + 0x1c0: 0x75, 0x1c1: 0x19, 0x1c2: 0x1a, 0x1c3: 0x1b, 0x1c4: 0x76, 0x1c5: 0x77, 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a, // Block 0x8, offset 0x200 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d, @@ -3477,8 +3489,8 @@ var nfcIndex = [1408]uint8{ 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d, 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e, // Block 0xc, offset 0x300 - 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e, - 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91, + 0x324: 0x1c, 0x325: 0x1d, 0x326: 0x1e, 0x327: 0x1f, + 0x328: 0x20, 0x329: 0x21, 0x32a: 0x22, 0x32b: 0x23, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91, 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95, 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b, // Block 0xd, offset 0x340 @@ -3487,36 +3499,37 @@ var nfcIndex = [1408]uint8{ 0x368: 0x9f, 0x36b: 0xa0, // Block 0xe, offset 0x380 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4, - 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3e, 0x38d: 0xa7, + 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3f, 0x38d: 0xa7, 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac, 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae, - 0x3b0: 0x73, + 0x3a8: 0xaf, 0x3a9: 0xb0, 0x3aa: 0xb1, + 0x3b0: 0x73, 0x3b5: 0xb2, // Block 0xf, offset 0x3c0 - 0x3eb: 0xaf, 0x3ec: 0xb0, + 0x3eb: 0xb3, 0x3ec: 0xb4, // Block 0x10, offset 0x400 - 0x432: 0xb1, + 0x432: 0xb5, // Block 0x11, offset 0x440 - 0x445: 0xb2, 0x446: 0xb3, 0x447: 0xb4, - 0x449: 0xb5, + 0x445: 0xb6, 0x446: 0xb7, 0x447: 0xb8, + 0x449: 0xb9, // Block 0x12, offset 0x480 - 0x480: 0xb6, - 0x4a3: 0xb7, 0x4a5: 0xb8, + 0x480: 0xba, + 0x4a3: 0xbb, 0x4a5: 0xbc, // Block 0x13, offset 0x4c0 - 0x4c8: 0xb9, + 0x4c8: 0xbd, // Block 0x14, offset 0x500 - 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a, - 0x528: 0x2b, + 0x520: 0x24, 0x521: 0x25, 0x522: 0x26, 0x523: 0x27, 0x524: 0x28, 0x525: 0x29, 0x526: 0x2a, 0x527: 0x2b, + 0x528: 0x2c, // Block 0x15, offset 0x540 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, 0x56f: 0x12, } -// nfcSparseOffset: 142 entries, 284 bytes -var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc7, 0xce, 0xd6, 0xd9, 0xdb, 0xdd, 0xdf, 0xe4, 0xf5, 0x101, 0x103, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x118, 0x11b, 0x11d, 0x120, 0x123, 0x127, 0x12c, 0x135, 0x137, 0x13a, 0x13c, 0x147, 0x157, 0x15b, 0x169, 0x16c, 0x172, 0x178, 0x183, 0x187, 0x189, 0x18b, 0x18d, 0x18f, 0x191, 0x197, 0x19b, 0x19d, 0x19f, 0x1a7, 0x1ab, 0x1ae, 0x1b0, 0x1b2, 0x1b4, 0x1b7, 0x1b9, 0x1bb, 0x1bd, 0x1bf, 0x1c5, 0x1c8, 0x1ca, 0x1d1, 0x1d7, 0x1dd, 0x1e5, 0x1eb, 0x1f1, 0x1f7, 0x1fb, 0x209, 0x212, 0x215, 0x218, 0x21a, 0x21d, 0x21f, 0x223, 0x228, 0x22a, 0x22c, 0x231, 0x237, 0x239, 0x23b, 0x23d, 0x243, 0x246, 0x249, 0x251, 0x258, 0x25b, 0x25e, 0x260, 0x268, 0x26b, 0x272, 0x275, 0x27b, 0x27d, 0x280, 0x282, 0x284, 0x286, 0x288, 0x295, 0x29f, 0x2a1, 0x2a3, 0x2a9, 0x2ab, 0x2ae} +// nfcSparseOffset: 145 entries, 290 bytes +var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc8, 0xcf, 0xd7, 0xda, 0xdc, 0xde, 0xe0, 0xe5, 0xf6, 0x102, 0x104, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x119, 0x11c, 0x11e, 0x121, 0x124, 0x128, 0x12d, 0x136, 0x138, 0x13b, 0x13d, 0x148, 0x14c, 0x15a, 0x15d, 0x163, 0x169, 0x174, 0x178, 0x17a, 0x17c, 0x17e, 0x180, 0x182, 0x188, 0x18c, 0x18e, 0x190, 0x198, 0x19c, 0x19f, 0x1a1, 0x1a3, 0x1a5, 0x1a8, 0x1aa, 0x1ac, 0x1ae, 0x1b0, 0x1b6, 0x1b9, 0x1bb, 0x1c2, 0x1c8, 0x1ce, 0x1d6, 0x1dc, 0x1e2, 0x1e8, 0x1ec, 0x1fa, 0x203, 0x206, 0x209, 0x20b, 0x20e, 0x210, 0x214, 0x219, 0x21b, 0x21d, 0x222, 0x228, 0x22a, 0x22c, 0x22e, 0x234, 0x237, 0x23a, 0x242, 0x249, 0x24c, 0x24f, 0x251, 0x259, 0x25c, 0x263, 0x266, 0x26c, 0x26e, 0x271, 0x273, 0x275, 0x277, 0x279, 0x27c, 0x27e, 0x280, 0x282, 0x28f, 0x299, 0x29b, 0x29d, 0x2a3, 0x2a5, 0x2a8} -// nfcSparseValues: 688 entries, 2752 bytes -var nfcSparseValues = [688]valueRange{ +// nfcSparseValues: 682 entries, 2728 bytes +var nfcSparseValues = [682]valueRange{ // Block 0x0, offset 0x0 {value: 0x0000, lo: 0x04}, {value: 0xa100, lo: 0xa8, hi: 0xa8}, @@ -3745,9 +3758,10 @@ var nfcSparseValues = [688]valueRange{ {value: 0x8104, lo: 0x8d, hi: 0x8d}, {value: 0x9900, lo: 0x95, hi: 0x96}, // Block 0x1e, offset 0xc5 - {value: 0x0000, lo: 0x01}, + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xbb, hi: 0xbc}, {value: 0x9900, lo: 0xbe, hi: 0xbe}, - // Block 0x1f, offset 0xc7 + // Block 0x1f, offset 0xc8 {value: 0x0000, lo: 0x06}, {value: 0xa000, lo: 0x86, hi: 0x87}, {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, @@ -3755,7 +3769,7 @@ var nfcSparseValues = [688]valueRange{ {value: 0x2d06, lo: 0x8c, hi: 0x8c}, {value: 0x8104, lo: 0x8d, hi: 0x8d}, {value: 0x9900, lo: 0x97, hi: 0x97}, - // Block 0x20, offset 0xce + // Block 0x20, offset 0xcf {value: 0x6bea, lo: 0x07}, {value: 0x9904, lo: 0x8a, hi: 0x8a}, {value: 0x9900, lo: 0x8f, hi: 0x8f}, @@ -3764,26 +3778,26 @@ var nfcSparseValues = [688]valueRange{ {value: 0x2f58, lo: 0x9c, hi: 0x9c}, {value: 0x2de3, lo: 0x9d, hi: 0x9d}, {value: 0x2d16, lo: 0x9e, hi: 0x9f}, - // Block 0x21, offset 0xd6 + // Block 0x21, offset 0xd7 {value: 0x0000, lo: 0x02}, {value: 0x8122, lo: 0xb8, hi: 0xb9}, {value: 0x8104, lo: 0xba, hi: 0xba}, - // Block 0x22, offset 0xd9 + // Block 0x22, offset 0xda {value: 0x0000, lo: 0x01}, {value: 0x8123, lo: 0x88, hi: 0x8b}, - // Block 0x23, offset 0xdb + // Block 0x23, offset 0xdc {value: 0x0000, lo: 0x01}, {value: 0x8124, lo: 0xb8, hi: 0xb9}, - // Block 0x24, offset 0xdd + // Block 0x24, offset 0xde {value: 0x0000, lo: 0x01}, {value: 0x8125, lo: 0x88, hi: 0x8b}, - // Block 0x25, offset 0xdf + // Block 0x25, offset 0xe0 {value: 0x0000, lo: 0x04}, {value: 0x812d, lo: 0x98, hi: 0x99}, {value: 0x812d, lo: 0xb5, hi: 0xb5}, {value: 0x812d, lo: 0xb7, hi: 0xb7}, {value: 0x812b, lo: 0xb9, hi: 0xb9}, - // Block 0x26, offset 0xe4 + // Block 0x26, offset 0xe5 {value: 0x0000, lo: 0x10}, {value: 0x2644, lo: 0x83, hi: 0x83}, {value: 0x264b, lo: 0x8d, hi: 0x8d}, @@ -3801,7 +3815,7 @@ var nfcSparseValues = [688]valueRange{ {value: 0x45bc, lo: 0xb8, hi: 0xb8}, {value: 0x8200, lo: 0xb9, hi: 0xb9}, {value: 0x8127, lo: 0xba, hi: 0xbd}, - // Block 0x27, offset 0xf5 + // Block 0x27, offset 0xf6 {value: 0x0000, lo: 0x0b}, {value: 0x8127, lo: 0x80, hi: 0x80}, {value: 0x4a96, lo: 0x81, hi: 0x81}, @@ -3814,65 +3828,65 @@ var nfcSparseValues = [688]valueRange{ {value: 0x2683, lo: 0xa7, hi: 0xa7}, {value: 0x268a, lo: 0xac, hi: 0xac}, {value: 0x2667, lo: 0xb9, hi: 0xb9}, - // Block 0x28, offset 0x101 + // Block 0x28, offset 0x102 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x86, hi: 0x86}, - // Block 0x29, offset 0x103 + // Block 0x29, offset 0x104 {value: 0x0000, lo: 0x05}, {value: 0xa000, lo: 0xa5, hi: 0xa5}, {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, {value: 0x9900, lo: 0xae, hi: 0xae}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, {value: 0x8104, lo: 0xb9, hi: 0xba}, - // Block 0x2a, offset 0x109 + // Block 0x2a, offset 0x10a {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x8d, hi: 0x8d}, - // Block 0x2b, offset 0x10b + // Block 0x2b, offset 0x10c {value: 0x0000, lo: 0x01}, {value: 0xa000, lo: 0x80, hi: 0x92}, - // Block 0x2c, offset 0x10d + // Block 0x2c, offset 0x10e {value: 0x0000, lo: 0x01}, {value: 0xb900, lo: 0xa1, hi: 0xb5}, - // Block 0x2d, offset 0x10f + // Block 0x2d, offset 0x110 {value: 0x0000, lo: 0x01}, {value: 0x9900, lo: 0xa8, hi: 0xbf}, - // Block 0x2e, offset 0x111 + // Block 0x2e, offset 0x112 {value: 0x0000, lo: 0x01}, {value: 0x9900, lo: 0x80, hi: 0x82}, - // Block 0x2f, offset 0x113 + // Block 0x2f, offset 0x114 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0x9d, hi: 0x9f}, - // Block 0x30, offset 0x115 + // Block 0x30, offset 0x116 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x94, hi: 0x94}, {value: 0x8104, lo: 0xb4, hi: 0xb4}, - // Block 0x31, offset 0x118 + // Block 0x31, offset 0x119 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x92, hi: 0x92}, {value: 0x8132, lo: 0x9d, hi: 0x9d}, - // Block 0x32, offset 0x11b + // Block 0x32, offset 0x11c {value: 0x0000, lo: 0x01}, {value: 0x8131, lo: 0xa9, hi: 0xa9}, - // Block 0x33, offset 0x11d + // Block 0x33, offset 0x11e {value: 0x0004, lo: 0x02}, {value: 0x812e, lo: 0xb9, hi: 0xba}, {value: 0x812d, lo: 0xbb, hi: 0xbb}, - // Block 0x34, offset 0x120 + // Block 0x34, offset 0x121 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x97, hi: 0x97}, {value: 0x812d, lo: 0x98, hi: 0x98}, - // Block 0x35, offset 0x123 + // Block 0x35, offset 0x124 {value: 0x0000, lo: 0x03}, {value: 0x8104, lo: 0xa0, hi: 0xa0}, {value: 0x8132, lo: 0xb5, hi: 0xbc}, {value: 0x812d, lo: 0xbf, hi: 0xbf}, - // Block 0x36, offset 0x127 + // Block 0x36, offset 0x128 {value: 0x0000, lo: 0x04}, {value: 0x8132, lo: 0xb0, hi: 0xb4}, {value: 0x812d, lo: 0xb5, hi: 0xba}, {value: 0x8132, lo: 0xbb, hi: 0xbc}, {value: 0x812d, lo: 0xbd, hi: 0xbd}, - // Block 0x37, offset 0x12c + // Block 0x37, offset 0x12d {value: 0x0000, lo: 0x08}, {value: 0x2d66, lo: 0x80, hi: 0x80}, {value: 0x2d6e, lo: 0x81, hi: 0x81}, @@ -3882,17 +3896,17 @@ var nfcSparseValues = [688]valueRange{ {value: 0x8132, lo: 0xab, hi: 0xab}, {value: 0x812d, lo: 0xac, hi: 0xac}, {value: 0x8132, lo: 0xad, hi: 0xb3}, - // Block 0x38, offset 0x135 + // Block 0x38, offset 0x136 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xaa, hi: 0xab}, - // Block 0x39, offset 0x137 + // Block 0x39, offset 0x138 {value: 0x0000, lo: 0x02}, {value: 0x8102, lo: 0xa6, hi: 0xa6}, {value: 0x8104, lo: 0xb2, hi: 0xb3}, - // Block 0x3a, offset 0x13a + // Block 0x3a, offset 0x13b {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, - // Block 0x3b, offset 0x13c + // Block 0x3b, offset 0x13d {value: 0x0000, lo: 0x0a}, {value: 0x8132, lo: 0x90, hi: 0x92}, {value: 0x8101, lo: 0x94, hi: 0x94}, @@ -3904,29 +3918,12 @@ var nfcSparseValues = [688]valueRange{ {value: 0x812d, lo: 0xad, hi: 0xad}, {value: 0x8132, lo: 0xb4, hi: 0xb4}, {value: 0x8132, lo: 0xb8, hi: 0xb9}, - // Block 0x3c, offset 0x147 - {value: 0x0000, lo: 0x0f}, - {value: 0x8132, lo: 0x80, hi: 0x81}, - {value: 0x812d, lo: 0x82, hi: 0x82}, - {value: 0x8132, lo: 0x83, hi: 0x89}, - {value: 0x812d, lo: 0x8a, hi: 0x8a}, - {value: 0x8132, lo: 0x8b, hi: 0x8c}, - {value: 0x8135, lo: 0x8d, hi: 0x8d}, - {value: 0x812a, lo: 0x8e, hi: 0x8e}, - {value: 0x812d, lo: 0x8f, hi: 0x8f}, - {value: 0x8129, lo: 0x90, hi: 0x90}, - {value: 0x8132, lo: 0x91, hi: 0xb5}, - {value: 0x8132, lo: 0xbb, hi: 0xbb}, - {value: 0x8134, lo: 0xbc, hi: 0xbc}, - {value: 0x812d, lo: 0xbd, hi: 0xbd}, - {value: 0x8132, lo: 0xbe, hi: 0xbe}, - {value: 0x812d, lo: 0xbf, hi: 0xbf}, - // Block 0x3d, offset 0x157 + // Block 0x3c, offset 0x148 {value: 0x0004, lo: 0x03}, {value: 0x0433, lo: 0x80, hi: 0x81}, {value: 0x8100, lo: 0x97, hi: 0x97}, {value: 0x8100, lo: 0xbe, hi: 0xbe}, - // Block 0x3e, offset 0x15b + // Block 0x3d, offset 0x14c {value: 0x0000, lo: 0x0d}, {value: 0x8132, lo: 0x90, hi: 0x91}, {value: 0x8101, lo: 0x92, hi: 0x93}, @@ -3941,25 +3938,25 @@ var nfcSparseValues = [688]valueRange{ {value: 0x8101, lo: 0xaa, hi: 0xab}, {value: 0x812d, lo: 0xac, hi: 0xaf}, {value: 0x8132, lo: 0xb0, hi: 0xb0}, - // Block 0x3f, offset 0x169 + // Block 0x3e, offset 0x15a {value: 0x427b, lo: 0x02}, {value: 0x01b8, lo: 0xa6, hi: 0xa6}, {value: 0x0057, lo: 0xaa, hi: 0xab}, - // Block 0x40, offset 0x16c + // Block 0x3f, offset 0x15d {value: 0x0007, lo: 0x05}, {value: 0xa000, lo: 0x90, hi: 0x90}, {value: 0xa000, lo: 0x92, hi: 0x92}, {value: 0xa000, lo: 0x94, hi: 0x94}, {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, {value: 0x3bc7, lo: 0xae, hi: 0xae}, - // Block 0x41, offset 0x172 + // Block 0x40, offset 0x163 {value: 0x000e, lo: 0x05}, {value: 0x3bce, lo: 0x8d, hi: 0x8e}, {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, {value: 0xa000, lo: 0x90, hi: 0x90}, {value: 0xa000, lo: 0x92, hi: 0x92}, {value: 0xa000, lo: 0x94, hi: 0x94}, - // Block 0x42, offset 0x178 + // Block 0x41, offset 0x169 {value: 0x6408, lo: 0x0a}, {value: 0xa000, lo: 0x83, hi: 0x83}, {value: 0x3be3, lo: 0x84, hi: 0x84}, @@ -3971,45 +3968,45 @@ var nfcSparseValues = [688]valueRange{ {value: 0x3bf8, lo: 0xa4, hi: 0xa5}, {value: 0x3bff, lo: 0xa6, hi: 0xa6}, {value: 0xa000, lo: 0xbc, hi: 0xbc}, - // Block 0x43, offset 0x183 + // Block 0x42, offset 0x174 {value: 0x0007, lo: 0x03}, {value: 0x3c68, lo: 0xa0, hi: 0xa1}, {value: 0x3c92, lo: 0xa2, hi: 0xa3}, {value: 0x3cbc, lo: 0xaa, hi: 0xad}, - // Block 0x44, offset 0x187 + // Block 0x43, offset 0x178 {value: 0x0004, lo: 0x01}, {value: 0x048b, lo: 0xa9, hi: 0xaa}, - // Block 0x45, offset 0x189 + // Block 0x44, offset 0x17a {value: 0x0000, lo: 0x01}, {value: 0x44dd, lo: 0x9c, hi: 0x9c}, - // Block 0x46, offset 0x18b + // Block 0x45, offset 0x17c {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xaf, hi: 0xb1}, - // Block 0x47, offset 0x18d + // Block 0x46, offset 0x17e {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x48, offset 0x18f + // Block 0x47, offset 0x180 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xa0, hi: 0xbf}, - // Block 0x49, offset 0x191 + // Block 0x48, offset 0x182 {value: 0x0000, lo: 0x05}, {value: 0x812c, lo: 0xaa, hi: 0xaa}, {value: 0x8131, lo: 0xab, hi: 0xab}, {value: 0x8133, lo: 0xac, hi: 0xac}, {value: 0x812e, lo: 0xad, hi: 0xad}, {value: 0x812f, lo: 0xae, hi: 0xaf}, - // Block 0x4a, offset 0x197 + // Block 0x49, offset 0x188 {value: 0x0000, lo: 0x03}, {value: 0x4a9f, lo: 0xb3, hi: 0xb3}, {value: 0x4a9f, lo: 0xb5, hi: 0xb6}, {value: 0x4a9f, lo: 0xba, hi: 0xbf}, - // Block 0x4b, offset 0x19b + // Block 0x4a, offset 0x18c {value: 0x0000, lo: 0x01}, {value: 0x4a9f, lo: 0x8f, hi: 0xa3}, - // Block 0x4c, offset 0x19d + // Block 0x4b, offset 0x18e {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0xae, hi: 0xbe}, - // Block 0x4d, offset 0x19f + // Block 0x4c, offset 0x190 {value: 0x0000, lo: 0x07}, {value: 0x8100, lo: 0x84, hi: 0x84}, {value: 0x8100, lo: 0x87, hi: 0x87}, @@ -4018,55 +4015,55 @@ var nfcSparseValues = [688]valueRange{ {value: 0x8100, lo: 0xa1, hi: 0xa1}, {value: 0x8100, lo: 0xb2, hi: 0xb2}, {value: 0x8100, lo: 0xbb, hi: 0xbb}, - // Block 0x4e, offset 0x1a7 + // Block 0x4d, offset 0x198 {value: 0x0000, lo: 0x03}, {value: 0x8100, lo: 0x80, hi: 0x80}, {value: 0x8100, lo: 0x8b, hi: 0x8b}, {value: 0x8100, lo: 0x8e, hi: 0x8e}, - // Block 0x4f, offset 0x1ab + // Block 0x4e, offset 0x19c {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0xaf, hi: 0xaf}, {value: 0x8132, lo: 0xb4, hi: 0xbd}, - // Block 0x50, offset 0x1ae + // Block 0x4f, offset 0x19f {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0x9e, hi: 0x9f}, - // Block 0x51, offset 0x1b0 + // Block 0x50, offset 0x1a1 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb0, hi: 0xb1}, - // Block 0x52, offset 0x1b2 + // Block 0x51, offset 0x1a3 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x86, hi: 0x86}, - // Block 0x53, offset 0x1b4 + // Block 0x52, offset 0x1a5 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x84, hi: 0x84}, {value: 0x8132, lo: 0xa0, hi: 0xb1}, - // Block 0x54, offset 0x1b7 + // Block 0x53, offset 0x1a8 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xab, hi: 0xad}, - // Block 0x55, offset 0x1b9 + // Block 0x54, offset 0x1aa {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x93, hi: 0x93}, - // Block 0x56, offset 0x1bb + // Block 0x55, offset 0x1ac {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0xb3, hi: 0xb3}, - // Block 0x57, offset 0x1bd + // Block 0x56, offset 0x1ae {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x80, hi: 0x80}, - // Block 0x58, offset 0x1bf + // Block 0x57, offset 0x1b0 {value: 0x0000, lo: 0x05}, {value: 0x8132, lo: 0xb0, hi: 0xb0}, {value: 0x8132, lo: 0xb2, hi: 0xb3}, {value: 0x812d, lo: 0xb4, hi: 0xb4}, {value: 0x8132, lo: 0xb7, hi: 0xb8}, {value: 0x8132, lo: 0xbe, hi: 0xbf}, - // Block 0x59, offset 0x1c5 + // Block 0x58, offset 0x1b6 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x81, hi: 0x81}, {value: 0x8104, lo: 0xb6, hi: 0xb6}, - // Block 0x5a, offset 0x1c8 + // Block 0x59, offset 0x1b9 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xad, hi: 0xad}, - // Block 0x5b, offset 0x1ca + // Block 0x5a, offset 0x1bb {value: 0x0000, lo: 0x06}, {value: 0xe500, lo: 0x80, hi: 0x80}, {value: 0xc600, lo: 0x81, hi: 0x9b}, @@ -4074,21 +4071,21 @@ var nfcSparseValues = [688]valueRange{ {value: 0xc600, lo: 0x9d, hi: 0xb7}, {value: 0xe500, lo: 0xb8, hi: 0xb8}, {value: 0xc600, lo: 0xb9, hi: 0xbf}, - // Block 0x5c, offset 0x1d1 + // Block 0x5b, offset 0x1c2 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x93}, {value: 0xe500, lo: 0x94, hi: 0x94}, {value: 0xc600, lo: 0x95, hi: 0xaf}, {value: 0xe500, lo: 0xb0, hi: 0xb0}, {value: 0xc600, lo: 0xb1, hi: 0xbf}, - // Block 0x5d, offset 0x1d7 + // Block 0x5c, offset 0x1c8 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x8b}, {value: 0xe500, lo: 0x8c, hi: 0x8c}, {value: 0xc600, lo: 0x8d, hi: 0xa7}, {value: 0xe500, lo: 0xa8, hi: 0xa8}, {value: 0xc600, lo: 0xa9, hi: 0xbf}, - // Block 0x5e, offset 0x1dd + // Block 0x5d, offset 0x1ce {value: 0x0000, lo: 0x07}, {value: 0xc600, lo: 0x80, hi: 0x83}, {value: 0xe500, lo: 0x84, hi: 0x84}, @@ -4097,33 +4094,33 @@ var nfcSparseValues = [688]valueRange{ {value: 0xc600, lo: 0xa1, hi: 0xbb}, {value: 0xe500, lo: 0xbc, hi: 0xbc}, {value: 0xc600, lo: 0xbd, hi: 0xbf}, - // Block 0x5f, offset 0x1e5 + // Block 0x5e, offset 0x1d6 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x97}, {value: 0xe500, lo: 0x98, hi: 0x98}, {value: 0xc600, lo: 0x99, hi: 0xb3}, {value: 0xe500, lo: 0xb4, hi: 0xb4}, {value: 0xc600, lo: 0xb5, hi: 0xbf}, - // Block 0x60, offset 0x1eb + // Block 0x5f, offset 0x1dc {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x8f}, {value: 0xe500, lo: 0x90, hi: 0x90}, {value: 0xc600, lo: 0x91, hi: 0xab}, {value: 0xe500, lo: 0xac, hi: 0xac}, {value: 0xc600, lo: 0xad, hi: 0xbf}, - // Block 0x61, offset 0x1f1 + // Block 0x60, offset 0x1e2 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x87}, {value: 0xe500, lo: 0x88, hi: 0x88}, {value: 0xc600, lo: 0x89, hi: 0xa3}, {value: 0xe500, lo: 0xa4, hi: 0xa4}, {value: 0xc600, lo: 0xa5, hi: 0xbf}, - // Block 0x62, offset 0x1f7 + // Block 0x61, offset 0x1e8 {value: 0x0000, lo: 0x03}, {value: 0xc600, lo: 0x80, hi: 0x87}, {value: 0xe500, lo: 0x88, hi: 0x88}, {value: 0xc600, lo: 0x89, hi: 0xa3}, - // Block 0x63, offset 0x1fb + // Block 0x62, offset 0x1ec {value: 0x0006, lo: 0x0d}, {value: 0x4390, lo: 0x9d, hi: 0x9d}, {value: 0x8115, lo: 0x9e, hi: 0x9e}, @@ -4138,7 +4135,7 @@ var nfcSparseValues = [688]valueRange{ {value: 0x4396, lo: 0xb9, hi: 0xbb}, {value: 0x43ae, lo: 0xbc, hi: 0xbc}, {value: 0x43b4, lo: 0xbe, hi: 0xbe}, - // Block 0x64, offset 0x209 + // Block 0x63, offset 0x1fa {value: 0x0006, lo: 0x08}, {value: 0x43ba, lo: 0x80, hi: 0x81}, {value: 0x43c6, lo: 0x83, hi: 0x84}, @@ -4148,79 +4145,79 @@ var nfcSparseValues = [688]valueRange{ {value: 0x4360, lo: 0x8c, hi: 0x8c}, {value: 0x43a8, lo: 0x8d, hi: 0x8d}, {value: 0x43d2, lo: 0x8e, hi: 0x8e}, - // Block 0x65, offset 0x212 + // Block 0x64, offset 0x203 {value: 0x0000, lo: 0x02}, {value: 0x8100, lo: 0xa4, hi: 0xa5}, {value: 0x8100, lo: 0xb0, hi: 0xb1}, - // Block 0x66, offset 0x215 + // Block 0x65, offset 0x206 {value: 0x0000, lo: 0x02}, {value: 0x8100, lo: 0x9b, hi: 0x9d}, {value: 0x8200, lo: 0x9e, hi: 0xa3}, - // Block 0x67, offset 0x218 + // Block 0x66, offset 0x209 {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0x90, hi: 0x90}, - // Block 0x68, offset 0x21a + // Block 0x67, offset 0x20b {value: 0x0000, lo: 0x02}, {value: 0x8100, lo: 0x99, hi: 0x99}, {value: 0x8200, lo: 0xb2, hi: 0xb4}, - // Block 0x69, offset 0x21d + // Block 0x68, offset 0x20e {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0xbc, hi: 0xbd}, - // Block 0x6a, offset 0x21f + // Block 0x69, offset 0x210 {value: 0x0000, lo: 0x03}, {value: 0x8132, lo: 0xa0, hi: 0xa6}, {value: 0x812d, lo: 0xa7, hi: 0xad}, {value: 0x8132, lo: 0xae, hi: 0xaf}, - // Block 0x6b, offset 0x223 + // Block 0x6a, offset 0x214 {value: 0x0000, lo: 0x04}, {value: 0x8100, lo: 0x89, hi: 0x8c}, {value: 0x8100, lo: 0xb0, hi: 0xb2}, {value: 0x8100, lo: 0xb4, hi: 0xb4}, {value: 0x8100, lo: 0xb6, hi: 0xbf}, - // Block 0x6c, offset 0x228 + // Block 0x6b, offset 0x219 {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0x81, hi: 0x8c}, - // Block 0x6d, offset 0x22a + // Block 0x6c, offset 0x21b {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0xb5, hi: 0xba}, - // Block 0x6e, offset 0x22c + // Block 0x6d, offset 0x21d {value: 0x0000, lo: 0x04}, {value: 0x4a9f, lo: 0x9e, hi: 0x9f}, {value: 0x4a9f, lo: 0xa3, hi: 0xa3}, {value: 0x4a9f, lo: 0xa5, hi: 0xa6}, {value: 0x4a9f, lo: 0xaa, hi: 0xaf}, - // Block 0x6f, offset 0x231 + // Block 0x6e, offset 0x222 {value: 0x0000, lo: 0x05}, {value: 0x4a9f, lo: 0x82, hi: 0x87}, {value: 0x4a9f, lo: 0x8a, hi: 0x8f}, {value: 0x4a9f, lo: 0x92, hi: 0x97}, {value: 0x4a9f, lo: 0x9a, hi: 0x9c}, {value: 0x8100, lo: 0xa3, hi: 0xa3}, - // Block 0x70, offset 0x237 + // Block 0x6f, offset 0x228 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xbd, hi: 0xbd}, - // Block 0x71, offset 0x239 + // Block 0x70, offset 0x22a {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xa0, hi: 0xa0}, - // Block 0x72, offset 0x23b + // Block 0x71, offset 0x22c {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb6, hi: 0xba}, - // Block 0x73, offset 0x23d + // Block 0x72, offset 0x22e {value: 0x002c, lo: 0x05}, {value: 0x812d, lo: 0x8d, hi: 0x8d}, {value: 0x8132, lo: 0x8f, hi: 0x8f}, {value: 0x8132, lo: 0xb8, hi: 0xb8}, {value: 0x8101, lo: 0xb9, hi: 0xba}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x74, offset 0x243 + // Block 0x73, offset 0x234 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0xa5, hi: 0xa5}, {value: 0x812d, lo: 0xa6, hi: 0xa6}, - // Block 0x75, offset 0x246 + // Block 0x74, offset 0x237 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x86, hi: 0x86}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x76, offset 0x249 + // Block 0x75, offset 0x23a {value: 0x17fe, lo: 0x07}, {value: 0xa000, lo: 0x99, hi: 0x99}, {value: 0x4238, lo: 0x9a, hi: 0x9a}, @@ -4229,7 +4226,7 @@ var nfcSparseValues = [688]valueRange{ {value: 0xa000, lo: 0xa5, hi: 0xa5}, {value: 0x424c, lo: 0xab, hi: 0xab}, {value: 0x8104, lo: 0xb9, hi: 0xba}, - // Block 0x77, offset 0x251 + // Block 0x76, offset 0x242 {value: 0x0000, lo: 0x06}, {value: 0x8132, lo: 0x80, hi: 0x82}, {value: 0x9900, lo: 0xa7, hi: 0xa7}, @@ -4237,18 +4234,18 @@ var nfcSparseValues = [688]valueRange{ {value: 0x2d88, lo: 0xaf, hi: 0xaf}, {value: 0xa000, lo: 0xb1, hi: 0xb2}, {value: 0x8104, lo: 0xb3, hi: 0xb4}, - // Block 0x78, offset 0x258 + // Block 0x77, offset 0x249 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x80, hi: 0x80}, {value: 0x8102, lo: 0x8a, hi: 0x8a}, - // Block 0x79, offset 0x25b + // Block 0x78, offset 0x24c {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0xb5, hi: 0xb5}, {value: 0x8102, lo: 0xb6, hi: 0xb6}, - // Block 0x7a, offset 0x25e + // Block 0x79, offset 0x24f {value: 0x0002, lo: 0x01}, {value: 0x8102, lo: 0xa9, hi: 0xaa}, - // Block 0x7b, offset 0x260 + // Block 0x7a, offset 0x251 {value: 0x0000, lo: 0x07}, {value: 0xa000, lo: 0x87, hi: 0x87}, {value: 0x2d92, lo: 0x8b, hi: 0x8b}, @@ -4257,11 +4254,11 @@ var nfcSparseValues = [688]valueRange{ {value: 0x9900, lo: 0x97, hi: 0x97}, {value: 0x8132, lo: 0xa6, hi: 0xac}, {value: 0x8132, lo: 0xb0, hi: 0xb4}, - // Block 0x7c, offset 0x268 + // Block 0x7b, offset 0x259 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x82, hi: 0x82}, {value: 0x8102, lo: 0x86, hi: 0x86}, - // Block 0x7d, offset 0x26b + // Block 0x7c, offset 0x25c {value: 0x6b5a, lo: 0x06}, {value: 0x9900, lo: 0xb0, hi: 0xb0}, {value: 0xa000, lo: 0xb9, hi: 0xb9}, @@ -4269,37 +4266,50 @@ var nfcSparseValues = [688]valueRange{ {value: 0x2db0, lo: 0xbb, hi: 0xbb}, {value: 0x2da6, lo: 0xbc, hi: 0xbd}, {value: 0x2dba, lo: 0xbe, hi: 0xbe}, - // Block 0x7e, offset 0x272 + // Block 0x7d, offset 0x263 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x82, hi: 0x82}, {value: 0x8102, lo: 0x83, hi: 0x83}, - // Block 0x7f, offset 0x275 + // Block 0x7e, offset 0x266 {value: 0x0000, lo: 0x05}, {value: 0x9900, lo: 0xaf, hi: 0xaf}, {value: 0xa000, lo: 0xb8, hi: 0xb9}, {value: 0x2dc4, lo: 0xba, hi: 0xba}, {value: 0x2dce, lo: 0xbb, hi: 0xbb}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x80, offset 0x27b + // Block 0x7f, offset 0x26c {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0x80, hi: 0x80}, - // Block 0x81, offset 0x27d + // Block 0x80, offset 0x26e {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0xb6, hi: 0xb6}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, - // Block 0x82, offset 0x280 + // Block 0x81, offset 0x271 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xab, hi: 0xab}, - // Block 0x83, offset 0x282 + // Block 0x82, offset 0x273 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x83, offset 0x275 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x87, hi: 0x87}, + // Block 0x84, offset 0x277 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x99, hi: 0x99}, + // Block 0x85, offset 0x279 + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0x82, hi: 0x82}, + {value: 0x8104, lo: 0x84, hi: 0x85}, + // Block 0x86, offset 0x27c {value: 0x0000, lo: 0x01}, {value: 0x8101, lo: 0xb0, hi: 0xb4}, - // Block 0x84, offset 0x284 + // Block 0x87, offset 0x27e {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb0, hi: 0xb6}, - // Block 0x85, offset 0x286 + // Block 0x88, offset 0x280 {value: 0x0000, lo: 0x01}, {value: 0x8101, lo: 0x9e, hi: 0x9e}, - // Block 0x86, offset 0x288 + // Block 0x89, offset 0x282 {value: 0x0000, lo: 0x0c}, {value: 0x45cc, lo: 0x9e, hi: 0x9e}, {value: 0x45d6, lo: 0x9f, hi: 0x9f}, @@ -4313,7 +4323,7 @@ var nfcSparseValues = [688]valueRange{ {value: 0x8130, lo: 0xad, hi: 0xad}, {value: 0x812b, lo: 0xae, hi: 0xb2}, {value: 0x812d, lo: 0xbb, hi: 0xbf}, - // Block 0x87, offset 0x295 + // Block 0x8a, offset 0x28f {value: 0x0000, lo: 0x09}, {value: 0x812d, lo: 0x80, hi: 0x82}, {value: 0x8132, lo: 0x85, hi: 0x89}, @@ -4324,27 +4334,27 @@ var nfcSparseValues = [688]valueRange{ {value: 0x4650, lo: 0xbd, hi: 0xbd}, {value: 0x466c, lo: 0xbe, hi: 0xbe}, {value: 0x465e, lo: 0xbf, hi: 0xbf}, - // Block 0x88, offset 0x29f + // Block 0x8b, offset 0x299 {value: 0x0000, lo: 0x01}, {value: 0x467a, lo: 0x80, hi: 0x80}, - // Block 0x89, offset 0x2a1 + // Block 0x8c, offset 0x29b {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0x82, hi: 0x84}, - // Block 0x8a, offset 0x2a3 + // Block 0x8d, offset 0x29d {value: 0x0000, lo: 0x05}, {value: 0x8132, lo: 0x80, hi: 0x86}, {value: 0x8132, lo: 0x88, hi: 0x98}, {value: 0x8132, lo: 0x9b, hi: 0xa1}, {value: 0x8132, lo: 0xa3, hi: 0xa4}, {value: 0x8132, lo: 0xa6, hi: 0xaa}, - // Block 0x8b, offset 0x2a9 + // Block 0x8e, offset 0x2a3 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x90, hi: 0x96}, - // Block 0x8c, offset 0x2ab + // Block 0x8f, offset 0x2a5 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x84, hi: 0x89}, {value: 0x8102, lo: 0x8a, hi: 0x8a}, - // Block 0x8d, offset 0x2ae + // Block 0x90, offset 0x2a8 {value: 0x0000, lo: 0x01}, {value: 0x8100, lo: 0x93, hi: 0x93}, } @@ -4519,7 +4529,7 @@ func (t *nfkcTrie) lookupStringUnsafe(s string) uint16 { return 0 } -// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: c3ed54ee046f3c46. +// nfkcTrie. Total size: 17104 bytes (16.70 KiB). Checksum: d985061cf5307b35. type nfkcTrie struct{} func newNfkcTrie(i int) *nfkcTrie { @@ -4529,17 +4539,17 @@ func newNfkcTrie(i int) *nfkcTrie { // lookupValue determines the type of block n and looks up the value for b. func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 { switch { - case n < 90: + case n < 91: return uint16(nfkcValues[n<<6+uint32(b)]) default: - n -= 90 + n -= 91 return uint16(nfkcSparse.lookup(n, b)) } } -// nfkcValues: 92 blocks, 5888 entries, 11776 bytes +// nfkcValues: 93 blocks, 5952 entries, 11904 bytes // The third block is the zero block. -var nfkcValues = [5888]uint16{ +var nfkcValues = [5952]uint16{ // Block 0x0, offset 0x0 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000, // Block 0x1, offset 0x40 @@ -4723,824 +4733,836 @@ var nfkcValues = [5888]uint16{ 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5, 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0, // Block 0x13, offset 0x4c0 - 0x4c0: 0x2f97, 0x4c1: 0x32a3, 0x4c2: 0x2fa1, 0x4c3: 0x32ad, 0x4c4: 0x2fa6, 0x4c5: 0x32b2, - 0x4c6: 0x2fab, 0x4c7: 0x32b7, 0x4c8: 0x38cc, 0x4c9: 0x3a5b, 0x4ca: 0x2fc4, 0x4cb: 0x32d0, - 0x4cc: 0x2fce, 0x4cd: 0x32da, 0x4ce: 0x2fdd, 0x4cf: 0x32e9, 0x4d0: 0x2fd3, 0x4d1: 0x32df, - 0x4d2: 0x2fd8, 0x4d3: 0x32e4, 0x4d4: 0x38ef, 0x4d5: 0x3a7e, 0x4d6: 0x38f6, 0x4d7: 0x3a85, - 0x4d8: 0x3019, 0x4d9: 0x3325, 0x4da: 0x301e, 0x4db: 0x332a, 0x4dc: 0x3904, 0x4dd: 0x3a93, - 0x4de: 0x3023, 0x4df: 0x332f, 0x4e0: 0x3032, 0x4e1: 0x333e, 0x4e2: 0x3050, 0x4e3: 0x335c, - 0x4e4: 0x305f, 0x4e5: 0x336b, 0x4e6: 0x3055, 0x4e7: 0x3361, 0x4e8: 0x3064, 0x4e9: 0x3370, - 0x4ea: 0x3069, 0x4eb: 0x3375, 0x4ec: 0x30af, 0x4ed: 0x33bb, 0x4ee: 0x390b, 0x4ef: 0x3a9a, - 0x4f0: 0x30b9, 0x4f1: 0x33ca, 0x4f2: 0x30c3, 0x4f3: 0x33d4, 0x4f4: 0x30cd, 0x4f5: 0x33de, - 0x4f6: 0x46c4, 0x4f7: 0x4755, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x30e6, 0x4fb: 0x33f7, - 0x4fc: 0x30e1, 0x4fd: 0x33f2, 0x4fe: 0x30eb, 0x4ff: 0x33fc, + 0x4c0: 0x8132, 0x4c1: 0x8132, 0x4c2: 0x812d, 0x4c3: 0x8132, 0x4c4: 0x8132, 0x4c5: 0x8132, + 0x4c6: 0x8132, 0x4c7: 0x8132, 0x4c8: 0x8132, 0x4c9: 0x8132, 0x4ca: 0x812d, 0x4cb: 0x8132, + 0x4cc: 0x8132, 0x4cd: 0x8135, 0x4ce: 0x812a, 0x4cf: 0x812d, 0x4d0: 0x8129, 0x4d1: 0x8132, + 0x4d2: 0x8132, 0x4d3: 0x8132, 0x4d4: 0x8132, 0x4d5: 0x8132, 0x4d6: 0x8132, 0x4d7: 0x8132, + 0x4d8: 0x8132, 0x4d9: 0x8132, 0x4da: 0x8132, 0x4db: 0x8132, 0x4dc: 0x8132, 0x4dd: 0x8132, + 0x4de: 0x8132, 0x4df: 0x8132, 0x4e0: 0x8132, 0x4e1: 0x8132, 0x4e2: 0x8132, 0x4e3: 0x8132, + 0x4e4: 0x8132, 0x4e5: 0x8132, 0x4e6: 0x8132, 0x4e7: 0x8132, 0x4e8: 0x8132, 0x4e9: 0x8132, + 0x4ea: 0x8132, 0x4eb: 0x8132, 0x4ec: 0x8132, 0x4ed: 0x8132, 0x4ee: 0x8132, 0x4ef: 0x8132, + 0x4f0: 0x8132, 0x4f1: 0x8132, 0x4f2: 0x8132, 0x4f3: 0x8132, 0x4f4: 0x8132, 0x4f5: 0x8132, + 0x4f6: 0x8133, 0x4f7: 0x8131, 0x4f8: 0x8131, 0x4f9: 0x812d, 0x4fb: 0x8132, + 0x4fc: 0x8134, 0x4fd: 0x812d, 0x4fe: 0x8132, 0x4ff: 0x812d, // Block 0x14, offset 0x500 - 0x500: 0x30f0, 0x501: 0x3401, 0x502: 0x30f5, 0x503: 0x3406, 0x504: 0x3109, 0x505: 0x341a, - 0x506: 0x3113, 0x507: 0x3424, 0x508: 0x3122, 0x509: 0x3433, 0x50a: 0x311d, 0x50b: 0x342e, - 0x50c: 0x3935, 0x50d: 0x3ac4, 0x50e: 0x3943, 0x50f: 0x3ad2, 0x510: 0x394a, 0x511: 0x3ad9, - 0x512: 0x3951, 0x513: 0x3ae0, 0x514: 0x314f, 0x515: 0x3460, 0x516: 0x3154, 0x517: 0x3465, - 0x518: 0x315e, 0x519: 0x346f, 0x51a: 0x46f1, 0x51b: 0x4782, 0x51c: 0x3997, 0x51d: 0x3b26, - 0x51e: 0x3177, 0x51f: 0x3488, 0x520: 0x3181, 0x521: 0x3492, 0x522: 0x4700, 0x523: 0x4791, - 0x524: 0x399e, 0x525: 0x3b2d, 0x526: 0x39a5, 0x527: 0x3b34, 0x528: 0x39ac, 0x529: 0x3b3b, - 0x52a: 0x3190, 0x52b: 0x34a1, 0x52c: 0x319a, 0x52d: 0x34b0, 0x52e: 0x31ae, 0x52f: 0x34c4, - 0x530: 0x31a9, 0x531: 0x34bf, 0x532: 0x31ea, 0x533: 0x3500, 0x534: 0x31f9, 0x535: 0x350f, - 0x536: 0x31f4, 0x537: 0x350a, 0x538: 0x39b3, 0x539: 0x3b42, 0x53a: 0x39ba, 0x53b: 0x3b49, - 0x53c: 0x31fe, 0x53d: 0x3514, 0x53e: 0x3203, 0x53f: 0x3519, + 0x500: 0x2f97, 0x501: 0x32a3, 0x502: 0x2fa1, 0x503: 0x32ad, 0x504: 0x2fa6, 0x505: 0x32b2, + 0x506: 0x2fab, 0x507: 0x32b7, 0x508: 0x38cc, 0x509: 0x3a5b, 0x50a: 0x2fc4, 0x50b: 0x32d0, + 0x50c: 0x2fce, 0x50d: 0x32da, 0x50e: 0x2fdd, 0x50f: 0x32e9, 0x510: 0x2fd3, 0x511: 0x32df, + 0x512: 0x2fd8, 0x513: 0x32e4, 0x514: 0x38ef, 0x515: 0x3a7e, 0x516: 0x38f6, 0x517: 0x3a85, + 0x518: 0x3019, 0x519: 0x3325, 0x51a: 0x301e, 0x51b: 0x332a, 0x51c: 0x3904, 0x51d: 0x3a93, + 0x51e: 0x3023, 0x51f: 0x332f, 0x520: 0x3032, 0x521: 0x333e, 0x522: 0x3050, 0x523: 0x335c, + 0x524: 0x305f, 0x525: 0x336b, 0x526: 0x3055, 0x527: 0x3361, 0x528: 0x3064, 0x529: 0x3370, + 0x52a: 0x3069, 0x52b: 0x3375, 0x52c: 0x30af, 0x52d: 0x33bb, 0x52e: 0x390b, 0x52f: 0x3a9a, + 0x530: 0x30b9, 0x531: 0x33ca, 0x532: 0x30c3, 0x533: 0x33d4, 0x534: 0x30cd, 0x535: 0x33de, + 0x536: 0x46c4, 0x537: 0x4755, 0x538: 0x3912, 0x539: 0x3aa1, 0x53a: 0x30e6, 0x53b: 0x33f7, + 0x53c: 0x30e1, 0x53d: 0x33f2, 0x53e: 0x30eb, 0x53f: 0x33fc, // Block 0x15, offset 0x540 - 0x540: 0x3208, 0x541: 0x351e, 0x542: 0x320d, 0x543: 0x3523, 0x544: 0x321c, 0x545: 0x3532, - 0x546: 0x3217, 0x547: 0x352d, 0x548: 0x3221, 0x549: 0x353c, 0x54a: 0x3226, 0x54b: 0x3541, - 0x54c: 0x322b, 0x54d: 0x3546, 0x54e: 0x3249, 0x54f: 0x3564, 0x550: 0x3262, 0x551: 0x3582, - 0x552: 0x3271, 0x553: 0x3591, 0x554: 0x3276, 0x555: 0x3596, 0x556: 0x337a, 0x557: 0x34a6, - 0x558: 0x3537, 0x559: 0x3573, 0x55a: 0x1be0, 0x55b: 0x42d7, - 0x560: 0x46a1, 0x561: 0x4732, 0x562: 0x2f83, 0x563: 0x328f, - 0x564: 0x3878, 0x565: 0x3a07, 0x566: 0x3871, 0x567: 0x3a00, 0x568: 0x3886, 0x569: 0x3a15, - 0x56a: 0x387f, 0x56b: 0x3a0e, 0x56c: 0x38be, 0x56d: 0x3a4d, 0x56e: 0x3894, 0x56f: 0x3a23, - 0x570: 0x388d, 0x571: 0x3a1c, 0x572: 0x38a2, 0x573: 0x3a31, 0x574: 0x389b, 0x575: 0x3a2a, - 0x576: 0x38c5, 0x577: 0x3a54, 0x578: 0x46b5, 0x579: 0x4746, 0x57a: 0x3000, 0x57b: 0x330c, - 0x57c: 0x2fec, 0x57d: 0x32f8, 0x57e: 0x38da, 0x57f: 0x3a69, + 0x540: 0x30f0, 0x541: 0x3401, 0x542: 0x30f5, 0x543: 0x3406, 0x544: 0x3109, 0x545: 0x341a, + 0x546: 0x3113, 0x547: 0x3424, 0x548: 0x3122, 0x549: 0x3433, 0x54a: 0x311d, 0x54b: 0x342e, + 0x54c: 0x3935, 0x54d: 0x3ac4, 0x54e: 0x3943, 0x54f: 0x3ad2, 0x550: 0x394a, 0x551: 0x3ad9, + 0x552: 0x3951, 0x553: 0x3ae0, 0x554: 0x314f, 0x555: 0x3460, 0x556: 0x3154, 0x557: 0x3465, + 0x558: 0x315e, 0x559: 0x346f, 0x55a: 0x46f1, 0x55b: 0x4782, 0x55c: 0x3997, 0x55d: 0x3b26, + 0x55e: 0x3177, 0x55f: 0x3488, 0x560: 0x3181, 0x561: 0x3492, 0x562: 0x4700, 0x563: 0x4791, + 0x564: 0x399e, 0x565: 0x3b2d, 0x566: 0x39a5, 0x567: 0x3b34, 0x568: 0x39ac, 0x569: 0x3b3b, + 0x56a: 0x3190, 0x56b: 0x34a1, 0x56c: 0x319a, 0x56d: 0x34b0, 0x56e: 0x31ae, 0x56f: 0x34c4, + 0x570: 0x31a9, 0x571: 0x34bf, 0x572: 0x31ea, 0x573: 0x3500, 0x574: 0x31f9, 0x575: 0x350f, + 0x576: 0x31f4, 0x577: 0x350a, 0x578: 0x39b3, 0x579: 0x3b42, 0x57a: 0x39ba, 0x57b: 0x3b49, + 0x57c: 0x31fe, 0x57d: 0x3514, 0x57e: 0x3203, 0x57f: 0x3519, // Block 0x16, offset 0x580 - 0x580: 0x38d3, 0x581: 0x3a62, 0x582: 0x38e8, 0x583: 0x3a77, 0x584: 0x38e1, 0x585: 0x3a70, - 0x586: 0x38fd, 0x587: 0x3a8c, 0x588: 0x3091, 0x589: 0x339d, 0x58a: 0x30a5, 0x58b: 0x33b1, - 0x58c: 0x46e7, 0x58d: 0x4778, 0x58e: 0x3136, 0x58f: 0x3447, 0x590: 0x3920, 0x591: 0x3aaf, - 0x592: 0x3919, 0x593: 0x3aa8, 0x594: 0x392e, 0x595: 0x3abd, 0x596: 0x3927, 0x597: 0x3ab6, - 0x598: 0x3989, 0x599: 0x3b18, 0x59a: 0x396d, 0x59b: 0x3afc, 0x59c: 0x3966, 0x59d: 0x3af5, - 0x59e: 0x397b, 0x59f: 0x3b0a, 0x5a0: 0x3974, 0x5a1: 0x3b03, 0x5a2: 0x3982, 0x5a3: 0x3b11, - 0x5a4: 0x31e5, 0x5a5: 0x34fb, 0x5a6: 0x31c7, 0x5a7: 0x34dd, 0x5a8: 0x39e4, 0x5a9: 0x3b73, - 0x5aa: 0x39dd, 0x5ab: 0x3b6c, 0x5ac: 0x39f2, 0x5ad: 0x3b81, 0x5ae: 0x39eb, 0x5af: 0x3b7a, - 0x5b0: 0x39f9, 0x5b1: 0x3b88, 0x5b2: 0x3230, 0x5b3: 0x354b, 0x5b4: 0x3258, 0x5b5: 0x3578, - 0x5b6: 0x3253, 0x5b7: 0x356e, 0x5b8: 0x323f, 0x5b9: 0x355a, + 0x580: 0x3208, 0x581: 0x351e, 0x582: 0x320d, 0x583: 0x3523, 0x584: 0x321c, 0x585: 0x3532, + 0x586: 0x3217, 0x587: 0x352d, 0x588: 0x3221, 0x589: 0x353c, 0x58a: 0x3226, 0x58b: 0x3541, + 0x58c: 0x322b, 0x58d: 0x3546, 0x58e: 0x3249, 0x58f: 0x3564, 0x590: 0x3262, 0x591: 0x3582, + 0x592: 0x3271, 0x593: 0x3591, 0x594: 0x3276, 0x595: 0x3596, 0x596: 0x337a, 0x597: 0x34a6, + 0x598: 0x3537, 0x599: 0x3573, 0x59a: 0x1be0, 0x59b: 0x42d7, + 0x5a0: 0x46a1, 0x5a1: 0x4732, 0x5a2: 0x2f83, 0x5a3: 0x328f, + 0x5a4: 0x3878, 0x5a5: 0x3a07, 0x5a6: 0x3871, 0x5a7: 0x3a00, 0x5a8: 0x3886, 0x5a9: 0x3a15, + 0x5aa: 0x387f, 0x5ab: 0x3a0e, 0x5ac: 0x38be, 0x5ad: 0x3a4d, 0x5ae: 0x3894, 0x5af: 0x3a23, + 0x5b0: 0x388d, 0x5b1: 0x3a1c, 0x5b2: 0x38a2, 0x5b3: 0x3a31, 0x5b4: 0x389b, 0x5b5: 0x3a2a, + 0x5b6: 0x38c5, 0x5b7: 0x3a54, 0x5b8: 0x46b5, 0x5b9: 0x4746, 0x5ba: 0x3000, 0x5bb: 0x330c, + 0x5bc: 0x2fec, 0x5bd: 0x32f8, 0x5be: 0x38da, 0x5bf: 0x3a69, // Block 0x17, offset 0x5c0 - 0x5c0: 0x4804, 0x5c1: 0x480a, 0x5c2: 0x491e, 0x5c3: 0x4936, 0x5c4: 0x4926, 0x5c5: 0x493e, - 0x5c6: 0x492e, 0x5c7: 0x4946, 0x5c8: 0x47aa, 0x5c9: 0x47b0, 0x5ca: 0x488e, 0x5cb: 0x48a6, - 0x5cc: 0x4896, 0x5cd: 0x48ae, 0x5ce: 0x489e, 0x5cf: 0x48b6, 0x5d0: 0x4816, 0x5d1: 0x481c, - 0x5d2: 0x3db8, 0x5d3: 0x3dc8, 0x5d4: 0x3dc0, 0x5d5: 0x3dd0, - 0x5d8: 0x47b6, 0x5d9: 0x47bc, 0x5da: 0x3ce8, 0x5db: 0x3cf8, 0x5dc: 0x3cf0, 0x5dd: 0x3d00, - 0x5e0: 0x482e, 0x5e1: 0x4834, 0x5e2: 0x494e, 0x5e3: 0x4966, - 0x5e4: 0x4956, 0x5e5: 0x496e, 0x5e6: 0x495e, 0x5e7: 0x4976, 0x5e8: 0x47c2, 0x5e9: 0x47c8, - 0x5ea: 0x48be, 0x5eb: 0x48d6, 0x5ec: 0x48c6, 0x5ed: 0x48de, 0x5ee: 0x48ce, 0x5ef: 0x48e6, - 0x5f0: 0x4846, 0x5f1: 0x484c, 0x5f2: 0x3e18, 0x5f3: 0x3e30, 0x5f4: 0x3e20, 0x5f5: 0x3e38, - 0x5f6: 0x3e28, 0x5f7: 0x3e40, 0x5f8: 0x47ce, 0x5f9: 0x47d4, 0x5fa: 0x3d18, 0x5fb: 0x3d30, - 0x5fc: 0x3d20, 0x5fd: 0x3d38, 0x5fe: 0x3d28, 0x5ff: 0x3d40, + 0x5c0: 0x38d3, 0x5c1: 0x3a62, 0x5c2: 0x38e8, 0x5c3: 0x3a77, 0x5c4: 0x38e1, 0x5c5: 0x3a70, + 0x5c6: 0x38fd, 0x5c7: 0x3a8c, 0x5c8: 0x3091, 0x5c9: 0x339d, 0x5ca: 0x30a5, 0x5cb: 0x33b1, + 0x5cc: 0x46e7, 0x5cd: 0x4778, 0x5ce: 0x3136, 0x5cf: 0x3447, 0x5d0: 0x3920, 0x5d1: 0x3aaf, + 0x5d2: 0x3919, 0x5d3: 0x3aa8, 0x5d4: 0x392e, 0x5d5: 0x3abd, 0x5d6: 0x3927, 0x5d7: 0x3ab6, + 0x5d8: 0x3989, 0x5d9: 0x3b18, 0x5da: 0x396d, 0x5db: 0x3afc, 0x5dc: 0x3966, 0x5dd: 0x3af5, + 0x5de: 0x397b, 0x5df: 0x3b0a, 0x5e0: 0x3974, 0x5e1: 0x3b03, 0x5e2: 0x3982, 0x5e3: 0x3b11, + 0x5e4: 0x31e5, 0x5e5: 0x34fb, 0x5e6: 0x31c7, 0x5e7: 0x34dd, 0x5e8: 0x39e4, 0x5e9: 0x3b73, + 0x5ea: 0x39dd, 0x5eb: 0x3b6c, 0x5ec: 0x39f2, 0x5ed: 0x3b81, 0x5ee: 0x39eb, 0x5ef: 0x3b7a, + 0x5f0: 0x39f9, 0x5f1: 0x3b88, 0x5f2: 0x3230, 0x5f3: 0x354b, 0x5f4: 0x3258, 0x5f5: 0x3578, + 0x5f6: 0x3253, 0x5f7: 0x356e, 0x5f8: 0x323f, 0x5f9: 0x355a, // Block 0x18, offset 0x600 - 0x600: 0x4852, 0x601: 0x4858, 0x602: 0x3e48, 0x603: 0x3e58, 0x604: 0x3e50, 0x605: 0x3e60, - 0x608: 0x47da, 0x609: 0x47e0, 0x60a: 0x3d48, 0x60b: 0x3d58, - 0x60c: 0x3d50, 0x60d: 0x3d60, 0x610: 0x4864, 0x611: 0x486a, - 0x612: 0x3e80, 0x613: 0x3e98, 0x614: 0x3e88, 0x615: 0x3ea0, 0x616: 0x3e90, 0x617: 0x3ea8, - 0x619: 0x47e6, 0x61b: 0x3d68, 0x61d: 0x3d70, - 0x61f: 0x3d78, 0x620: 0x487c, 0x621: 0x4882, 0x622: 0x497e, 0x623: 0x4996, - 0x624: 0x4986, 0x625: 0x499e, 0x626: 0x498e, 0x627: 0x49a6, 0x628: 0x47ec, 0x629: 0x47f2, - 0x62a: 0x48ee, 0x62b: 0x4906, 0x62c: 0x48f6, 0x62d: 0x490e, 0x62e: 0x48fe, 0x62f: 0x4916, - 0x630: 0x47f8, 0x631: 0x431e, 0x632: 0x3691, 0x633: 0x4324, 0x634: 0x4822, 0x635: 0x432a, - 0x636: 0x36a3, 0x637: 0x4330, 0x638: 0x36c1, 0x639: 0x4336, 0x63a: 0x36d9, 0x63b: 0x433c, - 0x63c: 0x4870, 0x63d: 0x4342, + 0x600: 0x4804, 0x601: 0x480a, 0x602: 0x491e, 0x603: 0x4936, 0x604: 0x4926, 0x605: 0x493e, + 0x606: 0x492e, 0x607: 0x4946, 0x608: 0x47aa, 0x609: 0x47b0, 0x60a: 0x488e, 0x60b: 0x48a6, + 0x60c: 0x4896, 0x60d: 0x48ae, 0x60e: 0x489e, 0x60f: 0x48b6, 0x610: 0x4816, 0x611: 0x481c, + 0x612: 0x3db8, 0x613: 0x3dc8, 0x614: 0x3dc0, 0x615: 0x3dd0, + 0x618: 0x47b6, 0x619: 0x47bc, 0x61a: 0x3ce8, 0x61b: 0x3cf8, 0x61c: 0x3cf0, 0x61d: 0x3d00, + 0x620: 0x482e, 0x621: 0x4834, 0x622: 0x494e, 0x623: 0x4966, + 0x624: 0x4956, 0x625: 0x496e, 0x626: 0x495e, 0x627: 0x4976, 0x628: 0x47c2, 0x629: 0x47c8, + 0x62a: 0x48be, 0x62b: 0x48d6, 0x62c: 0x48c6, 0x62d: 0x48de, 0x62e: 0x48ce, 0x62f: 0x48e6, + 0x630: 0x4846, 0x631: 0x484c, 0x632: 0x3e18, 0x633: 0x3e30, 0x634: 0x3e20, 0x635: 0x3e38, + 0x636: 0x3e28, 0x637: 0x3e40, 0x638: 0x47ce, 0x639: 0x47d4, 0x63a: 0x3d18, 0x63b: 0x3d30, + 0x63c: 0x3d20, 0x63d: 0x3d38, 0x63e: 0x3d28, 0x63f: 0x3d40, // Block 0x19, offset 0x640 - 0x640: 0x3da0, 0x641: 0x3da8, 0x642: 0x4184, 0x643: 0x41a2, 0x644: 0x418e, 0x645: 0x41ac, - 0x646: 0x4198, 0x647: 0x41b6, 0x648: 0x3cd8, 0x649: 0x3ce0, 0x64a: 0x40d0, 0x64b: 0x40ee, - 0x64c: 0x40da, 0x64d: 0x40f8, 0x64e: 0x40e4, 0x64f: 0x4102, 0x650: 0x3de8, 0x651: 0x3df0, - 0x652: 0x41c0, 0x653: 0x41de, 0x654: 0x41ca, 0x655: 0x41e8, 0x656: 0x41d4, 0x657: 0x41f2, - 0x658: 0x3d08, 0x659: 0x3d10, 0x65a: 0x410c, 0x65b: 0x412a, 0x65c: 0x4116, 0x65d: 0x4134, - 0x65e: 0x4120, 0x65f: 0x413e, 0x660: 0x3ec0, 0x661: 0x3ec8, 0x662: 0x41fc, 0x663: 0x421a, - 0x664: 0x4206, 0x665: 0x4224, 0x666: 0x4210, 0x667: 0x422e, 0x668: 0x3d80, 0x669: 0x3d88, - 0x66a: 0x4148, 0x66b: 0x4166, 0x66c: 0x4152, 0x66d: 0x4170, 0x66e: 0x415c, 0x66f: 0x417a, - 0x670: 0x3685, 0x671: 0x367f, 0x672: 0x3d90, 0x673: 0x368b, 0x674: 0x3d98, - 0x676: 0x4810, 0x677: 0x3db0, 0x678: 0x35f5, 0x679: 0x35ef, 0x67a: 0x35e3, 0x67b: 0x42ee, - 0x67c: 0x35fb, 0x67d: 0x4287, 0x67e: 0x01d3, 0x67f: 0x4287, + 0x640: 0x4852, 0x641: 0x4858, 0x642: 0x3e48, 0x643: 0x3e58, 0x644: 0x3e50, 0x645: 0x3e60, + 0x648: 0x47da, 0x649: 0x47e0, 0x64a: 0x3d48, 0x64b: 0x3d58, + 0x64c: 0x3d50, 0x64d: 0x3d60, 0x650: 0x4864, 0x651: 0x486a, + 0x652: 0x3e80, 0x653: 0x3e98, 0x654: 0x3e88, 0x655: 0x3ea0, 0x656: 0x3e90, 0x657: 0x3ea8, + 0x659: 0x47e6, 0x65b: 0x3d68, 0x65d: 0x3d70, + 0x65f: 0x3d78, 0x660: 0x487c, 0x661: 0x4882, 0x662: 0x497e, 0x663: 0x4996, + 0x664: 0x4986, 0x665: 0x499e, 0x666: 0x498e, 0x667: 0x49a6, 0x668: 0x47ec, 0x669: 0x47f2, + 0x66a: 0x48ee, 0x66b: 0x4906, 0x66c: 0x48f6, 0x66d: 0x490e, 0x66e: 0x48fe, 0x66f: 0x4916, + 0x670: 0x47f8, 0x671: 0x431e, 0x672: 0x3691, 0x673: 0x4324, 0x674: 0x4822, 0x675: 0x432a, + 0x676: 0x36a3, 0x677: 0x4330, 0x678: 0x36c1, 0x679: 0x4336, 0x67a: 0x36d9, 0x67b: 0x433c, + 0x67c: 0x4870, 0x67d: 0x4342, // Block 0x1a, offset 0x680 - 0x680: 0x42a0, 0x681: 0x4482, 0x682: 0x3dd8, 0x683: 0x369d, 0x684: 0x3de0, - 0x686: 0x483a, 0x687: 0x3df8, 0x688: 0x3601, 0x689: 0x42f4, 0x68a: 0x360d, 0x68b: 0x42fa, - 0x68c: 0x3619, 0x68d: 0x4489, 0x68e: 0x4490, 0x68f: 0x4497, 0x690: 0x36b5, 0x691: 0x36af, - 0x692: 0x3e00, 0x693: 0x44e4, 0x696: 0x36bb, 0x697: 0x3e10, - 0x698: 0x3631, 0x699: 0x362b, 0x69a: 0x361f, 0x69b: 0x4300, 0x69d: 0x449e, - 0x69e: 0x44a5, 0x69f: 0x44ac, 0x6a0: 0x36eb, 0x6a1: 0x36e5, 0x6a2: 0x3e68, 0x6a3: 0x44ec, - 0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b, - 0x6aa: 0x364f, 0x6ab: 0x430c, 0x6ac: 0x3649, 0x6ad: 0x4474, 0x6ae: 0x447b, 0x6af: 0x0081, - 0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8, - 0x6b6: 0x4888, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x4306, 0x6ba: 0x366d, 0x6bb: 0x4318, - 0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c, + 0x680: 0x3da0, 0x681: 0x3da8, 0x682: 0x4184, 0x683: 0x41a2, 0x684: 0x418e, 0x685: 0x41ac, + 0x686: 0x4198, 0x687: 0x41b6, 0x688: 0x3cd8, 0x689: 0x3ce0, 0x68a: 0x40d0, 0x68b: 0x40ee, + 0x68c: 0x40da, 0x68d: 0x40f8, 0x68e: 0x40e4, 0x68f: 0x4102, 0x690: 0x3de8, 0x691: 0x3df0, + 0x692: 0x41c0, 0x693: 0x41de, 0x694: 0x41ca, 0x695: 0x41e8, 0x696: 0x41d4, 0x697: 0x41f2, + 0x698: 0x3d08, 0x699: 0x3d10, 0x69a: 0x410c, 0x69b: 0x412a, 0x69c: 0x4116, 0x69d: 0x4134, + 0x69e: 0x4120, 0x69f: 0x413e, 0x6a0: 0x3ec0, 0x6a1: 0x3ec8, 0x6a2: 0x41fc, 0x6a3: 0x421a, + 0x6a4: 0x4206, 0x6a5: 0x4224, 0x6a6: 0x4210, 0x6a7: 0x422e, 0x6a8: 0x3d80, 0x6a9: 0x3d88, + 0x6aa: 0x4148, 0x6ab: 0x4166, 0x6ac: 0x4152, 0x6ad: 0x4170, 0x6ae: 0x415c, 0x6af: 0x417a, + 0x6b0: 0x3685, 0x6b1: 0x367f, 0x6b2: 0x3d90, 0x6b3: 0x368b, 0x6b4: 0x3d98, + 0x6b6: 0x4810, 0x6b7: 0x3db0, 0x6b8: 0x35f5, 0x6b9: 0x35ef, 0x6ba: 0x35e3, 0x6bb: 0x42ee, + 0x6bc: 0x35fb, 0x6bd: 0x4287, 0x6be: 0x01d3, 0x6bf: 0x4287, // Block 0x1b, offset 0x6c0 - 0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8, - 0x6c6: 0x1bec, 0x6c7: 0x00e9, 0x6c9: 0x1c58, 0x6ca: 0x008f, 0x6cb: 0x0051, - 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053, - 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x198d, - 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065, - 0x6e0: 0x199f, 0x6e1: 0x1bc8, 0x6e2: 0x19a8, - 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075, - 0x6ea: 0x0057, 0x6eb: 0x42d2, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b, - 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215, - 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1b98, - 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0, + 0x6c0: 0x42a0, 0x6c1: 0x4482, 0x6c2: 0x3dd8, 0x6c3: 0x369d, 0x6c4: 0x3de0, + 0x6c6: 0x483a, 0x6c7: 0x3df8, 0x6c8: 0x3601, 0x6c9: 0x42f4, 0x6ca: 0x360d, 0x6cb: 0x42fa, + 0x6cc: 0x3619, 0x6cd: 0x4489, 0x6ce: 0x4490, 0x6cf: 0x4497, 0x6d0: 0x36b5, 0x6d1: 0x36af, + 0x6d2: 0x3e00, 0x6d3: 0x44e4, 0x6d6: 0x36bb, 0x6d7: 0x3e10, + 0x6d8: 0x3631, 0x6d9: 0x362b, 0x6da: 0x361f, 0x6db: 0x4300, 0x6dd: 0x449e, + 0x6de: 0x44a5, 0x6df: 0x44ac, 0x6e0: 0x36eb, 0x6e1: 0x36e5, 0x6e2: 0x3e68, 0x6e3: 0x44ec, + 0x6e4: 0x36cd, 0x6e5: 0x36d3, 0x6e6: 0x36f1, 0x6e7: 0x3e78, 0x6e8: 0x3661, 0x6e9: 0x365b, + 0x6ea: 0x364f, 0x6eb: 0x430c, 0x6ec: 0x3649, 0x6ed: 0x4474, 0x6ee: 0x447b, 0x6ef: 0x0081, + 0x6f2: 0x3eb0, 0x6f3: 0x36f7, 0x6f4: 0x3eb8, + 0x6f6: 0x4888, 0x6f7: 0x3ed0, 0x6f8: 0x363d, 0x6f9: 0x4306, 0x6fa: 0x366d, 0x6fb: 0x4318, + 0x6fc: 0x3679, 0x6fd: 0x425a, 0x6fe: 0x428c, // Block 0x1c, offset 0x700 - 0x700: 0x0463, 0x705: 0x0049, - 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095, - 0x710: 0x222e, 0x711: 0x223a, - 0x712: 0x22ee, 0x713: 0x2216, 0x714: 0x229a, 0x715: 0x2222, 0x716: 0x22a0, 0x717: 0x22b8, - 0x718: 0x22c4, 0x719: 0x2228, 0x71a: 0x22ca, 0x71b: 0x2234, 0x71c: 0x22be, 0x71d: 0x22d0, - 0x71e: 0x22d6, 0x71f: 0x1cbc, 0x720: 0x0053, 0x721: 0x195a, 0x722: 0x1ba4, 0x723: 0x1963, - 0x724: 0x006d, 0x725: 0x19ab, 0x726: 0x1bd0, 0x727: 0x1d48, 0x728: 0x1966, 0x729: 0x0071, - 0x72a: 0x19b7, 0x72b: 0x1bd4, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b, - 0x730: 0x0093, 0x731: 0x19e4, 0x732: 0x1c18, 0x733: 0x19ed, 0x734: 0x00ad, 0x735: 0x1a62, - 0x736: 0x1c4c, 0x737: 0x1d5c, 0x738: 0x19f0, 0x739: 0x00b1, 0x73a: 0x1a65, 0x73b: 0x1c50, - 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b, + 0x700: 0x1bd8, 0x701: 0x1bdc, 0x702: 0x0047, 0x703: 0x1c54, 0x705: 0x1be8, + 0x706: 0x1bec, 0x707: 0x00e9, 0x709: 0x1c58, 0x70a: 0x008f, 0x70b: 0x0051, + 0x70c: 0x0051, 0x70d: 0x0051, 0x70e: 0x0091, 0x70f: 0x00da, 0x710: 0x0053, 0x711: 0x0053, + 0x712: 0x0059, 0x713: 0x0099, 0x715: 0x005d, 0x716: 0x198d, + 0x719: 0x0061, 0x71a: 0x0063, 0x71b: 0x0065, 0x71c: 0x0065, 0x71d: 0x0065, + 0x720: 0x199f, 0x721: 0x1bc8, 0x722: 0x19a8, + 0x724: 0x0075, 0x726: 0x01b8, 0x728: 0x0075, + 0x72a: 0x0057, 0x72b: 0x42d2, 0x72c: 0x0045, 0x72d: 0x0047, 0x72f: 0x008b, + 0x730: 0x004b, 0x731: 0x004d, 0x733: 0x005b, 0x734: 0x009f, 0x735: 0x0215, + 0x736: 0x0218, 0x737: 0x021b, 0x738: 0x021e, 0x739: 0x0093, 0x73b: 0x1b98, + 0x73c: 0x01e8, 0x73d: 0x01c1, 0x73e: 0x0179, 0x73f: 0x01a0, // Block 0x1d, offset 0x740 - 0x741: 0x3c06, 0x743: 0xa000, 0x744: 0x3c0d, 0x745: 0xa000, - 0x747: 0x3c14, 0x748: 0xa000, 0x749: 0x3c1b, - 0x74d: 0xa000, - 0x760: 0x2f65, 0x761: 0xa000, 0x762: 0x3c29, - 0x764: 0xa000, 0x765: 0xa000, - 0x76d: 0x3c22, 0x76e: 0x2f60, 0x76f: 0x2f6a, - 0x770: 0x3c30, 0x771: 0x3c37, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c3e, 0x775: 0x3c45, - 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c4c, 0x779: 0x3c53, 0x77a: 0xa000, 0x77b: 0xa000, - 0x77c: 0xa000, 0x77d: 0xa000, + 0x740: 0x0463, 0x745: 0x0049, + 0x746: 0x0089, 0x747: 0x008b, 0x748: 0x0093, 0x749: 0x0095, + 0x750: 0x222e, 0x751: 0x223a, + 0x752: 0x22ee, 0x753: 0x2216, 0x754: 0x229a, 0x755: 0x2222, 0x756: 0x22a0, 0x757: 0x22b8, + 0x758: 0x22c4, 0x759: 0x2228, 0x75a: 0x22ca, 0x75b: 0x2234, 0x75c: 0x22be, 0x75d: 0x22d0, + 0x75e: 0x22d6, 0x75f: 0x1cbc, 0x760: 0x0053, 0x761: 0x195a, 0x762: 0x1ba4, 0x763: 0x1963, + 0x764: 0x006d, 0x765: 0x19ab, 0x766: 0x1bd0, 0x767: 0x1d48, 0x768: 0x1966, 0x769: 0x0071, + 0x76a: 0x19b7, 0x76b: 0x1bd4, 0x76c: 0x0059, 0x76d: 0x0047, 0x76e: 0x0049, 0x76f: 0x005b, + 0x770: 0x0093, 0x771: 0x19e4, 0x772: 0x1c18, 0x773: 0x19ed, 0x774: 0x00ad, 0x775: 0x1a62, + 0x776: 0x1c4c, 0x777: 0x1d5c, 0x778: 0x19f0, 0x779: 0x00b1, 0x77a: 0x1a65, 0x77b: 0x1c50, + 0x77c: 0x0099, 0x77d: 0x0087, 0x77e: 0x0089, 0x77f: 0x009b, // Block 0x1e, offset 0x780 - 0x780: 0x3c5a, 0x781: 0x3c61, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3c76, 0x785: 0x3c7d, - 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3c84, 0x789: 0x3c8b, - 0x791: 0xa000, - 0x792: 0xa000, - 0x7a2: 0xa000, - 0x7a8: 0xa000, 0x7a9: 0xa000, - 0x7ab: 0xa000, 0x7ac: 0x3ca0, 0x7ad: 0x3ca7, 0x7ae: 0x3cae, 0x7af: 0x3cb5, - 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000, + 0x781: 0x3c06, 0x783: 0xa000, 0x784: 0x3c0d, 0x785: 0xa000, + 0x787: 0x3c14, 0x788: 0xa000, 0x789: 0x3c1b, + 0x78d: 0xa000, + 0x7a0: 0x2f65, 0x7a1: 0xa000, 0x7a2: 0x3c29, + 0x7a4: 0xa000, 0x7a5: 0xa000, + 0x7ad: 0x3c22, 0x7ae: 0x2f60, 0x7af: 0x2f6a, + 0x7b0: 0x3c30, 0x7b1: 0x3c37, 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0x3c3e, 0x7b5: 0x3c45, + 0x7b6: 0xa000, 0x7b7: 0xa000, 0x7b8: 0x3c4c, 0x7b9: 0x3c53, 0x7ba: 0xa000, 0x7bb: 0xa000, + 0x7bc: 0xa000, 0x7bd: 0xa000, // Block 0x1f, offset 0x7c0 - 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029, - 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1882, - 0x7ea: 0x1885, 0x7eb: 0x1888, 0x7ec: 0x188b, 0x7ed: 0x188e, 0x7ee: 0x1891, 0x7ef: 0x1894, - 0x7f0: 0x1897, 0x7f1: 0x189a, 0x7f2: 0x189d, 0x7f3: 0x18a6, 0x7f4: 0x1a68, 0x7f5: 0x1a6c, - 0x7f6: 0x1a70, 0x7f7: 0x1a74, 0x7f8: 0x1a78, 0x7f9: 0x1a7c, 0x7fa: 0x1a80, 0x7fb: 0x1a84, - 0x7fc: 0x1a88, 0x7fd: 0x1c80, 0x7fe: 0x1c85, 0x7ff: 0x1c8a, + 0x7c0: 0x3c5a, 0x7c1: 0x3c61, 0x7c2: 0xa000, 0x7c3: 0xa000, 0x7c4: 0x3c76, 0x7c5: 0x3c7d, + 0x7c6: 0xa000, 0x7c7: 0xa000, 0x7c8: 0x3c84, 0x7c9: 0x3c8b, + 0x7d1: 0xa000, + 0x7d2: 0xa000, + 0x7e2: 0xa000, + 0x7e8: 0xa000, 0x7e9: 0xa000, + 0x7eb: 0xa000, 0x7ec: 0x3ca0, 0x7ed: 0x3ca7, 0x7ee: 0x3cae, 0x7ef: 0x3cb5, + 0x7f2: 0xa000, 0x7f3: 0xa000, 0x7f4: 0xa000, 0x7f5: 0xa000, // Block 0x20, offset 0x800 - 0x800: 0x1c8f, 0x801: 0x1c94, 0x802: 0x1c99, 0x803: 0x1c9e, 0x804: 0x1ca3, 0x805: 0x1ca8, - 0x806: 0x1cad, 0x807: 0x1cb2, 0x808: 0x187f, 0x809: 0x18a3, 0x80a: 0x18c7, 0x80b: 0x18eb, - 0x80c: 0x190f, 0x80d: 0x1918, 0x80e: 0x191e, 0x80f: 0x1924, 0x810: 0x192a, 0x811: 0x1b60, - 0x812: 0x1b64, 0x813: 0x1b68, 0x814: 0x1b6c, 0x815: 0x1b70, 0x816: 0x1b74, 0x817: 0x1b78, - 0x818: 0x1b7c, 0x819: 0x1b80, 0x81a: 0x1b84, 0x81b: 0x1b88, 0x81c: 0x1af4, 0x81d: 0x1af8, - 0x81e: 0x1afc, 0x81f: 0x1b00, 0x820: 0x1b04, 0x821: 0x1b08, 0x822: 0x1b0c, 0x823: 0x1b10, - 0x824: 0x1b14, 0x825: 0x1b18, 0x826: 0x1b1c, 0x827: 0x1b20, 0x828: 0x1b24, 0x829: 0x1b28, - 0x82a: 0x1b2c, 0x82b: 0x1b30, 0x82c: 0x1b34, 0x82d: 0x1b38, 0x82e: 0x1b3c, 0x82f: 0x1b40, - 0x830: 0x1b44, 0x831: 0x1b48, 0x832: 0x1b4c, 0x833: 0x1b50, 0x834: 0x1b54, 0x835: 0x1b58, - 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d, - 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055, + 0x820: 0x0023, 0x821: 0x0025, 0x822: 0x0027, 0x823: 0x0029, + 0x824: 0x002b, 0x825: 0x002d, 0x826: 0x002f, 0x827: 0x0031, 0x828: 0x0033, 0x829: 0x1882, + 0x82a: 0x1885, 0x82b: 0x1888, 0x82c: 0x188b, 0x82d: 0x188e, 0x82e: 0x1891, 0x82f: 0x1894, + 0x830: 0x1897, 0x831: 0x189a, 0x832: 0x189d, 0x833: 0x18a6, 0x834: 0x1a68, 0x835: 0x1a6c, + 0x836: 0x1a70, 0x837: 0x1a74, 0x838: 0x1a78, 0x839: 0x1a7c, 0x83a: 0x1a80, 0x83b: 0x1a84, + 0x83c: 0x1a88, 0x83d: 0x1c80, 0x83e: 0x1c85, 0x83f: 0x1c8a, // Block 0x21, offset 0x840 - 0x840: 0x06bf, 0x841: 0x06e3, 0x842: 0x06ef, 0x843: 0x06ff, 0x844: 0x0707, 0x845: 0x0713, - 0x846: 0x071b, 0x847: 0x0723, 0x848: 0x072f, 0x849: 0x0783, 0x84a: 0x079b, 0x84b: 0x07ab, - 0x84c: 0x07bb, 0x84d: 0x07cb, 0x84e: 0x07db, 0x84f: 0x07fb, 0x850: 0x07ff, 0x851: 0x0803, - 0x852: 0x0837, 0x853: 0x085f, 0x854: 0x086f, 0x855: 0x0877, 0x856: 0x087b, 0x857: 0x0887, - 0x858: 0x08a3, 0x859: 0x08a7, 0x85a: 0x08bf, 0x85b: 0x08c3, 0x85c: 0x08cb, 0x85d: 0x08db, - 0x85e: 0x0977, 0x85f: 0x098b, 0x860: 0x09cb, 0x861: 0x09df, 0x862: 0x09e7, 0x863: 0x09eb, - 0x864: 0x09fb, 0x865: 0x0a17, 0x866: 0x0a43, 0x867: 0x0a4f, 0x868: 0x0a6f, 0x869: 0x0a7b, - 0x86a: 0x0a7f, 0x86b: 0x0a83, 0x86c: 0x0a9b, 0x86d: 0x0a9f, 0x86e: 0x0acb, 0x86f: 0x0ad7, - 0x870: 0x0adf, 0x871: 0x0ae7, 0x872: 0x0af7, 0x873: 0x0aff, 0x874: 0x0b07, 0x875: 0x0b33, - 0x876: 0x0b37, 0x877: 0x0b3f, 0x878: 0x0b43, 0x879: 0x0b4b, 0x87a: 0x0b53, 0x87b: 0x0b63, - 0x87c: 0x0b7f, 0x87d: 0x0bf7, 0x87e: 0x0c0b, 0x87f: 0x0c0f, + 0x840: 0x1c8f, 0x841: 0x1c94, 0x842: 0x1c99, 0x843: 0x1c9e, 0x844: 0x1ca3, 0x845: 0x1ca8, + 0x846: 0x1cad, 0x847: 0x1cb2, 0x848: 0x187f, 0x849: 0x18a3, 0x84a: 0x18c7, 0x84b: 0x18eb, + 0x84c: 0x190f, 0x84d: 0x1918, 0x84e: 0x191e, 0x84f: 0x1924, 0x850: 0x192a, 0x851: 0x1b60, + 0x852: 0x1b64, 0x853: 0x1b68, 0x854: 0x1b6c, 0x855: 0x1b70, 0x856: 0x1b74, 0x857: 0x1b78, + 0x858: 0x1b7c, 0x859: 0x1b80, 0x85a: 0x1b84, 0x85b: 0x1b88, 0x85c: 0x1af4, 0x85d: 0x1af8, + 0x85e: 0x1afc, 0x85f: 0x1b00, 0x860: 0x1b04, 0x861: 0x1b08, 0x862: 0x1b0c, 0x863: 0x1b10, + 0x864: 0x1b14, 0x865: 0x1b18, 0x866: 0x1b1c, 0x867: 0x1b20, 0x868: 0x1b24, 0x869: 0x1b28, + 0x86a: 0x1b2c, 0x86b: 0x1b30, 0x86c: 0x1b34, 0x86d: 0x1b38, 0x86e: 0x1b3c, 0x86f: 0x1b40, + 0x870: 0x1b44, 0x871: 0x1b48, 0x872: 0x1b4c, 0x873: 0x1b50, 0x874: 0x1b54, 0x875: 0x1b58, + 0x876: 0x0043, 0x877: 0x0045, 0x878: 0x0047, 0x879: 0x0049, 0x87a: 0x004b, 0x87b: 0x004d, + 0x87c: 0x004f, 0x87d: 0x0051, 0x87e: 0x0053, 0x87f: 0x0055, // Block 0x22, offset 0x880 - 0x880: 0x0c8f, 0x881: 0x0c93, 0x882: 0x0ca7, 0x883: 0x0cab, 0x884: 0x0cb3, 0x885: 0x0cbb, - 0x886: 0x0cc3, 0x887: 0x0ccf, 0x888: 0x0cf7, 0x889: 0x0d07, 0x88a: 0x0d1b, 0x88b: 0x0d8b, - 0x88c: 0x0d97, 0x88d: 0x0da7, 0x88e: 0x0db3, 0x88f: 0x0dbf, 0x890: 0x0dc7, 0x891: 0x0dcb, - 0x892: 0x0dcf, 0x893: 0x0dd3, 0x894: 0x0dd7, 0x895: 0x0e8f, 0x896: 0x0ed7, 0x897: 0x0ee3, - 0x898: 0x0ee7, 0x899: 0x0eeb, 0x89a: 0x0eef, 0x89b: 0x0ef7, 0x89c: 0x0efb, 0x89d: 0x0f0f, - 0x89e: 0x0f2b, 0x89f: 0x0f33, 0x8a0: 0x0f73, 0x8a1: 0x0f77, 0x8a2: 0x0f7f, 0x8a3: 0x0f83, - 0x8a4: 0x0f8b, 0x8a5: 0x0f8f, 0x8a6: 0x0fb3, 0x8a7: 0x0fb7, 0x8a8: 0x0fd3, 0x8a9: 0x0fd7, - 0x8aa: 0x0fdb, 0x8ab: 0x0fdf, 0x8ac: 0x0ff3, 0x8ad: 0x1017, 0x8ae: 0x101b, 0x8af: 0x101f, - 0x8b0: 0x1043, 0x8b1: 0x1083, 0x8b2: 0x1087, 0x8b3: 0x10a7, 0x8b4: 0x10b7, 0x8b5: 0x10bf, - 0x8b6: 0x10df, 0x8b7: 0x1103, 0x8b8: 0x1147, 0x8b9: 0x114f, 0x8ba: 0x1163, 0x8bb: 0x116f, - 0x8bc: 0x1177, 0x8bd: 0x117f, 0x8be: 0x1183, 0x8bf: 0x1187, + 0x880: 0x06bf, 0x881: 0x06e3, 0x882: 0x06ef, 0x883: 0x06ff, 0x884: 0x0707, 0x885: 0x0713, + 0x886: 0x071b, 0x887: 0x0723, 0x888: 0x072f, 0x889: 0x0783, 0x88a: 0x079b, 0x88b: 0x07ab, + 0x88c: 0x07bb, 0x88d: 0x07cb, 0x88e: 0x07db, 0x88f: 0x07fb, 0x890: 0x07ff, 0x891: 0x0803, + 0x892: 0x0837, 0x893: 0x085f, 0x894: 0x086f, 0x895: 0x0877, 0x896: 0x087b, 0x897: 0x0887, + 0x898: 0x08a3, 0x899: 0x08a7, 0x89a: 0x08bf, 0x89b: 0x08c3, 0x89c: 0x08cb, 0x89d: 0x08db, + 0x89e: 0x0977, 0x89f: 0x098b, 0x8a0: 0x09cb, 0x8a1: 0x09df, 0x8a2: 0x09e7, 0x8a3: 0x09eb, + 0x8a4: 0x09fb, 0x8a5: 0x0a17, 0x8a6: 0x0a43, 0x8a7: 0x0a4f, 0x8a8: 0x0a6f, 0x8a9: 0x0a7b, + 0x8aa: 0x0a7f, 0x8ab: 0x0a83, 0x8ac: 0x0a9b, 0x8ad: 0x0a9f, 0x8ae: 0x0acb, 0x8af: 0x0ad7, + 0x8b0: 0x0adf, 0x8b1: 0x0ae7, 0x8b2: 0x0af7, 0x8b3: 0x0aff, 0x8b4: 0x0b07, 0x8b5: 0x0b33, + 0x8b6: 0x0b37, 0x8b7: 0x0b3f, 0x8b8: 0x0b43, 0x8b9: 0x0b4b, 0x8ba: 0x0b53, 0x8bb: 0x0b63, + 0x8bc: 0x0b7f, 0x8bd: 0x0bf7, 0x8be: 0x0c0b, 0x8bf: 0x0c0f, // Block 0x23, offset 0x8c0 - 0x8c0: 0x119f, 0x8c1: 0x11a3, 0x8c2: 0x11bf, 0x8c3: 0x11c7, 0x8c4: 0x11cf, 0x8c5: 0x11d3, - 0x8c6: 0x11df, 0x8c7: 0x11e7, 0x8c8: 0x11eb, 0x8c9: 0x11ef, 0x8ca: 0x11f7, 0x8cb: 0x11fb, - 0x8cc: 0x129b, 0x8cd: 0x12af, 0x8ce: 0x12e3, 0x8cf: 0x12e7, 0x8d0: 0x12ef, 0x8d1: 0x131b, - 0x8d2: 0x1323, 0x8d3: 0x132b, 0x8d4: 0x1333, 0x8d5: 0x136f, 0x8d6: 0x1373, 0x8d7: 0x137b, - 0x8d8: 0x137f, 0x8d9: 0x1383, 0x8da: 0x13af, 0x8db: 0x13b3, 0x8dc: 0x13bb, 0x8dd: 0x13cf, - 0x8de: 0x13d3, 0x8df: 0x13ef, 0x8e0: 0x13f7, 0x8e1: 0x13fb, 0x8e2: 0x141f, 0x8e3: 0x143f, - 0x8e4: 0x1453, 0x8e5: 0x1457, 0x8e6: 0x145f, 0x8e7: 0x148b, 0x8e8: 0x148f, 0x8e9: 0x149f, - 0x8ea: 0x14c3, 0x8eb: 0x14cf, 0x8ec: 0x14df, 0x8ed: 0x14f7, 0x8ee: 0x14ff, 0x8ef: 0x1503, - 0x8f0: 0x1507, 0x8f1: 0x150b, 0x8f2: 0x1517, 0x8f3: 0x151b, 0x8f4: 0x1523, 0x8f5: 0x153f, - 0x8f6: 0x1543, 0x8f7: 0x1547, 0x8f8: 0x155f, 0x8f9: 0x1563, 0x8fa: 0x156b, 0x8fb: 0x157f, - 0x8fc: 0x1583, 0x8fd: 0x1587, 0x8fe: 0x158f, 0x8ff: 0x1593, + 0x8c0: 0x0c8f, 0x8c1: 0x0c93, 0x8c2: 0x0ca7, 0x8c3: 0x0cab, 0x8c4: 0x0cb3, 0x8c5: 0x0cbb, + 0x8c6: 0x0cc3, 0x8c7: 0x0ccf, 0x8c8: 0x0cf7, 0x8c9: 0x0d07, 0x8ca: 0x0d1b, 0x8cb: 0x0d8b, + 0x8cc: 0x0d97, 0x8cd: 0x0da7, 0x8ce: 0x0db3, 0x8cf: 0x0dbf, 0x8d0: 0x0dc7, 0x8d1: 0x0dcb, + 0x8d2: 0x0dcf, 0x8d3: 0x0dd3, 0x8d4: 0x0dd7, 0x8d5: 0x0e8f, 0x8d6: 0x0ed7, 0x8d7: 0x0ee3, + 0x8d8: 0x0ee7, 0x8d9: 0x0eeb, 0x8da: 0x0eef, 0x8db: 0x0ef7, 0x8dc: 0x0efb, 0x8dd: 0x0f0f, + 0x8de: 0x0f2b, 0x8df: 0x0f33, 0x8e0: 0x0f73, 0x8e1: 0x0f77, 0x8e2: 0x0f7f, 0x8e3: 0x0f83, + 0x8e4: 0x0f8b, 0x8e5: 0x0f8f, 0x8e6: 0x0fb3, 0x8e7: 0x0fb7, 0x8e8: 0x0fd3, 0x8e9: 0x0fd7, + 0x8ea: 0x0fdb, 0x8eb: 0x0fdf, 0x8ec: 0x0ff3, 0x8ed: 0x1017, 0x8ee: 0x101b, 0x8ef: 0x101f, + 0x8f0: 0x1043, 0x8f1: 0x1083, 0x8f2: 0x1087, 0x8f3: 0x10a7, 0x8f4: 0x10b7, 0x8f5: 0x10bf, + 0x8f6: 0x10df, 0x8f7: 0x1103, 0x8f8: 0x1147, 0x8f9: 0x114f, 0x8fa: 0x1163, 0x8fb: 0x116f, + 0x8fc: 0x1177, 0x8fd: 0x117f, 0x8fe: 0x1183, 0x8ff: 0x1187, // Block 0x24, offset 0x900 - 0x906: 0xa000, 0x90b: 0xa000, - 0x90c: 0x3f08, 0x90d: 0xa000, 0x90e: 0x3f10, 0x90f: 0xa000, 0x910: 0x3f18, 0x911: 0xa000, - 0x912: 0x3f20, 0x913: 0xa000, 0x914: 0x3f28, 0x915: 0xa000, 0x916: 0x3f30, 0x917: 0xa000, - 0x918: 0x3f38, 0x919: 0xa000, 0x91a: 0x3f40, 0x91b: 0xa000, 0x91c: 0x3f48, 0x91d: 0xa000, - 0x91e: 0x3f50, 0x91f: 0xa000, 0x920: 0x3f58, 0x921: 0xa000, 0x922: 0x3f60, - 0x924: 0xa000, 0x925: 0x3f68, 0x926: 0xa000, 0x927: 0x3f70, 0x928: 0xa000, 0x929: 0x3f78, - 0x92f: 0xa000, - 0x930: 0x3f80, 0x931: 0x3f88, 0x932: 0xa000, 0x933: 0x3f90, 0x934: 0x3f98, 0x935: 0xa000, - 0x936: 0x3fa0, 0x937: 0x3fa8, 0x938: 0xa000, 0x939: 0x3fb0, 0x93a: 0x3fb8, 0x93b: 0xa000, - 0x93c: 0x3fc0, 0x93d: 0x3fc8, + 0x900: 0x119f, 0x901: 0x11a3, 0x902: 0x11bf, 0x903: 0x11c7, 0x904: 0x11cf, 0x905: 0x11d3, + 0x906: 0x11df, 0x907: 0x11e7, 0x908: 0x11eb, 0x909: 0x11ef, 0x90a: 0x11f7, 0x90b: 0x11fb, + 0x90c: 0x129b, 0x90d: 0x12af, 0x90e: 0x12e3, 0x90f: 0x12e7, 0x910: 0x12ef, 0x911: 0x131b, + 0x912: 0x1323, 0x913: 0x132b, 0x914: 0x1333, 0x915: 0x136f, 0x916: 0x1373, 0x917: 0x137b, + 0x918: 0x137f, 0x919: 0x1383, 0x91a: 0x13af, 0x91b: 0x13b3, 0x91c: 0x13bb, 0x91d: 0x13cf, + 0x91e: 0x13d3, 0x91f: 0x13ef, 0x920: 0x13f7, 0x921: 0x13fb, 0x922: 0x141f, 0x923: 0x143f, + 0x924: 0x1453, 0x925: 0x1457, 0x926: 0x145f, 0x927: 0x148b, 0x928: 0x148f, 0x929: 0x149f, + 0x92a: 0x14c3, 0x92b: 0x14cf, 0x92c: 0x14df, 0x92d: 0x14f7, 0x92e: 0x14ff, 0x92f: 0x1503, + 0x930: 0x1507, 0x931: 0x150b, 0x932: 0x1517, 0x933: 0x151b, 0x934: 0x1523, 0x935: 0x153f, + 0x936: 0x1543, 0x937: 0x1547, 0x938: 0x155f, 0x939: 0x1563, 0x93a: 0x156b, 0x93b: 0x157f, + 0x93c: 0x1583, 0x93d: 0x1587, 0x93e: 0x158f, 0x93f: 0x1593, // Block 0x25, offset 0x940 - 0x954: 0x3f00, - 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x42dc, 0x95c: 0x42e2, 0x95d: 0xa000, - 0x95e: 0x3fd0, 0x95f: 0x26b4, - 0x966: 0xa000, - 0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000, - 0x970: 0x3ff0, 0x971: 0xa000, 0x972: 0x3ff8, 0x973: 0xa000, 0x974: 0x4000, 0x975: 0xa000, - 0x976: 0x4008, 0x977: 0xa000, 0x978: 0x4010, 0x979: 0xa000, 0x97a: 0x4018, 0x97b: 0xa000, - 0x97c: 0x4020, 0x97d: 0xa000, 0x97e: 0x4028, 0x97f: 0xa000, + 0x946: 0xa000, 0x94b: 0xa000, + 0x94c: 0x3f08, 0x94d: 0xa000, 0x94e: 0x3f10, 0x94f: 0xa000, 0x950: 0x3f18, 0x951: 0xa000, + 0x952: 0x3f20, 0x953: 0xa000, 0x954: 0x3f28, 0x955: 0xa000, 0x956: 0x3f30, 0x957: 0xa000, + 0x958: 0x3f38, 0x959: 0xa000, 0x95a: 0x3f40, 0x95b: 0xa000, 0x95c: 0x3f48, 0x95d: 0xa000, + 0x95e: 0x3f50, 0x95f: 0xa000, 0x960: 0x3f58, 0x961: 0xa000, 0x962: 0x3f60, + 0x964: 0xa000, 0x965: 0x3f68, 0x966: 0xa000, 0x967: 0x3f70, 0x968: 0xa000, 0x969: 0x3f78, + 0x96f: 0xa000, + 0x970: 0x3f80, 0x971: 0x3f88, 0x972: 0xa000, 0x973: 0x3f90, 0x974: 0x3f98, 0x975: 0xa000, + 0x976: 0x3fa0, 0x977: 0x3fa8, 0x978: 0xa000, 0x979: 0x3fb0, 0x97a: 0x3fb8, 0x97b: 0xa000, + 0x97c: 0x3fc0, 0x97d: 0x3fc8, // Block 0x26, offset 0x980 - 0x980: 0x4030, 0x981: 0xa000, 0x982: 0x4038, 0x984: 0xa000, 0x985: 0x4040, - 0x986: 0xa000, 0x987: 0x4048, 0x988: 0xa000, 0x989: 0x4050, - 0x98f: 0xa000, 0x990: 0x4058, 0x991: 0x4060, - 0x992: 0xa000, 0x993: 0x4068, 0x994: 0x4070, 0x995: 0xa000, 0x996: 0x4078, 0x997: 0x4080, - 0x998: 0xa000, 0x999: 0x4088, 0x99a: 0x4090, 0x99b: 0xa000, 0x99c: 0x4098, 0x99d: 0x40a0, - 0x9af: 0xa000, - 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x3fd8, - 0x9b7: 0x40a8, 0x9b8: 0x40b0, 0x9b9: 0x40b8, 0x9ba: 0x40c0, - 0x9bd: 0xa000, 0x9be: 0x40c8, 0x9bf: 0x26c9, + 0x994: 0x3f00, + 0x999: 0x9903, 0x99a: 0x9903, 0x99b: 0x42dc, 0x99c: 0x42e2, 0x99d: 0xa000, + 0x99e: 0x3fd0, 0x99f: 0x26b4, + 0x9a6: 0xa000, + 0x9ab: 0xa000, 0x9ac: 0x3fe0, 0x9ad: 0xa000, 0x9ae: 0x3fe8, 0x9af: 0xa000, + 0x9b0: 0x3ff0, 0x9b1: 0xa000, 0x9b2: 0x3ff8, 0x9b3: 0xa000, 0x9b4: 0x4000, 0x9b5: 0xa000, + 0x9b6: 0x4008, 0x9b7: 0xa000, 0x9b8: 0x4010, 0x9b9: 0xa000, 0x9ba: 0x4018, 0x9bb: 0xa000, + 0x9bc: 0x4020, 0x9bd: 0xa000, 0x9be: 0x4028, 0x9bf: 0xa000, // Block 0x27, offset 0x9c0 - 0x9c0: 0x0367, 0x9c1: 0x032b, 0x9c2: 0x032f, 0x9c3: 0x0333, 0x9c4: 0x037b, 0x9c5: 0x0337, - 0x9c6: 0x033b, 0x9c7: 0x033f, 0x9c8: 0x0343, 0x9c9: 0x0347, 0x9ca: 0x034b, 0x9cb: 0x034f, - 0x9cc: 0x0353, 0x9cd: 0x0357, 0x9ce: 0x035b, 0x9cf: 0x49bd, 0x9d0: 0x49c3, 0x9d1: 0x49c9, - 0x9d2: 0x49cf, 0x9d3: 0x49d5, 0x9d4: 0x49db, 0x9d5: 0x49e1, 0x9d6: 0x49e7, 0x9d7: 0x49ed, - 0x9d8: 0x49f3, 0x9d9: 0x49f9, 0x9da: 0x49ff, 0x9db: 0x4a05, 0x9dc: 0x4a0b, 0x9dd: 0x4a11, - 0x9de: 0x4a17, 0x9df: 0x4a1d, 0x9e0: 0x4a23, 0x9e1: 0x4a29, 0x9e2: 0x4a2f, 0x9e3: 0x4a35, - 0x9e4: 0x03c3, 0x9e5: 0x035f, 0x9e6: 0x0363, 0x9e7: 0x03e7, 0x9e8: 0x03eb, 0x9e9: 0x03ef, - 0x9ea: 0x03f3, 0x9eb: 0x03f7, 0x9ec: 0x03fb, 0x9ed: 0x03ff, 0x9ee: 0x036b, 0x9ef: 0x0403, - 0x9f0: 0x0407, 0x9f1: 0x036f, 0x9f2: 0x0373, 0x9f3: 0x0377, 0x9f4: 0x037f, 0x9f5: 0x0383, - 0x9f6: 0x0387, 0x9f7: 0x038b, 0x9f8: 0x038f, 0x9f9: 0x0393, 0x9fa: 0x0397, 0x9fb: 0x039b, - 0x9fc: 0x039f, 0x9fd: 0x03a3, 0x9fe: 0x03a7, 0x9ff: 0x03ab, + 0x9c0: 0x4030, 0x9c1: 0xa000, 0x9c2: 0x4038, 0x9c4: 0xa000, 0x9c5: 0x4040, + 0x9c6: 0xa000, 0x9c7: 0x4048, 0x9c8: 0xa000, 0x9c9: 0x4050, + 0x9cf: 0xa000, 0x9d0: 0x4058, 0x9d1: 0x4060, + 0x9d2: 0xa000, 0x9d3: 0x4068, 0x9d4: 0x4070, 0x9d5: 0xa000, 0x9d6: 0x4078, 0x9d7: 0x4080, + 0x9d8: 0xa000, 0x9d9: 0x4088, 0x9da: 0x4090, 0x9db: 0xa000, 0x9dc: 0x4098, 0x9dd: 0x40a0, + 0x9ef: 0xa000, + 0x9f0: 0xa000, 0x9f1: 0xa000, 0x9f2: 0xa000, 0x9f4: 0x3fd8, + 0x9f7: 0x40a8, 0x9f8: 0x40b0, 0x9f9: 0x40b8, 0x9fa: 0x40c0, + 0x9fd: 0xa000, 0x9fe: 0x40c8, 0x9ff: 0x26c9, // Block 0x28, offset 0xa00 - 0xa00: 0x03af, 0xa01: 0x03b3, 0xa02: 0x040b, 0xa03: 0x040f, 0xa04: 0x03b7, 0xa05: 0x03bb, - 0xa06: 0x03bf, 0xa07: 0x03c7, 0xa08: 0x03cb, 0xa09: 0x03cf, 0xa0a: 0x03d3, 0xa0b: 0x03d7, - 0xa0c: 0x03db, 0xa0d: 0x03df, 0xa0e: 0x03e3, - 0xa12: 0x06bf, 0xa13: 0x071b, 0xa14: 0x06cb, 0xa15: 0x097b, 0xa16: 0x06cf, 0xa17: 0x06e7, - 0xa18: 0x06d3, 0xa19: 0x0f93, 0xa1a: 0x0707, 0xa1b: 0x06db, 0xa1c: 0x06c3, 0xa1d: 0x09ff, - 0xa1e: 0x098f, 0xa1f: 0x072f, + 0xa00: 0x0367, 0xa01: 0x032b, 0xa02: 0x032f, 0xa03: 0x0333, 0xa04: 0x037b, 0xa05: 0x0337, + 0xa06: 0x033b, 0xa07: 0x033f, 0xa08: 0x0343, 0xa09: 0x0347, 0xa0a: 0x034b, 0xa0b: 0x034f, + 0xa0c: 0x0353, 0xa0d: 0x0357, 0xa0e: 0x035b, 0xa0f: 0x49bd, 0xa10: 0x49c3, 0xa11: 0x49c9, + 0xa12: 0x49cf, 0xa13: 0x49d5, 0xa14: 0x49db, 0xa15: 0x49e1, 0xa16: 0x49e7, 0xa17: 0x49ed, + 0xa18: 0x49f3, 0xa19: 0x49f9, 0xa1a: 0x49ff, 0xa1b: 0x4a05, 0xa1c: 0x4a0b, 0xa1d: 0x4a11, + 0xa1e: 0x4a17, 0xa1f: 0x4a1d, 0xa20: 0x4a23, 0xa21: 0x4a29, 0xa22: 0x4a2f, 0xa23: 0x4a35, + 0xa24: 0x03c3, 0xa25: 0x035f, 0xa26: 0x0363, 0xa27: 0x03e7, 0xa28: 0x03eb, 0xa29: 0x03ef, + 0xa2a: 0x03f3, 0xa2b: 0x03f7, 0xa2c: 0x03fb, 0xa2d: 0x03ff, 0xa2e: 0x036b, 0xa2f: 0x0403, + 0xa30: 0x0407, 0xa31: 0x036f, 0xa32: 0x0373, 0xa33: 0x0377, 0xa34: 0x037f, 0xa35: 0x0383, + 0xa36: 0x0387, 0xa37: 0x038b, 0xa38: 0x038f, 0xa39: 0x0393, 0xa3a: 0x0397, 0xa3b: 0x039b, + 0xa3c: 0x039f, 0xa3d: 0x03a3, 0xa3e: 0x03a7, 0xa3f: 0x03ab, // Block 0x29, offset 0xa40 - 0xa40: 0x2054, 0xa41: 0x205a, 0xa42: 0x2060, 0xa43: 0x2066, 0xa44: 0x206c, 0xa45: 0x2072, - 0xa46: 0x2078, 0xa47: 0x207e, 0xa48: 0x2084, 0xa49: 0x208a, 0xa4a: 0x2090, 0xa4b: 0x2096, - 0xa4c: 0x209c, 0xa4d: 0x20a2, 0xa4e: 0x2726, 0xa4f: 0x272f, 0xa50: 0x2738, 0xa51: 0x2741, - 0xa52: 0x274a, 0xa53: 0x2753, 0xa54: 0x275c, 0xa55: 0x2765, 0xa56: 0x276e, 0xa57: 0x2780, - 0xa58: 0x2789, 0xa59: 0x2792, 0xa5a: 0x279b, 0xa5b: 0x27a4, 0xa5c: 0x2777, 0xa5d: 0x2bac, - 0xa5e: 0x2aed, 0xa60: 0x20a8, 0xa61: 0x20c0, 0xa62: 0x20b4, 0xa63: 0x2108, - 0xa64: 0x20c6, 0xa65: 0x20e4, 0xa66: 0x20ae, 0xa67: 0x20de, 0xa68: 0x20ba, 0xa69: 0x20f0, - 0xa6a: 0x2120, 0xa6b: 0x213e, 0xa6c: 0x2138, 0xa6d: 0x212c, 0xa6e: 0x217a, 0xa6f: 0x210e, - 0xa70: 0x211a, 0xa71: 0x2132, 0xa72: 0x2126, 0xa73: 0x2150, 0xa74: 0x20fc, 0xa75: 0x2144, - 0xa76: 0x216e, 0xa77: 0x2156, 0xa78: 0x20ea, 0xa79: 0x20cc, 0xa7a: 0x2102, 0xa7b: 0x2114, - 0xa7c: 0x214a, 0xa7d: 0x20d2, 0xa7e: 0x2174, 0xa7f: 0x20f6, + 0xa40: 0x03af, 0xa41: 0x03b3, 0xa42: 0x040b, 0xa43: 0x040f, 0xa44: 0x03b7, 0xa45: 0x03bb, + 0xa46: 0x03bf, 0xa47: 0x03c7, 0xa48: 0x03cb, 0xa49: 0x03cf, 0xa4a: 0x03d3, 0xa4b: 0x03d7, + 0xa4c: 0x03db, 0xa4d: 0x03df, 0xa4e: 0x03e3, + 0xa52: 0x06bf, 0xa53: 0x071b, 0xa54: 0x06cb, 0xa55: 0x097b, 0xa56: 0x06cf, 0xa57: 0x06e7, + 0xa58: 0x06d3, 0xa59: 0x0f93, 0xa5a: 0x0707, 0xa5b: 0x06db, 0xa5c: 0x06c3, 0xa5d: 0x09ff, + 0xa5e: 0x098f, 0xa5f: 0x072f, // Block 0x2a, offset 0xa80 - 0xa80: 0x215c, 0xa81: 0x20d8, 0xa82: 0x2162, 0xa83: 0x2168, 0xa84: 0x092f, 0xa85: 0x0b03, - 0xa86: 0x0ca7, 0xa87: 0x10c7, - 0xa90: 0x1bc4, 0xa91: 0x18a9, - 0xa92: 0x18ac, 0xa93: 0x18af, 0xa94: 0x18b2, 0xa95: 0x18b5, 0xa96: 0x18b8, 0xa97: 0x18bb, - 0xa98: 0x18be, 0xa99: 0x18c1, 0xa9a: 0x18ca, 0xa9b: 0x18cd, 0xa9c: 0x18d0, 0xa9d: 0x18d3, - 0xa9e: 0x18d6, 0xa9f: 0x18d9, 0xaa0: 0x0313, 0xaa1: 0x031b, 0xaa2: 0x031f, 0xaa3: 0x0327, - 0xaa4: 0x032b, 0xaa5: 0x032f, 0xaa6: 0x0337, 0xaa7: 0x033f, 0xaa8: 0x0343, 0xaa9: 0x034b, - 0xaaa: 0x034f, 0xaab: 0x0353, 0xaac: 0x0357, 0xaad: 0x035b, 0xaae: 0x2e18, 0xaaf: 0x2e20, - 0xab0: 0x2e28, 0xab1: 0x2e30, 0xab2: 0x2e38, 0xab3: 0x2e40, 0xab4: 0x2e48, 0xab5: 0x2e50, - 0xab6: 0x2e60, 0xab7: 0x2e68, 0xab8: 0x2e70, 0xab9: 0x2e78, 0xaba: 0x2e80, 0xabb: 0x2e88, - 0xabc: 0x2ed3, 0xabd: 0x2e9b, 0xabe: 0x2e58, + 0xa80: 0x2054, 0xa81: 0x205a, 0xa82: 0x2060, 0xa83: 0x2066, 0xa84: 0x206c, 0xa85: 0x2072, + 0xa86: 0x2078, 0xa87: 0x207e, 0xa88: 0x2084, 0xa89: 0x208a, 0xa8a: 0x2090, 0xa8b: 0x2096, + 0xa8c: 0x209c, 0xa8d: 0x20a2, 0xa8e: 0x2726, 0xa8f: 0x272f, 0xa90: 0x2738, 0xa91: 0x2741, + 0xa92: 0x274a, 0xa93: 0x2753, 0xa94: 0x275c, 0xa95: 0x2765, 0xa96: 0x276e, 0xa97: 0x2780, + 0xa98: 0x2789, 0xa99: 0x2792, 0xa9a: 0x279b, 0xa9b: 0x27a4, 0xa9c: 0x2777, 0xa9d: 0x2bac, + 0xa9e: 0x2aed, 0xaa0: 0x20a8, 0xaa1: 0x20c0, 0xaa2: 0x20b4, 0xaa3: 0x2108, + 0xaa4: 0x20c6, 0xaa5: 0x20e4, 0xaa6: 0x20ae, 0xaa7: 0x20de, 0xaa8: 0x20ba, 0xaa9: 0x20f0, + 0xaaa: 0x2120, 0xaab: 0x213e, 0xaac: 0x2138, 0xaad: 0x212c, 0xaae: 0x217a, 0xaaf: 0x210e, + 0xab0: 0x211a, 0xab1: 0x2132, 0xab2: 0x2126, 0xab3: 0x2150, 0xab4: 0x20fc, 0xab5: 0x2144, + 0xab6: 0x216e, 0xab7: 0x2156, 0xab8: 0x20ea, 0xab9: 0x20cc, 0xaba: 0x2102, 0xabb: 0x2114, + 0xabc: 0x214a, 0xabd: 0x20d2, 0xabe: 0x2174, 0xabf: 0x20f6, // Block 0x2b, offset 0xac0 - 0xac0: 0x06bf, 0xac1: 0x071b, 0xac2: 0x06cb, 0xac3: 0x097b, 0xac4: 0x071f, 0xac5: 0x07af, - 0xac6: 0x06c7, 0xac7: 0x07ab, 0xac8: 0x070b, 0xac9: 0x0887, 0xaca: 0x0d07, 0xacb: 0x0e8f, - 0xacc: 0x0dd7, 0xacd: 0x0d1b, 0xace: 0x145f, 0xacf: 0x098b, 0xad0: 0x0ccf, 0xad1: 0x0d4b, - 0xad2: 0x0d0b, 0xad3: 0x104b, 0xad4: 0x08fb, 0xad5: 0x0f03, 0xad6: 0x1387, 0xad7: 0x105f, - 0xad8: 0x0843, 0xad9: 0x108f, 0xada: 0x0f9b, 0xadb: 0x0a17, 0xadc: 0x140f, 0xadd: 0x077f, - 0xade: 0x08ab, 0xadf: 0x0df7, 0xae0: 0x1527, 0xae1: 0x0743, 0xae2: 0x07d3, 0xae3: 0x0d9b, - 0xae4: 0x06cf, 0xae5: 0x06e7, 0xae6: 0x06d3, 0xae7: 0x0adb, 0xae8: 0x08ef, 0xae9: 0x087f, - 0xaea: 0x0a57, 0xaeb: 0x0a4b, 0xaec: 0x0feb, 0xaed: 0x073f, 0xaee: 0x139b, 0xaef: 0x089b, - 0xaf0: 0x09f3, 0xaf1: 0x18dc, 0xaf2: 0x18df, 0xaf3: 0x18e2, 0xaf4: 0x18e5, 0xaf5: 0x18ee, - 0xaf6: 0x18f1, 0xaf7: 0x18f4, 0xaf8: 0x18f7, 0xaf9: 0x18fa, 0xafa: 0x18fd, 0xafb: 0x1900, - 0xafc: 0x1903, 0xafd: 0x1906, 0xafe: 0x1909, 0xaff: 0x1912, + 0xac0: 0x215c, 0xac1: 0x20d8, 0xac2: 0x2162, 0xac3: 0x2168, 0xac4: 0x092f, 0xac5: 0x0b03, + 0xac6: 0x0ca7, 0xac7: 0x10c7, + 0xad0: 0x1bc4, 0xad1: 0x18a9, + 0xad2: 0x18ac, 0xad3: 0x18af, 0xad4: 0x18b2, 0xad5: 0x18b5, 0xad6: 0x18b8, 0xad7: 0x18bb, + 0xad8: 0x18be, 0xad9: 0x18c1, 0xada: 0x18ca, 0xadb: 0x18cd, 0xadc: 0x18d0, 0xadd: 0x18d3, + 0xade: 0x18d6, 0xadf: 0x18d9, 0xae0: 0x0313, 0xae1: 0x031b, 0xae2: 0x031f, 0xae3: 0x0327, + 0xae4: 0x032b, 0xae5: 0x032f, 0xae6: 0x0337, 0xae7: 0x033f, 0xae8: 0x0343, 0xae9: 0x034b, + 0xaea: 0x034f, 0xaeb: 0x0353, 0xaec: 0x0357, 0xaed: 0x035b, 0xaee: 0x2e18, 0xaef: 0x2e20, + 0xaf0: 0x2e28, 0xaf1: 0x2e30, 0xaf2: 0x2e38, 0xaf3: 0x2e40, 0xaf4: 0x2e48, 0xaf5: 0x2e50, + 0xaf6: 0x2e60, 0xaf7: 0x2e68, 0xaf8: 0x2e70, 0xaf9: 0x2e78, 0xafa: 0x2e80, 0xafb: 0x2e88, + 0xafc: 0x2ed3, 0xafd: 0x2e9b, 0xafe: 0x2e58, // Block 0x2c, offset 0xb00 - 0xb00: 0x1cc6, 0xb01: 0x1cd5, 0xb02: 0x1ce4, 0xb03: 0x1cf3, 0xb04: 0x1d02, 0xb05: 0x1d11, - 0xb06: 0x1d20, 0xb07: 0x1d2f, 0xb08: 0x1d3e, 0xb09: 0x218c, 0xb0a: 0x219e, 0xb0b: 0x21b0, - 0xb0c: 0x1954, 0xb0d: 0x1c04, 0xb0e: 0x19d2, 0xb0f: 0x1ba8, 0xb10: 0x04cb, 0xb11: 0x04d3, - 0xb12: 0x04db, 0xb13: 0x04e3, 0xb14: 0x04eb, 0xb15: 0x04ef, 0xb16: 0x04f3, 0xb17: 0x04f7, - 0xb18: 0x04fb, 0xb19: 0x04ff, 0xb1a: 0x0503, 0xb1b: 0x0507, 0xb1c: 0x050b, 0xb1d: 0x050f, - 0xb1e: 0x0513, 0xb1f: 0x0517, 0xb20: 0x051b, 0xb21: 0x0523, 0xb22: 0x0527, 0xb23: 0x052b, - 0xb24: 0x052f, 0xb25: 0x0533, 0xb26: 0x0537, 0xb27: 0x053b, 0xb28: 0x053f, 0xb29: 0x0543, - 0xb2a: 0x0547, 0xb2b: 0x054b, 0xb2c: 0x054f, 0xb2d: 0x0553, 0xb2e: 0x0557, 0xb2f: 0x055b, - 0xb30: 0x055f, 0xb31: 0x0563, 0xb32: 0x0567, 0xb33: 0x056f, 0xb34: 0x0577, 0xb35: 0x057f, - 0xb36: 0x0583, 0xb37: 0x0587, 0xb38: 0x058b, 0xb39: 0x058f, 0xb3a: 0x0593, 0xb3b: 0x0597, - 0xb3c: 0x059b, 0xb3d: 0x059f, 0xb3e: 0x05a3, + 0xb00: 0x06bf, 0xb01: 0x071b, 0xb02: 0x06cb, 0xb03: 0x097b, 0xb04: 0x071f, 0xb05: 0x07af, + 0xb06: 0x06c7, 0xb07: 0x07ab, 0xb08: 0x070b, 0xb09: 0x0887, 0xb0a: 0x0d07, 0xb0b: 0x0e8f, + 0xb0c: 0x0dd7, 0xb0d: 0x0d1b, 0xb0e: 0x145f, 0xb0f: 0x098b, 0xb10: 0x0ccf, 0xb11: 0x0d4b, + 0xb12: 0x0d0b, 0xb13: 0x104b, 0xb14: 0x08fb, 0xb15: 0x0f03, 0xb16: 0x1387, 0xb17: 0x105f, + 0xb18: 0x0843, 0xb19: 0x108f, 0xb1a: 0x0f9b, 0xb1b: 0x0a17, 0xb1c: 0x140f, 0xb1d: 0x077f, + 0xb1e: 0x08ab, 0xb1f: 0x0df7, 0xb20: 0x1527, 0xb21: 0x0743, 0xb22: 0x07d3, 0xb23: 0x0d9b, + 0xb24: 0x06cf, 0xb25: 0x06e7, 0xb26: 0x06d3, 0xb27: 0x0adb, 0xb28: 0x08ef, 0xb29: 0x087f, + 0xb2a: 0x0a57, 0xb2b: 0x0a4b, 0xb2c: 0x0feb, 0xb2d: 0x073f, 0xb2e: 0x139b, 0xb2f: 0x089b, + 0xb30: 0x09f3, 0xb31: 0x18dc, 0xb32: 0x18df, 0xb33: 0x18e2, 0xb34: 0x18e5, 0xb35: 0x18ee, + 0xb36: 0x18f1, 0xb37: 0x18f4, 0xb38: 0x18f7, 0xb39: 0x18fa, 0xb3a: 0x18fd, 0xb3b: 0x1900, + 0xb3c: 0x1903, 0xb3d: 0x1906, 0xb3e: 0x1909, 0xb3f: 0x1912, // Block 0x2d, offset 0xb40 - 0xb40: 0x2b0c, 0xb41: 0x29a8, 0xb42: 0x2b1c, 0xb43: 0x2880, 0xb44: 0x2ee4, 0xb45: 0x288a, - 0xb46: 0x2894, 0xb47: 0x2f28, 0xb48: 0x29b5, 0xb49: 0x289e, 0xb4a: 0x28a8, 0xb4b: 0x28b2, - 0xb4c: 0x29dc, 0xb4d: 0x29e9, 0xb4e: 0x29c2, 0xb4f: 0x29cf, 0xb50: 0x2ea9, 0xb51: 0x29f6, - 0xb52: 0x2a03, 0xb53: 0x2bbe, 0xb54: 0x26bb, 0xb55: 0x2bd1, 0xb56: 0x2be4, 0xb57: 0x2b2c, - 0xb58: 0x2a10, 0xb59: 0x2bf7, 0xb5a: 0x2c0a, 0xb5b: 0x2a1d, 0xb5c: 0x28bc, 0xb5d: 0x28c6, - 0xb5e: 0x2eb7, 0xb5f: 0x2a2a, 0xb60: 0x2b3c, 0xb61: 0x2ef5, 0xb62: 0x28d0, 0xb63: 0x28da, - 0xb64: 0x2a37, 0xb65: 0x28e4, 0xb66: 0x28ee, 0xb67: 0x26d0, 0xb68: 0x26d7, 0xb69: 0x28f8, - 0xb6a: 0x2902, 0xb6b: 0x2c1d, 0xb6c: 0x2a44, 0xb6d: 0x2b4c, 0xb6e: 0x2c30, 0xb6f: 0x2a51, - 0xb70: 0x2916, 0xb71: 0x290c, 0xb72: 0x2f3c, 0xb73: 0x2a5e, 0xb74: 0x2c43, 0xb75: 0x2920, - 0xb76: 0x2b5c, 0xb77: 0x292a, 0xb78: 0x2a78, 0xb79: 0x2934, 0xb7a: 0x2a85, 0xb7b: 0x2f06, - 0xb7c: 0x2a6b, 0xb7d: 0x2b6c, 0xb7e: 0x2a92, 0xb7f: 0x26de, + 0xb40: 0x1cc6, 0xb41: 0x1cd5, 0xb42: 0x1ce4, 0xb43: 0x1cf3, 0xb44: 0x1d02, 0xb45: 0x1d11, + 0xb46: 0x1d20, 0xb47: 0x1d2f, 0xb48: 0x1d3e, 0xb49: 0x218c, 0xb4a: 0x219e, 0xb4b: 0x21b0, + 0xb4c: 0x1954, 0xb4d: 0x1c04, 0xb4e: 0x19d2, 0xb4f: 0x1ba8, 0xb50: 0x04cb, 0xb51: 0x04d3, + 0xb52: 0x04db, 0xb53: 0x04e3, 0xb54: 0x04eb, 0xb55: 0x04ef, 0xb56: 0x04f3, 0xb57: 0x04f7, + 0xb58: 0x04fb, 0xb59: 0x04ff, 0xb5a: 0x0503, 0xb5b: 0x0507, 0xb5c: 0x050b, 0xb5d: 0x050f, + 0xb5e: 0x0513, 0xb5f: 0x0517, 0xb60: 0x051b, 0xb61: 0x0523, 0xb62: 0x0527, 0xb63: 0x052b, + 0xb64: 0x052f, 0xb65: 0x0533, 0xb66: 0x0537, 0xb67: 0x053b, 0xb68: 0x053f, 0xb69: 0x0543, + 0xb6a: 0x0547, 0xb6b: 0x054b, 0xb6c: 0x054f, 0xb6d: 0x0553, 0xb6e: 0x0557, 0xb6f: 0x055b, + 0xb70: 0x055f, 0xb71: 0x0563, 0xb72: 0x0567, 0xb73: 0x056f, 0xb74: 0x0577, 0xb75: 0x057f, + 0xb76: 0x0583, 0xb77: 0x0587, 0xb78: 0x058b, 0xb79: 0x058f, 0xb7a: 0x0593, 0xb7b: 0x0597, + 0xb7c: 0x059b, 0xb7d: 0x059f, 0xb7e: 0x05a3, // Block 0x2e, offset 0xb80 - 0xb80: 0x2f17, 0xb81: 0x293e, 0xb82: 0x2948, 0xb83: 0x2a9f, 0xb84: 0x2952, 0xb85: 0x295c, - 0xb86: 0x2966, 0xb87: 0x2b7c, 0xb88: 0x2aac, 0xb89: 0x26e5, 0xb8a: 0x2c56, 0xb8b: 0x2e90, - 0xb8c: 0x2b8c, 0xb8d: 0x2ab9, 0xb8e: 0x2ec5, 0xb8f: 0x2970, 0xb90: 0x297a, 0xb91: 0x2ac6, - 0xb92: 0x26ec, 0xb93: 0x2ad3, 0xb94: 0x2b9c, 0xb95: 0x26f3, 0xb96: 0x2c69, 0xb97: 0x2984, - 0xb98: 0x1cb7, 0xb99: 0x1ccb, 0xb9a: 0x1cda, 0xb9b: 0x1ce9, 0xb9c: 0x1cf8, 0xb9d: 0x1d07, - 0xb9e: 0x1d16, 0xb9f: 0x1d25, 0xba0: 0x1d34, 0xba1: 0x1d43, 0xba2: 0x2192, 0xba3: 0x21a4, - 0xba4: 0x21b6, 0xba5: 0x21c2, 0xba6: 0x21ce, 0xba7: 0x21da, 0xba8: 0x21e6, 0xba9: 0x21f2, - 0xbaa: 0x21fe, 0xbab: 0x220a, 0xbac: 0x2246, 0xbad: 0x2252, 0xbae: 0x225e, 0xbaf: 0x226a, - 0xbb0: 0x2276, 0xbb1: 0x1c14, 0xbb2: 0x19c6, 0xbb3: 0x1936, 0xbb4: 0x1be4, 0xbb5: 0x1a47, - 0xbb6: 0x1a56, 0xbb7: 0x19cc, 0xbb8: 0x1bfc, 0xbb9: 0x1c00, 0xbba: 0x1960, 0xbbb: 0x2701, - 0xbbc: 0x270f, 0xbbd: 0x26fa, 0xbbe: 0x2708, 0xbbf: 0x2ae0, + 0xb80: 0x2b0c, 0xb81: 0x29a8, 0xb82: 0x2b1c, 0xb83: 0x2880, 0xb84: 0x2ee4, 0xb85: 0x288a, + 0xb86: 0x2894, 0xb87: 0x2f28, 0xb88: 0x29b5, 0xb89: 0x289e, 0xb8a: 0x28a8, 0xb8b: 0x28b2, + 0xb8c: 0x29dc, 0xb8d: 0x29e9, 0xb8e: 0x29c2, 0xb8f: 0x29cf, 0xb90: 0x2ea9, 0xb91: 0x29f6, + 0xb92: 0x2a03, 0xb93: 0x2bbe, 0xb94: 0x26bb, 0xb95: 0x2bd1, 0xb96: 0x2be4, 0xb97: 0x2b2c, + 0xb98: 0x2a10, 0xb99: 0x2bf7, 0xb9a: 0x2c0a, 0xb9b: 0x2a1d, 0xb9c: 0x28bc, 0xb9d: 0x28c6, + 0xb9e: 0x2eb7, 0xb9f: 0x2a2a, 0xba0: 0x2b3c, 0xba1: 0x2ef5, 0xba2: 0x28d0, 0xba3: 0x28da, + 0xba4: 0x2a37, 0xba5: 0x28e4, 0xba6: 0x28ee, 0xba7: 0x26d0, 0xba8: 0x26d7, 0xba9: 0x28f8, + 0xbaa: 0x2902, 0xbab: 0x2c1d, 0xbac: 0x2a44, 0xbad: 0x2b4c, 0xbae: 0x2c30, 0xbaf: 0x2a51, + 0xbb0: 0x2916, 0xbb1: 0x290c, 0xbb2: 0x2f3c, 0xbb3: 0x2a5e, 0xbb4: 0x2c43, 0xbb5: 0x2920, + 0xbb6: 0x2b5c, 0xbb7: 0x292a, 0xbb8: 0x2a78, 0xbb9: 0x2934, 0xbba: 0x2a85, 0xbbb: 0x2f06, + 0xbbc: 0x2a6b, 0xbbd: 0x2b6c, 0xbbe: 0x2a92, 0xbbf: 0x26de, // Block 0x2f, offset 0xbc0 - 0xbc0: 0x1a4a, 0xbc1: 0x1a32, 0xbc2: 0x1c60, 0xbc3: 0x1a1a, 0xbc4: 0x19f3, 0xbc5: 0x1969, - 0xbc6: 0x1978, 0xbc7: 0x1948, 0xbc8: 0x1bf0, 0xbc9: 0x1d52, 0xbca: 0x1a4d, 0xbcb: 0x1a35, - 0xbcc: 0x1c64, 0xbcd: 0x1c70, 0xbce: 0x1a26, 0xbcf: 0x19fc, 0xbd0: 0x1957, 0xbd1: 0x1c1c, - 0xbd2: 0x1bb0, 0xbd3: 0x1b9c, 0xbd4: 0x1bcc, 0xbd5: 0x1c74, 0xbd6: 0x1a29, 0xbd7: 0x19c9, - 0xbd8: 0x19ff, 0xbd9: 0x19de, 0xbda: 0x1a41, 0xbdb: 0x1c78, 0xbdc: 0x1a2c, 0xbdd: 0x19c0, - 0xbde: 0x1a02, 0xbdf: 0x1c3c, 0xbe0: 0x1bf4, 0xbe1: 0x1a14, 0xbe2: 0x1c24, 0xbe3: 0x1c40, - 0xbe4: 0x1bf8, 0xbe5: 0x1a17, 0xbe6: 0x1c28, 0xbe7: 0x22e8, 0xbe8: 0x22fc, 0xbe9: 0x1996, - 0xbea: 0x1c20, 0xbeb: 0x1bb4, 0xbec: 0x1ba0, 0xbed: 0x1c48, 0xbee: 0x2716, 0xbef: 0x27ad, - 0xbf0: 0x1a59, 0xbf1: 0x1a44, 0xbf2: 0x1c7c, 0xbf3: 0x1a2f, 0xbf4: 0x1a50, 0xbf5: 0x1a38, - 0xbf6: 0x1c68, 0xbf7: 0x1a1d, 0xbf8: 0x19f6, 0xbf9: 0x1981, 0xbfa: 0x1a53, 0xbfb: 0x1a3b, - 0xbfc: 0x1c6c, 0xbfd: 0x1a20, 0xbfe: 0x19f9, 0xbff: 0x1984, + 0xbc0: 0x2f17, 0xbc1: 0x293e, 0xbc2: 0x2948, 0xbc3: 0x2a9f, 0xbc4: 0x2952, 0xbc5: 0x295c, + 0xbc6: 0x2966, 0xbc7: 0x2b7c, 0xbc8: 0x2aac, 0xbc9: 0x26e5, 0xbca: 0x2c56, 0xbcb: 0x2e90, + 0xbcc: 0x2b8c, 0xbcd: 0x2ab9, 0xbce: 0x2ec5, 0xbcf: 0x2970, 0xbd0: 0x297a, 0xbd1: 0x2ac6, + 0xbd2: 0x26ec, 0xbd3: 0x2ad3, 0xbd4: 0x2b9c, 0xbd5: 0x26f3, 0xbd6: 0x2c69, 0xbd7: 0x2984, + 0xbd8: 0x1cb7, 0xbd9: 0x1ccb, 0xbda: 0x1cda, 0xbdb: 0x1ce9, 0xbdc: 0x1cf8, 0xbdd: 0x1d07, + 0xbde: 0x1d16, 0xbdf: 0x1d25, 0xbe0: 0x1d34, 0xbe1: 0x1d43, 0xbe2: 0x2192, 0xbe3: 0x21a4, + 0xbe4: 0x21b6, 0xbe5: 0x21c2, 0xbe6: 0x21ce, 0xbe7: 0x21da, 0xbe8: 0x21e6, 0xbe9: 0x21f2, + 0xbea: 0x21fe, 0xbeb: 0x220a, 0xbec: 0x2246, 0xbed: 0x2252, 0xbee: 0x225e, 0xbef: 0x226a, + 0xbf0: 0x2276, 0xbf1: 0x1c14, 0xbf2: 0x19c6, 0xbf3: 0x1936, 0xbf4: 0x1be4, 0xbf5: 0x1a47, + 0xbf6: 0x1a56, 0xbf7: 0x19cc, 0xbf8: 0x1bfc, 0xbf9: 0x1c00, 0xbfa: 0x1960, 0xbfb: 0x2701, + 0xbfc: 0x270f, 0xbfd: 0x26fa, 0xbfe: 0x2708, 0xbff: 0x2ae0, // Block 0x30, offset 0xc00 - 0xc00: 0x1c2c, 0xc01: 0x1bb8, 0xc02: 0x1d4d, 0xc03: 0x1939, 0xc04: 0x19ba, 0xc05: 0x19bd, - 0xc06: 0x22f5, 0xc07: 0x1b94, 0xc08: 0x19c3, 0xc09: 0x194b, 0xc0a: 0x19e1, 0xc0b: 0x194e, - 0xc0c: 0x19ea, 0xc0d: 0x196c, 0xc0e: 0x196f, 0xc0f: 0x1a05, 0xc10: 0x1a0b, 0xc11: 0x1a0e, - 0xc12: 0x1c30, 0xc13: 0x1a11, 0xc14: 0x1a23, 0xc15: 0x1c38, 0xc16: 0x1c44, 0xc17: 0x1990, - 0xc18: 0x1d57, 0xc19: 0x1bbc, 0xc1a: 0x1993, 0xc1b: 0x1a5c, 0xc1c: 0x19a5, 0xc1d: 0x19b4, - 0xc1e: 0x22e2, 0xc1f: 0x22dc, 0xc20: 0x1cc1, 0xc21: 0x1cd0, 0xc22: 0x1cdf, 0xc23: 0x1cee, - 0xc24: 0x1cfd, 0xc25: 0x1d0c, 0xc26: 0x1d1b, 0xc27: 0x1d2a, 0xc28: 0x1d39, 0xc29: 0x2186, - 0xc2a: 0x2198, 0xc2b: 0x21aa, 0xc2c: 0x21bc, 0xc2d: 0x21c8, 0xc2e: 0x21d4, 0xc2f: 0x21e0, - 0xc30: 0x21ec, 0xc31: 0x21f8, 0xc32: 0x2204, 0xc33: 0x2240, 0xc34: 0x224c, 0xc35: 0x2258, - 0xc36: 0x2264, 0xc37: 0x2270, 0xc38: 0x227c, 0xc39: 0x2282, 0xc3a: 0x2288, 0xc3b: 0x228e, - 0xc3c: 0x2294, 0xc3d: 0x22a6, 0xc3e: 0x22ac, 0xc3f: 0x1c10, + 0xc00: 0x1a4a, 0xc01: 0x1a32, 0xc02: 0x1c60, 0xc03: 0x1a1a, 0xc04: 0x19f3, 0xc05: 0x1969, + 0xc06: 0x1978, 0xc07: 0x1948, 0xc08: 0x1bf0, 0xc09: 0x1d52, 0xc0a: 0x1a4d, 0xc0b: 0x1a35, + 0xc0c: 0x1c64, 0xc0d: 0x1c70, 0xc0e: 0x1a26, 0xc0f: 0x19fc, 0xc10: 0x1957, 0xc11: 0x1c1c, + 0xc12: 0x1bb0, 0xc13: 0x1b9c, 0xc14: 0x1bcc, 0xc15: 0x1c74, 0xc16: 0x1a29, 0xc17: 0x19c9, + 0xc18: 0x19ff, 0xc19: 0x19de, 0xc1a: 0x1a41, 0xc1b: 0x1c78, 0xc1c: 0x1a2c, 0xc1d: 0x19c0, + 0xc1e: 0x1a02, 0xc1f: 0x1c3c, 0xc20: 0x1bf4, 0xc21: 0x1a14, 0xc22: 0x1c24, 0xc23: 0x1c40, + 0xc24: 0x1bf8, 0xc25: 0x1a17, 0xc26: 0x1c28, 0xc27: 0x22e8, 0xc28: 0x22fc, 0xc29: 0x1996, + 0xc2a: 0x1c20, 0xc2b: 0x1bb4, 0xc2c: 0x1ba0, 0xc2d: 0x1c48, 0xc2e: 0x2716, 0xc2f: 0x27ad, + 0xc30: 0x1a59, 0xc31: 0x1a44, 0xc32: 0x1c7c, 0xc33: 0x1a2f, 0xc34: 0x1a50, 0xc35: 0x1a38, + 0xc36: 0x1c68, 0xc37: 0x1a1d, 0xc38: 0x19f6, 0xc39: 0x1981, 0xc3a: 0x1a53, 0xc3b: 0x1a3b, + 0xc3c: 0x1c6c, 0xc3d: 0x1a20, 0xc3e: 0x19f9, 0xc3f: 0x1984, // Block 0x31, offset 0xc40 - 0xc40: 0x1377, 0xc41: 0x0cfb, 0xc42: 0x13d3, 0xc43: 0x139f, 0xc44: 0x0e57, 0xc45: 0x06eb, - 0xc46: 0x08df, 0xc47: 0x162b, 0xc48: 0x162b, 0xc49: 0x0a0b, 0xc4a: 0x145f, 0xc4b: 0x0943, - 0xc4c: 0x0a07, 0xc4d: 0x0bef, 0xc4e: 0x0fcf, 0xc4f: 0x115f, 0xc50: 0x1297, 0xc51: 0x12d3, - 0xc52: 0x1307, 0xc53: 0x141b, 0xc54: 0x0d73, 0xc55: 0x0dff, 0xc56: 0x0eab, 0xc57: 0x0f43, - 0xc58: 0x125f, 0xc59: 0x1447, 0xc5a: 0x1573, 0xc5b: 0x070f, 0xc5c: 0x08b3, 0xc5d: 0x0d87, - 0xc5e: 0x0ecf, 0xc5f: 0x1293, 0xc60: 0x15c3, 0xc61: 0x0ab3, 0xc62: 0x0e77, 0xc63: 0x1283, - 0xc64: 0x1317, 0xc65: 0x0c23, 0xc66: 0x11bb, 0xc67: 0x12df, 0xc68: 0x0b1f, 0xc69: 0x0d0f, - 0xc6a: 0x0e17, 0xc6b: 0x0f1b, 0xc6c: 0x1427, 0xc6d: 0x074f, 0xc6e: 0x07e7, 0xc6f: 0x0853, - 0xc70: 0x0c8b, 0xc71: 0x0d7f, 0xc72: 0x0ecb, 0xc73: 0x0fef, 0xc74: 0x1177, 0xc75: 0x128b, - 0xc76: 0x12a3, 0xc77: 0x13c7, 0xc78: 0x14ef, 0xc79: 0x15a3, 0xc7a: 0x15bf, 0xc7b: 0x102b, - 0xc7c: 0x106b, 0xc7d: 0x1123, 0xc7e: 0x1243, 0xc7f: 0x147b, + 0xc40: 0x1c2c, 0xc41: 0x1bb8, 0xc42: 0x1d4d, 0xc43: 0x1939, 0xc44: 0x19ba, 0xc45: 0x19bd, + 0xc46: 0x22f5, 0xc47: 0x1b94, 0xc48: 0x19c3, 0xc49: 0x194b, 0xc4a: 0x19e1, 0xc4b: 0x194e, + 0xc4c: 0x19ea, 0xc4d: 0x196c, 0xc4e: 0x196f, 0xc4f: 0x1a05, 0xc50: 0x1a0b, 0xc51: 0x1a0e, + 0xc52: 0x1c30, 0xc53: 0x1a11, 0xc54: 0x1a23, 0xc55: 0x1c38, 0xc56: 0x1c44, 0xc57: 0x1990, + 0xc58: 0x1d57, 0xc59: 0x1bbc, 0xc5a: 0x1993, 0xc5b: 0x1a5c, 0xc5c: 0x19a5, 0xc5d: 0x19b4, + 0xc5e: 0x22e2, 0xc5f: 0x22dc, 0xc60: 0x1cc1, 0xc61: 0x1cd0, 0xc62: 0x1cdf, 0xc63: 0x1cee, + 0xc64: 0x1cfd, 0xc65: 0x1d0c, 0xc66: 0x1d1b, 0xc67: 0x1d2a, 0xc68: 0x1d39, 0xc69: 0x2186, + 0xc6a: 0x2198, 0xc6b: 0x21aa, 0xc6c: 0x21bc, 0xc6d: 0x21c8, 0xc6e: 0x21d4, 0xc6f: 0x21e0, + 0xc70: 0x21ec, 0xc71: 0x21f8, 0xc72: 0x2204, 0xc73: 0x2240, 0xc74: 0x224c, 0xc75: 0x2258, + 0xc76: 0x2264, 0xc77: 0x2270, 0xc78: 0x227c, 0xc79: 0x2282, 0xc7a: 0x2288, 0xc7b: 0x228e, + 0xc7c: 0x2294, 0xc7d: 0x22a6, 0xc7e: 0x22ac, 0xc7f: 0x1c10, // Block 0x32, offset 0xc80 - 0xc80: 0x15cb, 0xc81: 0x134b, 0xc82: 0x09c7, 0xc83: 0x0b3b, 0xc84: 0x10db, 0xc85: 0x119b, - 0xc86: 0x0eff, 0xc87: 0x1033, 0xc88: 0x1397, 0xc89: 0x14e7, 0xc8a: 0x09c3, 0xc8b: 0x0a8f, - 0xc8c: 0x0d77, 0xc8d: 0x0e2b, 0xc8e: 0x0e5f, 0xc8f: 0x1113, 0xc90: 0x113b, 0xc91: 0x14a7, - 0xc92: 0x084f, 0xc93: 0x11a7, 0xc94: 0x07f3, 0xc95: 0x07ef, 0xc96: 0x1097, 0xc97: 0x1127, - 0xc98: 0x125b, 0xc99: 0x14af, 0xc9a: 0x1367, 0xc9b: 0x0c27, 0xc9c: 0x0d73, 0xc9d: 0x1357, - 0xc9e: 0x06f7, 0xc9f: 0x0a63, 0xca0: 0x0b93, 0xca1: 0x0f2f, 0xca2: 0x0faf, 0xca3: 0x0873, - 0xca4: 0x103b, 0xca5: 0x075f, 0xca6: 0x0b77, 0xca7: 0x06d7, 0xca8: 0x0deb, 0xca9: 0x0ca3, - 0xcaa: 0x110f, 0xcab: 0x08c7, 0xcac: 0x09b3, 0xcad: 0x0ffb, 0xcae: 0x1263, 0xcaf: 0x133b, - 0xcb0: 0x0db7, 0xcb1: 0x13f7, 0xcb2: 0x0de3, 0xcb3: 0x0c37, 0xcb4: 0x121b, 0xcb5: 0x0c57, - 0xcb6: 0x0fab, 0xcb7: 0x072b, 0xcb8: 0x07a7, 0xcb9: 0x07eb, 0xcba: 0x0d53, 0xcbb: 0x10fb, - 0xcbc: 0x11f3, 0xcbd: 0x1347, 0xcbe: 0x145b, 0xcbf: 0x085b, + 0xc80: 0x1377, 0xc81: 0x0cfb, 0xc82: 0x13d3, 0xc83: 0x139f, 0xc84: 0x0e57, 0xc85: 0x06eb, + 0xc86: 0x08df, 0xc87: 0x162b, 0xc88: 0x162b, 0xc89: 0x0a0b, 0xc8a: 0x145f, 0xc8b: 0x0943, + 0xc8c: 0x0a07, 0xc8d: 0x0bef, 0xc8e: 0x0fcf, 0xc8f: 0x115f, 0xc90: 0x1297, 0xc91: 0x12d3, + 0xc92: 0x1307, 0xc93: 0x141b, 0xc94: 0x0d73, 0xc95: 0x0dff, 0xc96: 0x0eab, 0xc97: 0x0f43, + 0xc98: 0x125f, 0xc99: 0x1447, 0xc9a: 0x1573, 0xc9b: 0x070f, 0xc9c: 0x08b3, 0xc9d: 0x0d87, + 0xc9e: 0x0ecf, 0xc9f: 0x1293, 0xca0: 0x15c3, 0xca1: 0x0ab3, 0xca2: 0x0e77, 0xca3: 0x1283, + 0xca4: 0x1317, 0xca5: 0x0c23, 0xca6: 0x11bb, 0xca7: 0x12df, 0xca8: 0x0b1f, 0xca9: 0x0d0f, + 0xcaa: 0x0e17, 0xcab: 0x0f1b, 0xcac: 0x1427, 0xcad: 0x074f, 0xcae: 0x07e7, 0xcaf: 0x0853, + 0xcb0: 0x0c8b, 0xcb1: 0x0d7f, 0xcb2: 0x0ecb, 0xcb3: 0x0fef, 0xcb4: 0x1177, 0xcb5: 0x128b, + 0xcb6: 0x12a3, 0xcb7: 0x13c7, 0xcb8: 0x14ef, 0xcb9: 0x15a3, 0xcba: 0x15bf, 0xcbb: 0x102b, + 0xcbc: 0x106b, 0xcbd: 0x1123, 0xcbe: 0x1243, 0xcbf: 0x147b, // Block 0x33, offset 0xcc0 - 0xcc0: 0x090f, 0xcc1: 0x0a17, 0xcc2: 0x0b2f, 0xcc3: 0x0cbf, 0xcc4: 0x0e7b, 0xcc5: 0x103f, - 0xcc6: 0x1497, 0xcc7: 0x157b, 0xcc8: 0x15cf, 0xcc9: 0x15e7, 0xcca: 0x0837, 0xccb: 0x0cf3, - 0xccc: 0x0da3, 0xccd: 0x13eb, 0xcce: 0x0afb, 0xccf: 0x0bd7, 0xcd0: 0x0bf3, 0xcd1: 0x0c83, - 0xcd2: 0x0e6b, 0xcd3: 0x0eb7, 0xcd4: 0x0f67, 0xcd5: 0x108b, 0xcd6: 0x112f, 0xcd7: 0x1193, - 0xcd8: 0x13db, 0xcd9: 0x126b, 0xcda: 0x1403, 0xcdb: 0x147f, 0xcdc: 0x080f, 0xcdd: 0x083b, - 0xcde: 0x0923, 0xcdf: 0x0ea7, 0xce0: 0x12f3, 0xce1: 0x133b, 0xce2: 0x0b1b, 0xce3: 0x0b8b, - 0xce4: 0x0c4f, 0xce5: 0x0daf, 0xce6: 0x10d7, 0xce7: 0x0f23, 0xce8: 0x073b, 0xce9: 0x097f, - 0xcea: 0x0a63, 0xceb: 0x0ac7, 0xcec: 0x0b97, 0xced: 0x0f3f, 0xcee: 0x0f5b, 0xcef: 0x116b, - 0xcf0: 0x118b, 0xcf1: 0x1463, 0xcf2: 0x14e3, 0xcf3: 0x14f3, 0xcf4: 0x152f, 0xcf5: 0x0753, - 0xcf6: 0x107f, 0xcf7: 0x144f, 0xcf8: 0x14cb, 0xcf9: 0x0baf, 0xcfa: 0x0717, 0xcfb: 0x0777, - 0xcfc: 0x0a67, 0xcfd: 0x0a87, 0xcfe: 0x0caf, 0xcff: 0x0d73, + 0xcc0: 0x15cb, 0xcc1: 0x134b, 0xcc2: 0x09c7, 0xcc3: 0x0b3b, 0xcc4: 0x10db, 0xcc5: 0x119b, + 0xcc6: 0x0eff, 0xcc7: 0x1033, 0xcc8: 0x1397, 0xcc9: 0x14e7, 0xcca: 0x09c3, 0xccb: 0x0a8f, + 0xccc: 0x0d77, 0xccd: 0x0e2b, 0xcce: 0x0e5f, 0xccf: 0x1113, 0xcd0: 0x113b, 0xcd1: 0x14a7, + 0xcd2: 0x084f, 0xcd3: 0x11a7, 0xcd4: 0x07f3, 0xcd5: 0x07ef, 0xcd6: 0x1097, 0xcd7: 0x1127, + 0xcd8: 0x125b, 0xcd9: 0x14af, 0xcda: 0x1367, 0xcdb: 0x0c27, 0xcdc: 0x0d73, 0xcdd: 0x1357, + 0xcde: 0x06f7, 0xcdf: 0x0a63, 0xce0: 0x0b93, 0xce1: 0x0f2f, 0xce2: 0x0faf, 0xce3: 0x0873, + 0xce4: 0x103b, 0xce5: 0x075f, 0xce6: 0x0b77, 0xce7: 0x06d7, 0xce8: 0x0deb, 0xce9: 0x0ca3, + 0xcea: 0x110f, 0xceb: 0x08c7, 0xcec: 0x09b3, 0xced: 0x0ffb, 0xcee: 0x1263, 0xcef: 0x133b, + 0xcf0: 0x0db7, 0xcf1: 0x13f7, 0xcf2: 0x0de3, 0xcf3: 0x0c37, 0xcf4: 0x121b, 0xcf5: 0x0c57, + 0xcf6: 0x0fab, 0xcf7: 0x072b, 0xcf8: 0x07a7, 0xcf9: 0x07eb, 0xcfa: 0x0d53, 0xcfb: 0x10fb, + 0xcfc: 0x11f3, 0xcfd: 0x1347, 0xcfe: 0x145b, 0xcff: 0x085b, // Block 0x34, offset 0xd00 - 0xd00: 0x0ec3, 0xd01: 0x0fcb, 0xd02: 0x1277, 0xd03: 0x1417, 0xd04: 0x1623, 0xd05: 0x0ce3, - 0xd06: 0x14a3, 0xd07: 0x0833, 0xd08: 0x0d2f, 0xd09: 0x0d3b, 0xd0a: 0x0e0f, 0xd0b: 0x0e47, - 0xd0c: 0x0f4b, 0xd0d: 0x0fa7, 0xd0e: 0x1027, 0xd0f: 0x110b, 0xd10: 0x153b, 0xd11: 0x07af, - 0xd12: 0x0c03, 0xd13: 0x14b3, 0xd14: 0x0767, 0xd15: 0x0aab, 0xd16: 0x0e2f, 0xd17: 0x13df, - 0xd18: 0x0b67, 0xd19: 0x0bb7, 0xd1a: 0x0d43, 0xd1b: 0x0f2f, 0xd1c: 0x14bb, 0xd1d: 0x0817, - 0xd1e: 0x08ff, 0xd1f: 0x0a97, 0xd20: 0x0cd3, 0xd21: 0x0d1f, 0xd22: 0x0d5f, 0xd23: 0x0df3, - 0xd24: 0x0f47, 0xd25: 0x0fbb, 0xd26: 0x1157, 0xd27: 0x12f7, 0xd28: 0x1303, 0xd29: 0x1457, - 0xd2a: 0x14d7, 0xd2b: 0x0883, 0xd2c: 0x0e4b, 0xd2d: 0x0903, 0xd2e: 0x0ec7, 0xd2f: 0x0f6b, - 0xd30: 0x1287, 0xd31: 0x14bf, 0xd32: 0x15ab, 0xd33: 0x15d3, 0xd34: 0x0d37, 0xd35: 0x0e27, - 0xd36: 0x11c3, 0xd37: 0x10b7, 0xd38: 0x10c3, 0xd39: 0x10e7, 0xd3a: 0x0f17, 0xd3b: 0x0e9f, - 0xd3c: 0x1363, 0xd3d: 0x0733, 0xd3e: 0x122b, 0xd3f: 0x081b, + 0xd00: 0x090f, 0xd01: 0x0a17, 0xd02: 0x0b2f, 0xd03: 0x0cbf, 0xd04: 0x0e7b, 0xd05: 0x103f, + 0xd06: 0x1497, 0xd07: 0x157b, 0xd08: 0x15cf, 0xd09: 0x15e7, 0xd0a: 0x0837, 0xd0b: 0x0cf3, + 0xd0c: 0x0da3, 0xd0d: 0x13eb, 0xd0e: 0x0afb, 0xd0f: 0x0bd7, 0xd10: 0x0bf3, 0xd11: 0x0c83, + 0xd12: 0x0e6b, 0xd13: 0x0eb7, 0xd14: 0x0f67, 0xd15: 0x108b, 0xd16: 0x112f, 0xd17: 0x1193, + 0xd18: 0x13db, 0xd19: 0x126b, 0xd1a: 0x1403, 0xd1b: 0x147f, 0xd1c: 0x080f, 0xd1d: 0x083b, + 0xd1e: 0x0923, 0xd1f: 0x0ea7, 0xd20: 0x12f3, 0xd21: 0x133b, 0xd22: 0x0b1b, 0xd23: 0x0b8b, + 0xd24: 0x0c4f, 0xd25: 0x0daf, 0xd26: 0x10d7, 0xd27: 0x0f23, 0xd28: 0x073b, 0xd29: 0x097f, + 0xd2a: 0x0a63, 0xd2b: 0x0ac7, 0xd2c: 0x0b97, 0xd2d: 0x0f3f, 0xd2e: 0x0f5b, 0xd2f: 0x116b, + 0xd30: 0x118b, 0xd31: 0x1463, 0xd32: 0x14e3, 0xd33: 0x14f3, 0xd34: 0x152f, 0xd35: 0x0753, + 0xd36: 0x107f, 0xd37: 0x144f, 0xd38: 0x14cb, 0xd39: 0x0baf, 0xd3a: 0x0717, 0xd3b: 0x0777, + 0xd3c: 0x0a67, 0xd3d: 0x0a87, 0xd3e: 0x0caf, 0xd3f: 0x0d73, // Block 0x35, offset 0xd40 - 0xd40: 0x080b, 0xd41: 0x0b0b, 0xd42: 0x0c2b, 0xd43: 0x10f3, 0xd44: 0x0a53, 0xd45: 0x0e03, - 0xd46: 0x0cef, 0xd47: 0x13e7, 0xd48: 0x12e7, 0xd49: 0x14ab, 0xd4a: 0x1323, 0xd4b: 0x0b27, - 0xd4c: 0x0787, 0xd4d: 0x095b, 0xd50: 0x09af, - 0xd52: 0x0cdf, 0xd55: 0x07f7, 0xd56: 0x0f1f, 0xd57: 0x0fe3, - 0xd58: 0x1047, 0xd59: 0x1063, 0xd5a: 0x1067, 0xd5b: 0x107b, 0xd5c: 0x14fb, 0xd5d: 0x10eb, - 0xd5e: 0x116f, 0xd60: 0x128f, 0xd62: 0x1353, - 0xd65: 0x1407, 0xd66: 0x1433, - 0xd6a: 0x154f, 0xd6b: 0x1553, 0xd6c: 0x1557, 0xd6d: 0x15bb, 0xd6e: 0x142b, 0xd6f: 0x14c7, - 0xd70: 0x0757, 0xd71: 0x077b, 0xd72: 0x078f, 0xd73: 0x084b, 0xd74: 0x0857, 0xd75: 0x0897, - 0xd76: 0x094b, 0xd77: 0x0967, 0xd78: 0x096f, 0xd79: 0x09ab, 0xd7a: 0x09b7, 0xd7b: 0x0a93, - 0xd7c: 0x0a9b, 0xd7d: 0x0ba3, 0xd7e: 0x0bcb, 0xd7f: 0x0bd3, + 0xd40: 0x0ec3, 0xd41: 0x0fcb, 0xd42: 0x1277, 0xd43: 0x1417, 0xd44: 0x1623, 0xd45: 0x0ce3, + 0xd46: 0x14a3, 0xd47: 0x0833, 0xd48: 0x0d2f, 0xd49: 0x0d3b, 0xd4a: 0x0e0f, 0xd4b: 0x0e47, + 0xd4c: 0x0f4b, 0xd4d: 0x0fa7, 0xd4e: 0x1027, 0xd4f: 0x110b, 0xd50: 0x153b, 0xd51: 0x07af, + 0xd52: 0x0c03, 0xd53: 0x14b3, 0xd54: 0x0767, 0xd55: 0x0aab, 0xd56: 0x0e2f, 0xd57: 0x13df, + 0xd58: 0x0b67, 0xd59: 0x0bb7, 0xd5a: 0x0d43, 0xd5b: 0x0f2f, 0xd5c: 0x14bb, 0xd5d: 0x0817, + 0xd5e: 0x08ff, 0xd5f: 0x0a97, 0xd60: 0x0cd3, 0xd61: 0x0d1f, 0xd62: 0x0d5f, 0xd63: 0x0df3, + 0xd64: 0x0f47, 0xd65: 0x0fbb, 0xd66: 0x1157, 0xd67: 0x12f7, 0xd68: 0x1303, 0xd69: 0x1457, + 0xd6a: 0x14d7, 0xd6b: 0x0883, 0xd6c: 0x0e4b, 0xd6d: 0x0903, 0xd6e: 0x0ec7, 0xd6f: 0x0f6b, + 0xd70: 0x1287, 0xd71: 0x14bf, 0xd72: 0x15ab, 0xd73: 0x15d3, 0xd74: 0x0d37, 0xd75: 0x0e27, + 0xd76: 0x11c3, 0xd77: 0x10b7, 0xd78: 0x10c3, 0xd79: 0x10e7, 0xd7a: 0x0f17, 0xd7b: 0x0e9f, + 0xd7c: 0x1363, 0xd7d: 0x0733, 0xd7e: 0x122b, 0xd7f: 0x081b, // Block 0x36, offset 0xd80 - 0xd80: 0x0beb, 0xd81: 0x0c97, 0xd82: 0x0cc7, 0xd83: 0x0ce7, 0xd84: 0x0d57, 0xd85: 0x0e1b, - 0xd86: 0x0e37, 0xd87: 0x0e67, 0xd88: 0x0ebb, 0xd89: 0x0edb, 0xd8a: 0x0f4f, 0xd8b: 0x102f, - 0xd8c: 0x104b, 0xd8d: 0x1053, 0xd8e: 0x104f, 0xd8f: 0x1057, 0xd90: 0x105b, 0xd91: 0x105f, - 0xd92: 0x1073, 0xd93: 0x1077, 0xd94: 0x109b, 0xd95: 0x10af, 0xd96: 0x10cb, 0xd97: 0x112f, - 0xd98: 0x1137, 0xd99: 0x113f, 0xd9a: 0x1153, 0xd9b: 0x117b, 0xd9c: 0x11cb, 0xd9d: 0x11ff, - 0xd9e: 0x11ff, 0xd9f: 0x1267, 0xda0: 0x130f, 0xda1: 0x1327, 0xda2: 0x135b, 0xda3: 0x135f, - 0xda4: 0x13a3, 0xda5: 0x13a7, 0xda6: 0x13ff, 0xda7: 0x1407, 0xda8: 0x14db, 0xda9: 0x151f, - 0xdaa: 0x1537, 0xdab: 0x0b9b, 0xdac: 0x171e, 0xdad: 0x11e3, - 0xdb0: 0x06df, 0xdb1: 0x07e3, 0xdb2: 0x07a3, 0xdb3: 0x074b, 0xdb4: 0x078b, 0xdb5: 0x07b7, - 0xdb6: 0x0847, 0xdb7: 0x0863, 0xdb8: 0x094b, 0xdb9: 0x0937, 0xdba: 0x0947, 0xdbb: 0x0963, - 0xdbc: 0x09af, 0xdbd: 0x09bf, 0xdbe: 0x0a03, 0xdbf: 0x0a0f, + 0xd80: 0x080b, 0xd81: 0x0b0b, 0xd82: 0x0c2b, 0xd83: 0x10f3, 0xd84: 0x0a53, 0xd85: 0x0e03, + 0xd86: 0x0cef, 0xd87: 0x13e7, 0xd88: 0x12e7, 0xd89: 0x14ab, 0xd8a: 0x1323, 0xd8b: 0x0b27, + 0xd8c: 0x0787, 0xd8d: 0x095b, 0xd90: 0x09af, + 0xd92: 0x0cdf, 0xd95: 0x07f7, 0xd96: 0x0f1f, 0xd97: 0x0fe3, + 0xd98: 0x1047, 0xd99: 0x1063, 0xd9a: 0x1067, 0xd9b: 0x107b, 0xd9c: 0x14fb, 0xd9d: 0x10eb, + 0xd9e: 0x116f, 0xda0: 0x128f, 0xda2: 0x1353, + 0xda5: 0x1407, 0xda6: 0x1433, + 0xdaa: 0x154f, 0xdab: 0x1553, 0xdac: 0x1557, 0xdad: 0x15bb, 0xdae: 0x142b, 0xdaf: 0x14c7, + 0xdb0: 0x0757, 0xdb1: 0x077b, 0xdb2: 0x078f, 0xdb3: 0x084b, 0xdb4: 0x0857, 0xdb5: 0x0897, + 0xdb6: 0x094b, 0xdb7: 0x0967, 0xdb8: 0x096f, 0xdb9: 0x09ab, 0xdba: 0x09b7, 0xdbb: 0x0a93, + 0xdbc: 0x0a9b, 0xdbd: 0x0ba3, 0xdbe: 0x0bcb, 0xdbf: 0x0bd3, // Block 0x37, offset 0xdc0 - 0xdc0: 0x0a2b, 0xdc1: 0x0a3b, 0xdc2: 0x0b23, 0xdc3: 0x0b2b, 0xdc4: 0x0b5b, 0xdc5: 0x0b7b, - 0xdc6: 0x0bab, 0xdc7: 0x0bc3, 0xdc8: 0x0bb3, 0xdc9: 0x0bd3, 0xdca: 0x0bc7, 0xdcb: 0x0beb, - 0xdcc: 0x0c07, 0xdcd: 0x0c5f, 0xdce: 0x0c6b, 0xdcf: 0x0c73, 0xdd0: 0x0c9b, 0xdd1: 0x0cdf, - 0xdd2: 0x0d0f, 0xdd3: 0x0d13, 0xdd4: 0x0d27, 0xdd5: 0x0da7, 0xdd6: 0x0db7, 0xdd7: 0x0e0f, - 0xdd8: 0x0e5b, 0xdd9: 0x0e53, 0xdda: 0x0e67, 0xddb: 0x0e83, 0xddc: 0x0ebb, 0xddd: 0x1013, - 0xdde: 0x0edf, 0xddf: 0x0f13, 0xde0: 0x0f1f, 0xde1: 0x0f5f, 0xde2: 0x0f7b, 0xde3: 0x0f9f, - 0xde4: 0x0fc3, 0xde5: 0x0fc7, 0xde6: 0x0fe3, 0xde7: 0x0fe7, 0xde8: 0x0ff7, 0xde9: 0x100b, - 0xdea: 0x1007, 0xdeb: 0x1037, 0xdec: 0x10b3, 0xded: 0x10cb, 0xdee: 0x10e3, 0xdef: 0x111b, - 0xdf0: 0x112f, 0xdf1: 0x114b, 0xdf2: 0x117b, 0xdf3: 0x122f, 0xdf4: 0x1257, 0xdf5: 0x12cb, - 0xdf6: 0x1313, 0xdf7: 0x131f, 0xdf8: 0x1327, 0xdf9: 0x133f, 0xdfa: 0x1353, 0xdfb: 0x1343, - 0xdfc: 0x135b, 0xdfd: 0x1357, 0xdfe: 0x134f, 0xdff: 0x135f, + 0xdc0: 0x0beb, 0xdc1: 0x0c97, 0xdc2: 0x0cc7, 0xdc3: 0x0ce7, 0xdc4: 0x0d57, 0xdc5: 0x0e1b, + 0xdc6: 0x0e37, 0xdc7: 0x0e67, 0xdc8: 0x0ebb, 0xdc9: 0x0edb, 0xdca: 0x0f4f, 0xdcb: 0x102f, + 0xdcc: 0x104b, 0xdcd: 0x1053, 0xdce: 0x104f, 0xdcf: 0x1057, 0xdd0: 0x105b, 0xdd1: 0x105f, + 0xdd2: 0x1073, 0xdd3: 0x1077, 0xdd4: 0x109b, 0xdd5: 0x10af, 0xdd6: 0x10cb, 0xdd7: 0x112f, + 0xdd8: 0x1137, 0xdd9: 0x113f, 0xdda: 0x1153, 0xddb: 0x117b, 0xddc: 0x11cb, 0xddd: 0x11ff, + 0xdde: 0x11ff, 0xddf: 0x1267, 0xde0: 0x130f, 0xde1: 0x1327, 0xde2: 0x135b, 0xde3: 0x135f, + 0xde4: 0x13a3, 0xde5: 0x13a7, 0xde6: 0x13ff, 0xde7: 0x1407, 0xde8: 0x14db, 0xde9: 0x151f, + 0xdea: 0x1537, 0xdeb: 0x0b9b, 0xdec: 0x171e, 0xded: 0x11e3, + 0xdf0: 0x06df, 0xdf1: 0x07e3, 0xdf2: 0x07a3, 0xdf3: 0x074b, 0xdf4: 0x078b, 0xdf5: 0x07b7, + 0xdf6: 0x0847, 0xdf7: 0x0863, 0xdf8: 0x094b, 0xdf9: 0x0937, 0xdfa: 0x0947, 0xdfb: 0x0963, + 0xdfc: 0x09af, 0xdfd: 0x09bf, 0xdfe: 0x0a03, 0xdff: 0x0a0f, // Block 0x38, offset 0xe00 - 0xe00: 0x136b, 0xe01: 0x13a7, 0xe02: 0x13e3, 0xe03: 0x1413, 0xe04: 0x144b, 0xe05: 0x146b, - 0xe06: 0x14b7, 0xe07: 0x14db, 0xe08: 0x14fb, 0xe09: 0x150f, 0xe0a: 0x151f, 0xe0b: 0x152b, - 0xe0c: 0x1537, 0xe0d: 0x158b, 0xe0e: 0x162b, 0xe0f: 0x16b5, 0xe10: 0x16b0, 0xe11: 0x16e2, - 0xe12: 0x0607, 0xe13: 0x062f, 0xe14: 0x0633, 0xe15: 0x1764, 0xe16: 0x1791, 0xe17: 0x1809, - 0xe18: 0x1617, 0xe19: 0x1627, + 0xe00: 0x0a2b, 0xe01: 0x0a3b, 0xe02: 0x0b23, 0xe03: 0x0b2b, 0xe04: 0x0b5b, 0xe05: 0x0b7b, + 0xe06: 0x0bab, 0xe07: 0x0bc3, 0xe08: 0x0bb3, 0xe09: 0x0bd3, 0xe0a: 0x0bc7, 0xe0b: 0x0beb, + 0xe0c: 0x0c07, 0xe0d: 0x0c5f, 0xe0e: 0x0c6b, 0xe0f: 0x0c73, 0xe10: 0x0c9b, 0xe11: 0x0cdf, + 0xe12: 0x0d0f, 0xe13: 0x0d13, 0xe14: 0x0d27, 0xe15: 0x0da7, 0xe16: 0x0db7, 0xe17: 0x0e0f, + 0xe18: 0x0e5b, 0xe19: 0x0e53, 0xe1a: 0x0e67, 0xe1b: 0x0e83, 0xe1c: 0x0ebb, 0xe1d: 0x1013, + 0xe1e: 0x0edf, 0xe1f: 0x0f13, 0xe20: 0x0f1f, 0xe21: 0x0f5f, 0xe22: 0x0f7b, 0xe23: 0x0f9f, + 0xe24: 0x0fc3, 0xe25: 0x0fc7, 0xe26: 0x0fe3, 0xe27: 0x0fe7, 0xe28: 0x0ff7, 0xe29: 0x100b, + 0xe2a: 0x1007, 0xe2b: 0x1037, 0xe2c: 0x10b3, 0xe2d: 0x10cb, 0xe2e: 0x10e3, 0xe2f: 0x111b, + 0xe30: 0x112f, 0xe31: 0x114b, 0xe32: 0x117b, 0xe33: 0x122f, 0xe34: 0x1257, 0xe35: 0x12cb, + 0xe36: 0x1313, 0xe37: 0x131f, 0xe38: 0x1327, 0xe39: 0x133f, 0xe3a: 0x1353, 0xe3b: 0x1343, + 0xe3c: 0x135b, 0xe3d: 0x1357, 0xe3e: 0x134f, 0xe3f: 0x135f, // Block 0x39, offset 0xe40 - 0xe40: 0x19d5, 0xe41: 0x19d8, 0xe42: 0x19db, 0xe43: 0x1c08, 0xe44: 0x1c0c, 0xe45: 0x1a5f, - 0xe46: 0x1a5f, - 0xe53: 0x1d75, 0xe54: 0x1d66, 0xe55: 0x1d6b, 0xe56: 0x1d7a, 0xe57: 0x1d70, - 0xe5d: 0x4390, - 0xe5e: 0x8115, 0xe5f: 0x4402, 0xe60: 0x022d, 0xe61: 0x0215, 0xe62: 0x021e, 0xe63: 0x0221, - 0xe64: 0x0224, 0xe65: 0x0227, 0xe66: 0x022a, 0xe67: 0x0230, 0xe68: 0x0233, 0xe69: 0x0017, - 0xe6a: 0x43f0, 0xe6b: 0x43f6, 0xe6c: 0x44f4, 0xe6d: 0x44fc, 0xe6e: 0x4348, 0xe6f: 0x434e, - 0xe70: 0x4354, 0xe71: 0x435a, 0xe72: 0x4366, 0xe73: 0x436c, 0xe74: 0x4372, 0xe75: 0x437e, - 0xe76: 0x4384, 0xe78: 0x438a, 0xe79: 0x4396, 0xe7a: 0x439c, 0xe7b: 0x43a2, - 0xe7c: 0x43ae, 0xe7e: 0x43b4, + 0xe40: 0x136b, 0xe41: 0x13a7, 0xe42: 0x13e3, 0xe43: 0x1413, 0xe44: 0x144b, 0xe45: 0x146b, + 0xe46: 0x14b7, 0xe47: 0x14db, 0xe48: 0x14fb, 0xe49: 0x150f, 0xe4a: 0x151f, 0xe4b: 0x152b, + 0xe4c: 0x1537, 0xe4d: 0x158b, 0xe4e: 0x162b, 0xe4f: 0x16b5, 0xe50: 0x16b0, 0xe51: 0x16e2, + 0xe52: 0x0607, 0xe53: 0x062f, 0xe54: 0x0633, 0xe55: 0x1764, 0xe56: 0x1791, 0xe57: 0x1809, + 0xe58: 0x1617, 0xe59: 0x1627, // Block 0x3a, offset 0xe80 - 0xe80: 0x43ba, 0xe81: 0x43c0, 0xe83: 0x43c6, 0xe84: 0x43cc, - 0xe86: 0x43d8, 0xe87: 0x43de, 0xe88: 0x43e4, 0xe89: 0x43ea, 0xe8a: 0x43fc, 0xe8b: 0x4378, - 0xe8c: 0x4360, 0xe8d: 0x43a8, 0xe8e: 0x43d2, 0xe8f: 0x1d7f, 0xe90: 0x0299, 0xe91: 0x0299, - 0xe92: 0x02a2, 0xe93: 0x02a2, 0xe94: 0x02a2, 0xe95: 0x02a2, 0xe96: 0x02a5, 0xe97: 0x02a5, - 0xe98: 0x02a5, 0xe99: 0x02a5, 0xe9a: 0x02ab, 0xe9b: 0x02ab, 0xe9c: 0x02ab, 0xe9d: 0x02ab, - 0xe9e: 0x029f, 0xe9f: 0x029f, 0xea0: 0x029f, 0xea1: 0x029f, 0xea2: 0x02a8, 0xea3: 0x02a8, - 0xea4: 0x02a8, 0xea5: 0x02a8, 0xea6: 0x029c, 0xea7: 0x029c, 0xea8: 0x029c, 0xea9: 0x029c, - 0xeaa: 0x02cf, 0xeab: 0x02cf, 0xeac: 0x02cf, 0xead: 0x02cf, 0xeae: 0x02d2, 0xeaf: 0x02d2, - 0xeb0: 0x02d2, 0xeb1: 0x02d2, 0xeb2: 0x02b1, 0xeb3: 0x02b1, 0xeb4: 0x02b1, 0xeb5: 0x02b1, - 0xeb6: 0x02ae, 0xeb7: 0x02ae, 0xeb8: 0x02ae, 0xeb9: 0x02ae, 0xeba: 0x02b4, 0xebb: 0x02b4, - 0xebc: 0x02b4, 0xebd: 0x02b4, 0xebe: 0x02b7, 0xebf: 0x02b7, + 0xe80: 0x19d5, 0xe81: 0x19d8, 0xe82: 0x19db, 0xe83: 0x1c08, 0xe84: 0x1c0c, 0xe85: 0x1a5f, + 0xe86: 0x1a5f, + 0xe93: 0x1d75, 0xe94: 0x1d66, 0xe95: 0x1d6b, 0xe96: 0x1d7a, 0xe97: 0x1d70, + 0xe9d: 0x4390, + 0xe9e: 0x8115, 0xe9f: 0x4402, 0xea0: 0x022d, 0xea1: 0x0215, 0xea2: 0x021e, 0xea3: 0x0221, + 0xea4: 0x0224, 0xea5: 0x0227, 0xea6: 0x022a, 0xea7: 0x0230, 0xea8: 0x0233, 0xea9: 0x0017, + 0xeaa: 0x43f0, 0xeab: 0x43f6, 0xeac: 0x44f4, 0xead: 0x44fc, 0xeae: 0x4348, 0xeaf: 0x434e, + 0xeb0: 0x4354, 0xeb1: 0x435a, 0xeb2: 0x4366, 0xeb3: 0x436c, 0xeb4: 0x4372, 0xeb5: 0x437e, + 0xeb6: 0x4384, 0xeb8: 0x438a, 0xeb9: 0x4396, 0xeba: 0x439c, 0xebb: 0x43a2, + 0xebc: 0x43ae, 0xebe: 0x43b4, // Block 0x3b, offset 0xec0 - 0xec0: 0x02b7, 0xec1: 0x02b7, 0xec2: 0x02c0, 0xec3: 0x02c0, 0xec4: 0x02bd, 0xec5: 0x02bd, - 0xec6: 0x02c3, 0xec7: 0x02c3, 0xec8: 0x02ba, 0xec9: 0x02ba, 0xeca: 0x02c9, 0xecb: 0x02c9, - 0xecc: 0x02c6, 0xecd: 0x02c6, 0xece: 0x02d5, 0xecf: 0x02d5, 0xed0: 0x02d5, 0xed1: 0x02d5, - 0xed2: 0x02db, 0xed3: 0x02db, 0xed4: 0x02db, 0xed5: 0x02db, 0xed6: 0x02e1, 0xed7: 0x02e1, - 0xed8: 0x02e1, 0xed9: 0x02e1, 0xeda: 0x02de, 0xedb: 0x02de, 0xedc: 0x02de, 0xedd: 0x02de, - 0xede: 0x02e4, 0xedf: 0x02e4, 0xee0: 0x02e7, 0xee1: 0x02e7, 0xee2: 0x02e7, 0xee3: 0x02e7, - 0xee4: 0x446e, 0xee5: 0x446e, 0xee6: 0x02ed, 0xee7: 0x02ed, 0xee8: 0x02ed, 0xee9: 0x02ed, - 0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308, - 0xef0: 0x4468, 0xef1: 0x4468, + 0xec0: 0x43ba, 0xec1: 0x43c0, 0xec3: 0x43c6, 0xec4: 0x43cc, + 0xec6: 0x43d8, 0xec7: 0x43de, 0xec8: 0x43e4, 0xec9: 0x43ea, 0xeca: 0x43fc, 0xecb: 0x4378, + 0xecc: 0x4360, 0xecd: 0x43a8, 0xece: 0x43d2, 0xecf: 0x1d7f, 0xed0: 0x0299, 0xed1: 0x0299, + 0xed2: 0x02a2, 0xed3: 0x02a2, 0xed4: 0x02a2, 0xed5: 0x02a2, 0xed6: 0x02a5, 0xed7: 0x02a5, + 0xed8: 0x02a5, 0xed9: 0x02a5, 0xeda: 0x02ab, 0xedb: 0x02ab, 0xedc: 0x02ab, 0xedd: 0x02ab, + 0xede: 0x029f, 0xedf: 0x029f, 0xee0: 0x029f, 0xee1: 0x029f, 0xee2: 0x02a8, 0xee3: 0x02a8, + 0xee4: 0x02a8, 0xee5: 0x02a8, 0xee6: 0x029c, 0xee7: 0x029c, 0xee8: 0x029c, 0xee9: 0x029c, + 0xeea: 0x02cf, 0xeeb: 0x02cf, 0xeec: 0x02cf, 0xeed: 0x02cf, 0xeee: 0x02d2, 0xeef: 0x02d2, + 0xef0: 0x02d2, 0xef1: 0x02d2, 0xef2: 0x02b1, 0xef3: 0x02b1, 0xef4: 0x02b1, 0xef5: 0x02b1, + 0xef6: 0x02ae, 0xef7: 0x02ae, 0xef8: 0x02ae, 0xef9: 0x02ae, 0xefa: 0x02b4, 0xefb: 0x02b4, + 0xefc: 0x02b4, 0xefd: 0x02b4, 0xefe: 0x02b7, 0xeff: 0x02b7, // Block 0x3c, offset 0xf00 - 0xf13: 0x02d8, 0xf14: 0x02d8, 0xf15: 0x02d8, 0xf16: 0x02d8, 0xf17: 0x02f6, - 0xf18: 0x02f6, 0xf19: 0x02f3, 0xf1a: 0x02f3, 0xf1b: 0x02f9, 0xf1c: 0x02f9, 0xf1d: 0x204f, - 0xf1e: 0x02ff, 0xf1f: 0x02ff, 0xf20: 0x02f0, 0xf21: 0x02f0, 0xf22: 0x02fc, 0xf23: 0x02fc, - 0xf24: 0x0305, 0xf25: 0x0305, 0xf26: 0x0305, 0xf27: 0x0305, 0xf28: 0x028d, 0xf29: 0x028d, - 0xf2a: 0x25aa, 0xf2b: 0x25aa, 0xf2c: 0x261a, 0xf2d: 0x261a, 0xf2e: 0x25e9, 0xf2f: 0x25e9, - 0xf30: 0x2605, 0xf31: 0x2605, 0xf32: 0x25fe, 0xf33: 0x25fe, 0xf34: 0x260c, 0xf35: 0x260c, - 0xf36: 0x2613, 0xf37: 0x2613, 0xf38: 0x2613, 0xf39: 0x25f0, 0xf3a: 0x25f0, 0xf3b: 0x25f0, - 0xf3c: 0x0302, 0xf3d: 0x0302, 0xf3e: 0x0302, 0xf3f: 0x0302, + 0xf00: 0x02b7, 0xf01: 0x02b7, 0xf02: 0x02c0, 0xf03: 0x02c0, 0xf04: 0x02bd, 0xf05: 0x02bd, + 0xf06: 0x02c3, 0xf07: 0x02c3, 0xf08: 0x02ba, 0xf09: 0x02ba, 0xf0a: 0x02c9, 0xf0b: 0x02c9, + 0xf0c: 0x02c6, 0xf0d: 0x02c6, 0xf0e: 0x02d5, 0xf0f: 0x02d5, 0xf10: 0x02d5, 0xf11: 0x02d5, + 0xf12: 0x02db, 0xf13: 0x02db, 0xf14: 0x02db, 0xf15: 0x02db, 0xf16: 0x02e1, 0xf17: 0x02e1, + 0xf18: 0x02e1, 0xf19: 0x02e1, 0xf1a: 0x02de, 0xf1b: 0x02de, 0xf1c: 0x02de, 0xf1d: 0x02de, + 0xf1e: 0x02e4, 0xf1f: 0x02e4, 0xf20: 0x02e7, 0xf21: 0x02e7, 0xf22: 0x02e7, 0xf23: 0x02e7, + 0xf24: 0x446e, 0xf25: 0x446e, 0xf26: 0x02ed, 0xf27: 0x02ed, 0xf28: 0x02ed, 0xf29: 0x02ed, + 0xf2a: 0x02ea, 0xf2b: 0x02ea, 0xf2c: 0x02ea, 0xf2d: 0x02ea, 0xf2e: 0x0308, 0xf2f: 0x0308, + 0xf30: 0x4468, 0xf31: 0x4468, // Block 0x3d, offset 0xf40 - 0xf40: 0x25b1, 0xf41: 0x25b8, 0xf42: 0x25d4, 0xf43: 0x25f0, 0xf44: 0x25f7, 0xf45: 0x1d89, - 0xf46: 0x1d8e, 0xf47: 0x1d93, 0xf48: 0x1da2, 0xf49: 0x1db1, 0xf4a: 0x1db6, 0xf4b: 0x1dbb, - 0xf4c: 0x1dc0, 0xf4d: 0x1dc5, 0xf4e: 0x1dd4, 0xf4f: 0x1de3, 0xf50: 0x1de8, 0xf51: 0x1ded, - 0xf52: 0x1dfc, 0xf53: 0x1e0b, 0xf54: 0x1e10, 0xf55: 0x1e15, 0xf56: 0x1e1a, 0xf57: 0x1e29, - 0xf58: 0x1e2e, 0xf59: 0x1e3d, 0xf5a: 0x1e42, 0xf5b: 0x1e47, 0xf5c: 0x1e56, 0xf5d: 0x1e5b, - 0xf5e: 0x1e60, 0xf5f: 0x1e6a, 0xf60: 0x1ea6, 0xf61: 0x1eb5, 0xf62: 0x1ec4, 0xf63: 0x1ec9, - 0xf64: 0x1ece, 0xf65: 0x1ed8, 0xf66: 0x1ee7, 0xf67: 0x1eec, 0xf68: 0x1efb, 0xf69: 0x1f00, - 0xf6a: 0x1f05, 0xf6b: 0x1f14, 0xf6c: 0x1f19, 0xf6d: 0x1f28, 0xf6e: 0x1f2d, 0xf6f: 0x1f32, - 0xf70: 0x1f37, 0xf71: 0x1f3c, 0xf72: 0x1f41, 0xf73: 0x1f46, 0xf74: 0x1f4b, 0xf75: 0x1f50, - 0xf76: 0x1f55, 0xf77: 0x1f5a, 0xf78: 0x1f5f, 0xf79: 0x1f64, 0xf7a: 0x1f69, 0xf7b: 0x1f6e, - 0xf7c: 0x1f73, 0xf7d: 0x1f78, 0xf7e: 0x1f7d, 0xf7f: 0x1f87, + 0xf53: 0x02d8, 0xf54: 0x02d8, 0xf55: 0x02d8, 0xf56: 0x02d8, 0xf57: 0x02f6, + 0xf58: 0x02f6, 0xf59: 0x02f3, 0xf5a: 0x02f3, 0xf5b: 0x02f9, 0xf5c: 0x02f9, 0xf5d: 0x204f, + 0xf5e: 0x02ff, 0xf5f: 0x02ff, 0xf60: 0x02f0, 0xf61: 0x02f0, 0xf62: 0x02fc, 0xf63: 0x02fc, + 0xf64: 0x0305, 0xf65: 0x0305, 0xf66: 0x0305, 0xf67: 0x0305, 0xf68: 0x028d, 0xf69: 0x028d, + 0xf6a: 0x25aa, 0xf6b: 0x25aa, 0xf6c: 0x261a, 0xf6d: 0x261a, 0xf6e: 0x25e9, 0xf6f: 0x25e9, + 0xf70: 0x2605, 0xf71: 0x2605, 0xf72: 0x25fe, 0xf73: 0x25fe, 0xf74: 0x260c, 0xf75: 0x260c, + 0xf76: 0x2613, 0xf77: 0x2613, 0xf78: 0x2613, 0xf79: 0x25f0, 0xf7a: 0x25f0, 0xf7b: 0x25f0, + 0xf7c: 0x0302, 0xf7d: 0x0302, 0xf7e: 0x0302, 0xf7f: 0x0302, // Block 0x3e, offset 0xf80 - 0xf80: 0x1f8c, 0xf81: 0x1f91, 0xf82: 0x1f96, 0xf83: 0x1fa0, 0xf84: 0x1fa5, 0xf85: 0x1faf, - 0xf86: 0x1fb4, 0xf87: 0x1fb9, 0xf88: 0x1fbe, 0xf89: 0x1fc3, 0xf8a: 0x1fc8, 0xf8b: 0x1fcd, - 0xf8c: 0x1fd2, 0xf8d: 0x1fd7, 0xf8e: 0x1fe6, 0xf8f: 0x1ff5, 0xf90: 0x1ffa, 0xf91: 0x1fff, - 0xf92: 0x2004, 0xf93: 0x2009, 0xf94: 0x200e, 0xf95: 0x2018, 0xf96: 0x201d, 0xf97: 0x2022, - 0xf98: 0x2031, 0xf99: 0x2040, 0xf9a: 0x2045, 0xf9b: 0x4420, 0xf9c: 0x4426, 0xf9d: 0x445c, - 0xf9e: 0x44b3, 0xf9f: 0x44ba, 0xfa0: 0x44c1, 0xfa1: 0x44c8, 0xfa2: 0x44cf, 0xfa3: 0x44d6, - 0xfa4: 0x25c6, 0xfa5: 0x25cd, 0xfa6: 0x25d4, 0xfa7: 0x25db, 0xfa8: 0x25f0, 0xfa9: 0x25f7, - 0xfaa: 0x1d98, 0xfab: 0x1d9d, 0xfac: 0x1da2, 0xfad: 0x1da7, 0xfae: 0x1db1, 0xfaf: 0x1db6, - 0xfb0: 0x1dca, 0xfb1: 0x1dcf, 0xfb2: 0x1dd4, 0xfb3: 0x1dd9, 0xfb4: 0x1de3, 0xfb5: 0x1de8, - 0xfb6: 0x1df2, 0xfb7: 0x1df7, 0xfb8: 0x1dfc, 0xfb9: 0x1e01, 0xfba: 0x1e0b, 0xfbb: 0x1e10, - 0xfbc: 0x1f3c, 0xfbd: 0x1f41, 0xfbe: 0x1f50, 0xfbf: 0x1f55, + 0xf80: 0x25b1, 0xf81: 0x25b8, 0xf82: 0x25d4, 0xf83: 0x25f0, 0xf84: 0x25f7, 0xf85: 0x1d89, + 0xf86: 0x1d8e, 0xf87: 0x1d93, 0xf88: 0x1da2, 0xf89: 0x1db1, 0xf8a: 0x1db6, 0xf8b: 0x1dbb, + 0xf8c: 0x1dc0, 0xf8d: 0x1dc5, 0xf8e: 0x1dd4, 0xf8f: 0x1de3, 0xf90: 0x1de8, 0xf91: 0x1ded, + 0xf92: 0x1dfc, 0xf93: 0x1e0b, 0xf94: 0x1e10, 0xf95: 0x1e15, 0xf96: 0x1e1a, 0xf97: 0x1e29, + 0xf98: 0x1e2e, 0xf99: 0x1e3d, 0xf9a: 0x1e42, 0xf9b: 0x1e47, 0xf9c: 0x1e56, 0xf9d: 0x1e5b, + 0xf9e: 0x1e60, 0xf9f: 0x1e6a, 0xfa0: 0x1ea6, 0xfa1: 0x1eb5, 0xfa2: 0x1ec4, 0xfa3: 0x1ec9, + 0xfa4: 0x1ece, 0xfa5: 0x1ed8, 0xfa6: 0x1ee7, 0xfa7: 0x1eec, 0xfa8: 0x1efb, 0xfa9: 0x1f00, + 0xfaa: 0x1f05, 0xfab: 0x1f14, 0xfac: 0x1f19, 0xfad: 0x1f28, 0xfae: 0x1f2d, 0xfaf: 0x1f32, + 0xfb0: 0x1f37, 0xfb1: 0x1f3c, 0xfb2: 0x1f41, 0xfb3: 0x1f46, 0xfb4: 0x1f4b, 0xfb5: 0x1f50, + 0xfb6: 0x1f55, 0xfb7: 0x1f5a, 0xfb8: 0x1f5f, 0xfb9: 0x1f64, 0xfba: 0x1f69, 0xfbb: 0x1f6e, + 0xfbc: 0x1f73, 0xfbd: 0x1f78, 0xfbe: 0x1f7d, 0xfbf: 0x1f87, // Block 0x3f, offset 0xfc0 - 0xfc0: 0x1f5a, 0xfc1: 0x1f6e, 0xfc2: 0x1f73, 0xfc3: 0x1f78, 0xfc4: 0x1f7d, 0xfc5: 0x1f96, - 0xfc6: 0x1fa0, 0xfc7: 0x1fa5, 0xfc8: 0x1faa, 0xfc9: 0x1fbe, 0xfca: 0x1fdc, 0xfcb: 0x1fe1, - 0xfcc: 0x1fe6, 0xfcd: 0x1feb, 0xfce: 0x1ff5, 0xfcf: 0x1ffa, 0xfd0: 0x445c, 0xfd1: 0x2027, - 0xfd2: 0x202c, 0xfd3: 0x2031, 0xfd4: 0x2036, 0xfd5: 0x2040, 0xfd6: 0x2045, 0xfd7: 0x25b1, - 0xfd8: 0x25b8, 0xfd9: 0x25bf, 0xfda: 0x25d4, 0xfdb: 0x25e2, 0xfdc: 0x1d89, 0xfdd: 0x1d8e, - 0xfde: 0x1d93, 0xfdf: 0x1da2, 0xfe0: 0x1dac, 0xfe1: 0x1dbb, 0xfe2: 0x1dc0, 0xfe3: 0x1dc5, - 0xfe4: 0x1dd4, 0xfe5: 0x1dde, 0xfe6: 0x1dfc, 0xfe7: 0x1e15, 0xfe8: 0x1e1a, 0xfe9: 0x1e29, - 0xfea: 0x1e2e, 0xfeb: 0x1e3d, 0xfec: 0x1e47, 0xfed: 0x1e56, 0xfee: 0x1e5b, 0xfef: 0x1e60, - 0xff0: 0x1e6a, 0xff1: 0x1ea6, 0xff2: 0x1eab, 0xff3: 0x1eb5, 0xff4: 0x1ec4, 0xff5: 0x1ec9, - 0xff6: 0x1ece, 0xff7: 0x1ed8, 0xff8: 0x1ee7, 0xff9: 0x1efb, 0xffa: 0x1f00, 0xffb: 0x1f05, - 0xffc: 0x1f14, 0xffd: 0x1f19, 0xffe: 0x1f28, 0xfff: 0x1f2d, + 0xfc0: 0x1f8c, 0xfc1: 0x1f91, 0xfc2: 0x1f96, 0xfc3: 0x1fa0, 0xfc4: 0x1fa5, 0xfc5: 0x1faf, + 0xfc6: 0x1fb4, 0xfc7: 0x1fb9, 0xfc8: 0x1fbe, 0xfc9: 0x1fc3, 0xfca: 0x1fc8, 0xfcb: 0x1fcd, + 0xfcc: 0x1fd2, 0xfcd: 0x1fd7, 0xfce: 0x1fe6, 0xfcf: 0x1ff5, 0xfd0: 0x1ffa, 0xfd1: 0x1fff, + 0xfd2: 0x2004, 0xfd3: 0x2009, 0xfd4: 0x200e, 0xfd5: 0x2018, 0xfd6: 0x201d, 0xfd7: 0x2022, + 0xfd8: 0x2031, 0xfd9: 0x2040, 0xfda: 0x2045, 0xfdb: 0x4420, 0xfdc: 0x4426, 0xfdd: 0x445c, + 0xfde: 0x44b3, 0xfdf: 0x44ba, 0xfe0: 0x44c1, 0xfe1: 0x44c8, 0xfe2: 0x44cf, 0xfe3: 0x44d6, + 0xfe4: 0x25c6, 0xfe5: 0x25cd, 0xfe6: 0x25d4, 0xfe7: 0x25db, 0xfe8: 0x25f0, 0xfe9: 0x25f7, + 0xfea: 0x1d98, 0xfeb: 0x1d9d, 0xfec: 0x1da2, 0xfed: 0x1da7, 0xfee: 0x1db1, 0xfef: 0x1db6, + 0xff0: 0x1dca, 0xff1: 0x1dcf, 0xff2: 0x1dd4, 0xff3: 0x1dd9, 0xff4: 0x1de3, 0xff5: 0x1de8, + 0xff6: 0x1df2, 0xff7: 0x1df7, 0xff8: 0x1dfc, 0xff9: 0x1e01, 0xffa: 0x1e0b, 0xffb: 0x1e10, + 0xffc: 0x1f3c, 0xffd: 0x1f41, 0xffe: 0x1f50, 0xfff: 0x1f55, // Block 0x40, offset 0x1000 - 0x1000: 0x1f32, 0x1001: 0x1f37, 0x1002: 0x1f46, 0x1003: 0x1f4b, 0x1004: 0x1f5f, 0x1005: 0x1f64, - 0x1006: 0x1f69, 0x1007: 0x1f6e, 0x1008: 0x1f73, 0x1009: 0x1f87, 0x100a: 0x1f8c, 0x100b: 0x1f91, - 0x100c: 0x1f96, 0x100d: 0x1f9b, 0x100e: 0x1faf, 0x100f: 0x1fb4, 0x1010: 0x1fb9, 0x1011: 0x1fbe, - 0x1012: 0x1fcd, 0x1013: 0x1fd2, 0x1014: 0x1fd7, 0x1015: 0x1fe6, 0x1016: 0x1ff0, 0x1017: 0x1fff, - 0x1018: 0x2004, 0x1019: 0x4450, 0x101a: 0x2018, 0x101b: 0x201d, 0x101c: 0x2022, 0x101d: 0x2031, - 0x101e: 0x203b, 0x101f: 0x25d4, 0x1020: 0x25e2, 0x1021: 0x1da2, 0x1022: 0x1dac, 0x1023: 0x1dd4, - 0x1024: 0x1dde, 0x1025: 0x1dfc, 0x1026: 0x1e06, 0x1027: 0x1e6a, 0x1028: 0x1e6f, 0x1029: 0x1e92, - 0x102a: 0x1e97, 0x102b: 0x1f6e, 0x102c: 0x1f73, 0x102d: 0x1f96, 0x102e: 0x1fe6, 0x102f: 0x1ff0, - 0x1030: 0x2031, 0x1031: 0x203b, 0x1032: 0x4504, 0x1033: 0x450c, 0x1034: 0x4514, 0x1035: 0x1ef1, - 0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74, - 0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33, + 0x1000: 0x1f5a, 0x1001: 0x1f6e, 0x1002: 0x1f73, 0x1003: 0x1f78, 0x1004: 0x1f7d, 0x1005: 0x1f96, + 0x1006: 0x1fa0, 0x1007: 0x1fa5, 0x1008: 0x1faa, 0x1009: 0x1fbe, 0x100a: 0x1fdc, 0x100b: 0x1fe1, + 0x100c: 0x1fe6, 0x100d: 0x1feb, 0x100e: 0x1ff5, 0x100f: 0x1ffa, 0x1010: 0x445c, 0x1011: 0x2027, + 0x1012: 0x202c, 0x1013: 0x2031, 0x1014: 0x2036, 0x1015: 0x2040, 0x1016: 0x2045, 0x1017: 0x25b1, + 0x1018: 0x25b8, 0x1019: 0x25bf, 0x101a: 0x25d4, 0x101b: 0x25e2, 0x101c: 0x1d89, 0x101d: 0x1d8e, + 0x101e: 0x1d93, 0x101f: 0x1da2, 0x1020: 0x1dac, 0x1021: 0x1dbb, 0x1022: 0x1dc0, 0x1023: 0x1dc5, + 0x1024: 0x1dd4, 0x1025: 0x1dde, 0x1026: 0x1dfc, 0x1027: 0x1e15, 0x1028: 0x1e1a, 0x1029: 0x1e29, + 0x102a: 0x1e2e, 0x102b: 0x1e3d, 0x102c: 0x1e47, 0x102d: 0x1e56, 0x102e: 0x1e5b, 0x102f: 0x1e60, + 0x1030: 0x1e6a, 0x1031: 0x1ea6, 0x1032: 0x1eab, 0x1033: 0x1eb5, 0x1034: 0x1ec4, 0x1035: 0x1ec9, + 0x1036: 0x1ece, 0x1037: 0x1ed8, 0x1038: 0x1ee7, 0x1039: 0x1efb, 0x103a: 0x1f00, 0x103b: 0x1f05, + 0x103c: 0x1f14, 0x103d: 0x1f19, 0x103e: 0x1f28, 0x103f: 0x1f2d, // Block 0x41, offset 0x1040 - 0x1040: 0x1e38, 0x1041: 0x1e1f, 0x1042: 0x1e24, 0x1043: 0x1e4c, 0x1044: 0x1e51, 0x1045: 0x1eba, - 0x1046: 0x1ebf, 0x1047: 0x1edd, 0x1048: 0x1ee2, 0x1049: 0x1e7e, 0x104a: 0x1e83, 0x104b: 0x1e88, - 0x104c: 0x1e92, 0x104d: 0x1e8d, 0x104e: 0x1e65, 0x104f: 0x1eb0, 0x1050: 0x1ed3, 0x1051: 0x1ef1, - 0x1052: 0x1ef6, 0x1053: 0x1f0a, 0x1054: 0x1f0f, 0x1055: 0x1f1e, 0x1056: 0x1f23, 0x1057: 0x1e74, - 0x1058: 0x1e79, 0x1059: 0x1e9c, 0x105a: 0x1ea1, 0x105b: 0x1e33, 0x105c: 0x1e38, 0x105d: 0x1e1f, - 0x105e: 0x1e24, 0x105f: 0x1e4c, 0x1060: 0x1e51, 0x1061: 0x1eba, 0x1062: 0x1ebf, 0x1063: 0x1edd, - 0x1064: 0x1ee2, 0x1065: 0x1e7e, 0x1066: 0x1e83, 0x1067: 0x1e88, 0x1068: 0x1e92, 0x1069: 0x1e8d, - 0x106a: 0x1e65, 0x106b: 0x1eb0, 0x106c: 0x1ed3, 0x106d: 0x1e7e, 0x106e: 0x1e83, 0x106f: 0x1e88, - 0x1070: 0x1e92, 0x1071: 0x1e6f, 0x1072: 0x1e97, 0x1073: 0x1eec, 0x1074: 0x1e56, 0x1075: 0x1e5b, - 0x1076: 0x1e60, 0x1077: 0x1e7e, 0x1078: 0x1e83, 0x1079: 0x1e88, 0x107a: 0x1eec, 0x107b: 0x1efb, - 0x107c: 0x4408, 0x107d: 0x4408, + 0x1040: 0x1f32, 0x1041: 0x1f37, 0x1042: 0x1f46, 0x1043: 0x1f4b, 0x1044: 0x1f5f, 0x1045: 0x1f64, + 0x1046: 0x1f69, 0x1047: 0x1f6e, 0x1048: 0x1f73, 0x1049: 0x1f87, 0x104a: 0x1f8c, 0x104b: 0x1f91, + 0x104c: 0x1f96, 0x104d: 0x1f9b, 0x104e: 0x1faf, 0x104f: 0x1fb4, 0x1050: 0x1fb9, 0x1051: 0x1fbe, + 0x1052: 0x1fcd, 0x1053: 0x1fd2, 0x1054: 0x1fd7, 0x1055: 0x1fe6, 0x1056: 0x1ff0, 0x1057: 0x1fff, + 0x1058: 0x2004, 0x1059: 0x4450, 0x105a: 0x2018, 0x105b: 0x201d, 0x105c: 0x2022, 0x105d: 0x2031, + 0x105e: 0x203b, 0x105f: 0x25d4, 0x1060: 0x25e2, 0x1061: 0x1da2, 0x1062: 0x1dac, 0x1063: 0x1dd4, + 0x1064: 0x1dde, 0x1065: 0x1dfc, 0x1066: 0x1e06, 0x1067: 0x1e6a, 0x1068: 0x1e6f, 0x1069: 0x1e92, + 0x106a: 0x1e97, 0x106b: 0x1f6e, 0x106c: 0x1f73, 0x106d: 0x1f96, 0x106e: 0x1fe6, 0x106f: 0x1ff0, + 0x1070: 0x2031, 0x1071: 0x203b, 0x1072: 0x4504, 0x1073: 0x450c, 0x1074: 0x4514, 0x1075: 0x1ef1, + 0x1076: 0x1ef6, 0x1077: 0x1f0a, 0x1078: 0x1f0f, 0x1079: 0x1f1e, 0x107a: 0x1f23, 0x107b: 0x1e74, + 0x107c: 0x1e79, 0x107d: 0x1e9c, 0x107e: 0x1ea1, 0x107f: 0x1e33, // Block 0x42, offset 0x1080 - 0x1090: 0x2311, 0x1091: 0x2326, - 0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357, - 0x1098: 0x237a, 0x1099: 0x237a, 0x109a: 0x239d, 0x109b: 0x2396, 0x109c: 0x23b2, 0x109d: 0x23a4, - 0x109e: 0x23ab, 0x109f: 0x23ce, 0x10a0: 0x23ce, 0x10a1: 0x23c7, 0x10a2: 0x23d5, 0x10a3: 0x23d5, - 0x10a4: 0x23ff, 0x10a5: 0x23ff, 0x10a6: 0x241b, 0x10a7: 0x23e3, 0x10a8: 0x23e3, 0x10a9: 0x23dc, - 0x10aa: 0x23f1, 0x10ab: 0x23f1, 0x10ac: 0x23f8, 0x10ad: 0x23f8, 0x10ae: 0x2422, 0x10af: 0x2430, - 0x10b0: 0x2430, 0x10b1: 0x2437, 0x10b2: 0x2437, 0x10b3: 0x243e, 0x10b4: 0x2445, 0x10b5: 0x244c, - 0x10b6: 0x2453, 0x10b7: 0x2453, 0x10b8: 0x245a, 0x10b9: 0x2468, 0x10ba: 0x2476, 0x10bb: 0x246f, - 0x10bc: 0x247d, 0x10bd: 0x247d, 0x10be: 0x2492, 0x10bf: 0x2499, + 0x1080: 0x1e38, 0x1081: 0x1e1f, 0x1082: 0x1e24, 0x1083: 0x1e4c, 0x1084: 0x1e51, 0x1085: 0x1eba, + 0x1086: 0x1ebf, 0x1087: 0x1edd, 0x1088: 0x1ee2, 0x1089: 0x1e7e, 0x108a: 0x1e83, 0x108b: 0x1e88, + 0x108c: 0x1e92, 0x108d: 0x1e8d, 0x108e: 0x1e65, 0x108f: 0x1eb0, 0x1090: 0x1ed3, 0x1091: 0x1ef1, + 0x1092: 0x1ef6, 0x1093: 0x1f0a, 0x1094: 0x1f0f, 0x1095: 0x1f1e, 0x1096: 0x1f23, 0x1097: 0x1e74, + 0x1098: 0x1e79, 0x1099: 0x1e9c, 0x109a: 0x1ea1, 0x109b: 0x1e33, 0x109c: 0x1e38, 0x109d: 0x1e1f, + 0x109e: 0x1e24, 0x109f: 0x1e4c, 0x10a0: 0x1e51, 0x10a1: 0x1eba, 0x10a2: 0x1ebf, 0x10a3: 0x1edd, + 0x10a4: 0x1ee2, 0x10a5: 0x1e7e, 0x10a6: 0x1e83, 0x10a7: 0x1e88, 0x10a8: 0x1e92, 0x10a9: 0x1e8d, + 0x10aa: 0x1e65, 0x10ab: 0x1eb0, 0x10ac: 0x1ed3, 0x10ad: 0x1e7e, 0x10ae: 0x1e83, 0x10af: 0x1e88, + 0x10b0: 0x1e92, 0x10b1: 0x1e6f, 0x10b2: 0x1e97, 0x10b3: 0x1eec, 0x10b4: 0x1e56, 0x10b5: 0x1e5b, + 0x10b6: 0x1e60, 0x10b7: 0x1e7e, 0x10b8: 0x1e83, 0x10b9: 0x1e88, 0x10ba: 0x1eec, 0x10bb: 0x1efb, + 0x10bc: 0x4408, 0x10bd: 0x4408, // Block 0x43, offset 0x10c0 - 0x10c0: 0x24ca, 0x10c1: 0x24d8, 0x10c2: 0x24d1, 0x10c3: 0x24b5, 0x10c4: 0x24b5, 0x10c5: 0x24df, - 0x10c6: 0x24df, 0x10c7: 0x24e6, 0x10c8: 0x24e6, 0x10c9: 0x2510, 0x10ca: 0x2517, 0x10cb: 0x251e, - 0x10cc: 0x24f4, 0x10cd: 0x2502, 0x10ce: 0x2525, 0x10cf: 0x252c, - 0x10d2: 0x24fb, 0x10d3: 0x2580, 0x10d4: 0x2587, 0x10d5: 0x255d, 0x10d6: 0x2564, 0x10d7: 0x2548, - 0x10d8: 0x2548, 0x10d9: 0x254f, 0x10da: 0x2579, 0x10db: 0x2572, 0x10dc: 0x259c, 0x10dd: 0x259c, - 0x10de: 0x230a, 0x10df: 0x231f, 0x10e0: 0x2318, 0x10e1: 0x2342, 0x10e2: 0x233b, 0x10e3: 0x2365, - 0x10e4: 0x235e, 0x10e5: 0x2388, 0x10e6: 0x236c, 0x10e7: 0x2381, 0x10e8: 0x23b9, 0x10e9: 0x2406, - 0x10ea: 0x23ea, 0x10eb: 0x2429, 0x10ec: 0x24c3, 0x10ed: 0x24ed, 0x10ee: 0x2595, 0x10ef: 0x258e, - 0x10f0: 0x25a3, 0x10f1: 0x253a, 0x10f2: 0x24a0, 0x10f3: 0x256b, 0x10f4: 0x2492, 0x10f5: 0x24ca, - 0x10f6: 0x2461, 0x10f7: 0x24ae, 0x10f8: 0x2541, 0x10f9: 0x2533, 0x10fa: 0x24bc, 0x10fb: 0x24a7, - 0x10fc: 0x24bc, 0x10fd: 0x2541, 0x10fe: 0x2373, 0x10ff: 0x238f, + 0x10d0: 0x2311, 0x10d1: 0x2326, + 0x10d2: 0x2326, 0x10d3: 0x232d, 0x10d4: 0x2334, 0x10d5: 0x2349, 0x10d6: 0x2350, 0x10d7: 0x2357, + 0x10d8: 0x237a, 0x10d9: 0x237a, 0x10da: 0x239d, 0x10db: 0x2396, 0x10dc: 0x23b2, 0x10dd: 0x23a4, + 0x10de: 0x23ab, 0x10df: 0x23ce, 0x10e0: 0x23ce, 0x10e1: 0x23c7, 0x10e2: 0x23d5, 0x10e3: 0x23d5, + 0x10e4: 0x23ff, 0x10e5: 0x23ff, 0x10e6: 0x241b, 0x10e7: 0x23e3, 0x10e8: 0x23e3, 0x10e9: 0x23dc, + 0x10ea: 0x23f1, 0x10eb: 0x23f1, 0x10ec: 0x23f8, 0x10ed: 0x23f8, 0x10ee: 0x2422, 0x10ef: 0x2430, + 0x10f0: 0x2430, 0x10f1: 0x2437, 0x10f2: 0x2437, 0x10f3: 0x243e, 0x10f4: 0x2445, 0x10f5: 0x244c, + 0x10f6: 0x2453, 0x10f7: 0x2453, 0x10f8: 0x245a, 0x10f9: 0x2468, 0x10fa: 0x2476, 0x10fb: 0x246f, + 0x10fc: 0x247d, 0x10fd: 0x247d, 0x10fe: 0x2492, 0x10ff: 0x2499, // Block 0x44, offset 0x1100 - 0x1100: 0x2509, 0x1101: 0x2484, 0x1102: 0x2303, 0x1103: 0x24a7, 0x1104: 0x244c, 0x1105: 0x241b, - 0x1106: 0x23c0, 0x1107: 0x2556, - 0x1130: 0x2414, 0x1131: 0x248b, 0x1132: 0x27bf, 0x1133: 0x27b6, 0x1134: 0x27ec, 0x1135: 0x27da, - 0x1136: 0x27c8, 0x1137: 0x27e3, 0x1138: 0x27f5, 0x1139: 0x240d, 0x113a: 0x2c7c, 0x113b: 0x2afc, - 0x113c: 0x27d1, + 0x1100: 0x24ca, 0x1101: 0x24d8, 0x1102: 0x24d1, 0x1103: 0x24b5, 0x1104: 0x24b5, 0x1105: 0x24df, + 0x1106: 0x24df, 0x1107: 0x24e6, 0x1108: 0x24e6, 0x1109: 0x2510, 0x110a: 0x2517, 0x110b: 0x251e, + 0x110c: 0x24f4, 0x110d: 0x2502, 0x110e: 0x2525, 0x110f: 0x252c, + 0x1112: 0x24fb, 0x1113: 0x2580, 0x1114: 0x2587, 0x1115: 0x255d, 0x1116: 0x2564, 0x1117: 0x2548, + 0x1118: 0x2548, 0x1119: 0x254f, 0x111a: 0x2579, 0x111b: 0x2572, 0x111c: 0x259c, 0x111d: 0x259c, + 0x111e: 0x230a, 0x111f: 0x231f, 0x1120: 0x2318, 0x1121: 0x2342, 0x1122: 0x233b, 0x1123: 0x2365, + 0x1124: 0x235e, 0x1125: 0x2388, 0x1126: 0x236c, 0x1127: 0x2381, 0x1128: 0x23b9, 0x1129: 0x2406, + 0x112a: 0x23ea, 0x112b: 0x2429, 0x112c: 0x24c3, 0x112d: 0x24ed, 0x112e: 0x2595, 0x112f: 0x258e, + 0x1130: 0x25a3, 0x1131: 0x253a, 0x1132: 0x24a0, 0x1133: 0x256b, 0x1134: 0x2492, 0x1135: 0x24ca, + 0x1136: 0x2461, 0x1137: 0x24ae, 0x1138: 0x2541, 0x1139: 0x2533, 0x113a: 0x24bc, 0x113b: 0x24a7, + 0x113c: 0x24bc, 0x113d: 0x2541, 0x113e: 0x2373, 0x113f: 0x238f, // Block 0x45, offset 0x1140 - 0x1150: 0x0019, 0x1151: 0x0483, - 0x1152: 0x0487, 0x1153: 0x0035, 0x1154: 0x0037, 0x1155: 0x0003, 0x1156: 0x003f, 0x1157: 0x04bf, - 0x1158: 0x04c3, 0x1159: 0x1b5c, - 0x1160: 0x8132, 0x1161: 0x8132, 0x1162: 0x8132, 0x1163: 0x8132, - 0x1164: 0x8132, 0x1165: 0x8132, 0x1166: 0x8132, 0x1167: 0x812d, 0x1168: 0x812d, 0x1169: 0x812d, - 0x116a: 0x812d, 0x116b: 0x812d, 0x116c: 0x812d, 0x116d: 0x812d, 0x116e: 0x8132, 0x116f: 0x8132, - 0x1170: 0x1873, 0x1171: 0x0443, 0x1172: 0x043f, 0x1173: 0x007f, 0x1174: 0x007f, 0x1175: 0x0011, - 0x1176: 0x0013, 0x1177: 0x00b7, 0x1178: 0x00bb, 0x1179: 0x04b7, 0x117a: 0x04bb, 0x117b: 0x04ab, - 0x117c: 0x04af, 0x117d: 0x0493, 0x117e: 0x0497, 0x117f: 0x048b, + 0x1140: 0x2509, 0x1141: 0x2484, 0x1142: 0x2303, 0x1143: 0x24a7, 0x1144: 0x244c, 0x1145: 0x241b, + 0x1146: 0x23c0, 0x1147: 0x2556, + 0x1170: 0x2414, 0x1171: 0x248b, 0x1172: 0x27bf, 0x1173: 0x27b6, 0x1174: 0x27ec, 0x1175: 0x27da, + 0x1176: 0x27c8, 0x1177: 0x27e3, 0x1178: 0x27f5, 0x1179: 0x240d, 0x117a: 0x2c7c, 0x117b: 0x2afc, + 0x117c: 0x27d1, // Block 0x46, offset 0x1180 - 0x1180: 0x048f, 0x1181: 0x049b, 0x1182: 0x049f, 0x1183: 0x04a3, 0x1184: 0x04a7, - 0x1187: 0x0077, 0x1188: 0x007b, 0x1189: 0x4269, 0x118a: 0x4269, 0x118b: 0x4269, - 0x118c: 0x4269, 0x118d: 0x007f, 0x118e: 0x007f, 0x118f: 0x007f, 0x1190: 0x0019, 0x1191: 0x0483, - 0x1192: 0x001d, 0x1194: 0x0037, 0x1195: 0x0035, 0x1196: 0x003f, 0x1197: 0x0003, - 0x1198: 0x0443, 0x1199: 0x0011, 0x119a: 0x0013, 0x119b: 0x00b7, 0x119c: 0x00bb, 0x119d: 0x04b7, - 0x119e: 0x04bb, 0x119f: 0x0007, 0x11a0: 0x000d, 0x11a1: 0x0015, 0x11a2: 0x0017, 0x11a3: 0x001b, - 0x11a4: 0x0039, 0x11a5: 0x003d, 0x11a6: 0x003b, 0x11a8: 0x0079, 0x11a9: 0x0009, - 0x11aa: 0x000b, 0x11ab: 0x0041, - 0x11b0: 0x42aa, 0x11b1: 0x442c, 0x11b2: 0x42af, 0x11b4: 0x42b4, - 0x11b6: 0x42b9, 0x11b7: 0x4432, 0x11b8: 0x42be, 0x11b9: 0x4438, 0x11ba: 0x42c3, 0x11bb: 0x443e, - 0x11bc: 0x42c8, 0x11bd: 0x4444, 0x11be: 0x42cd, 0x11bf: 0x444a, + 0x1190: 0x0019, 0x1191: 0x0483, + 0x1192: 0x0487, 0x1193: 0x0035, 0x1194: 0x0037, 0x1195: 0x0003, 0x1196: 0x003f, 0x1197: 0x04bf, + 0x1198: 0x04c3, 0x1199: 0x1b5c, + 0x11a0: 0x8132, 0x11a1: 0x8132, 0x11a2: 0x8132, 0x11a3: 0x8132, + 0x11a4: 0x8132, 0x11a5: 0x8132, 0x11a6: 0x8132, 0x11a7: 0x812d, 0x11a8: 0x812d, 0x11a9: 0x812d, + 0x11aa: 0x812d, 0x11ab: 0x812d, 0x11ac: 0x812d, 0x11ad: 0x812d, 0x11ae: 0x8132, 0x11af: 0x8132, + 0x11b0: 0x1873, 0x11b1: 0x0443, 0x11b2: 0x043f, 0x11b3: 0x007f, 0x11b4: 0x007f, 0x11b5: 0x0011, + 0x11b6: 0x0013, 0x11b7: 0x00b7, 0x11b8: 0x00bb, 0x11b9: 0x04b7, 0x11ba: 0x04bb, 0x11bb: 0x04ab, + 0x11bc: 0x04af, 0x11bd: 0x0493, 0x11be: 0x0497, 0x11bf: 0x048b, // Block 0x47, offset 0x11c0 - 0x11c0: 0x0236, 0x11c1: 0x440e, 0x11c2: 0x440e, 0x11c3: 0x4414, 0x11c4: 0x4414, 0x11c5: 0x4456, - 0x11c6: 0x4456, 0x11c7: 0x441a, 0x11c8: 0x441a, 0x11c9: 0x4462, 0x11ca: 0x4462, 0x11cb: 0x4462, - 0x11cc: 0x4462, 0x11cd: 0x0239, 0x11ce: 0x0239, 0x11cf: 0x023c, 0x11d0: 0x023c, 0x11d1: 0x023c, - 0x11d2: 0x023c, 0x11d3: 0x023f, 0x11d4: 0x023f, 0x11d5: 0x0242, 0x11d6: 0x0242, 0x11d7: 0x0242, - 0x11d8: 0x0242, 0x11d9: 0x0245, 0x11da: 0x0245, 0x11db: 0x0245, 0x11dc: 0x0245, 0x11dd: 0x0248, - 0x11de: 0x0248, 0x11df: 0x0248, 0x11e0: 0x0248, 0x11e1: 0x024b, 0x11e2: 0x024b, 0x11e3: 0x024b, - 0x11e4: 0x024b, 0x11e5: 0x024e, 0x11e6: 0x024e, 0x11e7: 0x024e, 0x11e8: 0x024e, 0x11e9: 0x0251, - 0x11ea: 0x0251, 0x11eb: 0x0254, 0x11ec: 0x0254, 0x11ed: 0x0257, 0x11ee: 0x0257, 0x11ef: 0x025a, - 0x11f0: 0x025a, 0x11f1: 0x025d, 0x11f2: 0x025d, 0x11f3: 0x025d, 0x11f4: 0x025d, 0x11f5: 0x0260, - 0x11f6: 0x0260, 0x11f7: 0x0260, 0x11f8: 0x0260, 0x11f9: 0x0263, 0x11fa: 0x0263, 0x11fb: 0x0263, - 0x11fc: 0x0263, 0x11fd: 0x0266, 0x11fe: 0x0266, 0x11ff: 0x0266, + 0x11c0: 0x048f, 0x11c1: 0x049b, 0x11c2: 0x049f, 0x11c3: 0x04a3, 0x11c4: 0x04a7, + 0x11c7: 0x0077, 0x11c8: 0x007b, 0x11c9: 0x4269, 0x11ca: 0x4269, 0x11cb: 0x4269, + 0x11cc: 0x4269, 0x11cd: 0x007f, 0x11ce: 0x007f, 0x11cf: 0x007f, 0x11d0: 0x0019, 0x11d1: 0x0483, + 0x11d2: 0x001d, 0x11d4: 0x0037, 0x11d5: 0x0035, 0x11d6: 0x003f, 0x11d7: 0x0003, + 0x11d8: 0x0443, 0x11d9: 0x0011, 0x11da: 0x0013, 0x11db: 0x00b7, 0x11dc: 0x00bb, 0x11dd: 0x04b7, + 0x11de: 0x04bb, 0x11df: 0x0007, 0x11e0: 0x000d, 0x11e1: 0x0015, 0x11e2: 0x0017, 0x11e3: 0x001b, + 0x11e4: 0x0039, 0x11e5: 0x003d, 0x11e6: 0x003b, 0x11e8: 0x0079, 0x11e9: 0x0009, + 0x11ea: 0x000b, 0x11eb: 0x0041, + 0x11f0: 0x42aa, 0x11f1: 0x442c, 0x11f2: 0x42af, 0x11f4: 0x42b4, + 0x11f6: 0x42b9, 0x11f7: 0x4432, 0x11f8: 0x42be, 0x11f9: 0x4438, 0x11fa: 0x42c3, 0x11fb: 0x443e, + 0x11fc: 0x42c8, 0x11fd: 0x4444, 0x11fe: 0x42cd, 0x11ff: 0x444a, // Block 0x48, offset 0x1200 - 0x1200: 0x0266, 0x1201: 0x0269, 0x1202: 0x0269, 0x1203: 0x0269, 0x1204: 0x0269, 0x1205: 0x026c, - 0x1206: 0x026c, 0x1207: 0x026c, 0x1208: 0x026c, 0x1209: 0x026f, 0x120a: 0x026f, 0x120b: 0x026f, - 0x120c: 0x026f, 0x120d: 0x0272, 0x120e: 0x0272, 0x120f: 0x0272, 0x1210: 0x0272, 0x1211: 0x0275, - 0x1212: 0x0275, 0x1213: 0x0275, 0x1214: 0x0275, 0x1215: 0x0278, 0x1216: 0x0278, 0x1217: 0x0278, - 0x1218: 0x0278, 0x1219: 0x027b, 0x121a: 0x027b, 0x121b: 0x027b, 0x121c: 0x027b, 0x121d: 0x027e, - 0x121e: 0x027e, 0x121f: 0x027e, 0x1220: 0x027e, 0x1221: 0x0281, 0x1222: 0x0281, 0x1223: 0x0281, - 0x1224: 0x0281, 0x1225: 0x0284, 0x1226: 0x0284, 0x1227: 0x0284, 0x1228: 0x0284, 0x1229: 0x0287, - 0x122a: 0x0287, 0x122b: 0x0287, 0x122c: 0x0287, 0x122d: 0x028a, 0x122e: 0x028a, 0x122f: 0x028d, - 0x1230: 0x028d, 0x1231: 0x0290, 0x1232: 0x0290, 0x1233: 0x0290, 0x1234: 0x0290, 0x1235: 0x2e00, - 0x1236: 0x2e00, 0x1237: 0x2e08, 0x1238: 0x2e08, 0x1239: 0x2e10, 0x123a: 0x2e10, 0x123b: 0x1f82, - 0x123c: 0x1f82, + 0x1200: 0x0236, 0x1201: 0x440e, 0x1202: 0x440e, 0x1203: 0x4414, 0x1204: 0x4414, 0x1205: 0x4456, + 0x1206: 0x4456, 0x1207: 0x441a, 0x1208: 0x441a, 0x1209: 0x4462, 0x120a: 0x4462, 0x120b: 0x4462, + 0x120c: 0x4462, 0x120d: 0x0239, 0x120e: 0x0239, 0x120f: 0x023c, 0x1210: 0x023c, 0x1211: 0x023c, + 0x1212: 0x023c, 0x1213: 0x023f, 0x1214: 0x023f, 0x1215: 0x0242, 0x1216: 0x0242, 0x1217: 0x0242, + 0x1218: 0x0242, 0x1219: 0x0245, 0x121a: 0x0245, 0x121b: 0x0245, 0x121c: 0x0245, 0x121d: 0x0248, + 0x121e: 0x0248, 0x121f: 0x0248, 0x1220: 0x0248, 0x1221: 0x024b, 0x1222: 0x024b, 0x1223: 0x024b, + 0x1224: 0x024b, 0x1225: 0x024e, 0x1226: 0x024e, 0x1227: 0x024e, 0x1228: 0x024e, 0x1229: 0x0251, + 0x122a: 0x0251, 0x122b: 0x0254, 0x122c: 0x0254, 0x122d: 0x0257, 0x122e: 0x0257, 0x122f: 0x025a, + 0x1230: 0x025a, 0x1231: 0x025d, 0x1232: 0x025d, 0x1233: 0x025d, 0x1234: 0x025d, 0x1235: 0x0260, + 0x1236: 0x0260, 0x1237: 0x0260, 0x1238: 0x0260, 0x1239: 0x0263, 0x123a: 0x0263, 0x123b: 0x0263, + 0x123c: 0x0263, 0x123d: 0x0266, 0x123e: 0x0266, 0x123f: 0x0266, // Block 0x49, offset 0x1240 - 0x1240: 0x0081, 0x1241: 0x0083, 0x1242: 0x0085, 0x1243: 0x0087, 0x1244: 0x0089, 0x1245: 0x008b, - 0x1246: 0x008d, 0x1247: 0x008f, 0x1248: 0x0091, 0x1249: 0x0093, 0x124a: 0x0095, 0x124b: 0x0097, - 0x124c: 0x0099, 0x124d: 0x009b, 0x124e: 0x009d, 0x124f: 0x009f, 0x1250: 0x00a1, 0x1251: 0x00a3, - 0x1252: 0x00a5, 0x1253: 0x00a7, 0x1254: 0x00a9, 0x1255: 0x00ab, 0x1256: 0x00ad, 0x1257: 0x00af, - 0x1258: 0x00b1, 0x1259: 0x00b3, 0x125a: 0x00b5, 0x125b: 0x00b7, 0x125c: 0x00b9, 0x125d: 0x00bb, - 0x125e: 0x00bd, 0x125f: 0x0477, 0x1260: 0x047b, 0x1261: 0x0487, 0x1262: 0x049b, 0x1263: 0x049f, - 0x1264: 0x0483, 0x1265: 0x05ab, 0x1266: 0x05a3, 0x1267: 0x04c7, 0x1268: 0x04cf, 0x1269: 0x04d7, - 0x126a: 0x04df, 0x126b: 0x04e7, 0x126c: 0x056b, 0x126d: 0x0573, 0x126e: 0x057b, 0x126f: 0x051f, - 0x1270: 0x05af, 0x1271: 0x04cb, 0x1272: 0x04d3, 0x1273: 0x04db, 0x1274: 0x04e3, 0x1275: 0x04eb, - 0x1276: 0x04ef, 0x1277: 0x04f3, 0x1278: 0x04f7, 0x1279: 0x04fb, 0x127a: 0x04ff, 0x127b: 0x0503, - 0x127c: 0x0507, 0x127d: 0x050b, 0x127e: 0x050f, 0x127f: 0x0513, + 0x1240: 0x0266, 0x1241: 0x0269, 0x1242: 0x0269, 0x1243: 0x0269, 0x1244: 0x0269, 0x1245: 0x026c, + 0x1246: 0x026c, 0x1247: 0x026c, 0x1248: 0x026c, 0x1249: 0x026f, 0x124a: 0x026f, 0x124b: 0x026f, + 0x124c: 0x026f, 0x124d: 0x0272, 0x124e: 0x0272, 0x124f: 0x0272, 0x1250: 0x0272, 0x1251: 0x0275, + 0x1252: 0x0275, 0x1253: 0x0275, 0x1254: 0x0275, 0x1255: 0x0278, 0x1256: 0x0278, 0x1257: 0x0278, + 0x1258: 0x0278, 0x1259: 0x027b, 0x125a: 0x027b, 0x125b: 0x027b, 0x125c: 0x027b, 0x125d: 0x027e, + 0x125e: 0x027e, 0x125f: 0x027e, 0x1260: 0x027e, 0x1261: 0x0281, 0x1262: 0x0281, 0x1263: 0x0281, + 0x1264: 0x0281, 0x1265: 0x0284, 0x1266: 0x0284, 0x1267: 0x0284, 0x1268: 0x0284, 0x1269: 0x0287, + 0x126a: 0x0287, 0x126b: 0x0287, 0x126c: 0x0287, 0x126d: 0x028a, 0x126e: 0x028a, 0x126f: 0x028d, + 0x1270: 0x028d, 0x1271: 0x0290, 0x1272: 0x0290, 0x1273: 0x0290, 0x1274: 0x0290, 0x1275: 0x2e00, + 0x1276: 0x2e00, 0x1277: 0x2e08, 0x1278: 0x2e08, 0x1279: 0x2e10, 0x127a: 0x2e10, 0x127b: 0x1f82, + 0x127c: 0x1f82, // Block 0x4a, offset 0x1280 - 0x1280: 0x0517, 0x1281: 0x051b, 0x1282: 0x0523, 0x1283: 0x0527, 0x1284: 0x052b, 0x1285: 0x052f, - 0x1286: 0x0533, 0x1287: 0x0537, 0x1288: 0x053b, 0x1289: 0x053f, 0x128a: 0x0543, 0x128b: 0x0547, - 0x128c: 0x054b, 0x128d: 0x054f, 0x128e: 0x0553, 0x128f: 0x0557, 0x1290: 0x055b, 0x1291: 0x055f, - 0x1292: 0x0563, 0x1293: 0x0567, 0x1294: 0x056f, 0x1295: 0x0577, 0x1296: 0x057f, 0x1297: 0x0583, - 0x1298: 0x0587, 0x1299: 0x058b, 0x129a: 0x058f, 0x129b: 0x0593, 0x129c: 0x0597, 0x129d: 0x05a7, - 0x129e: 0x4a78, 0x129f: 0x4a7e, 0x12a0: 0x03c3, 0x12a1: 0x0313, 0x12a2: 0x0317, 0x12a3: 0x4a3b, - 0x12a4: 0x031b, 0x12a5: 0x4a41, 0x12a6: 0x4a47, 0x12a7: 0x031f, 0x12a8: 0x0323, 0x12a9: 0x0327, - 0x12aa: 0x4a4d, 0x12ab: 0x4a53, 0x12ac: 0x4a59, 0x12ad: 0x4a5f, 0x12ae: 0x4a65, 0x12af: 0x4a6b, - 0x12b0: 0x0367, 0x12b1: 0x032b, 0x12b2: 0x032f, 0x12b3: 0x0333, 0x12b4: 0x037b, 0x12b5: 0x0337, - 0x12b6: 0x033b, 0x12b7: 0x033f, 0x12b8: 0x0343, 0x12b9: 0x0347, 0x12ba: 0x034b, 0x12bb: 0x034f, - 0x12bc: 0x0353, 0x12bd: 0x0357, 0x12be: 0x035b, + 0x1280: 0x0081, 0x1281: 0x0083, 0x1282: 0x0085, 0x1283: 0x0087, 0x1284: 0x0089, 0x1285: 0x008b, + 0x1286: 0x008d, 0x1287: 0x008f, 0x1288: 0x0091, 0x1289: 0x0093, 0x128a: 0x0095, 0x128b: 0x0097, + 0x128c: 0x0099, 0x128d: 0x009b, 0x128e: 0x009d, 0x128f: 0x009f, 0x1290: 0x00a1, 0x1291: 0x00a3, + 0x1292: 0x00a5, 0x1293: 0x00a7, 0x1294: 0x00a9, 0x1295: 0x00ab, 0x1296: 0x00ad, 0x1297: 0x00af, + 0x1298: 0x00b1, 0x1299: 0x00b3, 0x129a: 0x00b5, 0x129b: 0x00b7, 0x129c: 0x00b9, 0x129d: 0x00bb, + 0x129e: 0x00bd, 0x129f: 0x0477, 0x12a0: 0x047b, 0x12a1: 0x0487, 0x12a2: 0x049b, 0x12a3: 0x049f, + 0x12a4: 0x0483, 0x12a5: 0x05ab, 0x12a6: 0x05a3, 0x12a7: 0x04c7, 0x12a8: 0x04cf, 0x12a9: 0x04d7, + 0x12aa: 0x04df, 0x12ab: 0x04e7, 0x12ac: 0x056b, 0x12ad: 0x0573, 0x12ae: 0x057b, 0x12af: 0x051f, + 0x12b0: 0x05af, 0x12b1: 0x04cb, 0x12b2: 0x04d3, 0x12b3: 0x04db, 0x12b4: 0x04e3, 0x12b5: 0x04eb, + 0x12b6: 0x04ef, 0x12b7: 0x04f3, 0x12b8: 0x04f7, 0x12b9: 0x04fb, 0x12ba: 0x04ff, 0x12bb: 0x0503, + 0x12bc: 0x0507, 0x12bd: 0x050b, 0x12be: 0x050f, 0x12bf: 0x0513, // Block 0x4b, offset 0x12c0 - 0x12c2: 0x49bd, 0x12c3: 0x49c3, 0x12c4: 0x49c9, 0x12c5: 0x49cf, - 0x12c6: 0x49d5, 0x12c7: 0x49db, 0x12ca: 0x49e1, 0x12cb: 0x49e7, - 0x12cc: 0x49ed, 0x12cd: 0x49f3, 0x12ce: 0x49f9, 0x12cf: 0x49ff, - 0x12d2: 0x4a05, 0x12d3: 0x4a0b, 0x12d4: 0x4a11, 0x12d5: 0x4a17, 0x12d6: 0x4a1d, 0x12d7: 0x4a23, - 0x12da: 0x4a29, 0x12db: 0x4a2f, 0x12dc: 0x4a35, - 0x12e0: 0x00bf, 0x12e1: 0x00c2, 0x12e2: 0x00cb, 0x12e3: 0x4264, - 0x12e4: 0x00c8, 0x12e5: 0x00c5, 0x12e6: 0x0447, 0x12e8: 0x046b, 0x12e9: 0x044b, - 0x12ea: 0x044f, 0x12eb: 0x0453, 0x12ec: 0x0457, 0x12ed: 0x046f, 0x12ee: 0x0473, + 0x12c0: 0x0517, 0x12c1: 0x051b, 0x12c2: 0x0523, 0x12c3: 0x0527, 0x12c4: 0x052b, 0x12c5: 0x052f, + 0x12c6: 0x0533, 0x12c7: 0x0537, 0x12c8: 0x053b, 0x12c9: 0x053f, 0x12ca: 0x0543, 0x12cb: 0x0547, + 0x12cc: 0x054b, 0x12cd: 0x054f, 0x12ce: 0x0553, 0x12cf: 0x0557, 0x12d0: 0x055b, 0x12d1: 0x055f, + 0x12d2: 0x0563, 0x12d3: 0x0567, 0x12d4: 0x056f, 0x12d5: 0x0577, 0x12d6: 0x057f, 0x12d7: 0x0583, + 0x12d8: 0x0587, 0x12d9: 0x058b, 0x12da: 0x058f, 0x12db: 0x0593, 0x12dc: 0x0597, 0x12dd: 0x05a7, + 0x12de: 0x4a78, 0x12df: 0x4a7e, 0x12e0: 0x03c3, 0x12e1: 0x0313, 0x12e2: 0x0317, 0x12e3: 0x4a3b, + 0x12e4: 0x031b, 0x12e5: 0x4a41, 0x12e6: 0x4a47, 0x12e7: 0x031f, 0x12e8: 0x0323, 0x12e9: 0x0327, + 0x12ea: 0x4a4d, 0x12eb: 0x4a53, 0x12ec: 0x4a59, 0x12ed: 0x4a5f, 0x12ee: 0x4a65, 0x12ef: 0x4a6b, + 0x12f0: 0x0367, 0x12f1: 0x032b, 0x12f2: 0x032f, 0x12f3: 0x0333, 0x12f4: 0x037b, 0x12f5: 0x0337, + 0x12f6: 0x033b, 0x12f7: 0x033f, 0x12f8: 0x0343, 0x12f9: 0x0347, 0x12fa: 0x034b, 0x12fb: 0x034f, + 0x12fc: 0x0353, 0x12fd: 0x0357, 0x12fe: 0x035b, // Block 0x4c, offset 0x1300 - 0x1300: 0x0063, 0x1301: 0x0065, 0x1302: 0x0067, 0x1303: 0x0069, 0x1304: 0x006b, 0x1305: 0x006d, - 0x1306: 0x006f, 0x1307: 0x0071, 0x1308: 0x0073, 0x1309: 0x0075, 0x130a: 0x0083, 0x130b: 0x0085, - 0x130c: 0x0087, 0x130d: 0x0089, 0x130e: 0x008b, 0x130f: 0x008d, 0x1310: 0x008f, 0x1311: 0x0091, - 0x1312: 0x0093, 0x1313: 0x0095, 0x1314: 0x0097, 0x1315: 0x0099, 0x1316: 0x009b, 0x1317: 0x009d, - 0x1318: 0x009f, 0x1319: 0x00a1, 0x131a: 0x00a3, 0x131b: 0x00a5, 0x131c: 0x00a7, 0x131d: 0x00a9, - 0x131e: 0x00ab, 0x131f: 0x00ad, 0x1320: 0x00af, 0x1321: 0x00b1, 0x1322: 0x00b3, 0x1323: 0x00b5, - 0x1324: 0x00dd, 0x1325: 0x00f2, 0x1328: 0x0173, 0x1329: 0x0176, - 0x132a: 0x0179, 0x132b: 0x017c, 0x132c: 0x017f, 0x132d: 0x0182, 0x132e: 0x0185, 0x132f: 0x0188, - 0x1330: 0x018b, 0x1331: 0x018e, 0x1332: 0x0191, 0x1333: 0x0194, 0x1334: 0x0197, 0x1335: 0x019a, - 0x1336: 0x019d, 0x1337: 0x01a0, 0x1338: 0x01a3, 0x1339: 0x0188, 0x133a: 0x01a6, 0x133b: 0x01a9, - 0x133c: 0x01ac, 0x133d: 0x01af, 0x133e: 0x01b2, 0x133f: 0x01b5, + 0x1302: 0x49bd, 0x1303: 0x49c3, 0x1304: 0x49c9, 0x1305: 0x49cf, + 0x1306: 0x49d5, 0x1307: 0x49db, 0x130a: 0x49e1, 0x130b: 0x49e7, + 0x130c: 0x49ed, 0x130d: 0x49f3, 0x130e: 0x49f9, 0x130f: 0x49ff, + 0x1312: 0x4a05, 0x1313: 0x4a0b, 0x1314: 0x4a11, 0x1315: 0x4a17, 0x1316: 0x4a1d, 0x1317: 0x4a23, + 0x131a: 0x4a29, 0x131b: 0x4a2f, 0x131c: 0x4a35, + 0x1320: 0x00bf, 0x1321: 0x00c2, 0x1322: 0x00cb, 0x1323: 0x4264, + 0x1324: 0x00c8, 0x1325: 0x00c5, 0x1326: 0x0447, 0x1328: 0x046b, 0x1329: 0x044b, + 0x132a: 0x044f, 0x132b: 0x0453, 0x132c: 0x0457, 0x132d: 0x046f, 0x132e: 0x0473, // Block 0x4d, offset 0x1340 - 0x1340: 0x01fd, 0x1341: 0x0200, 0x1342: 0x0203, 0x1343: 0x045b, 0x1344: 0x01c7, 0x1345: 0x01d0, - 0x1346: 0x01d6, 0x1347: 0x01fa, 0x1348: 0x01eb, 0x1349: 0x01e8, 0x134a: 0x0206, 0x134b: 0x0209, - 0x134e: 0x0021, 0x134f: 0x0023, 0x1350: 0x0025, 0x1351: 0x0027, - 0x1352: 0x0029, 0x1353: 0x002b, 0x1354: 0x002d, 0x1355: 0x002f, 0x1356: 0x0031, 0x1357: 0x0033, - 0x1358: 0x0021, 0x1359: 0x0023, 0x135a: 0x0025, 0x135b: 0x0027, 0x135c: 0x0029, 0x135d: 0x002b, - 0x135e: 0x002d, 0x135f: 0x002f, 0x1360: 0x0031, 0x1361: 0x0033, 0x1362: 0x0021, 0x1363: 0x0023, - 0x1364: 0x0025, 0x1365: 0x0027, 0x1366: 0x0029, 0x1367: 0x002b, 0x1368: 0x002d, 0x1369: 0x002f, - 0x136a: 0x0031, 0x136b: 0x0033, 0x136c: 0x0021, 0x136d: 0x0023, 0x136e: 0x0025, 0x136f: 0x0027, - 0x1370: 0x0029, 0x1371: 0x002b, 0x1372: 0x002d, 0x1373: 0x002f, 0x1374: 0x0031, 0x1375: 0x0033, - 0x1376: 0x0021, 0x1377: 0x0023, 0x1378: 0x0025, 0x1379: 0x0027, 0x137a: 0x0029, 0x137b: 0x002b, - 0x137c: 0x002d, 0x137d: 0x002f, 0x137e: 0x0031, 0x137f: 0x0033, + 0x1340: 0x0063, 0x1341: 0x0065, 0x1342: 0x0067, 0x1343: 0x0069, 0x1344: 0x006b, 0x1345: 0x006d, + 0x1346: 0x006f, 0x1347: 0x0071, 0x1348: 0x0073, 0x1349: 0x0075, 0x134a: 0x0083, 0x134b: 0x0085, + 0x134c: 0x0087, 0x134d: 0x0089, 0x134e: 0x008b, 0x134f: 0x008d, 0x1350: 0x008f, 0x1351: 0x0091, + 0x1352: 0x0093, 0x1353: 0x0095, 0x1354: 0x0097, 0x1355: 0x0099, 0x1356: 0x009b, 0x1357: 0x009d, + 0x1358: 0x009f, 0x1359: 0x00a1, 0x135a: 0x00a3, 0x135b: 0x00a5, 0x135c: 0x00a7, 0x135d: 0x00a9, + 0x135e: 0x00ab, 0x135f: 0x00ad, 0x1360: 0x00af, 0x1361: 0x00b1, 0x1362: 0x00b3, 0x1363: 0x00b5, + 0x1364: 0x00dd, 0x1365: 0x00f2, 0x1368: 0x0173, 0x1369: 0x0176, + 0x136a: 0x0179, 0x136b: 0x017c, 0x136c: 0x017f, 0x136d: 0x0182, 0x136e: 0x0185, 0x136f: 0x0188, + 0x1370: 0x018b, 0x1371: 0x018e, 0x1372: 0x0191, 0x1373: 0x0194, 0x1374: 0x0197, 0x1375: 0x019a, + 0x1376: 0x019d, 0x1377: 0x01a0, 0x1378: 0x01a3, 0x1379: 0x0188, 0x137a: 0x01a6, 0x137b: 0x01a9, + 0x137c: 0x01ac, 0x137d: 0x01af, 0x137e: 0x01b2, 0x137f: 0x01b5, // Block 0x4e, offset 0x1380 - 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1385: 0x028a, - 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138a: 0x027b, 0x138b: 0x027e, - 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263, - 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e, - 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, 0x139c: 0x0293, 0x139d: 0x02e4, - 0x139e: 0x02cc, 0x139f: 0x0296, 0x13a1: 0x023c, 0x13a2: 0x0248, - 0x13a4: 0x0287, 0x13a7: 0x024b, 0x13a9: 0x0290, - 0x13aa: 0x027b, 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f, - 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b4: 0x0260, 0x13b5: 0x0242, - 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b9: 0x0266, 0x13bb: 0x0272, + 0x1380: 0x01fd, 0x1381: 0x0200, 0x1382: 0x0203, 0x1383: 0x045b, 0x1384: 0x01c7, 0x1385: 0x01d0, + 0x1386: 0x01d6, 0x1387: 0x01fa, 0x1388: 0x01eb, 0x1389: 0x01e8, 0x138a: 0x0206, 0x138b: 0x0209, + 0x138e: 0x0021, 0x138f: 0x0023, 0x1390: 0x0025, 0x1391: 0x0027, + 0x1392: 0x0029, 0x1393: 0x002b, 0x1394: 0x002d, 0x1395: 0x002f, 0x1396: 0x0031, 0x1397: 0x0033, + 0x1398: 0x0021, 0x1399: 0x0023, 0x139a: 0x0025, 0x139b: 0x0027, 0x139c: 0x0029, 0x139d: 0x002b, + 0x139e: 0x002d, 0x139f: 0x002f, 0x13a0: 0x0031, 0x13a1: 0x0033, 0x13a2: 0x0021, 0x13a3: 0x0023, + 0x13a4: 0x0025, 0x13a5: 0x0027, 0x13a6: 0x0029, 0x13a7: 0x002b, 0x13a8: 0x002d, 0x13a9: 0x002f, + 0x13aa: 0x0031, 0x13ab: 0x0033, 0x13ac: 0x0021, 0x13ad: 0x0023, 0x13ae: 0x0025, 0x13af: 0x0027, + 0x13b0: 0x0029, 0x13b1: 0x002b, 0x13b2: 0x002d, 0x13b3: 0x002f, 0x13b4: 0x0031, 0x13b5: 0x0033, + 0x13b6: 0x0021, 0x13b7: 0x0023, 0x13b8: 0x0025, 0x13b9: 0x0027, 0x13ba: 0x0029, 0x13bb: 0x002b, + 0x13bc: 0x002d, 0x13bd: 0x002f, 0x13be: 0x0031, 0x13bf: 0x0033, // Block 0x4f, offset 0x13c0 - 0x13c2: 0x0248, - 0x13c7: 0x024b, 0x13c9: 0x0290, 0x13cb: 0x027e, - 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d1: 0x0263, - 0x13d2: 0x0278, 0x13d4: 0x0260, 0x13d7: 0x024e, - 0x13d9: 0x0266, 0x13db: 0x0272, 0x13dd: 0x02e4, - 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248, - 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e8: 0x0269, 0x13e9: 0x0290, - 0x13ea: 0x027b, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f, + 0x13c0: 0x0239, 0x13c1: 0x023c, 0x13c2: 0x0248, 0x13c3: 0x0251, 0x13c5: 0x028a, + 0x13c6: 0x025a, 0x13c7: 0x024b, 0x13c8: 0x0269, 0x13c9: 0x0290, 0x13ca: 0x027b, 0x13cb: 0x027e, + 0x13cc: 0x0281, 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d0: 0x0275, 0x13d1: 0x0263, + 0x13d2: 0x0278, 0x13d3: 0x0257, 0x13d4: 0x0260, 0x13d5: 0x0242, 0x13d6: 0x0245, 0x13d7: 0x024e, + 0x13d8: 0x0254, 0x13d9: 0x0266, 0x13da: 0x026c, 0x13db: 0x0272, 0x13dc: 0x0293, 0x13dd: 0x02e4, + 0x13de: 0x02cc, 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248, + 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e9: 0x0290, + 0x13ea: 0x027b, 0x13eb: 0x027e, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f, 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242, - 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fa: 0x026c, 0x13fb: 0x0272, - 0x13fc: 0x0293, 0x13fe: 0x02cc, + 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fb: 0x0272, // Block 0x50, offset 0x1400 - 0x1400: 0x0239, 0x1401: 0x023c, 0x1402: 0x0248, 0x1403: 0x0251, 0x1404: 0x0287, 0x1405: 0x028a, - 0x1406: 0x025a, 0x1407: 0x024b, 0x1408: 0x0269, 0x1409: 0x0290, 0x140b: 0x027e, - 0x140c: 0x0281, 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1410: 0x0275, 0x1411: 0x0263, - 0x1412: 0x0278, 0x1413: 0x0257, 0x1414: 0x0260, 0x1415: 0x0242, 0x1416: 0x0245, 0x1417: 0x024e, - 0x1418: 0x0254, 0x1419: 0x0266, 0x141a: 0x026c, 0x141b: 0x0272, - 0x1421: 0x023c, 0x1422: 0x0248, 0x1423: 0x0251, - 0x1425: 0x028a, 0x1426: 0x025a, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290, - 0x142b: 0x027e, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f, - 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1433: 0x0257, 0x1434: 0x0260, 0x1435: 0x0242, - 0x1436: 0x0245, 0x1437: 0x024e, 0x1438: 0x0254, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272, + 0x1402: 0x0248, + 0x1407: 0x024b, 0x1409: 0x0290, 0x140b: 0x027e, + 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1411: 0x0263, + 0x1412: 0x0278, 0x1414: 0x0260, 0x1417: 0x024e, + 0x1419: 0x0266, 0x141b: 0x0272, 0x141d: 0x02e4, + 0x141f: 0x0296, 0x1421: 0x023c, 0x1422: 0x0248, + 0x1424: 0x0287, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290, + 0x142a: 0x027b, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f, + 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1434: 0x0260, 0x1435: 0x0242, + 0x1436: 0x0245, 0x1437: 0x024e, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272, + 0x143c: 0x0293, 0x143e: 0x02cc, // Block 0x51, offset 0x1440 - 0x1440: 0x1879, 0x1441: 0x1876, 0x1442: 0x187c, 0x1443: 0x18a0, 0x1444: 0x18c4, 0x1445: 0x18e8, - 0x1446: 0x190c, 0x1447: 0x1915, 0x1448: 0x191b, 0x1449: 0x1921, 0x144a: 0x1927, - 0x1450: 0x1a8c, 0x1451: 0x1a90, - 0x1452: 0x1a94, 0x1453: 0x1a98, 0x1454: 0x1a9c, 0x1455: 0x1aa0, 0x1456: 0x1aa4, 0x1457: 0x1aa8, - 0x1458: 0x1aac, 0x1459: 0x1ab0, 0x145a: 0x1ab4, 0x145b: 0x1ab8, 0x145c: 0x1abc, 0x145d: 0x1ac0, - 0x145e: 0x1ac4, 0x145f: 0x1ac8, 0x1460: 0x1acc, 0x1461: 0x1ad0, 0x1462: 0x1ad4, 0x1463: 0x1ad8, - 0x1464: 0x1adc, 0x1465: 0x1ae0, 0x1466: 0x1ae4, 0x1467: 0x1ae8, 0x1468: 0x1aec, 0x1469: 0x1af0, - 0x146a: 0x271e, 0x146b: 0x0047, 0x146c: 0x0065, 0x146d: 0x193c, 0x146e: 0x19b1, - 0x1470: 0x0043, 0x1471: 0x0045, 0x1472: 0x0047, 0x1473: 0x0049, 0x1474: 0x004b, 0x1475: 0x004d, - 0x1476: 0x004f, 0x1477: 0x0051, 0x1478: 0x0053, 0x1479: 0x0055, 0x147a: 0x0057, 0x147b: 0x0059, - 0x147c: 0x005b, 0x147d: 0x005d, 0x147e: 0x005f, 0x147f: 0x0061, + 0x1440: 0x0239, 0x1441: 0x023c, 0x1442: 0x0248, 0x1443: 0x0251, 0x1444: 0x0287, 0x1445: 0x028a, + 0x1446: 0x025a, 0x1447: 0x024b, 0x1448: 0x0269, 0x1449: 0x0290, 0x144b: 0x027e, + 0x144c: 0x0281, 0x144d: 0x0284, 0x144e: 0x025d, 0x144f: 0x026f, 0x1450: 0x0275, 0x1451: 0x0263, + 0x1452: 0x0278, 0x1453: 0x0257, 0x1454: 0x0260, 0x1455: 0x0242, 0x1456: 0x0245, 0x1457: 0x024e, + 0x1458: 0x0254, 0x1459: 0x0266, 0x145a: 0x026c, 0x145b: 0x0272, + 0x1461: 0x023c, 0x1462: 0x0248, 0x1463: 0x0251, + 0x1465: 0x028a, 0x1466: 0x025a, 0x1467: 0x024b, 0x1468: 0x0269, 0x1469: 0x0290, + 0x146b: 0x027e, 0x146c: 0x0281, 0x146d: 0x0284, 0x146e: 0x025d, 0x146f: 0x026f, + 0x1470: 0x0275, 0x1471: 0x0263, 0x1472: 0x0278, 0x1473: 0x0257, 0x1474: 0x0260, 0x1475: 0x0242, + 0x1476: 0x0245, 0x1477: 0x024e, 0x1478: 0x0254, 0x1479: 0x0266, 0x147a: 0x026c, 0x147b: 0x0272, // Block 0x52, offset 0x1480 - 0x1480: 0x26ad, 0x1481: 0x26c2, 0x1482: 0x0503, - 0x1490: 0x0c0f, 0x1491: 0x0a47, - 0x1492: 0x08d3, 0x1493: 0x45c4, 0x1494: 0x071b, 0x1495: 0x09ef, 0x1496: 0x132f, 0x1497: 0x09ff, - 0x1498: 0x0727, 0x1499: 0x0cd7, 0x149a: 0x0eaf, 0x149b: 0x0caf, 0x149c: 0x0827, 0x149d: 0x0b6b, - 0x149e: 0x07bf, 0x149f: 0x0cb7, 0x14a0: 0x0813, 0x14a1: 0x1117, 0x14a2: 0x0f83, 0x14a3: 0x138b, - 0x14a4: 0x09d3, 0x14a5: 0x090b, 0x14a6: 0x0e63, 0x14a7: 0x0c1b, 0x14a8: 0x0c47, 0x14a9: 0x06bf, - 0x14aa: 0x06cb, 0x14ab: 0x140b, 0x14ac: 0x0adb, 0x14ad: 0x06e7, 0x14ae: 0x08ef, 0x14af: 0x0c3b, - 0x14b0: 0x13b3, 0x14b1: 0x0c13, 0x14b2: 0x106f, 0x14b3: 0x10ab, 0x14b4: 0x08f7, 0x14b5: 0x0e43, - 0x14b6: 0x0d0b, 0x14b7: 0x0d07, 0x14b8: 0x0f97, 0x14b9: 0x082b, 0x14ba: 0x0957, 0x14bb: 0x1443, + 0x1480: 0x1879, 0x1481: 0x1876, 0x1482: 0x187c, 0x1483: 0x18a0, 0x1484: 0x18c4, 0x1485: 0x18e8, + 0x1486: 0x190c, 0x1487: 0x1915, 0x1488: 0x191b, 0x1489: 0x1921, 0x148a: 0x1927, + 0x1490: 0x1a8c, 0x1491: 0x1a90, + 0x1492: 0x1a94, 0x1493: 0x1a98, 0x1494: 0x1a9c, 0x1495: 0x1aa0, 0x1496: 0x1aa4, 0x1497: 0x1aa8, + 0x1498: 0x1aac, 0x1499: 0x1ab0, 0x149a: 0x1ab4, 0x149b: 0x1ab8, 0x149c: 0x1abc, 0x149d: 0x1ac0, + 0x149e: 0x1ac4, 0x149f: 0x1ac8, 0x14a0: 0x1acc, 0x14a1: 0x1ad0, 0x14a2: 0x1ad4, 0x14a3: 0x1ad8, + 0x14a4: 0x1adc, 0x14a5: 0x1ae0, 0x14a6: 0x1ae4, 0x14a7: 0x1ae8, 0x14a8: 0x1aec, 0x14a9: 0x1af0, + 0x14aa: 0x271e, 0x14ab: 0x0047, 0x14ac: 0x0065, 0x14ad: 0x193c, 0x14ae: 0x19b1, + 0x14b0: 0x0043, 0x14b1: 0x0045, 0x14b2: 0x0047, 0x14b3: 0x0049, 0x14b4: 0x004b, 0x14b5: 0x004d, + 0x14b6: 0x004f, 0x14b7: 0x0051, 0x14b8: 0x0053, 0x14b9: 0x0055, 0x14ba: 0x0057, 0x14bb: 0x0059, + 0x14bc: 0x005b, 0x14bd: 0x005d, 0x14be: 0x005f, 0x14bf: 0x0061, // Block 0x53, offset 0x14c0 - 0x14c0: 0x06fb, 0x14c1: 0x06f3, 0x14c2: 0x0703, 0x14c3: 0x1647, 0x14c4: 0x0747, 0x14c5: 0x0757, - 0x14c6: 0x075b, 0x14c7: 0x0763, 0x14c8: 0x076b, 0x14c9: 0x076f, 0x14ca: 0x077b, 0x14cb: 0x0773, - 0x14cc: 0x05b3, 0x14cd: 0x165b, 0x14ce: 0x078f, 0x14cf: 0x0793, 0x14d0: 0x0797, 0x14d1: 0x07b3, - 0x14d2: 0x164c, 0x14d3: 0x05b7, 0x14d4: 0x079f, 0x14d5: 0x07bf, 0x14d6: 0x1656, 0x14d7: 0x07cf, - 0x14d8: 0x07d7, 0x14d9: 0x0737, 0x14da: 0x07df, 0x14db: 0x07e3, 0x14dc: 0x1831, 0x14dd: 0x07ff, - 0x14de: 0x0807, 0x14df: 0x05bf, 0x14e0: 0x081f, 0x14e1: 0x0823, 0x14e2: 0x082b, 0x14e3: 0x082f, - 0x14e4: 0x05c3, 0x14e5: 0x0847, 0x14e6: 0x084b, 0x14e7: 0x0857, 0x14e8: 0x0863, 0x14e9: 0x0867, - 0x14ea: 0x086b, 0x14eb: 0x0873, 0x14ec: 0x0893, 0x14ed: 0x0897, 0x14ee: 0x089f, 0x14ef: 0x08af, - 0x14f0: 0x08b7, 0x14f1: 0x08bb, 0x14f2: 0x08bb, 0x14f3: 0x08bb, 0x14f4: 0x166a, 0x14f5: 0x0e93, - 0x14f6: 0x08cf, 0x14f7: 0x08d7, 0x14f8: 0x166f, 0x14f9: 0x08e3, 0x14fa: 0x08eb, 0x14fb: 0x08f3, - 0x14fc: 0x091b, 0x14fd: 0x0907, 0x14fe: 0x0913, 0x14ff: 0x0917, + 0x14c0: 0x26ad, 0x14c1: 0x26c2, 0x14c2: 0x0503, + 0x14d0: 0x0c0f, 0x14d1: 0x0a47, + 0x14d2: 0x08d3, 0x14d3: 0x45c4, 0x14d4: 0x071b, 0x14d5: 0x09ef, 0x14d6: 0x132f, 0x14d7: 0x09ff, + 0x14d8: 0x0727, 0x14d9: 0x0cd7, 0x14da: 0x0eaf, 0x14db: 0x0caf, 0x14dc: 0x0827, 0x14dd: 0x0b6b, + 0x14de: 0x07bf, 0x14df: 0x0cb7, 0x14e0: 0x0813, 0x14e1: 0x1117, 0x14e2: 0x0f83, 0x14e3: 0x138b, + 0x14e4: 0x09d3, 0x14e5: 0x090b, 0x14e6: 0x0e63, 0x14e7: 0x0c1b, 0x14e8: 0x0c47, 0x14e9: 0x06bf, + 0x14ea: 0x06cb, 0x14eb: 0x140b, 0x14ec: 0x0adb, 0x14ed: 0x06e7, 0x14ee: 0x08ef, 0x14ef: 0x0c3b, + 0x14f0: 0x13b3, 0x14f1: 0x0c13, 0x14f2: 0x106f, 0x14f3: 0x10ab, 0x14f4: 0x08f7, 0x14f5: 0x0e43, + 0x14f6: 0x0d0b, 0x14f7: 0x0d07, 0x14f8: 0x0f97, 0x14f9: 0x082b, 0x14fa: 0x0957, 0x14fb: 0x1443, // Block 0x54, offset 0x1500 - 0x1500: 0x091f, 0x1501: 0x0927, 0x1502: 0x092b, 0x1503: 0x0933, 0x1504: 0x093b, 0x1505: 0x093f, - 0x1506: 0x093f, 0x1507: 0x0947, 0x1508: 0x094f, 0x1509: 0x0953, 0x150a: 0x095f, 0x150b: 0x0983, - 0x150c: 0x0967, 0x150d: 0x0987, 0x150e: 0x096b, 0x150f: 0x0973, 0x1510: 0x080b, 0x1511: 0x09cf, - 0x1512: 0x0997, 0x1513: 0x099b, 0x1514: 0x099f, 0x1515: 0x0993, 0x1516: 0x09a7, 0x1517: 0x09a3, - 0x1518: 0x09bb, 0x1519: 0x1674, 0x151a: 0x09d7, 0x151b: 0x09db, 0x151c: 0x09e3, 0x151d: 0x09ef, - 0x151e: 0x09f7, 0x151f: 0x0a13, 0x1520: 0x1679, 0x1521: 0x167e, 0x1522: 0x0a1f, 0x1523: 0x0a23, - 0x1524: 0x0a27, 0x1525: 0x0a1b, 0x1526: 0x0a2f, 0x1527: 0x05c7, 0x1528: 0x05cb, 0x1529: 0x0a37, - 0x152a: 0x0a3f, 0x152b: 0x0a3f, 0x152c: 0x1683, 0x152d: 0x0a5b, 0x152e: 0x0a5f, 0x152f: 0x0a63, - 0x1530: 0x0a6b, 0x1531: 0x1688, 0x1532: 0x0a73, 0x1533: 0x0a77, 0x1534: 0x0b4f, 0x1535: 0x0a7f, - 0x1536: 0x05cf, 0x1537: 0x0a8b, 0x1538: 0x0a9b, 0x1539: 0x0aa7, 0x153a: 0x0aa3, 0x153b: 0x1692, - 0x153c: 0x0aaf, 0x153d: 0x1697, 0x153e: 0x0abb, 0x153f: 0x0ab7, + 0x1500: 0x06fb, 0x1501: 0x06f3, 0x1502: 0x0703, 0x1503: 0x1647, 0x1504: 0x0747, 0x1505: 0x0757, + 0x1506: 0x075b, 0x1507: 0x0763, 0x1508: 0x076b, 0x1509: 0x076f, 0x150a: 0x077b, 0x150b: 0x0773, + 0x150c: 0x05b3, 0x150d: 0x165b, 0x150e: 0x078f, 0x150f: 0x0793, 0x1510: 0x0797, 0x1511: 0x07b3, + 0x1512: 0x164c, 0x1513: 0x05b7, 0x1514: 0x079f, 0x1515: 0x07bf, 0x1516: 0x1656, 0x1517: 0x07cf, + 0x1518: 0x07d7, 0x1519: 0x0737, 0x151a: 0x07df, 0x151b: 0x07e3, 0x151c: 0x1831, 0x151d: 0x07ff, + 0x151e: 0x0807, 0x151f: 0x05bf, 0x1520: 0x081f, 0x1521: 0x0823, 0x1522: 0x082b, 0x1523: 0x082f, + 0x1524: 0x05c3, 0x1525: 0x0847, 0x1526: 0x084b, 0x1527: 0x0857, 0x1528: 0x0863, 0x1529: 0x0867, + 0x152a: 0x086b, 0x152b: 0x0873, 0x152c: 0x0893, 0x152d: 0x0897, 0x152e: 0x089f, 0x152f: 0x08af, + 0x1530: 0x08b7, 0x1531: 0x08bb, 0x1532: 0x08bb, 0x1533: 0x08bb, 0x1534: 0x166a, 0x1535: 0x0e93, + 0x1536: 0x08cf, 0x1537: 0x08d7, 0x1538: 0x166f, 0x1539: 0x08e3, 0x153a: 0x08eb, 0x153b: 0x08f3, + 0x153c: 0x091b, 0x153d: 0x0907, 0x153e: 0x0913, 0x153f: 0x0917, // Block 0x55, offset 0x1540 - 0x1540: 0x0abf, 0x1541: 0x0acf, 0x1542: 0x0ad3, 0x1543: 0x05d3, 0x1544: 0x0ae3, 0x1545: 0x0aeb, - 0x1546: 0x0aef, 0x1547: 0x0af3, 0x1548: 0x05d7, 0x1549: 0x169c, 0x154a: 0x05db, 0x154b: 0x0b0f, - 0x154c: 0x0b13, 0x154d: 0x0b17, 0x154e: 0x0b1f, 0x154f: 0x1863, 0x1550: 0x0b37, 0x1551: 0x16a6, - 0x1552: 0x16a6, 0x1553: 0x11d7, 0x1554: 0x0b47, 0x1555: 0x0b47, 0x1556: 0x05df, 0x1557: 0x16c9, - 0x1558: 0x179b, 0x1559: 0x0b57, 0x155a: 0x0b5f, 0x155b: 0x05e3, 0x155c: 0x0b73, 0x155d: 0x0b83, - 0x155e: 0x0b87, 0x155f: 0x0b8f, 0x1560: 0x0b9f, 0x1561: 0x05eb, 0x1562: 0x05e7, 0x1563: 0x0ba3, - 0x1564: 0x16ab, 0x1565: 0x0ba7, 0x1566: 0x0bbb, 0x1567: 0x0bbf, 0x1568: 0x0bc3, 0x1569: 0x0bbf, - 0x156a: 0x0bcf, 0x156b: 0x0bd3, 0x156c: 0x0be3, 0x156d: 0x0bdb, 0x156e: 0x0bdf, 0x156f: 0x0be7, - 0x1570: 0x0beb, 0x1571: 0x0bef, 0x1572: 0x0bfb, 0x1573: 0x0bff, 0x1574: 0x0c17, 0x1575: 0x0c1f, - 0x1576: 0x0c2f, 0x1577: 0x0c43, 0x1578: 0x16ba, 0x1579: 0x0c3f, 0x157a: 0x0c33, 0x157b: 0x0c4b, - 0x157c: 0x0c53, 0x157d: 0x0c67, 0x157e: 0x16bf, 0x157f: 0x0c6f, + 0x1540: 0x091f, 0x1541: 0x0927, 0x1542: 0x092b, 0x1543: 0x0933, 0x1544: 0x093b, 0x1545: 0x093f, + 0x1546: 0x093f, 0x1547: 0x0947, 0x1548: 0x094f, 0x1549: 0x0953, 0x154a: 0x095f, 0x154b: 0x0983, + 0x154c: 0x0967, 0x154d: 0x0987, 0x154e: 0x096b, 0x154f: 0x0973, 0x1550: 0x080b, 0x1551: 0x09cf, + 0x1552: 0x0997, 0x1553: 0x099b, 0x1554: 0x099f, 0x1555: 0x0993, 0x1556: 0x09a7, 0x1557: 0x09a3, + 0x1558: 0x09bb, 0x1559: 0x1674, 0x155a: 0x09d7, 0x155b: 0x09db, 0x155c: 0x09e3, 0x155d: 0x09ef, + 0x155e: 0x09f7, 0x155f: 0x0a13, 0x1560: 0x1679, 0x1561: 0x167e, 0x1562: 0x0a1f, 0x1563: 0x0a23, + 0x1564: 0x0a27, 0x1565: 0x0a1b, 0x1566: 0x0a2f, 0x1567: 0x05c7, 0x1568: 0x05cb, 0x1569: 0x0a37, + 0x156a: 0x0a3f, 0x156b: 0x0a3f, 0x156c: 0x1683, 0x156d: 0x0a5b, 0x156e: 0x0a5f, 0x156f: 0x0a63, + 0x1570: 0x0a6b, 0x1571: 0x1688, 0x1572: 0x0a73, 0x1573: 0x0a77, 0x1574: 0x0b4f, 0x1575: 0x0a7f, + 0x1576: 0x05cf, 0x1577: 0x0a8b, 0x1578: 0x0a9b, 0x1579: 0x0aa7, 0x157a: 0x0aa3, 0x157b: 0x1692, + 0x157c: 0x0aaf, 0x157d: 0x1697, 0x157e: 0x0abb, 0x157f: 0x0ab7, // Block 0x56, offset 0x1580 - 0x1580: 0x0c63, 0x1581: 0x0c5b, 0x1582: 0x05ef, 0x1583: 0x0c77, 0x1584: 0x0c7f, 0x1585: 0x0c87, - 0x1586: 0x0c7b, 0x1587: 0x05f3, 0x1588: 0x0c97, 0x1589: 0x0c9f, 0x158a: 0x16c4, 0x158b: 0x0ccb, - 0x158c: 0x0cff, 0x158d: 0x0cdb, 0x158e: 0x05ff, 0x158f: 0x0ce7, 0x1590: 0x05fb, 0x1591: 0x05f7, - 0x1592: 0x07c3, 0x1593: 0x07c7, 0x1594: 0x0d03, 0x1595: 0x0ceb, 0x1596: 0x11ab, 0x1597: 0x0663, - 0x1598: 0x0d0f, 0x1599: 0x0d13, 0x159a: 0x0d17, 0x159b: 0x0d2b, 0x159c: 0x0d23, 0x159d: 0x16dd, - 0x159e: 0x0603, 0x159f: 0x0d3f, 0x15a0: 0x0d33, 0x15a1: 0x0d4f, 0x15a2: 0x0d57, 0x15a3: 0x16e7, - 0x15a4: 0x0d5b, 0x15a5: 0x0d47, 0x15a6: 0x0d63, 0x15a7: 0x0607, 0x15a8: 0x0d67, 0x15a9: 0x0d6b, - 0x15aa: 0x0d6f, 0x15ab: 0x0d7b, 0x15ac: 0x16ec, 0x15ad: 0x0d83, 0x15ae: 0x060b, 0x15af: 0x0d8f, - 0x15b0: 0x16f1, 0x15b1: 0x0d93, 0x15b2: 0x060f, 0x15b3: 0x0d9f, 0x15b4: 0x0dab, 0x15b5: 0x0db7, - 0x15b6: 0x0dbb, 0x15b7: 0x16f6, 0x15b8: 0x168d, 0x15b9: 0x16fb, 0x15ba: 0x0ddb, 0x15bb: 0x1700, - 0x15bc: 0x0de7, 0x15bd: 0x0def, 0x15be: 0x0ddf, 0x15bf: 0x0dfb, + 0x1580: 0x0abf, 0x1581: 0x0acf, 0x1582: 0x0ad3, 0x1583: 0x05d3, 0x1584: 0x0ae3, 0x1585: 0x0aeb, + 0x1586: 0x0aef, 0x1587: 0x0af3, 0x1588: 0x05d7, 0x1589: 0x169c, 0x158a: 0x05db, 0x158b: 0x0b0f, + 0x158c: 0x0b13, 0x158d: 0x0b17, 0x158e: 0x0b1f, 0x158f: 0x1863, 0x1590: 0x0b37, 0x1591: 0x16a6, + 0x1592: 0x16a6, 0x1593: 0x11d7, 0x1594: 0x0b47, 0x1595: 0x0b47, 0x1596: 0x05df, 0x1597: 0x16c9, + 0x1598: 0x179b, 0x1599: 0x0b57, 0x159a: 0x0b5f, 0x159b: 0x05e3, 0x159c: 0x0b73, 0x159d: 0x0b83, + 0x159e: 0x0b87, 0x159f: 0x0b8f, 0x15a0: 0x0b9f, 0x15a1: 0x05eb, 0x15a2: 0x05e7, 0x15a3: 0x0ba3, + 0x15a4: 0x16ab, 0x15a5: 0x0ba7, 0x15a6: 0x0bbb, 0x15a7: 0x0bbf, 0x15a8: 0x0bc3, 0x15a9: 0x0bbf, + 0x15aa: 0x0bcf, 0x15ab: 0x0bd3, 0x15ac: 0x0be3, 0x15ad: 0x0bdb, 0x15ae: 0x0bdf, 0x15af: 0x0be7, + 0x15b0: 0x0beb, 0x15b1: 0x0bef, 0x15b2: 0x0bfb, 0x15b3: 0x0bff, 0x15b4: 0x0c17, 0x15b5: 0x0c1f, + 0x15b6: 0x0c2f, 0x15b7: 0x0c43, 0x15b8: 0x16ba, 0x15b9: 0x0c3f, 0x15ba: 0x0c33, 0x15bb: 0x0c4b, + 0x15bc: 0x0c53, 0x15bd: 0x0c67, 0x15be: 0x16bf, 0x15bf: 0x0c6f, // Block 0x57, offset 0x15c0 - 0x15c0: 0x0e0b, 0x15c1: 0x0e1b, 0x15c2: 0x0e0f, 0x15c3: 0x0e13, 0x15c4: 0x0e1f, 0x15c5: 0x0e23, - 0x15c6: 0x1705, 0x15c7: 0x0e07, 0x15c8: 0x0e3b, 0x15c9: 0x0e3f, 0x15ca: 0x0613, 0x15cb: 0x0e53, - 0x15cc: 0x0e4f, 0x15cd: 0x170a, 0x15ce: 0x0e33, 0x15cf: 0x0e6f, 0x15d0: 0x170f, 0x15d1: 0x1714, - 0x15d2: 0x0e73, 0x15d3: 0x0e87, 0x15d4: 0x0e83, 0x15d5: 0x0e7f, 0x15d6: 0x0617, 0x15d7: 0x0e8b, - 0x15d8: 0x0e9b, 0x15d9: 0x0e97, 0x15da: 0x0ea3, 0x15db: 0x1651, 0x15dc: 0x0eb3, 0x15dd: 0x1719, - 0x15de: 0x0ebf, 0x15df: 0x1723, 0x15e0: 0x0ed3, 0x15e1: 0x0edf, 0x15e2: 0x0ef3, 0x15e3: 0x1728, - 0x15e4: 0x0f07, 0x15e5: 0x0f0b, 0x15e6: 0x172d, 0x15e7: 0x1732, 0x15e8: 0x0f27, 0x15e9: 0x0f37, - 0x15ea: 0x061b, 0x15eb: 0x0f3b, 0x15ec: 0x061f, 0x15ed: 0x061f, 0x15ee: 0x0f53, 0x15ef: 0x0f57, - 0x15f0: 0x0f5f, 0x15f1: 0x0f63, 0x15f2: 0x0f6f, 0x15f3: 0x0623, 0x15f4: 0x0f87, 0x15f5: 0x1737, - 0x15f6: 0x0fa3, 0x15f7: 0x173c, 0x15f8: 0x0faf, 0x15f9: 0x16a1, 0x15fa: 0x0fbf, 0x15fb: 0x1741, - 0x15fc: 0x1746, 0x15fd: 0x174b, 0x15fe: 0x0627, 0x15ff: 0x062b, + 0x15c0: 0x0c63, 0x15c1: 0x0c5b, 0x15c2: 0x05ef, 0x15c3: 0x0c77, 0x15c4: 0x0c7f, 0x15c5: 0x0c87, + 0x15c6: 0x0c7b, 0x15c7: 0x05f3, 0x15c8: 0x0c97, 0x15c9: 0x0c9f, 0x15ca: 0x16c4, 0x15cb: 0x0ccb, + 0x15cc: 0x0cff, 0x15cd: 0x0cdb, 0x15ce: 0x05ff, 0x15cf: 0x0ce7, 0x15d0: 0x05fb, 0x15d1: 0x05f7, + 0x15d2: 0x07c3, 0x15d3: 0x07c7, 0x15d4: 0x0d03, 0x15d5: 0x0ceb, 0x15d6: 0x11ab, 0x15d7: 0x0663, + 0x15d8: 0x0d0f, 0x15d9: 0x0d13, 0x15da: 0x0d17, 0x15db: 0x0d2b, 0x15dc: 0x0d23, 0x15dd: 0x16dd, + 0x15de: 0x0603, 0x15df: 0x0d3f, 0x15e0: 0x0d33, 0x15e1: 0x0d4f, 0x15e2: 0x0d57, 0x15e3: 0x16e7, + 0x15e4: 0x0d5b, 0x15e5: 0x0d47, 0x15e6: 0x0d63, 0x15e7: 0x0607, 0x15e8: 0x0d67, 0x15e9: 0x0d6b, + 0x15ea: 0x0d6f, 0x15eb: 0x0d7b, 0x15ec: 0x16ec, 0x15ed: 0x0d83, 0x15ee: 0x060b, 0x15ef: 0x0d8f, + 0x15f0: 0x16f1, 0x15f1: 0x0d93, 0x15f2: 0x060f, 0x15f3: 0x0d9f, 0x15f4: 0x0dab, 0x15f5: 0x0db7, + 0x15f6: 0x0dbb, 0x15f7: 0x16f6, 0x15f8: 0x168d, 0x15f9: 0x16fb, 0x15fa: 0x0ddb, 0x15fb: 0x1700, + 0x15fc: 0x0de7, 0x15fd: 0x0def, 0x15fe: 0x0ddf, 0x15ff: 0x0dfb, // Block 0x58, offset 0x1600 - 0x1600: 0x0ff7, 0x1601: 0x1755, 0x1602: 0x1750, 0x1603: 0x175a, 0x1604: 0x175f, 0x1605: 0x0fff, - 0x1606: 0x1003, 0x1607: 0x1003, 0x1608: 0x100b, 0x1609: 0x0633, 0x160a: 0x100f, 0x160b: 0x0637, - 0x160c: 0x063b, 0x160d: 0x1769, 0x160e: 0x1023, 0x160f: 0x102b, 0x1610: 0x1037, 0x1611: 0x063f, - 0x1612: 0x176e, 0x1613: 0x105b, 0x1614: 0x1773, 0x1615: 0x1778, 0x1616: 0x107b, 0x1617: 0x1093, - 0x1618: 0x0643, 0x1619: 0x109b, 0x161a: 0x109f, 0x161b: 0x10a3, 0x161c: 0x177d, 0x161d: 0x1782, - 0x161e: 0x1782, 0x161f: 0x10bb, 0x1620: 0x0647, 0x1621: 0x1787, 0x1622: 0x10cf, 0x1623: 0x10d3, - 0x1624: 0x064b, 0x1625: 0x178c, 0x1626: 0x10ef, 0x1627: 0x064f, 0x1628: 0x10ff, 0x1629: 0x10f7, - 0x162a: 0x1107, 0x162b: 0x1796, 0x162c: 0x111f, 0x162d: 0x0653, 0x162e: 0x112b, 0x162f: 0x1133, - 0x1630: 0x1143, 0x1631: 0x0657, 0x1632: 0x17a0, 0x1633: 0x17a5, 0x1634: 0x065b, 0x1635: 0x17aa, - 0x1636: 0x115b, 0x1637: 0x17af, 0x1638: 0x1167, 0x1639: 0x1173, 0x163a: 0x117b, 0x163b: 0x17b4, - 0x163c: 0x17b9, 0x163d: 0x118f, 0x163e: 0x17be, 0x163f: 0x1197, + 0x1600: 0x0e0b, 0x1601: 0x0e1b, 0x1602: 0x0e0f, 0x1603: 0x0e13, 0x1604: 0x0e1f, 0x1605: 0x0e23, + 0x1606: 0x1705, 0x1607: 0x0e07, 0x1608: 0x0e3b, 0x1609: 0x0e3f, 0x160a: 0x0613, 0x160b: 0x0e53, + 0x160c: 0x0e4f, 0x160d: 0x170a, 0x160e: 0x0e33, 0x160f: 0x0e6f, 0x1610: 0x170f, 0x1611: 0x1714, + 0x1612: 0x0e73, 0x1613: 0x0e87, 0x1614: 0x0e83, 0x1615: 0x0e7f, 0x1616: 0x0617, 0x1617: 0x0e8b, + 0x1618: 0x0e9b, 0x1619: 0x0e97, 0x161a: 0x0ea3, 0x161b: 0x1651, 0x161c: 0x0eb3, 0x161d: 0x1719, + 0x161e: 0x0ebf, 0x161f: 0x1723, 0x1620: 0x0ed3, 0x1621: 0x0edf, 0x1622: 0x0ef3, 0x1623: 0x1728, + 0x1624: 0x0f07, 0x1625: 0x0f0b, 0x1626: 0x172d, 0x1627: 0x1732, 0x1628: 0x0f27, 0x1629: 0x0f37, + 0x162a: 0x061b, 0x162b: 0x0f3b, 0x162c: 0x061f, 0x162d: 0x061f, 0x162e: 0x0f53, 0x162f: 0x0f57, + 0x1630: 0x0f5f, 0x1631: 0x0f63, 0x1632: 0x0f6f, 0x1633: 0x0623, 0x1634: 0x0f87, 0x1635: 0x1737, + 0x1636: 0x0fa3, 0x1637: 0x173c, 0x1638: 0x0faf, 0x1639: 0x16a1, 0x163a: 0x0fbf, 0x163b: 0x1741, + 0x163c: 0x1746, 0x163d: 0x174b, 0x163e: 0x0627, 0x163f: 0x062b, // Block 0x59, offset 0x1640 - 0x1640: 0x16ce, 0x1641: 0x065f, 0x1642: 0x11af, 0x1643: 0x11b3, 0x1644: 0x0667, 0x1645: 0x11b7, - 0x1646: 0x0a33, 0x1647: 0x17c3, 0x1648: 0x17c8, 0x1649: 0x16d3, 0x164a: 0x16d8, 0x164b: 0x11d7, - 0x164c: 0x11db, 0x164d: 0x13f3, 0x164e: 0x066b, 0x164f: 0x1207, 0x1650: 0x1203, 0x1651: 0x120b, - 0x1652: 0x083f, 0x1653: 0x120f, 0x1654: 0x1213, 0x1655: 0x1217, 0x1656: 0x121f, 0x1657: 0x17cd, - 0x1658: 0x121b, 0x1659: 0x1223, 0x165a: 0x1237, 0x165b: 0x123b, 0x165c: 0x1227, 0x165d: 0x123f, - 0x165e: 0x1253, 0x165f: 0x1267, 0x1660: 0x1233, 0x1661: 0x1247, 0x1662: 0x124b, 0x1663: 0x124f, - 0x1664: 0x17d2, 0x1665: 0x17dc, 0x1666: 0x17d7, 0x1667: 0x066f, 0x1668: 0x126f, 0x1669: 0x1273, - 0x166a: 0x127b, 0x166b: 0x17f0, 0x166c: 0x127f, 0x166d: 0x17e1, 0x166e: 0x0673, 0x166f: 0x0677, - 0x1670: 0x17e6, 0x1671: 0x17eb, 0x1672: 0x067b, 0x1673: 0x129f, 0x1674: 0x12a3, 0x1675: 0x12a7, - 0x1676: 0x12ab, 0x1677: 0x12b7, 0x1678: 0x12b3, 0x1679: 0x12bf, 0x167a: 0x12bb, 0x167b: 0x12cb, - 0x167c: 0x12c3, 0x167d: 0x12c7, 0x167e: 0x12cf, 0x167f: 0x067f, + 0x1640: 0x0ff7, 0x1641: 0x1755, 0x1642: 0x1750, 0x1643: 0x175a, 0x1644: 0x175f, 0x1645: 0x0fff, + 0x1646: 0x1003, 0x1647: 0x1003, 0x1648: 0x100b, 0x1649: 0x0633, 0x164a: 0x100f, 0x164b: 0x0637, + 0x164c: 0x063b, 0x164d: 0x1769, 0x164e: 0x1023, 0x164f: 0x102b, 0x1650: 0x1037, 0x1651: 0x063f, + 0x1652: 0x176e, 0x1653: 0x105b, 0x1654: 0x1773, 0x1655: 0x1778, 0x1656: 0x107b, 0x1657: 0x1093, + 0x1658: 0x0643, 0x1659: 0x109b, 0x165a: 0x109f, 0x165b: 0x10a3, 0x165c: 0x177d, 0x165d: 0x1782, + 0x165e: 0x1782, 0x165f: 0x10bb, 0x1660: 0x0647, 0x1661: 0x1787, 0x1662: 0x10cf, 0x1663: 0x10d3, + 0x1664: 0x064b, 0x1665: 0x178c, 0x1666: 0x10ef, 0x1667: 0x064f, 0x1668: 0x10ff, 0x1669: 0x10f7, + 0x166a: 0x1107, 0x166b: 0x1796, 0x166c: 0x111f, 0x166d: 0x0653, 0x166e: 0x112b, 0x166f: 0x1133, + 0x1670: 0x1143, 0x1671: 0x0657, 0x1672: 0x17a0, 0x1673: 0x17a5, 0x1674: 0x065b, 0x1675: 0x17aa, + 0x1676: 0x115b, 0x1677: 0x17af, 0x1678: 0x1167, 0x1679: 0x1173, 0x167a: 0x117b, 0x167b: 0x17b4, + 0x167c: 0x17b9, 0x167d: 0x118f, 0x167e: 0x17be, 0x167f: 0x1197, // Block 0x5a, offset 0x1680 - 0x1680: 0x12d7, 0x1681: 0x12db, 0x1682: 0x0683, 0x1683: 0x12eb, 0x1684: 0x12ef, 0x1685: 0x17f5, - 0x1686: 0x12fb, 0x1687: 0x12ff, 0x1688: 0x0687, 0x1689: 0x130b, 0x168a: 0x05bb, 0x168b: 0x17fa, - 0x168c: 0x17ff, 0x168d: 0x068b, 0x168e: 0x068f, 0x168f: 0x1337, 0x1690: 0x134f, 0x1691: 0x136b, - 0x1692: 0x137b, 0x1693: 0x1804, 0x1694: 0x138f, 0x1695: 0x1393, 0x1696: 0x13ab, 0x1697: 0x13b7, - 0x1698: 0x180e, 0x1699: 0x1660, 0x169a: 0x13c3, 0x169b: 0x13bf, 0x169c: 0x13cb, 0x169d: 0x1665, - 0x169e: 0x13d7, 0x169f: 0x13e3, 0x16a0: 0x1813, 0x16a1: 0x1818, 0x16a2: 0x1423, 0x16a3: 0x142f, - 0x16a4: 0x1437, 0x16a5: 0x181d, 0x16a6: 0x143b, 0x16a7: 0x1467, 0x16a8: 0x1473, 0x16a9: 0x1477, - 0x16aa: 0x146f, 0x16ab: 0x1483, 0x16ac: 0x1487, 0x16ad: 0x1822, 0x16ae: 0x1493, 0x16af: 0x0693, - 0x16b0: 0x149b, 0x16b1: 0x1827, 0x16b2: 0x0697, 0x16b3: 0x14d3, 0x16b4: 0x0ac3, 0x16b5: 0x14eb, - 0x16b6: 0x182c, 0x16b7: 0x1836, 0x16b8: 0x069b, 0x16b9: 0x069f, 0x16ba: 0x1513, 0x16bb: 0x183b, - 0x16bc: 0x06a3, 0x16bd: 0x1840, 0x16be: 0x152b, 0x16bf: 0x152b, + 0x1680: 0x16ce, 0x1681: 0x065f, 0x1682: 0x11af, 0x1683: 0x11b3, 0x1684: 0x0667, 0x1685: 0x11b7, + 0x1686: 0x0a33, 0x1687: 0x17c3, 0x1688: 0x17c8, 0x1689: 0x16d3, 0x168a: 0x16d8, 0x168b: 0x11d7, + 0x168c: 0x11db, 0x168d: 0x13f3, 0x168e: 0x066b, 0x168f: 0x1207, 0x1690: 0x1203, 0x1691: 0x120b, + 0x1692: 0x083f, 0x1693: 0x120f, 0x1694: 0x1213, 0x1695: 0x1217, 0x1696: 0x121f, 0x1697: 0x17cd, + 0x1698: 0x121b, 0x1699: 0x1223, 0x169a: 0x1237, 0x169b: 0x123b, 0x169c: 0x1227, 0x169d: 0x123f, + 0x169e: 0x1253, 0x169f: 0x1267, 0x16a0: 0x1233, 0x16a1: 0x1247, 0x16a2: 0x124b, 0x16a3: 0x124f, + 0x16a4: 0x17d2, 0x16a5: 0x17dc, 0x16a6: 0x17d7, 0x16a7: 0x066f, 0x16a8: 0x126f, 0x16a9: 0x1273, + 0x16aa: 0x127b, 0x16ab: 0x17f0, 0x16ac: 0x127f, 0x16ad: 0x17e1, 0x16ae: 0x0673, 0x16af: 0x0677, + 0x16b0: 0x17e6, 0x16b1: 0x17eb, 0x16b2: 0x067b, 0x16b3: 0x129f, 0x16b4: 0x12a3, 0x16b5: 0x12a7, + 0x16b6: 0x12ab, 0x16b7: 0x12b7, 0x16b8: 0x12b3, 0x16b9: 0x12bf, 0x16ba: 0x12bb, 0x16bb: 0x12cb, + 0x16bc: 0x12c3, 0x16bd: 0x12c7, 0x16be: 0x12cf, 0x16bf: 0x067f, // Block 0x5b, offset 0x16c0 - 0x16c0: 0x1533, 0x16c1: 0x1845, 0x16c2: 0x154b, 0x16c3: 0x06a7, 0x16c4: 0x155b, 0x16c5: 0x1567, - 0x16c6: 0x156f, 0x16c7: 0x1577, 0x16c8: 0x06ab, 0x16c9: 0x184a, 0x16ca: 0x158b, 0x16cb: 0x15a7, - 0x16cc: 0x15b3, 0x16cd: 0x06af, 0x16ce: 0x06b3, 0x16cf: 0x15b7, 0x16d0: 0x184f, 0x16d1: 0x06b7, - 0x16d2: 0x1854, 0x16d3: 0x1859, 0x16d4: 0x185e, 0x16d5: 0x15db, 0x16d6: 0x06bb, 0x16d7: 0x15ef, - 0x16d8: 0x15f7, 0x16d9: 0x15fb, 0x16da: 0x1603, 0x16db: 0x160b, 0x16dc: 0x1613, 0x16dd: 0x1868, + 0x16c0: 0x12d7, 0x16c1: 0x12db, 0x16c2: 0x0683, 0x16c3: 0x12eb, 0x16c4: 0x12ef, 0x16c5: 0x17f5, + 0x16c6: 0x12fb, 0x16c7: 0x12ff, 0x16c8: 0x0687, 0x16c9: 0x130b, 0x16ca: 0x05bb, 0x16cb: 0x17fa, + 0x16cc: 0x17ff, 0x16cd: 0x068b, 0x16ce: 0x068f, 0x16cf: 0x1337, 0x16d0: 0x134f, 0x16d1: 0x136b, + 0x16d2: 0x137b, 0x16d3: 0x1804, 0x16d4: 0x138f, 0x16d5: 0x1393, 0x16d6: 0x13ab, 0x16d7: 0x13b7, + 0x16d8: 0x180e, 0x16d9: 0x1660, 0x16da: 0x13c3, 0x16db: 0x13bf, 0x16dc: 0x13cb, 0x16dd: 0x1665, + 0x16de: 0x13d7, 0x16df: 0x13e3, 0x16e0: 0x1813, 0x16e1: 0x1818, 0x16e2: 0x1423, 0x16e3: 0x142f, + 0x16e4: 0x1437, 0x16e5: 0x181d, 0x16e6: 0x143b, 0x16e7: 0x1467, 0x16e8: 0x1473, 0x16e9: 0x1477, + 0x16ea: 0x146f, 0x16eb: 0x1483, 0x16ec: 0x1487, 0x16ed: 0x1822, 0x16ee: 0x1493, 0x16ef: 0x0693, + 0x16f0: 0x149b, 0x16f1: 0x1827, 0x16f2: 0x0697, 0x16f3: 0x14d3, 0x16f4: 0x0ac3, 0x16f5: 0x14eb, + 0x16f6: 0x182c, 0x16f7: 0x1836, 0x16f8: 0x069b, 0x16f9: 0x069f, 0x16fa: 0x1513, 0x16fb: 0x183b, + 0x16fc: 0x06a3, 0x16fd: 0x1840, 0x16fe: 0x152b, 0x16ff: 0x152b, + // Block 0x5c, offset 0x1700 + 0x1700: 0x1533, 0x1701: 0x1845, 0x1702: 0x154b, 0x1703: 0x06a7, 0x1704: 0x155b, 0x1705: 0x1567, + 0x1706: 0x156f, 0x1707: 0x1577, 0x1708: 0x06ab, 0x1709: 0x184a, 0x170a: 0x158b, 0x170b: 0x15a7, + 0x170c: 0x15b3, 0x170d: 0x06af, 0x170e: 0x06b3, 0x170f: 0x15b7, 0x1710: 0x184f, 0x1711: 0x06b7, + 0x1712: 0x1854, 0x1713: 0x1859, 0x1714: 0x185e, 0x1715: 0x15db, 0x1716: 0x06bb, 0x1717: 0x15ef, + 0x1718: 0x15f7, 0x1719: 0x15fb, 0x171a: 0x1603, 0x171b: 0x160b, 0x171c: 0x1613, 0x171d: 0x1868, } // nfkcIndex: 22 blocks, 1408 entries, 1408 bytes @@ -5550,36 +5572,36 @@ var nfkcIndex = [1408]uint8{ // Block 0x1, offset 0x40 // Block 0x2, offset 0x80 // Block 0x3, offset 0xc0 - 0xc2: 0x5a, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5b, 0xc7: 0x04, - 0xc8: 0x05, 0xca: 0x5c, 0xcb: 0x5d, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09, - 0xd0: 0x0a, 0xd1: 0x5e, 0xd2: 0x5f, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x60, - 0xd8: 0x61, 0xd9: 0x0d, 0xdb: 0x62, 0xdc: 0x63, 0xdd: 0x64, 0xdf: 0x65, + 0xc2: 0x5b, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5c, 0xc7: 0x04, + 0xc8: 0x05, 0xca: 0x5d, 0xcb: 0x5e, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09, + 0xd0: 0x0a, 0xd1: 0x5f, 0xd2: 0x60, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x61, + 0xd8: 0x62, 0xd9: 0x0d, 0xdb: 0x63, 0xdc: 0x64, 0xdd: 0x65, 0xdf: 0x66, 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, 0xf0: 0x13, // Block 0x4, offset 0x100 - 0x120: 0x66, 0x121: 0x67, 0x123: 0x68, 0x124: 0x69, 0x125: 0x6a, 0x126: 0x6b, 0x127: 0x6c, - 0x128: 0x6d, 0x129: 0x6e, 0x12a: 0x6f, 0x12b: 0x70, 0x12c: 0x6b, 0x12d: 0x71, 0x12e: 0x72, 0x12f: 0x73, - 0x131: 0x74, 0x132: 0x75, 0x133: 0x76, 0x134: 0x77, 0x135: 0x78, 0x137: 0x79, - 0x138: 0x7a, 0x139: 0x7b, 0x13a: 0x7c, 0x13b: 0x7d, 0x13c: 0x7e, 0x13d: 0x7f, 0x13e: 0x80, 0x13f: 0x81, + 0x120: 0x67, 0x121: 0x68, 0x123: 0x69, 0x124: 0x6a, 0x125: 0x6b, 0x126: 0x6c, 0x127: 0x6d, + 0x128: 0x6e, 0x129: 0x6f, 0x12a: 0x70, 0x12b: 0x71, 0x12c: 0x6c, 0x12d: 0x72, 0x12e: 0x73, 0x12f: 0x74, + 0x131: 0x75, 0x132: 0x76, 0x133: 0x77, 0x134: 0x78, 0x135: 0x79, 0x137: 0x7a, + 0x138: 0x7b, 0x139: 0x7c, 0x13a: 0x7d, 0x13b: 0x7e, 0x13c: 0x7f, 0x13d: 0x80, 0x13e: 0x81, 0x13f: 0x82, // Block 0x5, offset 0x140 - 0x140: 0x82, 0x142: 0x83, 0x143: 0x84, 0x144: 0x85, 0x145: 0x86, 0x146: 0x87, 0x147: 0x88, - 0x14d: 0x89, - 0x15c: 0x8a, 0x15f: 0x8b, - 0x162: 0x8c, 0x164: 0x8d, - 0x168: 0x8e, 0x169: 0x8f, 0x16a: 0x90, 0x16c: 0x0e, 0x16d: 0x91, 0x16e: 0x92, 0x16f: 0x93, - 0x170: 0x94, 0x173: 0x95, 0x174: 0x96, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x97, - 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18, + 0x140: 0x83, 0x142: 0x84, 0x143: 0x85, 0x144: 0x86, 0x145: 0x87, 0x146: 0x88, 0x147: 0x89, + 0x14d: 0x8a, + 0x15c: 0x8b, 0x15f: 0x8c, + 0x162: 0x8d, 0x164: 0x8e, + 0x168: 0x8f, 0x169: 0x90, 0x16a: 0x91, 0x16c: 0x0e, 0x16d: 0x92, 0x16e: 0x93, 0x16f: 0x94, + 0x170: 0x95, 0x173: 0x96, 0x174: 0x97, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x11, + 0x178: 0x12, 0x179: 0x13, 0x17a: 0x14, 0x17b: 0x15, 0x17c: 0x16, 0x17d: 0x17, 0x17e: 0x18, 0x17f: 0x19, // Block 0x6, offset 0x180 - 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9c, 0x187: 0x9d, - 0x188: 0x9e, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9f, 0x18c: 0xa0, - 0x191: 0x1d, 0x192: 0x1e, 0x193: 0xa1, + 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x1a, 0x185: 0x1b, 0x186: 0x9c, 0x187: 0x9d, + 0x188: 0x9e, 0x189: 0x1c, 0x18a: 0x1d, 0x18b: 0x9f, 0x18c: 0xa0, + 0x191: 0x1e, 0x192: 0x1f, 0x193: 0xa1, 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4, 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8, - 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xab, + 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x20, 0x1bd: 0x21, 0x1be: 0x22, 0x1bf: 0xab, // Block 0x7, offset 0x1c0 - 0x1c0: 0xac, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xad, 0x1c5: 0x25, 0x1c6: 0x26, - 0x1c8: 0x27, 0x1c9: 0x28, 0x1ca: 0x29, 0x1cb: 0x2a, 0x1cc: 0x2b, 0x1cd: 0x2c, 0x1ce: 0x2d, 0x1cf: 0x2e, + 0x1c0: 0xac, 0x1c1: 0x23, 0x1c2: 0x24, 0x1c3: 0x25, 0x1c4: 0xad, 0x1c5: 0x26, 0x1c6: 0x27, + 0x1c8: 0x28, 0x1c9: 0x29, 0x1ca: 0x2a, 0x1cb: 0x2b, 0x1cc: 0x2c, 0x1cd: 0x2d, 0x1ce: 0x2e, 0x1cf: 0x2f, // Block 0x8, offset 0x200 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2, 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8, @@ -5610,50 +5632,51 @@ var nfkcIndex = [1408]uint8{ 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3, 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4, // Block 0xc, offset 0x300 - 0x324: 0x2f, 0x325: 0x30, 0x326: 0x31, 0x327: 0x32, - 0x328: 0x33, 0x329: 0x34, 0x32a: 0x35, 0x32b: 0x36, 0x32c: 0x37, 0x32d: 0x38, 0x32e: 0x39, 0x32f: 0x3a, - 0x330: 0x3b, 0x331: 0x3c, 0x332: 0x3d, 0x333: 0x3e, 0x334: 0x3f, 0x335: 0x40, 0x336: 0x41, 0x337: 0x42, - 0x338: 0x43, 0x339: 0x44, 0x33a: 0x45, 0x33b: 0x46, 0x33c: 0xc5, 0x33d: 0x47, 0x33e: 0x48, 0x33f: 0x49, + 0x324: 0x30, 0x325: 0x31, 0x326: 0x32, 0x327: 0x33, + 0x328: 0x34, 0x329: 0x35, 0x32a: 0x36, 0x32b: 0x37, 0x32c: 0x38, 0x32d: 0x39, 0x32e: 0x3a, 0x32f: 0x3b, + 0x330: 0x3c, 0x331: 0x3d, 0x332: 0x3e, 0x333: 0x3f, 0x334: 0x40, 0x335: 0x41, 0x336: 0x42, 0x337: 0x43, + 0x338: 0x44, 0x339: 0x45, 0x33a: 0x46, 0x33b: 0x47, 0x33c: 0xc5, 0x33d: 0x48, 0x33e: 0x49, 0x33f: 0x4a, // Block 0xd, offset 0x340 0x347: 0xc6, 0x34b: 0xc7, 0x34d: 0xc8, 0x368: 0xc9, 0x36b: 0xca, // Block 0xe, offset 0x380 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce, - 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6b, 0x38d: 0xd1, + 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6c, 0x38d: 0xd1, 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6, 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9, - 0x3b0: 0xd7, + 0x3a8: 0xda, 0x3a9: 0xdb, 0x3aa: 0xdc, + 0x3b0: 0xd7, 0x3b5: 0xdd, // Block 0xf, offset 0x3c0 - 0x3eb: 0xda, 0x3ec: 0xdb, + 0x3eb: 0xde, 0x3ec: 0xdf, // Block 0x10, offset 0x400 - 0x432: 0xdc, + 0x432: 0xe0, // Block 0x11, offset 0x440 - 0x445: 0xdd, 0x446: 0xde, 0x447: 0xdf, - 0x449: 0xe0, - 0x450: 0xe1, 0x451: 0xe2, 0x452: 0xe3, 0x453: 0xe4, 0x454: 0xe5, 0x455: 0xe6, 0x456: 0xe7, 0x457: 0xe8, - 0x458: 0xe9, 0x459: 0xea, 0x45a: 0x4a, 0x45b: 0xeb, 0x45c: 0xec, 0x45d: 0xed, 0x45e: 0xee, 0x45f: 0x4b, + 0x445: 0xe1, 0x446: 0xe2, 0x447: 0xe3, + 0x449: 0xe4, + 0x450: 0xe5, 0x451: 0xe6, 0x452: 0xe7, 0x453: 0xe8, 0x454: 0xe9, 0x455: 0xea, 0x456: 0xeb, 0x457: 0xec, + 0x458: 0xed, 0x459: 0xee, 0x45a: 0x4b, 0x45b: 0xef, 0x45c: 0xf0, 0x45d: 0xf1, 0x45e: 0xf2, 0x45f: 0x4c, // Block 0x12, offset 0x480 - 0x480: 0xef, - 0x4a3: 0xf0, 0x4a5: 0xf1, - 0x4b8: 0x4c, 0x4b9: 0x4d, 0x4ba: 0x4e, + 0x480: 0xf3, + 0x4a3: 0xf4, 0x4a5: 0xf5, + 0x4b8: 0x4d, 0x4b9: 0x4e, 0x4ba: 0x4f, // Block 0x13, offset 0x4c0 - 0x4c4: 0x4f, 0x4c5: 0xf2, 0x4c6: 0xf3, - 0x4c8: 0x50, 0x4c9: 0xf4, + 0x4c4: 0x50, 0x4c5: 0xf6, 0x4c6: 0xf7, + 0x4c8: 0x51, 0x4c9: 0xf8, // Block 0x14, offset 0x500 - 0x520: 0x51, 0x521: 0x52, 0x522: 0x53, 0x523: 0x54, 0x524: 0x55, 0x525: 0x56, 0x526: 0x57, 0x527: 0x58, - 0x528: 0x59, + 0x520: 0x52, 0x521: 0x53, 0x522: 0x54, 0x523: 0x55, 0x524: 0x56, 0x525: 0x57, 0x526: 0x58, 0x527: 0x59, + 0x528: 0x5a, // Block 0x15, offset 0x540 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d, 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11, 0x56f: 0x12, } -// nfkcSparseOffset: 155 entries, 310 bytes -var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd4, 0xdb, 0xe3, 0xe7, 0xe9, 0xec, 0xf0, 0xf6, 0x107, 0x113, 0x115, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12c, 0x12f, 0x131, 0x134, 0x137, 0x13b, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x176, 0x184, 0x192, 0x1a2, 0x1b0, 0x1b7, 0x1bd, 0x1cc, 0x1d0, 0x1d2, 0x1d6, 0x1d8, 0x1db, 0x1dd, 0x1e0, 0x1e2, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1f7, 0x201, 0x20b, 0x20e, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x22b, 0x22e, 0x232, 0x234, 0x23b, 0x241, 0x247, 0x24f, 0x255, 0x25b, 0x261, 0x265, 0x267, 0x269, 0x26b, 0x26d, 0x273, 0x276, 0x279, 0x281, 0x288, 0x28b, 0x28e, 0x290, 0x298, 0x29b, 0x2a2, 0x2a5, 0x2ab, 0x2ad, 0x2af, 0x2b2, 0x2b4, 0x2b6, 0x2b8, 0x2ba, 0x2c7, 0x2d1, 0x2d3, 0x2d5, 0x2d9, 0x2de, 0x2ea, 0x2ef, 0x2f8, 0x2fe, 0x303, 0x307, 0x30c, 0x310, 0x320, 0x32e, 0x33c, 0x34a, 0x350, 0x352, 0x355, 0x35f, 0x361} +// nfkcSparseOffset: 158 entries, 316 bytes +var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd5, 0xdc, 0xe4, 0xe8, 0xea, 0xed, 0xf1, 0xf7, 0x108, 0x114, 0x116, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12d, 0x130, 0x132, 0x135, 0x138, 0x13c, 0x141, 0x14a, 0x14c, 0x14f, 0x151, 0x15c, 0x167, 0x175, 0x183, 0x193, 0x1a1, 0x1a8, 0x1ae, 0x1bd, 0x1c1, 0x1c3, 0x1c7, 0x1c9, 0x1cc, 0x1ce, 0x1d1, 0x1d3, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1e8, 0x1f2, 0x1fc, 0x1ff, 0x203, 0x205, 0x207, 0x209, 0x20b, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x21c, 0x21f, 0x223, 0x225, 0x22c, 0x232, 0x238, 0x240, 0x246, 0x24c, 0x252, 0x256, 0x258, 0x25a, 0x25c, 0x25e, 0x264, 0x267, 0x26a, 0x272, 0x279, 0x27c, 0x27f, 0x281, 0x289, 0x28c, 0x293, 0x296, 0x29c, 0x29e, 0x2a0, 0x2a3, 0x2a5, 0x2a7, 0x2a9, 0x2ab, 0x2ae, 0x2b0, 0x2b2, 0x2b4, 0x2c1, 0x2cb, 0x2cd, 0x2cf, 0x2d3, 0x2d8, 0x2e4, 0x2e9, 0x2f2, 0x2f8, 0x2fd, 0x301, 0x306, 0x30a, 0x31a, 0x328, 0x336, 0x344, 0x34a, 0x34c, 0x34f, 0x359, 0x35b} -// nfkcSparseValues: 875 entries, 3500 bytes -var nfkcSparseValues = [875]valueRange{ +// nfkcSparseValues: 869 entries, 3476 bytes +var nfkcSparseValues = [869]valueRange{ // Block 0x0, offset 0x0 {value: 0x0002, lo: 0x0d}, {value: 0x0001, lo: 0xa0, hi: 0xa0}, @@ -5894,9 +5917,10 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x8104, lo: 0x8d, hi: 0x8d}, {value: 0x9900, lo: 0x95, hi: 0x96}, // Block 0x1d, offset 0xd2 - {value: 0x0000, lo: 0x01}, + {value: 0x0000, lo: 0x02}, + {value: 0x8104, lo: 0xbb, hi: 0xbc}, {value: 0x9900, lo: 0xbe, hi: 0xbe}, - // Block 0x1e, offset 0xd4 + // Block 0x1e, offset 0xd5 {value: 0x0000, lo: 0x06}, {value: 0xa000, lo: 0x86, hi: 0x87}, {value: 0x2cfe, lo: 0x8a, hi: 0x8a}, @@ -5904,7 +5928,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2d06, lo: 0x8c, hi: 0x8c}, {value: 0x8104, lo: 0x8d, hi: 0x8d}, {value: 0x9900, lo: 0x97, hi: 0x97}, - // Block 0x1f, offset 0xdb + // Block 0x1f, offset 0xdc {value: 0x6bea, lo: 0x07}, {value: 0x9904, lo: 0x8a, hi: 0x8a}, {value: 0x9900, lo: 0x8f, hi: 0x8f}, @@ -5913,31 +5937,31 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2f58, lo: 0x9c, hi: 0x9c}, {value: 0x2de3, lo: 0x9d, hi: 0x9d}, {value: 0x2d16, lo: 0x9e, hi: 0x9f}, - // Block 0x20, offset 0xe3 + // Block 0x20, offset 0xe4 {value: 0x0000, lo: 0x03}, {value: 0x2621, lo: 0xb3, hi: 0xb3}, {value: 0x8122, lo: 0xb8, hi: 0xb9}, {value: 0x8104, lo: 0xba, hi: 0xba}, - // Block 0x21, offset 0xe7 + // Block 0x21, offset 0xe8 {value: 0x0000, lo: 0x01}, {value: 0x8123, lo: 0x88, hi: 0x8b}, - // Block 0x22, offset 0xe9 + // Block 0x22, offset 0xea {value: 0x0000, lo: 0x02}, {value: 0x2636, lo: 0xb3, hi: 0xb3}, {value: 0x8124, lo: 0xb8, hi: 0xb9}, - // Block 0x23, offset 0xec + // Block 0x23, offset 0xed {value: 0x0000, lo: 0x03}, {value: 0x8125, lo: 0x88, hi: 0x8b}, {value: 0x2628, lo: 0x9c, hi: 0x9c}, {value: 0x262f, lo: 0x9d, hi: 0x9d}, - // Block 0x24, offset 0xf0 + // Block 0x24, offset 0xf1 {value: 0x0000, lo: 0x05}, {value: 0x030b, lo: 0x8c, hi: 0x8c}, {value: 0x812d, lo: 0x98, hi: 0x99}, {value: 0x812d, lo: 0xb5, hi: 0xb5}, {value: 0x812d, lo: 0xb7, hi: 0xb7}, {value: 0x812b, lo: 0xb9, hi: 0xb9}, - // Block 0x25, offset 0xf6 + // Block 0x25, offset 0xf7 {value: 0x0000, lo: 0x10}, {value: 0x2644, lo: 0x83, hi: 0x83}, {value: 0x264b, lo: 0x8d, hi: 0x8d}, @@ -5955,7 +5979,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x45bc, lo: 0xb8, hi: 0xb8}, {value: 0x45ff, lo: 0xb9, hi: 0xb9}, {value: 0x8127, lo: 0xba, hi: 0xbd}, - // Block 0x26, offset 0x107 + // Block 0x26, offset 0x108 {value: 0x0000, lo: 0x0b}, {value: 0x8127, lo: 0x80, hi: 0x80}, {value: 0x4a96, lo: 0x81, hi: 0x81}, @@ -5968,68 +5992,68 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2683, lo: 0xa7, hi: 0xa7}, {value: 0x268a, lo: 0xac, hi: 0xac}, {value: 0x2667, lo: 0xb9, hi: 0xb9}, - // Block 0x27, offset 0x113 + // Block 0x27, offset 0x114 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x86, hi: 0x86}, - // Block 0x28, offset 0x115 + // Block 0x28, offset 0x116 {value: 0x0000, lo: 0x05}, {value: 0xa000, lo: 0xa5, hi: 0xa5}, {value: 0x2d1e, lo: 0xa6, hi: 0xa6}, {value: 0x9900, lo: 0xae, hi: 0xae}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, {value: 0x8104, lo: 0xb9, hi: 0xba}, - // Block 0x29, offset 0x11b + // Block 0x29, offset 0x11c {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x8d, hi: 0x8d}, - // Block 0x2a, offset 0x11d + // Block 0x2a, offset 0x11e {value: 0x0000, lo: 0x01}, {value: 0x030f, lo: 0xbc, hi: 0xbc}, - // Block 0x2b, offset 0x11f + // Block 0x2b, offset 0x120 {value: 0x0000, lo: 0x01}, {value: 0xa000, lo: 0x80, hi: 0x92}, - // Block 0x2c, offset 0x121 + // Block 0x2c, offset 0x122 {value: 0x0000, lo: 0x01}, {value: 0xb900, lo: 0xa1, hi: 0xb5}, - // Block 0x2d, offset 0x123 + // Block 0x2d, offset 0x124 {value: 0x0000, lo: 0x01}, {value: 0x9900, lo: 0xa8, hi: 0xbf}, - // Block 0x2e, offset 0x125 + // Block 0x2e, offset 0x126 {value: 0x0000, lo: 0x01}, {value: 0x9900, lo: 0x80, hi: 0x82}, - // Block 0x2f, offset 0x127 + // Block 0x2f, offset 0x128 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0x9d, hi: 0x9f}, - // Block 0x30, offset 0x129 + // Block 0x30, offset 0x12a {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x94, hi: 0x94}, {value: 0x8104, lo: 0xb4, hi: 0xb4}, - // Block 0x31, offset 0x12c + // Block 0x31, offset 0x12d {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x92, hi: 0x92}, {value: 0x8132, lo: 0x9d, hi: 0x9d}, - // Block 0x32, offset 0x12f + // Block 0x32, offset 0x130 {value: 0x0000, lo: 0x01}, {value: 0x8131, lo: 0xa9, hi: 0xa9}, - // Block 0x33, offset 0x131 + // Block 0x33, offset 0x132 {value: 0x0004, lo: 0x02}, {value: 0x812e, lo: 0xb9, hi: 0xba}, {value: 0x812d, lo: 0xbb, hi: 0xbb}, - // Block 0x34, offset 0x134 + // Block 0x34, offset 0x135 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x97, hi: 0x97}, {value: 0x812d, lo: 0x98, hi: 0x98}, - // Block 0x35, offset 0x137 + // Block 0x35, offset 0x138 {value: 0x0000, lo: 0x03}, {value: 0x8104, lo: 0xa0, hi: 0xa0}, {value: 0x8132, lo: 0xb5, hi: 0xbc}, {value: 0x812d, lo: 0xbf, hi: 0xbf}, - // Block 0x36, offset 0x13b + // Block 0x36, offset 0x13c {value: 0x0000, lo: 0x04}, {value: 0x8132, lo: 0xb0, hi: 0xb4}, {value: 0x812d, lo: 0xb5, hi: 0xba}, {value: 0x8132, lo: 0xbb, hi: 0xbc}, {value: 0x812d, lo: 0xbd, hi: 0xbd}, - // Block 0x37, offset 0x140 + // Block 0x37, offset 0x141 {value: 0x0000, lo: 0x08}, {value: 0x2d66, lo: 0x80, hi: 0x80}, {value: 0x2d6e, lo: 0x81, hi: 0x81}, @@ -6039,17 +6063,17 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x8132, lo: 0xab, hi: 0xab}, {value: 0x812d, lo: 0xac, hi: 0xac}, {value: 0x8132, lo: 0xad, hi: 0xb3}, - // Block 0x38, offset 0x149 + // Block 0x38, offset 0x14a {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xaa, hi: 0xab}, - // Block 0x39, offset 0x14b + // Block 0x39, offset 0x14c {value: 0x0000, lo: 0x02}, {value: 0x8102, lo: 0xa6, hi: 0xa6}, {value: 0x8104, lo: 0xb2, hi: 0xb3}, - // Block 0x3a, offset 0x14e + // Block 0x3a, offset 0x14f {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, - // Block 0x3b, offset 0x150 + // Block 0x3b, offset 0x151 {value: 0x0000, lo: 0x0a}, {value: 0x8132, lo: 0x90, hi: 0x92}, {value: 0x8101, lo: 0x94, hi: 0x94}, @@ -6061,7 +6085,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x812d, lo: 0xad, hi: 0xad}, {value: 0x8132, lo: 0xb4, hi: 0xb4}, {value: 0x8132, lo: 0xb8, hi: 0xb9}, - // Block 0x3c, offset 0x15b + // Block 0x3c, offset 0x15c {value: 0x0002, lo: 0x0a}, {value: 0x0043, lo: 0xac, hi: 0xac}, {value: 0x00d1, lo: 0xad, hi: 0xad}, @@ -6073,24 +6097,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x00ef, lo: 0xbd, hi: 0xbd}, {value: 0x0061, lo: 0xbe, hi: 0xbe}, {value: 0x0065, lo: 0xbf, hi: 0xbf}, - // Block 0x3d, offset 0x166 - {value: 0x0000, lo: 0x0f}, - {value: 0x8132, lo: 0x80, hi: 0x81}, - {value: 0x812d, lo: 0x82, hi: 0x82}, - {value: 0x8132, lo: 0x83, hi: 0x89}, - {value: 0x812d, lo: 0x8a, hi: 0x8a}, - {value: 0x8132, lo: 0x8b, hi: 0x8c}, - {value: 0x8135, lo: 0x8d, hi: 0x8d}, - {value: 0x812a, lo: 0x8e, hi: 0x8e}, - {value: 0x812d, lo: 0x8f, hi: 0x8f}, - {value: 0x8129, lo: 0x90, hi: 0x90}, - {value: 0x8132, lo: 0x91, hi: 0xb5}, - {value: 0x8132, lo: 0xbb, hi: 0xbb}, - {value: 0x8134, lo: 0xbc, hi: 0xbc}, - {value: 0x812d, lo: 0xbd, hi: 0xbd}, - {value: 0x8132, lo: 0xbe, hi: 0xbe}, - {value: 0x812d, lo: 0xbf, hi: 0xbf}, - // Block 0x3e, offset 0x176 + // Block 0x3d, offset 0x167 {value: 0x0000, lo: 0x0d}, {value: 0x0001, lo: 0x80, hi: 0x8a}, {value: 0x043b, lo: 0x91, hi: 0x91}, @@ -6105,7 +6112,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2808, lo: 0xb7, hi: 0xb7}, {value: 0x186d, lo: 0xbc, hi: 0xbc}, {value: 0x4269, lo: 0xbe, hi: 0xbe}, - // Block 0x3f, offset 0x184 + // Block 0x3e, offset 0x175 {value: 0x0002, lo: 0x0d}, {value: 0x1933, lo: 0x87, hi: 0x87}, {value: 0x1930, lo: 0x88, hi: 0x88}, @@ -6120,7 +6127,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x003b, lo: 0xbc, hi: 0xbc}, {value: 0x0011, lo: 0xbd, hi: 0xbe}, {value: 0x009d, lo: 0xbf, hi: 0xbf}, - // Block 0x40, offset 0x192 + // Block 0x3f, offset 0x183 {value: 0x0002, lo: 0x0f}, {value: 0x0021, lo: 0x80, hi: 0x89}, {value: 0x0017, lo: 0x8a, hi: 0x8a}, @@ -6137,7 +6144,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x00a1, lo: 0x9a, hi: 0x9a}, {value: 0x00a7, lo: 0x9b, hi: 0x9c}, {value: 0x1999, lo: 0xa8, hi: 0xa8}, - // Block 0x41, offset 0x1a2 + // Block 0x40, offset 0x193 {value: 0x0000, lo: 0x0d}, {value: 0x8132, lo: 0x90, hi: 0x91}, {value: 0x8101, lo: 0x92, hi: 0x93}, @@ -6152,7 +6159,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x8101, lo: 0xaa, hi: 0xab}, {value: 0x812d, lo: 0xac, hi: 0xaf}, {value: 0x8132, lo: 0xb0, hi: 0xb0}, - // Block 0x42, offset 0x1b0 + // Block 0x41, offset 0x1a1 {value: 0x0007, lo: 0x06}, {value: 0x2180, lo: 0x89, hi: 0x89}, {value: 0xa000, lo: 0x90, hi: 0x90}, @@ -6160,14 +6167,14 @@ var nfkcSparseValues = [875]valueRange{ {value: 0xa000, lo: 0x94, hi: 0x94}, {value: 0x3bb9, lo: 0x9a, hi: 0x9b}, {value: 0x3bc7, lo: 0xae, hi: 0xae}, - // Block 0x43, offset 0x1b7 + // Block 0x42, offset 0x1a8 {value: 0x000e, lo: 0x05}, {value: 0x3bce, lo: 0x8d, hi: 0x8e}, {value: 0x3bd5, lo: 0x8f, hi: 0x8f}, {value: 0xa000, lo: 0x90, hi: 0x90}, {value: 0xa000, lo: 0x92, hi: 0x92}, {value: 0xa000, lo: 0x94, hi: 0x94}, - // Block 0x44, offset 0x1bd + // Block 0x43, offset 0x1ae {value: 0x0173, lo: 0x0e}, {value: 0xa000, lo: 0x83, hi: 0x83}, {value: 0x3be3, lo: 0x84, hi: 0x84}, @@ -6183,50 +6190,50 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x26a6, lo: 0xaf, hi: 0xaf}, {value: 0x281c, lo: 0xb0, hi: 0xb0}, {value: 0xa000, lo: 0xbc, hi: 0xbc}, - // Block 0x45, offset 0x1cc + // Block 0x44, offset 0x1bd {value: 0x0007, lo: 0x03}, {value: 0x3c68, lo: 0xa0, hi: 0xa1}, {value: 0x3c92, lo: 0xa2, hi: 0xa3}, {value: 0x3cbc, lo: 0xaa, hi: 0xad}, - // Block 0x46, offset 0x1d0 + // Block 0x45, offset 0x1c1 {value: 0x0004, lo: 0x01}, {value: 0x048b, lo: 0xa9, hi: 0xaa}, - // Block 0x47, offset 0x1d2 + // Block 0x46, offset 0x1c3 {value: 0x0002, lo: 0x03}, {value: 0x0057, lo: 0x80, hi: 0x8f}, {value: 0x0083, lo: 0x90, hi: 0xa9}, {value: 0x0021, lo: 0xaa, hi: 0xaa}, - // Block 0x48, offset 0x1d6 + // Block 0x47, offset 0x1c7 {value: 0x0000, lo: 0x01}, {value: 0x299b, lo: 0x8c, hi: 0x8c}, - // Block 0x49, offset 0x1d8 + // Block 0x48, offset 0x1c9 {value: 0x0263, lo: 0x02}, {value: 0x1b8c, lo: 0xb4, hi: 0xb4}, {value: 0x192d, lo: 0xb5, hi: 0xb6}, - // Block 0x4a, offset 0x1db + // Block 0x49, offset 0x1cc {value: 0x0000, lo: 0x01}, {value: 0x44dd, lo: 0x9c, hi: 0x9c}, - // Block 0x4b, offset 0x1dd + // Block 0x4a, offset 0x1ce {value: 0x0000, lo: 0x02}, {value: 0x0095, lo: 0xbc, hi: 0xbc}, {value: 0x006d, lo: 0xbd, hi: 0xbd}, - // Block 0x4c, offset 0x1e0 + // Block 0x4b, offset 0x1d1 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xaf, hi: 0xb1}, - // Block 0x4d, offset 0x1e2 + // Block 0x4c, offset 0x1d3 {value: 0x0000, lo: 0x02}, {value: 0x047f, lo: 0xaf, hi: 0xaf}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x4e, offset 0x1e5 + // Block 0x4d, offset 0x1d6 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xa0, hi: 0xbf}, - // Block 0x4f, offset 0x1e7 + // Block 0x4e, offset 0x1d8 {value: 0x0000, lo: 0x01}, {value: 0x0dc3, lo: 0x9f, hi: 0x9f}, - // Block 0x50, offset 0x1e9 + // Block 0x4f, offset 0x1da {value: 0x0000, lo: 0x01}, {value: 0x162f, lo: 0xb3, hi: 0xb3}, - // Block 0x51, offset 0x1eb + // Block 0x50, offset 0x1dc {value: 0x0004, lo: 0x0b}, {value: 0x1597, lo: 0x80, hi: 0x82}, {value: 0x15af, lo: 0x83, hi: 0x83}, @@ -6239,7 +6246,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x161b, lo: 0x91, hi: 0x93}, {value: 0x162b, lo: 0x94, hi: 0x94}, {value: 0x1633, lo: 0x95, hi: 0x95}, - // Block 0x52, offset 0x1f7 + // Block 0x51, offset 0x1e8 {value: 0x0004, lo: 0x09}, {value: 0x0001, lo: 0x80, hi: 0x80}, {value: 0x812c, lo: 0xaa, hi: 0xaa}, @@ -6250,7 +6257,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x812f, lo: 0xaf, hi: 0xaf}, {value: 0x04b3, lo: 0xb6, hi: 0xb6}, {value: 0x0887, lo: 0xb8, hi: 0xba}, - // Block 0x53, offset 0x201 + // Block 0x52, offset 0x1f2 {value: 0x0006, lo: 0x09}, {value: 0x0313, lo: 0xb1, hi: 0xb1}, {value: 0x0317, lo: 0xb2, hi: 0xb2}, @@ -6261,63 +6268,63 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x0323, lo: 0xb8, hi: 0xb8}, {value: 0x0327, lo: 0xb9, hi: 0xb9}, {value: 0x4a4d, lo: 0xba, hi: 0xbf}, - // Block 0x54, offset 0x20b + // Block 0x53, offset 0x1fc {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0xaf, hi: 0xaf}, {value: 0x8132, lo: 0xb4, hi: 0xbd}, - // Block 0x55, offset 0x20e + // Block 0x54, offset 0x1ff {value: 0x0000, lo: 0x03}, {value: 0x020f, lo: 0x9c, hi: 0x9c}, {value: 0x0212, lo: 0x9d, hi: 0x9d}, {value: 0x8132, lo: 0x9e, hi: 0x9f}, - // Block 0x56, offset 0x212 + // Block 0x55, offset 0x203 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb0, hi: 0xb1}, - // Block 0x57, offset 0x214 + // Block 0x56, offset 0x205 {value: 0x0000, lo: 0x01}, {value: 0x163b, lo: 0xb0, hi: 0xb0}, - // Block 0x58, offset 0x216 + // Block 0x57, offset 0x207 {value: 0x000c, lo: 0x01}, {value: 0x00d7, lo: 0xb8, hi: 0xb9}, - // Block 0x59, offset 0x218 + // Block 0x58, offset 0x209 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x86, hi: 0x86}, - // Block 0x5a, offset 0x21a + // Block 0x59, offset 0x20b {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x84, hi: 0x84}, {value: 0x8132, lo: 0xa0, hi: 0xb1}, - // Block 0x5b, offset 0x21d + // Block 0x5a, offset 0x20e {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xab, hi: 0xad}, - // Block 0x5c, offset 0x21f + // Block 0x5b, offset 0x210 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x93, hi: 0x93}, - // Block 0x5d, offset 0x221 + // Block 0x5c, offset 0x212 {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0xb3, hi: 0xb3}, - // Block 0x5e, offset 0x223 + // Block 0x5d, offset 0x214 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0x80, hi: 0x80}, - // Block 0x5f, offset 0x225 + // Block 0x5e, offset 0x216 {value: 0x0000, lo: 0x05}, {value: 0x8132, lo: 0xb0, hi: 0xb0}, {value: 0x8132, lo: 0xb2, hi: 0xb3}, {value: 0x812d, lo: 0xb4, hi: 0xb4}, {value: 0x8132, lo: 0xb7, hi: 0xb8}, {value: 0x8132, lo: 0xbe, hi: 0xbf}, - // Block 0x60, offset 0x22b + // Block 0x5f, offset 0x21c {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x81, hi: 0x81}, {value: 0x8104, lo: 0xb6, hi: 0xb6}, - // Block 0x61, offset 0x22e + // Block 0x60, offset 0x21f {value: 0x0008, lo: 0x03}, {value: 0x1637, lo: 0x9c, hi: 0x9d}, {value: 0x0125, lo: 0x9e, hi: 0x9e}, {value: 0x1643, lo: 0x9f, hi: 0x9f}, - // Block 0x62, offset 0x232 + // Block 0x61, offset 0x223 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xad, hi: 0xad}, - // Block 0x63, offset 0x234 + // Block 0x62, offset 0x225 {value: 0x0000, lo: 0x06}, {value: 0xe500, lo: 0x80, hi: 0x80}, {value: 0xc600, lo: 0x81, hi: 0x9b}, @@ -6325,21 +6332,21 @@ var nfkcSparseValues = [875]valueRange{ {value: 0xc600, lo: 0x9d, hi: 0xb7}, {value: 0xe500, lo: 0xb8, hi: 0xb8}, {value: 0xc600, lo: 0xb9, hi: 0xbf}, - // Block 0x64, offset 0x23b + // Block 0x63, offset 0x22c {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x93}, {value: 0xe500, lo: 0x94, hi: 0x94}, {value: 0xc600, lo: 0x95, hi: 0xaf}, {value: 0xe500, lo: 0xb0, hi: 0xb0}, {value: 0xc600, lo: 0xb1, hi: 0xbf}, - // Block 0x65, offset 0x241 + // Block 0x64, offset 0x232 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x8b}, {value: 0xe500, lo: 0x8c, hi: 0x8c}, {value: 0xc600, lo: 0x8d, hi: 0xa7}, {value: 0xe500, lo: 0xa8, hi: 0xa8}, {value: 0xc600, lo: 0xa9, hi: 0xbf}, - // Block 0x66, offset 0x247 + // Block 0x65, offset 0x238 {value: 0x0000, lo: 0x07}, {value: 0xc600, lo: 0x80, hi: 0x83}, {value: 0xe500, lo: 0x84, hi: 0x84}, @@ -6348,60 +6355,60 @@ var nfkcSparseValues = [875]valueRange{ {value: 0xc600, lo: 0xa1, hi: 0xbb}, {value: 0xe500, lo: 0xbc, hi: 0xbc}, {value: 0xc600, lo: 0xbd, hi: 0xbf}, - // Block 0x67, offset 0x24f + // Block 0x66, offset 0x240 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x97}, {value: 0xe500, lo: 0x98, hi: 0x98}, {value: 0xc600, lo: 0x99, hi: 0xb3}, {value: 0xe500, lo: 0xb4, hi: 0xb4}, {value: 0xc600, lo: 0xb5, hi: 0xbf}, - // Block 0x68, offset 0x255 + // Block 0x67, offset 0x246 {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x8f}, {value: 0xe500, lo: 0x90, hi: 0x90}, {value: 0xc600, lo: 0x91, hi: 0xab}, {value: 0xe500, lo: 0xac, hi: 0xac}, {value: 0xc600, lo: 0xad, hi: 0xbf}, - // Block 0x69, offset 0x25b + // Block 0x68, offset 0x24c {value: 0x0000, lo: 0x05}, {value: 0xc600, lo: 0x80, hi: 0x87}, {value: 0xe500, lo: 0x88, hi: 0x88}, {value: 0xc600, lo: 0x89, hi: 0xa3}, {value: 0xe500, lo: 0xa4, hi: 0xa4}, {value: 0xc600, lo: 0xa5, hi: 0xbf}, - // Block 0x6a, offset 0x261 + // Block 0x69, offset 0x252 {value: 0x0000, lo: 0x03}, {value: 0xc600, lo: 0x80, hi: 0x87}, {value: 0xe500, lo: 0x88, hi: 0x88}, {value: 0xc600, lo: 0x89, hi: 0xa3}, - // Block 0x6b, offset 0x265 + // Block 0x6a, offset 0x256 {value: 0x0002, lo: 0x01}, {value: 0x0003, lo: 0x81, hi: 0xbf}, - // Block 0x6c, offset 0x267 + // Block 0x6b, offset 0x258 {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xbd, hi: 0xbd}, - // Block 0x6d, offset 0x269 + // Block 0x6c, offset 0x25a {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0xa0, hi: 0xa0}, - // Block 0x6e, offset 0x26b + // Block 0x6d, offset 0x25c {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb6, hi: 0xba}, - // Block 0x6f, offset 0x26d + // Block 0x6e, offset 0x25e {value: 0x002c, lo: 0x05}, {value: 0x812d, lo: 0x8d, hi: 0x8d}, {value: 0x8132, lo: 0x8f, hi: 0x8f}, {value: 0x8132, lo: 0xb8, hi: 0xb8}, {value: 0x8101, lo: 0xb9, hi: 0xba}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x70, offset 0x273 + // Block 0x6f, offset 0x264 {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0xa5, hi: 0xa5}, {value: 0x812d, lo: 0xa6, hi: 0xa6}, - // Block 0x71, offset 0x276 + // Block 0x70, offset 0x267 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x86, hi: 0x86}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x72, offset 0x279 + // Block 0x71, offset 0x26a {value: 0x17fe, lo: 0x07}, {value: 0xa000, lo: 0x99, hi: 0x99}, {value: 0x4238, lo: 0x9a, hi: 0x9a}, @@ -6410,7 +6417,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0xa000, lo: 0xa5, hi: 0xa5}, {value: 0x424c, lo: 0xab, hi: 0xab}, {value: 0x8104, lo: 0xb9, hi: 0xba}, - // Block 0x73, offset 0x281 + // Block 0x72, offset 0x272 {value: 0x0000, lo: 0x06}, {value: 0x8132, lo: 0x80, hi: 0x82}, {value: 0x9900, lo: 0xa7, hi: 0xa7}, @@ -6418,18 +6425,18 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2d88, lo: 0xaf, hi: 0xaf}, {value: 0xa000, lo: 0xb1, hi: 0xb2}, {value: 0x8104, lo: 0xb3, hi: 0xb4}, - // Block 0x74, offset 0x288 + // Block 0x73, offset 0x279 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x80, hi: 0x80}, {value: 0x8102, lo: 0x8a, hi: 0x8a}, - // Block 0x75, offset 0x28b + // Block 0x74, offset 0x27c {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0xb5, hi: 0xb5}, {value: 0x8102, lo: 0xb6, hi: 0xb6}, - // Block 0x76, offset 0x28e + // Block 0x75, offset 0x27f {value: 0x0002, lo: 0x01}, {value: 0x8102, lo: 0xa9, hi: 0xaa}, - // Block 0x77, offset 0x290 + // Block 0x76, offset 0x281 {value: 0x0000, lo: 0x07}, {value: 0xa000, lo: 0x87, hi: 0x87}, {value: 0x2d92, lo: 0x8b, hi: 0x8b}, @@ -6438,11 +6445,11 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x9900, lo: 0x97, hi: 0x97}, {value: 0x8132, lo: 0xa6, hi: 0xac}, {value: 0x8132, lo: 0xb0, hi: 0xb4}, - // Block 0x78, offset 0x298 + // Block 0x77, offset 0x289 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x82, hi: 0x82}, {value: 0x8102, lo: 0x86, hi: 0x86}, - // Block 0x79, offset 0x29b + // Block 0x78, offset 0x28c {value: 0x6b5a, lo: 0x06}, {value: 0x9900, lo: 0xb0, hi: 0xb0}, {value: 0xa000, lo: 0xb9, hi: 0xb9}, @@ -6450,40 +6457,53 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x2db0, lo: 0xbb, hi: 0xbb}, {value: 0x2da6, lo: 0xbc, hi: 0xbd}, {value: 0x2dba, lo: 0xbe, hi: 0xbe}, - // Block 0x7a, offset 0x2a2 + // Block 0x79, offset 0x293 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0x82, hi: 0x82}, {value: 0x8102, lo: 0x83, hi: 0x83}, - // Block 0x7b, offset 0x2a5 + // Block 0x7a, offset 0x296 {value: 0x0000, lo: 0x05}, {value: 0x9900, lo: 0xaf, hi: 0xaf}, {value: 0xa000, lo: 0xb8, hi: 0xb9}, {value: 0x2dc4, lo: 0xba, hi: 0xba}, {value: 0x2dce, lo: 0xbb, hi: 0xbb}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x7c, offset 0x2ab + // Block 0x7b, offset 0x29c {value: 0x0000, lo: 0x01}, {value: 0x8102, lo: 0x80, hi: 0x80}, - // Block 0x7d, offset 0x2ad + // Block 0x7c, offset 0x29e {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xbf, hi: 0xbf}, - // Block 0x7e, offset 0x2af + // Block 0x7d, offset 0x2a0 {value: 0x0000, lo: 0x02}, {value: 0x8104, lo: 0xb6, hi: 0xb6}, {value: 0x8102, lo: 0xb7, hi: 0xb7}, - // Block 0x7f, offset 0x2b2 + // Block 0x7e, offset 0x2a3 {value: 0x0000, lo: 0x01}, {value: 0x8104, lo: 0xab, hi: 0xab}, - // Block 0x80, offset 0x2b4 + // Block 0x7f, offset 0x2a5 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0xb4, hi: 0xb4}, + // Block 0x80, offset 0x2a7 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x87, hi: 0x87}, + // Block 0x81, offset 0x2a9 + {value: 0x0000, lo: 0x01}, + {value: 0x8104, lo: 0x99, hi: 0x99}, + // Block 0x82, offset 0x2ab + {value: 0x0000, lo: 0x02}, + {value: 0x8102, lo: 0x82, hi: 0x82}, + {value: 0x8104, lo: 0x84, hi: 0x85}, + // Block 0x83, offset 0x2ae {value: 0x0000, lo: 0x01}, {value: 0x8101, lo: 0xb0, hi: 0xb4}, - // Block 0x81, offset 0x2b6 + // Block 0x84, offset 0x2b0 {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0xb0, hi: 0xb6}, - // Block 0x82, offset 0x2b8 + // Block 0x85, offset 0x2b2 {value: 0x0000, lo: 0x01}, {value: 0x8101, lo: 0x9e, hi: 0x9e}, - // Block 0x83, offset 0x2ba + // Block 0x86, offset 0x2b4 {value: 0x0000, lo: 0x0c}, {value: 0x45cc, lo: 0x9e, hi: 0x9e}, {value: 0x45d6, lo: 0x9f, hi: 0x9f}, @@ -6497,7 +6517,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x8130, lo: 0xad, hi: 0xad}, {value: 0x812b, lo: 0xae, hi: 0xb2}, {value: 0x812d, lo: 0xbb, hi: 0xbf}, - // Block 0x84, offset 0x2c7 + // Block 0x87, offset 0x2c1 {value: 0x0000, lo: 0x09}, {value: 0x812d, lo: 0x80, hi: 0x82}, {value: 0x8132, lo: 0x85, hi: 0x89}, @@ -6508,24 +6528,24 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x4650, lo: 0xbd, hi: 0xbd}, {value: 0x466c, lo: 0xbe, hi: 0xbe}, {value: 0x465e, lo: 0xbf, hi: 0xbf}, - // Block 0x85, offset 0x2d1 + // Block 0x88, offset 0x2cb {value: 0x0000, lo: 0x01}, {value: 0x467a, lo: 0x80, hi: 0x80}, - // Block 0x86, offset 0x2d3 + // Block 0x89, offset 0x2cd {value: 0x0000, lo: 0x01}, {value: 0x8132, lo: 0x82, hi: 0x84}, - // Block 0x87, offset 0x2d5 + // Block 0x8a, offset 0x2cf {value: 0x0002, lo: 0x03}, {value: 0x0043, lo: 0x80, hi: 0x99}, {value: 0x0083, lo: 0x9a, hi: 0xb3}, {value: 0x0043, lo: 0xb4, hi: 0xbf}, - // Block 0x88, offset 0x2d9 + // Block 0x8b, offset 0x2d3 {value: 0x0002, lo: 0x04}, {value: 0x005b, lo: 0x80, hi: 0x8d}, {value: 0x0083, lo: 0x8e, hi: 0x94}, {value: 0x0093, lo: 0x96, hi: 0xa7}, {value: 0x0043, lo: 0xa8, hi: 0xbf}, - // Block 0x89, offset 0x2de + // Block 0x8c, offset 0x2d8 {value: 0x0002, lo: 0x0b}, {value: 0x0073, lo: 0x80, hi: 0x81}, {value: 0x0083, lo: 0x82, hi: 0x9b}, @@ -6538,13 +6558,13 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x0083, lo: 0xb6, hi: 0xb9}, {value: 0x008d, lo: 0xbb, hi: 0xbb}, {value: 0x0091, lo: 0xbd, hi: 0xbf}, - // Block 0x8a, offset 0x2ea + // Block 0x8d, offset 0x2e4 {value: 0x0002, lo: 0x04}, {value: 0x0097, lo: 0x80, hi: 0x83}, {value: 0x00a1, lo: 0x85, hi: 0x8f}, {value: 0x0043, lo: 0x90, hi: 0xa9}, {value: 0x0083, lo: 0xaa, hi: 0xbf}, - // Block 0x8b, offset 0x2ef + // Block 0x8e, offset 0x2e9 {value: 0x0002, lo: 0x08}, {value: 0x00af, lo: 0x80, hi: 0x83}, {value: 0x0043, lo: 0x84, hi: 0x85}, @@ -6554,36 +6574,36 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x0083, lo: 0x9e, hi: 0xb7}, {value: 0x0043, lo: 0xb8, hi: 0xb9}, {value: 0x0049, lo: 0xbb, hi: 0xbe}, - // Block 0x8c, offset 0x2f8 + // Block 0x8f, offset 0x2f2 {value: 0x0002, lo: 0x05}, {value: 0x0053, lo: 0x80, hi: 0x84}, {value: 0x005f, lo: 0x86, hi: 0x86}, {value: 0x0067, lo: 0x8a, hi: 0x90}, {value: 0x0083, lo: 0x92, hi: 0xab}, {value: 0x0043, lo: 0xac, hi: 0xbf}, - // Block 0x8d, offset 0x2fe + // Block 0x90, offset 0x2f8 {value: 0x0002, lo: 0x04}, {value: 0x006b, lo: 0x80, hi: 0x85}, {value: 0x0083, lo: 0x86, hi: 0x9f}, {value: 0x0043, lo: 0xa0, hi: 0xb9}, {value: 0x0083, lo: 0xba, hi: 0xbf}, - // Block 0x8e, offset 0x303 + // Block 0x91, offset 0x2fd {value: 0x0002, lo: 0x03}, {value: 0x008f, lo: 0x80, hi: 0x93}, {value: 0x0043, lo: 0x94, hi: 0xad}, {value: 0x0083, lo: 0xae, hi: 0xbf}, - // Block 0x8f, offset 0x307 + // Block 0x92, offset 0x301 {value: 0x0002, lo: 0x04}, {value: 0x00a7, lo: 0x80, hi: 0x87}, {value: 0x0043, lo: 0x88, hi: 0xa1}, {value: 0x0083, lo: 0xa2, hi: 0xbb}, {value: 0x0043, lo: 0xbc, hi: 0xbf}, - // Block 0x90, offset 0x30c + // Block 0x93, offset 0x306 {value: 0x0002, lo: 0x03}, {value: 0x004b, lo: 0x80, hi: 0x95}, {value: 0x0083, lo: 0x96, hi: 0xaf}, {value: 0x0043, lo: 0xb0, hi: 0xbf}, - // Block 0x91, offset 0x310 + // Block 0x94, offset 0x30a {value: 0x0003, lo: 0x0f}, {value: 0x01b8, lo: 0x80, hi: 0x80}, {value: 0x045f, lo: 0x81, hi: 0x81}, @@ -6600,7 +6620,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x01a6, lo: 0xb4, hi: 0xba}, {value: 0x045f, lo: 0xbb, hi: 0xbb}, {value: 0x01bb, lo: 0xbc, hi: 0xbf}, - // Block 0x92, offset 0x320 + // Block 0x95, offset 0x31a {value: 0x0003, lo: 0x0d}, {value: 0x01c7, lo: 0x80, hi: 0x94}, {value: 0x045b, lo: 0x95, hi: 0x95}, @@ -6615,7 +6635,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x01a6, lo: 0xae, hi: 0xb4}, {value: 0x045f, lo: 0xb5, hi: 0xb5}, {value: 0x01bb, lo: 0xb6, hi: 0xbf}, - // Block 0x93, offset 0x32e + // Block 0x96, offset 0x328 {value: 0x0003, lo: 0x0d}, {value: 0x01d9, lo: 0x80, hi: 0x8e}, {value: 0x045b, lo: 0x8f, hi: 0x8f}, @@ -6630,7 +6650,7 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x01a6, lo: 0xa8, hi: 0xae}, {value: 0x045f, lo: 0xaf, hi: 0xaf}, {value: 0x01bb, lo: 0xb0, hi: 0xbf}, - // Block 0x94, offset 0x33c + // Block 0x97, offset 0x336 {value: 0x0003, lo: 0x0d}, {value: 0x01eb, lo: 0x80, hi: 0x88}, {value: 0x045b, lo: 0x89, hi: 0x89}, @@ -6645,21 +6665,21 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x01a6, lo: 0xa2, hi: 0xa8}, {value: 0x045f, lo: 0xa9, hi: 0xa9}, {value: 0x01bb, lo: 0xaa, hi: 0xbf}, - // Block 0x95, offset 0x34a + // Block 0x98, offset 0x344 {value: 0x0000, lo: 0x05}, {value: 0x8132, lo: 0x80, hi: 0x86}, {value: 0x8132, lo: 0x88, hi: 0x98}, {value: 0x8132, lo: 0x9b, hi: 0xa1}, {value: 0x8132, lo: 0xa3, hi: 0xa4}, {value: 0x8132, lo: 0xa6, hi: 0xaa}, - // Block 0x96, offset 0x350 + // Block 0x99, offset 0x34a {value: 0x0000, lo: 0x01}, {value: 0x812d, lo: 0x90, hi: 0x96}, - // Block 0x97, offset 0x352 + // Block 0x9a, offset 0x34c {value: 0x0000, lo: 0x02}, {value: 0x8132, lo: 0x84, hi: 0x89}, {value: 0x8102, lo: 0x8a, hi: 0x8a}, - // Block 0x98, offset 0x355 + // Block 0x9b, offset 0x34f {value: 0x0002, lo: 0x09}, {value: 0x0063, lo: 0x80, hi: 0x89}, {value: 0x1951, lo: 0x8a, hi: 0x8a}, @@ -6670,10 +6690,10 @@ var nfkcSparseValues = [875]valueRange{ {value: 0x19ae, lo: 0x8f, hi: 0x8f}, {value: 0x197b, lo: 0xaa, hi: 0xaa}, {value: 0x197e, lo: 0xab, hi: 0xab}, - // Block 0x99, offset 0x35f + // Block 0x9c, offset 0x359 {value: 0x0000, lo: 0x01}, {value: 0x193f, lo: 0x90, hi: 0x90}, - // Block 0x9a, offset 0x361 + // Block 0x9d, offset 0x35b {value: 0x0028, lo: 0x09}, {value: 0x2862, lo: 0x80, hi: 0x80}, {value: 0x2826, lo: 0x81, hi: 0x81}, @@ -7630,4 +7650,4 @@ var recompMap = map[uint32]rune{ 0x15B915AF: 0x115BB, } -// Total size of tables: 53KB (54006 bytes) +// Total size of tables: 53KB (54226 bytes) diff --git a/libgo/go/golang_org/x/text/unicode/norm/transform.go b/libgo/go/golang_org/x/text/unicode/norm/transform.go index 4dec306adcf..73869a5a1cd 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/transform.go +++ b/libgo/go/golang_org/x/text/unicode/norm/transform.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -42,7 +42,7 @@ func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) } func flushTransform(rb *reorderBuffer) bool { - // Write out (must fully fit in dst, or else it is a ErrShortDst). + // Write out (must fully fit in dst, or else it is an ErrShortDst). if len(rb.out) < rb.nrune*utf8.UTFMax { return false } diff --git a/libgo/go/golang_org/x/text/unicode/norm/trie.go b/libgo/go/golang_org/x/text/unicode/norm/trie.go index 4cbea644a1d..761439ce592 100644 --- a/libgo/go/golang_org/x/text/unicode/norm/trie.go +++ b/libgo/go/golang_org/x/text/unicode/norm/trie.go @@ -1,4 +1,4 @@ -// Code generated by running "go run gen.go -core" in golang.org/x/text. DO NOT EDIT. +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go index 21d6a2e1dc6..e8783e4c39e 100644 --- a/libgo/go/hash/adler32/adler32.go +++ b/libgo/go/hash/adler32/adler32.go @@ -12,7 +12,10 @@ // significant-byte first (network) order. package adler32 -import "hash" +import ( + "errors" + "hash" +) const ( // mod is the largest prime that is less than 65536. @@ -32,8 +35,11 @@ type digest uint32 func (d *digest) Reset() { *d = 1 } -// New returns a new hash.Hash32 computing the Adler-32 checksum. -// Its Sum method will lay the value out in big-endian byte order. +// New returns a new hash.Hash32 computing the Adler-32 checksum. Its +// Sum method will lay the value out in big-endian byte order. The +// returned Hash32 also implements encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler to marshal and unmarshal the internal +// state of the hash. func New() hash.Hash32 { d := new(digest) d.Reset() @@ -44,6 +50,44 @@ func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return 4 } +const ( + magic = "adl\x01" + marshaledSize = len(magic) + 4 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, uint32(*d)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/adler32: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/adler32: invalid hash state size") + } + *d = digest(readUint32(b[len(magic):])) + return nil +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + // Add p to the running checksum d. func update(d digest, p []byte) digest { s1, s2 := uint32(d&0xffff), uint32(d>>16) diff --git a/libgo/go/hash/adler32/adler32_test.go b/libgo/go/hash/adler32/adler32_test.go index 0e9c938d80c..6bac8025076 100644 --- a/libgo/go/hash/adler32/adler32_test.go +++ b/libgo/go/hash/adler32/adler32_test.go @@ -5,57 +5,60 @@ package adler32 import ( + "encoding" + "io" "strings" "testing" ) var golden = []struct { - out uint32 - in string + out uint32 + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal }{ - {0x00000001, ""}, - {0x00620062, "a"}, - {0x012600c4, "ab"}, - {0x024d0127, "abc"}, - {0x03d8018b, "abcd"}, - {0x05c801f0, "abcde"}, - {0x081e0256, "abcdef"}, - {0x0adb02bd, "abcdefg"}, - {0x0e000325, "abcdefgh"}, - {0x118e038e, "abcdefghi"}, - {0x158603f8, "abcdefghij"}, - {0x3f090f02, "Discard medicine more than two years old."}, - {0x46d81477, "He who has a shady past knows that nice guys finish last."}, - {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."}, - {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x8c3c09ea, "Nepal premier won't resign."}, - {0x45ac18fd, "For every action there is an equal and opposite government program."}, - {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0x61b507df, "size: a.out: bad magic"}, - {0xb8631171, "The major problem is with sendmail. -Mark Horton"}, - {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x7cc6102b, "If the enemy is within range, then so are you."}, - {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0xb55b0b09, "C is as portable as Stonehedge!!"}, - {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"}, - {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"}, - {0x211297c8, strings.Repeat("\xff", 5548) + "8"}, - {0xbaa198c8, strings.Repeat("\xff", 5549) + "9"}, - {0x553499be, strings.Repeat("\xff", 5550) + "0"}, - {0xf0c19abe, strings.Repeat("\xff", 5551) + "1"}, - {0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2"}, - {0x2af69cbe, strings.Repeat("\xff", 5553) + "3"}, - {0xc9809dbe, strings.Repeat("\xff", 5554) + "4"}, - {0x69189ebe, strings.Repeat("\xff", 5555) + "5"}, - {0x86af0001, strings.Repeat("\x00", 1e5)}, - {0x79660b4d, strings.Repeat("a", 1e5)}, - {0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4)}, + {0x00000001, "", "adl\x01\x00\x00\x00\x01"}, + {0x00620062, "a", "adl\x01\x00\x00\x00\x01"}, + {0x012600c4, "ab", "adl\x01\x00b\x00b"}, + {0x024d0127, "abc", "adl\x01\x00b\x00b"}, + {0x03d8018b, "abcd", "adl\x01\x01&\x00\xc4"}, + {0x05c801f0, "abcde", "adl\x01\x01&\x00\xc4"}, + {0x081e0256, "abcdef", "adl\x01\x02M\x01'"}, + {0x0adb02bd, "abcdefg", "adl\x01\x02M\x01'"}, + {0x0e000325, "abcdefgh", "adl\x01\x03\xd8\x01\x8b"}, + {0x118e038e, "abcdefghi", "adl\x01\x03\xd8\x01\x8b"}, + {0x158603f8, "abcdefghij", "adl\x01\x05\xc8\x01\xf0"}, + {0x3f090f02, "Discard medicine more than two years old.", "adl\x01NU\a\x87"}, + {0x46d81477, "He who has a shady past knows that nice guys finish last.", "adl\x01\x89\x8e\t\xe9"}, + {0x40ee0ee1, "I wouldn't marry him with a ten foot pole.", "adl\x01R\t\ag"}, + {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "adl\x01\u007f\xbb\t\x10"}, + {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard", "adl\x01\x99:\n~"}, + {0x8c3c09ea, "Nepal premier won't resign.", "adl\x01\"\x05\x05\x05"}, + {0x45ac18fd, "For every action there is an equal and opposite government program.", "adl\x01\xcc\xfa\f\x00"}, + {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine.", "adl\x01\x93\xa9\n\b"}, + {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "adl\x01e\xf5\x10\x14"}, + {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "adl\x01\xee\x00\f\xb2"}, + {0x61b507df, "size: a.out: bad magic", "adl\x01\x1a\xfc\x04\x1d"}, + {0xb8631171, "The major problem is with sendmail. -Mark Horton", "adl\x01mi\b\xdc"}, + {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "adl\x01\xe3\n\f\x9f"}, + {0x7cc6102b, "If the enemy is within range, then so are you.", "adl\x01_\xe0\b\x1e"}, + {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams.", "adl\x01ۘ\f\x87"}, + {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway.", "adl\x01\xcc}\v\x83"}, + {0xb55b0b09, "C is as portable as Stonehedge!!", "adl\x01,^\x05\xad"}, + {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "adl\x01M\xd1\x0e\xc8"}, + {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "adl\x01#\xd8\x17\xd7"}, + {0x2e5d1316, "How can you write a big system without C++? -Paul Glick", "adl\x01\x8fU\n\x0f"}, + {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski", "adl\x01/\x98\x0e\xc4"}, + {0x211297c8, strings.Repeat("\xff", 5548) + "8", "adl\x01\x9a\xa6\xcb\xc1"}, + {0xbaa198c8, strings.Repeat("\xff", 5549) + "9", "adl\x01gu\xcc\xc0"}, + {0x553499be, strings.Repeat("\xff", 5550) + "0", "adl\x01gu\xcc\xc0"}, + {0xf0c19abe, strings.Repeat("\xff", 5551) + "1", "adl\x015CͿ"}, + {0x8d5c9bbe, strings.Repeat("\xff", 5552) + "2", "adl\x015CͿ"}, + {0x2af69cbe, strings.Repeat("\xff", 5553) + "3", "adl\x01\x04\x10ξ"}, + {0xc9809dbe, strings.Repeat("\xff", 5554) + "4", "adl\x01\x04\x10ξ"}, + {0x69189ebe, strings.Repeat("\xff", 5555) + "5", "adl\x01\xd3\xcdϽ"}, + {0x86af0001, strings.Repeat("\x00", 1e5), "adl\x01\xc3P\x00\x01"}, + {0x79660b4d, strings.Repeat("a", 1e5), "adl\x01\x81k\x05\xa7"}, + {0x110588ee, strings.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1e4), "adl\x01e\xd2\xc4p"}, } // checksum is a slow but simple implementation of the Adler-32 checksum. @@ -87,6 +90,38 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + for _, g := range golden { + h := New() + h2 := New() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("checksum(%q) state = %q, want %q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum32() != h2.Sum32() { + t.Errorf("checksum(%q) = 0x%x != marshaled (0x%x)", g.in, h.Sum32(), h2.Sum32()) + } + } +} + func BenchmarkAdler32KB(b *testing.B) { b.SetBytes(1024) data := make([]byte, 1024) diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 8aa91b17e90..1912caa212b 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -13,6 +13,7 @@ package crc32 import ( + "errors" "hash" "sync" ) @@ -138,9 +139,11 @@ type digest struct { tab *Table } -// New creates a new hash.Hash32 computing the CRC-32 checksum -// using the polynomial represented by the Table. -// Its Sum method will lay the value out in big-endian byte order. +// New creates a new hash.Hash32 computing the CRC-32 checksum using the +// polynomial represented by the Table. Its Sum method will lay the +// value out in big-endian byte order. The returned Hash32 also +// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. func New(tab *Table) hash.Hash32 { if tab == IEEETable { ieeeOnce.Do(ieeeInit) @@ -148,9 +151,11 @@ func New(tab *Table) hash.Hash32 { return &digest{0, tab} } -// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum -// using the IEEE polynomial. -// Its Sum method will lay the value out in big-endian byte order. +// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum using +// the IEEE polynomial. Its Sum method will lay the value out in +// big-endian byte order. The returned Hash32 also implements +// encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to marshal +// and unmarshal the internal state of the hash. func NewIEEE() hash.Hash32 { return New(IEEETable) } func (d *digest) Size() int { return Size } @@ -159,6 +164,48 @@ func (d *digest) BlockSize() int { return 1 } func (d *digest) Reset() { d.crc = 0 } +const ( + magic = "crc\x01" + marshaledSize = len(magic) + 4 + 4 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint32(b, tableSum(d.tab)) + b = appendUint32(b, d.crc) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("hash/crc32: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("hash/crc32: invalid hash state size") + } + if tableSum(d.tab) != readUint32(b[4:]) { + return errors.New("hash/crc32: tables do not match") + } + d.crc = readUint32(b[8:]) + return nil +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + // Update returns the result of adding the bytes in p to the crc. func Update(crc uint32, tab *Table, p []byte) uint32 { switch tab { @@ -205,3 +252,15 @@ func ChecksumIEEE(data []byte) uint32 { ieeeOnce.Do(ieeeInit) return updateIEEE(0, data) } + +// tableSum returns the IEEE checksum of table t. +func tableSum(t *Table) uint32 { + var a [1024]byte + b := a[:0] + if t != nil { + for _, x := range t { + b = appendUint32(b, x) + } + } + return ChecksumIEEE(b) +} diff --git a/libgo/go/hash/crc32/crc32_arm64.go b/libgo/go/hash/crc32/crc32_arm64.go index 4c5cad1181c..0d813b4f384 100644 --- a/libgo/go/hash/crc32/crc32_arm64.go +++ b/libgo/go/hash/crc32/crc32_arm64.go @@ -10,11 +10,12 @@ package crc32 -func supportsCRC32() bool +import "internal/cpu" + func castagnoliUpdate(crc uint32, p []byte) uint32 func ieeeUpdate(crc uint32, p []byte) uint32 -var hasCRC32 = supportsCRC32() +var hasCRC32 = cpu.ARM64.HasCRC32 func archAvailableCastagnoli() bool { return hasCRC32 diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go index 0492f46e8ce..4bdafaf8f52 100644 --- a/libgo/go/hash/crc32/crc32_test.go +++ b/libgo/go/hash/crc32/crc32_test.go @@ -5,49 +5,53 @@ package crc32 import ( + "encoding" "fmt" "hash" + "io" "math/rand" "testing" ) type test struct { - ieee, castagnoli uint32 - in string + ieee, castagnoli uint32 + in string + halfStateIEEE string // IEEE marshaled hash state after first half of in written, used by TestGoldenMarshal + halfStateCastagnoli string // Castagnoli marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []test{ - {0x0, 0x0, ""}, - {0xe8b7be43, 0xc1d04330, "a"}, - {0x9e83486d, 0xe2a22936, "ab"}, - {0x352441c2, 0x364b3fb7, "abc"}, - {0xed82cd11, 0x92c80a31, "abcd"}, - {0x8587d865, 0xc450d697, "abcde"}, - {0x4b8e39ef, 0x53bceff1, "abcdef"}, - {0x312a6aa6, 0xe627f441, "abcdefg"}, - {0xaeef2a50, 0xa9421b7, "abcdefgh"}, - {0x8da988af, 0x2ddc99fc, "abcdefghi"}, - {0x3981703a, 0xe6599437, "abcdefghij"}, - {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."}, - {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."}, - {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."}, - {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."}, - {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."}, - {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"}, - {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"}, - {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."}, - {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"}, - {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"}, + {0x0, 0x0, "", "crc\x01ʇ\x91M\x00\x00\x00\x00", "crc\x01wB\x84\x81\x00\x00\x00\x00"}, + {0xe8b7be43, 0xc1d04330, "a", "crc\x01ʇ\x91M\x00\x00\x00\x00", "crc\x01wB\x84\x81\x00\x00\x00\x00"}, + {0x9e83486d, 0xe2a22936, "ab", "crc\x01ʇ\x91M跾C", "crc\x01wB\x84\x81\xc1\xd0C0"}, + {0x352441c2, 0x364b3fb7, "abc", "crc\x01ʇ\x91M跾C", "crc\x01wB\x84\x81\xc1\xd0C0"}, + {0xed82cd11, 0x92c80a31, "abcd", "crc\x01ʇ\x91M\x9e\x83Hm", "crc\x01wB\x84\x81\xe2\xa2)6"}, + {0x8587d865, 0xc450d697, "abcde", "crc\x01ʇ\x91M\x9e\x83Hm", "crc\x01wB\x84\x81\xe2\xa2)6"}, + {0x4b8e39ef, 0x53bceff1, "abcdef", "crc\x01ʇ\x91M5$A\xc2", "crc\x01wB\x84\x816K?\xb7"}, + {0x312a6aa6, 0xe627f441, "abcdefg", "crc\x01ʇ\x91M5$A\xc2", "crc\x01wB\x84\x816K?\xb7"}, + {0xaeef2a50, 0xa9421b7, "abcdefgh", "crc\x01ʇ\x91M\xed\x82\xcd\x11", "crc\x01wB\x84\x81\x92\xc8\n1"}, + {0x8da988af, 0x2ddc99fc, "abcdefghi", "crc\x01ʇ\x91M\xed\x82\xcd\x11", "crc\x01wB\x84\x81\x92\xc8\n1"}, + {0x3981703a, 0xe6599437, "abcdefghij", "crc\x01ʇ\x91M\x85\x87\xd8e", "crc\x01wB\x84\x81\xc4P֗"}, + {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old.", "crc\x01ʇ\x91M\xfd\xe5\xc2J", "crc\x01wB\x84\x81S\"(\xe0"}, + {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last.", "crc\x01ʇ\x91M\x01Nj+", "crc\x01wB\x84\x81'\xdaR\x15"}, + {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole.", "crc\x01ʇ\x91M\x9d\x13\xce\x10", "crc\x01wB\x84\x81\xc3\xed\xabG"}, + {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "crc\x01ʇ\x91M-\xed\xf7\x94", "crc\x01wB\x84\x81\xce\xceb\x81"}, + {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard", "crc\x01ʇ\x91MOa\xa5\r", "crc\x01wB\x84\x81\xd3s\x9dP"}, + {0x4c418325, 0x85d3dc82, "Nepal premier won't resign.", "crc\x01ʇ\x91M\xa8S9\x85", "crc\x01wB\x84\x81{\x90\x8a\x14"}, + {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program.", "crc\x01ʇ\x91Ma\xe9>\x86", "crc\x01wB\x84\x81\xaa@\xc4\x1c"}, + {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine.", "crc\x01ʇ\x91M\\\x1an\x88", "crc\x01wB\x84\x81W\a8Z"}, + {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "crc\x01ʇ\x91M\xb7\xf5\xf2\xca", "crc\x01wB\x84\x81\xc4o\x9d\x85"}, + {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "crc\x01ʇ\x91M\x84g1\xe8", "crc\x01wB\x84\x81#\x98\f\xab"}, + {0xab3abe14, 0x572b74e2, "size: a.out: bad magic", "crc\x01ʇ\x91M\x8a\x0f\xad\b", "crc\x01wB\x84\x81\x80\xc9n\xd8"}, + {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton", "crc\x01ʇ\x91M\a\xf0\xb3\x15", "crc\x01wB\x84\x81liS\xcc"}, + {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "crc\x01ʇ\x91M\x0fa\xbc.", "crc\x01wB\x84\x81\xdb͏C"}, + {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you.", "crc\x01ʇ\x91My\x1b\x99\xf8", "crc\x01wB\x84\x81\xaaB\x037"}, + {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams.", "crc\x01ʇ\x91M\bqfY", "crc\x01wB\x84\x81\x16y\xa1\xd2"}, + {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway.", "crc\x01ʇ\x91M\xbdO,\xc2", "crc\x01wB\x84\x81f&\xc5\xe4"}, + {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!", "crc\x01ʇ\x91M\xf7\xd6\x00\xd5", "crc\x01wB\x84\x81de\\\xf8"}, + {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "crc\x01ʇ\x91Ml+\xb8\xa7", "crc\x01wB\x84\x81\xbf\xd6S\xdd"}, + {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "crc\x01ʇ\x91M> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint64(b []byte) uint64 { + _ = b[7] + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + func update(crc uint64, tab *Table, p []byte) uint64 { crc = ^crc // Table comparison is somewhat expensive, so avoid it for small sizes @@ -145,3 +197,15 @@ func (d *digest) Sum(in []byte) []byte { // Checksum returns the CRC-64 checksum of data // using the polynomial represented by the Table. func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) } + +// tableSum returns the ISO checksum of table t. +func tableSum(t *Table) uint64 { + var a [2048]byte + b := a[:0] + if t != nil { + for _, x := range t { + b = appendUint64(b, x) + } + } + return Checksum(b, MakeTable(ISO)) +} diff --git a/libgo/go/hash/crc64/crc64_test.go b/libgo/go/hash/crc64/crc64_test.go index 480b150e132..9db05b02fe9 100644 --- a/libgo/go/hash/crc64/crc64_test.go +++ b/libgo/go/hash/crc64/crc64_test.go @@ -5,49 +5,52 @@ package crc64 import ( + "encoding" "io" "testing" ) type test struct { - outISO uint64 - outECMA uint64 - in string + outISO uint64 + outECMA uint64 + in string + halfStateISO string // ISO marshaled hash state after first half of in written, used by TestGoldenMarshal + halfStateECMA string // ECMA marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden = []test{ - {0x0, 0x0, ""}, - {0x3420000000000000, 0x330284772e652b05, "a"}, - {0x36c4200000000000, 0xbc6573200e84b046, "ab"}, - {0x3776c42000000000, 0x2cd8094a1a277627, "abc"}, - {0x336776c420000000, 0x3c9d28596e5960ba, "abcd"}, - {0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde"}, - {0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef"}, - {0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg"}, - {0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh"}, - {0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi"}, - {0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij"}, - {0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old."}, - {0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last."}, - {0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole."}, - {0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign."}, - {0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program."}, - {0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size: a.out: bad magic"}, - {0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail. -Mark Horton"}, - {0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you."}, - {0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!"}, - {0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++? -Paul Glick"}, - {0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system."}, + {0x0, 0x0, "", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x00\x00\x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x00\x00\x00\x00\x00\x00\x00\x00"}, + {0x3420000000000000, 0x330284772e652b05, "a", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x00\x00\x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x00\x00\x00\x00\x00\x00\x00\x00"}, + {0x36c4200000000000, 0xbc6573200e84b046, "ab", "crc\x02s\xba\x84\x84\xbb\xcd]\xef4 \x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee3\x02\x84w.e+\x05"}, + {0x3776c42000000000, 0x2cd8094a1a277627, "abc", "crc\x02s\xba\x84\x84\xbb\xcd]\xef4 \x00\x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee3\x02\x84w.e+\x05"}, + {0x336776c420000000, 0x3c9d28596e5960ba, "abcd", "crc\x02s\xba\x84\x84\xbb\xcd]\xef6\xc4 \x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\xbces \x0e\x84\xb0F"}, + {0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde", "crc\x02s\xba\x84\x84\xbb\xcd]\xef6\xc4 \x00\x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\xbces \x0e\x84\xb0F"}, + {0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef", "crc\x02s\xba\x84\x84\xbb\xcd]\xef7v\xc4 \x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee,\xd8\tJ\x1a'v'"}, + {0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg", "crc\x02s\xba\x84\x84\xbb\xcd]\xef7v\xc4 \x00\x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee,\xd8\tJ\x1a'v'"}, + {0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh", "crc\x02s\xba\x84\x84\xbb\xcd]\xef3gv\xc4 \x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee<\x9d(YnY`\xba"}, + {0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi", "crc\x02s\xba\x84\x84\xbb\xcd]\xef3gv\xc4 \x00\x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee<\x9d(YnY`\xba"}, + {0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij", "crc\x02s\xba\x84\x84\xbb\xcd]\xef2\xd3gv\xc4 \x00\x00", "crc\x02`&\x9aR\xe1\xb7\xfee\x04\v\xdfX\xfb\b\x95\xf2"}, + {0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xc6\xc0\f\xac'\x11\x12\xd5", "crc\x02`&\x9aR\xe1\xb7\xfee\xfd%\xc0&\xa0R\xef\x95"}, + {0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\t\xcb\xd15X[r\t", "crc\x02`&\x9aR\xe1\xb7\xfee\a\x02\xe8|+\xc1\x06\xe3"}, + {0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x19\xc8d\xbe\x84\x14\x87_", "crc\x02`&\x9aR\xe1\xb7\xfee˷\xd3\xeeG\xdcE\x8c"}, + {0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xad\x1b*\xc0\xb1\xf3i(", "crc\x02`&\x9aR\xe1\xb7\xfee\xa7\x8a\xdb\xf6\xd2R\t\x96"}, + {0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered. -Tom Stoppard", "crc\x02s\xba\x84\x84\xbb\xcd]\xefv78\x1ak\x02\x8f\xff", "crc\x02`&\x9aR\xe1\xb7\xfeeT\xcbl\x10\xfb\x87K*"}, + {0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xcbf\x11R\xbfh\xde\xc9", "crc\x02`&\x9aR\xe1\xb7\xfee6\x13ُ\x06_\xbd\x9a"}, + {0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xf3pV\x01c_Wu", "crc\x02`&\x9aR\xe1\xb7\xfee\xe7\xc6\n\b\x12FL\xa0"}, + {0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine.", "crc\x02s\xba\x84\x84\xbb\xcd]\xefñ\xff\xf1\xe0/Δ", "crc\x02`&\x9aR\xe1\xb7\xfeeOL/\xb1\xec\xa2\x14\x87"}, + {0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "crc\x02s\xba\x84\x84\xbb\xcd]\xefݸa\xe1\xb5\xf8\xb9W", "crc\x02`&\x9aR\xe1\xb7\xfee\x87)GQ\x03\xf4K\t"}, + {0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "crc\x02s\xba\x84\x84\xbb\xcd]\xefV\xba\x12\x91\x81\x1fNU", "crc\x02`&\x9aR\xe1\xb7\xfee\n\xb8\x81v?\xdeL\xcb"}, + {0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size: a.out: bad magic", "crc\x02s\xba\x84\x84\xbb\xcd]\xefG\xad\xbc\xb2\xa8y\xc9\xdc", "crc\x02`&\x9aR\xe1\xb7\xfee\xcc\xce\xe5\xe6\x89p\x01\xb8"}, + {0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail. -Mark Horton", "crc\x02s\xba\x84\x84\xbb\xcd]\uf8acn\x8aT;&\xd5", "crc\x02`&\x9aR\xe1\xb7\xfeeFf\x9c\x1f\xc9x\xbfa"}, + {0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world. CCFestoon", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xeb\x18\xbf\xf9}\x91\xe5|", "crc\x02`&\x9aR\xe1\xb7\xfeea\x9e\x05:\xce[\xe7\x19"}, + {0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef^5k\xd0Aj_{", "crc\x02`&\x9aR\xe1\xb7\xfee\v#\x99\xa8r\x83YR"}, + {0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef|\xb5\x02\xdcw\x18/\x86", "crc\x02`&\x9aR\xe1\xb7\xfee]\x9d-\xed\x8c\xf9r9"}, + {0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\x03\x8bd\x1c\xb0_\x16\x98", "crc\x02`&\x9aR\xe1\xb7\xfee\xafW\x98\xaa\"\xe7\xd7|"}, + {0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!", "crc\x02s\xba\x84\x84\xbb\xcd]\xef.P\xe1I\xc6pi\xdc", "crc\x02`&\x9aR\xe1\xb7\xfee֚\x06\x01(\xc0\x1e\x8b"}, + {0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\xf7\xa04\x8a\xf2o\xe0;", "crc\x02`&\x9aR\xe1\xb7\xfee<[\xd2%\x9em\x94\x04"}, + {0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "crc\x02s\xba\x84\x84\xbb\xcd]\xef\u007f\xae\xb9\xbaX=\x19v", "crc\x02`&\x9aR\xe1\xb7\xfee\xb2˦Y\xc5\xd0G\x03"}, + {0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++? -Paul Glick", "crc\x02s\xba\x84\x84\xbb\xcd]\xefa\xed$js\xb9\xa5A", "crc\x02`&\x9aR\xe1\xb7\xfeeZm\x96\x8a\xe2\xaf\x13p"}, + {0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system.", "crc\x02s\xba\x84\x84\xbb\xcd]\xef}\xee[q\x16\xcb\xe4\x8d", "crc\x02`&\x9aR\xe1\xb7\xfee\xb1\x93] \xeb\xa9am"}, } func TestGolden(t *testing.T) { @@ -72,6 +75,87 @@ func TestGolden(t *testing.T) { } } +func TestGoldenMarshal(t *testing.T) { + t.Run("ISO", func(t *testing.T) { + table := MakeTable(ISO) + for _, g := range golden { + h := New(table) + h2 := New(table) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateISO { + t.Errorf("ISO crc64(%q) state = %q, want %q", g.in, state, g.halfStateISO) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum64() != h2.Sum64() { + t.Errorf("ISO crc64(%s) = 0x%x != marshaled (0x%x)", g.in, h.Sum64(), h2.Sum64()) + } + } + }) + t.Run("ECMA", func(t *testing.T) { + table := MakeTable(ECMA) + for _, g := range golden { + h := New(table) + h2 := New(table) + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfStateECMA { + t.Errorf("ECMA crc64(%q) state = %q, want %q", g.in, state, g.halfStateECMA) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if h.Sum64() != h2.Sum64() { + t.Errorf("ECMA crc64(%s) = 0x%x != marshaled (0x%x)", g.in, h.Sum64(), h2.Sum64()) + } + } + }) +} + +func TestMarshalTableMismatch(t *testing.T) { + h1 := New(MakeTable(ISO)) + h2 := New(MakeTable(ECMA)) + + state1, err := h1.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state1); err == nil { + t.Errorf("no error when one was expected") + } +} + func bench(b *testing.B, poly uint64, size int64) { b.SetBytes(size) data := make([]byte, size) diff --git a/libgo/go/hash/example_test.go b/libgo/go/hash/example_test.go new file mode 100644 index 00000000000..49dc8fc8abb --- /dev/null +++ b/libgo/go/hash/example_test.go @@ -0,0 +1,53 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package hash_test + +import ( + "bytes" + "crypto/sha256" + "encoding" + "fmt" + "log" +) + +func Example_binaryMarshaler() { + const ( + input1 = "The tunneling gopher digs downwards, " + input2 = "unaware of what he will find." + ) + + first := sha256.New() + first.Write([]byte(input1)) + + marshaler, ok := first.(encoding.BinaryMarshaler) + if !ok { + log.Fatal("first does not implement encoding.BinaryMarshaler") + } + state, err := marshaler.MarshalBinary() + if err != nil { + log.Fatal("unable to marshal hash:", err) + } + + second := sha256.New() + + unmarshaler, ok := second.(encoding.BinaryUnmarshaler) + if !ok { + log.Fatal("second does not implement encoding.BinaryUnmarshaler") + } + if err := unmarshaler.UnmarshalBinary(state); err != nil { + log.Fatal("unable to unmarshal hash:", err) + } + + first.Write([]byte(input2)) + second.Write([]byte(input2)) + + fmt.Printf("%x\n", first.Sum(nil)) + fmt.Println(bytes.Equal(first.Sum(nil), second.Sum(nil))) + // Output: + // 57d51a066f3a39942649cd9a76c77e97ceab246756ff3888659e6aa5a07f4a52 + // true +} diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go index 3d2df73d3dc..7662315d43c 100644 --- a/libgo/go/hash/fnv/fnv.go +++ b/libgo/go/hash/fnv/fnv.go @@ -6,9 +6,14 @@ // created by Glenn Fowler, Landon Curt Noll, and Phong Vo. // See // https://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function. +// +// All the hash.Hash implementations returned by this package also +// implement encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to +// marshal and unmarshal the internal state of the hash. package fnv import ( + "errors" "hash" ) @@ -215,3 +220,163 @@ func (s *sum128a) Sum(in []byte) []byte { byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]), ) } + +const ( + magic32 = "fnv\x01" + magic32a = "fnv\x02" + magic64 = "fnv\x03" + magic64a = "fnv\x04" + magic128 = "fnv\x05" + magic128a = "fnv\x06" + marshaledSize32 = len(magic32) + 4 + marshaledSize64 = len(magic64) + 8 + marshaledSize128 = len(magic128) + 8*2 +) + +func (s *sum32) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize32) + b = append(b, magic32...) + b = appendUint32(b, uint32(*s)) + return b, nil +} + +func (s *sum32a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize32) + b = append(b, magic32a...) + b = appendUint32(b, uint32(*s)) + return b, nil +} + +func (s *sum64) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize64) + b = append(b, magic64...) + b = appendUint64(b, uint64(*s)) + return b, nil + +} + +func (s *sum64a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize64) + b = append(b, magic64a...) + b = appendUint64(b, uint64(*s)) + return b, nil +} + +func (s *sum128) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize128) + b = append(b, magic128...) + b = appendUint64(b, s[0]) + b = appendUint64(b, s[1]) + return b, nil +} + +func (s *sum128a) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize128) + b = append(b, magic128a...) + b = appendUint64(b, s[0]) + b = appendUint64(b, s[1]) + return b, nil +} + +func (s *sum32) UnmarshalBinary(b []byte) error { + if len(b) < len(magic32) || string(b[:len(magic32)]) != magic32 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize32 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum32(readUint32(b[4:])) + return nil +} + +func (s *sum32a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic32a) || string(b[:len(magic32a)]) != magic32a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize32 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum32a(readUint32(b[4:])) + return nil +} + +func (s *sum64) UnmarshalBinary(b []byte) error { + if len(b) < len(magic64) || string(b[:len(magic64)]) != magic64 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize64 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum64(readUint64(b[4:])) + return nil +} + +func (s *sum64a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic64a) || string(b[:len(magic64a)]) != magic64a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize64 { + return errors.New("hash/fnv: invalid hash state size") + } + *s = sum64a(readUint64(b[4:])) + return nil +} + +func (s *sum128) UnmarshalBinary(b []byte) error { + if len(b) < len(magic128) || string(b[:len(magic128)]) != magic128 { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize128 { + return errors.New("hash/fnv: invalid hash state size") + } + s[0] = readUint64(b[4:]) + s[1] = readUint64(b[12:]) + return nil +} + +func (s *sum128a) UnmarshalBinary(b []byte) error { + if len(b) < len(magic128a) || string(b[:len(magic128a)]) != magic128a { + return errors.New("hash/fnv: invalid hash state identifier") + } + if len(b) != marshaledSize128 { + return errors.New("hash/fnv: invalid hash state size") + } + s[0] = readUint64(b[4:]) + s[1] = readUint64(b[12:]) + return nil +} + +func readUint32(b []byte) uint32 { + _ = b[3] + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func appendUint32(b []byte, x uint32) []byte { + a := [4]byte{ + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func appendUint64(b []byte, x uint64) []byte { + a := [8]byte{ + byte(x >> 56), + byte(x >> 48), + byte(x >> 40), + byte(x >> 32), + byte(x >> 24), + byte(x >> 16), + byte(x >> 8), + byte(x), + } + return append(b, a[:]...) +} + +func readUint64(b []byte) uint64 { + _ = b[7] + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} diff --git a/libgo/go/hash/fnv/fnv_test.go b/libgo/go/hash/fnv/fnv_test.go index 7da15ba9e82..7b1f7a32eaa 100644 --- a/libgo/go/hash/fnv/fnv_test.go +++ b/libgo/go/hash/fnv/fnv_test.go @@ -6,56 +6,59 @@ package fnv import ( "bytes" + "encoding" "encoding/binary" "hash" + "io" "testing" ) type golden struct { - sum []byte - text string + out []byte + in string + halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal } var golden32 = []golden{ - {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""}, - {[]byte{0x05, 0x0c, 0x5d, 0x7e}, "a"}, - {[]byte{0x70, 0x77, 0x2d, 0x38}, "ab"}, - {[]byte{0x43, 0x9c, 0x2f, 0x4b}, "abc"}, + {[]byte{0x81, 0x1c, 0x9d, 0xc5}, "", "fnv\x01\x81\x1c\x9d\xc5"}, + {[]byte{0x05, 0x0c, 0x5d, 0x7e}, "a", "fnv\x01\x81\x1c\x9d\xc5"}, + {[]byte{0x70, 0x77, 0x2d, 0x38}, "ab", "fnv\x01\x05\f]~"}, + {[]byte{0x43, 0x9c, 0x2f, 0x4b}, "abc", "fnv\x01\x05\f]~"}, } var golden32a = []golden{ - {[]byte{0x81, 0x1c, 0x9d, 0xc5}, ""}, - {[]byte{0xe4, 0x0c, 0x29, 0x2c}, "a"}, - {[]byte{0x4d, 0x25, 0x05, 0xca}, "ab"}, - {[]byte{0x1a, 0x47, 0xe9, 0x0b}, "abc"}, + {[]byte{0x81, 0x1c, 0x9d, 0xc5}, "", "fnv\x02\x81\x1c\x9d\xc5"}, + {[]byte{0xe4, 0x0c, 0x29, 0x2c}, "a", "fnv\x02\x81\x1c\x9d\xc5"}, + {[]byte{0x4d, 0x25, 0x05, 0xca}, "ab", "fnv\x02\xe4\f),"}, + {[]byte{0x1a, 0x47, 0xe9, 0x0b}, "abc", "fnv\x02\xe4\f),"}, } var golden64 = []golden{ - {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""}, - {[]byte{0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe}, "a"}, - {[]byte{0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8}, "ab"}, - {[]byte{0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb}, "abc"}, + {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, "", "fnv\x03\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0xaf, 0x63, 0xbd, 0x4c, 0x86, 0x01, 0xb7, 0xbe}, "a", "fnv\x03\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0x08, 0x32, 0x67, 0x07, 0xb4, 0xeb, 0x37, 0xb8}, "ab", "fnv\x03\xafc\xbdL\x86\x01\xb7\xbe"}, + {[]byte{0xd8, 0xdc, 0xca, 0x18, 0x6b, 0xaf, 0xad, 0xcb}, "abc", "fnv\x03\xafc\xbdL\x86\x01\xb7\xbe"}, } var golden64a = []golden{ - {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, ""}, - {[]byte{0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c}, "a"}, - {[]byte{0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a}, "ab"}, - {[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc"}, + {[]byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}, "", "fnv\x04\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0xaf, 0x63, 0xdc, 0x4c, 0x86, 0x01, 0xec, 0x8c}, "a", "fnv\x04\xcb\xf2\x9c\xe4\x84\"#%"}, + {[]byte{0x08, 0x9c, 0x44, 0x07, 0xb5, 0x45, 0x98, 0x6a}, "ab", "fnv\x04\xafc\xdcL\x86\x01\xec\x8c"}, + {[]byte{0xe7, 0x1f, 0xa2, 0x19, 0x05, 0x41, 0x57, 0x4b}, "abc", "fnv\x04\xafc\xdcL\x86\x01\xec\x8c"}, } var golden128 = []golden{ - {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""}, - {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e}, "a"}, - {[]byte{0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88}, "ab"}, - {[]byte{0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b}, "abc"}, + {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, "", "fnv\x05lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x10, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x14, 0x1e}, "a", "fnv\x05lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0x8, 0x80, 0x94, 0x5a, 0xee, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0x26, 0xc0, 0x88}, "ab", "fnv\x05\xd2(\xcbi\x10\x1a\x8c\xafx\x91+pNJ\x14\x1e"}, + {[]byte{0xa6, 0x8b, 0xb2, 0xa4, 0x34, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x78, 0xc6, 0xae, 0xe7, 0x3b}, "abc", "fnv\x05\xd2(\xcbi\x10\x1a\x8c\xafx\x91+pNJ\x14\x1e"}, } var golden128a = []golden{ - {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, ""}, - {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64}, "a"}, - {[]byte{0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62}, "ab"}, - {[]byte{0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b}, "abc"}, + {[]byte{0x6c, 0x62, 0x27, 0x2e, 0x07, 0xbb, 0x01, 0x42, 0x62, 0xb8, 0x21, 0x75, 0x62, 0x95, 0xc5, 0x8d}, "", "fnv\x06lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0xd2, 0x28, 0xcb, 0x69, 0x6f, 0x1a, 0x8c, 0xaf, 0x78, 0x91, 0x2b, 0x70, 0x4e, 0x4a, 0x89, 0x64}, "a", "fnv\x06lb'.\a\xbb\x01Bb\xb8!ub\x95ō"}, + {[]byte{0x08, 0x80, 0x95, 0x44, 0xbb, 0xab, 0x1b, 0xe9, 0x5a, 0xa0, 0x73, 0x30, 0x55, 0xb6, 0x9a, 0x62}, "ab", "fnv\x06\xd2(\xcbio\x1a\x8c\xafx\x91+pNJ\x89d"}, + {[]byte{0xa6, 0x8d, 0x62, 0x2c, 0xec, 0x8b, 0x58, 0x22, 0x83, 0x6d, 0xbc, 0x79, 0x77, 0xaf, 0x7f, 0x3b}, "abc", "fnv\x06\xd2(\xcbio\x1a\x8c\xafx\x91+pNJ\x89d"}, } func TestGolden32(t *testing.T) { @@ -85,19 +88,67 @@ func TestGolden128a(t *testing.T) { func testGolden(t *testing.T, hash hash.Hash, gold []golden) { for _, g := range gold { hash.Reset() - done, error := hash.Write([]byte(g.text)) + done, error := hash.Write([]byte(g.in)) if error != nil { t.Fatalf("write error: %s", error) } - if done != len(g.text) { - t.Fatalf("wrote only %d out of %d bytes", done, len(g.text)) + if done != len(g.in) { + t.Fatalf("wrote only %d out of %d bytes", done, len(g.in)) } - if actual := hash.Sum(nil); !bytes.Equal(g.sum, actual) { - t.Errorf("hash(%q) = 0x%x want 0x%x", g.text, actual, g.sum) + if actual := hash.Sum(nil); !bytes.Equal(g.out, actual) { + t.Errorf("hash(%q) = 0x%x want 0x%x", g.in, actual, g.out) } } } +func TestGoldenMarshal(t *testing.T) { + tests := []struct { + name string + newHash func() hash.Hash + gold []golden + }{ + {"32", func() hash.Hash { return New32() }, golden32}, + {"32a", func() hash.Hash { return New32a() }, golden32a}, + {"64", func() hash.Hash { return New64() }, golden64}, + {"64a", func() hash.Hash { return New64a() }, golden64a}, + {"128", func() hash.Hash { return New128() }, golden128}, + {"128a", func() hash.Hash { return New128a() }, golden128a}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, g := range tt.gold { + h := tt.newHash() + h2 := tt.newHash() + + io.WriteString(h, g.in[:len(g.in)/2]) + + state, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Errorf("could not marshal: %v", err) + continue + } + + if string(state) != g.halfState { + t.Errorf("checksum(%q) state = %q, want %q", g.in, state, g.halfState) + continue + } + + if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil { + t.Errorf("could not unmarshal: %v", err) + continue + } + + io.WriteString(h, g.in[len(g.in)/2:]) + io.WriteString(h2, g.in[len(g.in)/2:]) + + if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) { + t.Errorf("hash(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2) + } + } + }) + } +} + func TestIntegrity32(t *testing.T) { testIntegrity(t, New32()) } diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go index 8d138d07f93..62cf6a45184 100644 --- a/libgo/go/hash/hash.go +++ b/libgo/go/hash/hash.go @@ -8,6 +8,21 @@ package hash import "io" // Hash is the common interface implemented by all hash functions. +// +// Hash implementations in the standard library (e.g. hash/crc32 and +// crypto/sha256) implement the encoding.BinaryMarshaler and +// encoding.BinaryUnmarshaler interfaces. Marshaling a hash implementation +// allows its internal state to be saved and used for additional processing +// later, without having to re-write the data previously written to the hash. +// The hash state may contain portions of the input in its original form, +// which users are expected to handle for any possible security implications. +// +// Compatibility: Any future changes to hash or crypto packages will endeavor +// to maintain compatibility with state encoded using previous versions. +// That is, any released versions of the packages should be able to +// decode data written with any previously released version, +// subject to issues such as security fixes. +// See the Go compatibility document for background: https://golang.org/doc/go1compat type Hash interface { // Write (via the embedded io.Writer interface) adds more data to the running hash. // It never returns an error. diff --git a/libgo/go/hash/marshal_test.go b/libgo/go/hash/marshal_test.go new file mode 100644 index 00000000000..3091f7a67ac --- /dev/null +++ b/libgo/go/hash/marshal_test.go @@ -0,0 +1,107 @@ +// Copyright 2017 The Go 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 the hashes in the standard library implement +// BinaryMarshaler, BinaryUnmarshaler, +// and lock in the current representations. + +package hash_test + +import ( + "bytes" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding" + "encoding/hex" + "hash" + "hash/adler32" + "hash/crc32" + "hash/crc64" + "hash/fnv" + "testing" +) + +func fromHex(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +var marshalTests = []struct { + name string + new func() hash.Hash + golden []byte +}{ + {"adler32", func() hash.Hash { return adler32.New() }, fromHex("61646c01460a789d")}, + {"crc32", func() hash.Hash { return crc32.NewIEEE() }, fromHex("63726301ca87914dc956d3e8")}, + {"crc64", func() hash.Hash { return crc64.New(crc64.MakeTable(crc64.ISO)) }, fromHex("6372630273ba8484bbcd5def5d51c83c581695be")}, + {"fnv32", func() hash.Hash { return fnv.New32() }, fromHex("666e760171ba3d77")}, + {"fnv32a", func() hash.Hash { return fnv.New32a() }, fromHex("666e76027439f86f")}, + {"fnv64", func() hash.Hash { return fnv.New64() }, fromHex("666e7603cc64e0e97692c637")}, + {"fnv64a", func() hash.Hash { return fnv.New64a() }, fromHex("666e7604c522af9b0dede66f")}, + {"fnv128", func() hash.Hash { return fnv.New128() }, fromHex("666e760561587a70a0f66d7981dc980e2cabbaf7")}, + {"fnv128a", func() hash.Hash { return fnv.New128a() }, fromHex("666e7606a955802b0136cb67622b461d9f91e6ff")}, + {"md5", md5.New, fromHex("6d643501a91b0023007aa14740a3979210b5f024c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha1", sha1.New, fromHex("736861016dad5acb4dc003952f7a0b352ee5537ec381a228c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha224", sha256.New224, fromHex("73686102f8b92fc047c9b4d82f01a6370841277b7a0d92108440178c83db855a8e66c2d9c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha256", sha256.New, fromHex("736861032bed68b99987cae48183b2b049d393d0050868e4e8ba3730e9112b08765929b7c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha384", sha512.New384, fromHex("736861046f1664d213dd802f7c47bc50637cf93592570a2b8695839148bf38341c6eacd05326452ef1cbe64d90f1ef73bb5ac7d2803565467d0ddb10c5ee3fc050f9f0c1808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512_224", sha512.New512_224, fromHex("736861056f1a450ec15af20572d0d1ee6518104d7cbbbe79a038557af5450ed7dbd420b53b7335209e951b4d9aff401f90549b9604fa3d823fbb8581c73582a88aa84022808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512_256", sha512.New512_256, fromHex("736861067c541f1d1a72536b1f5dad64026bcc7c508f8a2126b51f46f8b9bff63a26fee70980718031e96832e95547f4fe76160ff84076db53b4549b86354af8e17b5116808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, + {"sha512", sha512.New, fromHex("736861078e03953cd57cd6879321270afa70c5827bb5b69be59a8f0130147e94f2aedf7bdc01c56c92343ca8bd837bb7f0208f5a23e155694516b6f147099d491a30b151808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f80000000000000000000000000000f9")}, +} + +func TestMarshalHash(t *testing.T) { + for _, tt := range marshalTests { + t.Run(tt.name, func(t *testing.T) { + buf := make([]byte, 256) + for i := range buf { + buf[i] = byte(i) + } + + h := tt.new() + h.Write(buf[:256]) + sum := h.Sum(nil) + + h2 := tt.new() + h3 := tt.new() + const split = 249 + for i := 0; i < split; i++ { + h2.Write(buf[i : i+1]) + } + h2m, ok := h2.(encoding.BinaryMarshaler) + if !ok { + t.Fatalf("Hash does not implement MarshalBinary") + } + enc, err := h2m.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + if !bytes.Equal(enc, tt.golden) { + t.Errorf("MarshalBinary = %x, want %x", enc, tt.golden) + } + h3u, ok := h3.(encoding.BinaryUnmarshaler) + if !ok { + t.Fatalf("Hash does not implement UnmarshalBinary") + } + if err := h3u.UnmarshalBinary(enc); err != nil { + t.Fatalf("UnmarshalBinary: %v", err) + } + h2.Write(buf[split:]) + h3.Write(buf[split:]) + sum2 := h2.Sum(nil) + sum3 := h3.Sum(nil) + if !bytes.Equal(sum2, sum) { + t.Fatalf("Sum after MarshalBinary = %x, want %x", sum2, sum) + } + if !bytes.Equal(sum3, sum) { + t.Fatalf("Sum after UnmarshalBinary = %x, want %x", sum3, sum) + } + }) + } +} diff --git a/libgo/go/html/entity.go b/libgo/go/html/entity.go index af8a007ed04..dfeaf6cabc7 100644 --- a/libgo/go/html/entity.go +++ b/libgo/go/html/entity.go @@ -8,7 +8,7 @@ package html const longestEntityWithoutSemicolon = 6 // entity is a map from HTML entity names to their values. The semicolon matters: -// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html +// https://html.spec.whatwg.org/multipage/named-characters.html // lists both "amp" and "amp;" as two separate entries. // // Note that the HTML5 list is larger than the HTML4 list at diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go index f5a4ce17364..92f12ca0e07 100644 --- a/libgo/go/html/template/escape_test.go +++ b/libgo/go/html/template/escape_test.go @@ -1840,7 +1840,7 @@ func TestErrorOnUndefined(t *testing.T) { err := tmpl.Execute(nil, nil) if err == nil { - t.Error("expected error") + t.Fatal("expected error") } if !strings.Contains(err.Error(), "incomplete") { t.Errorf("expected error about incomplete template; got %s", err) @@ -1860,10 +1860,10 @@ func TestIdempotentExecute(t *testing.T) { for i := 0; i < 2; i++ { err = tmpl.ExecuteTemplate(got, "hello", nil) if err != nil { - t.Errorf("unexpected error: %s", err) + t.Fatalf("unexpected error: %s", err) } if got.String() != want { - t.Errorf("after executing template \"hello\", got:\n\t%q\nwant:\n\t%q\n", got.String(), want) + t.Fatalf("after executing template \"hello\", got:\n\t%q\nwant:\n\t%q\n", got.String(), want) } got.Reset() } @@ -1871,7 +1871,7 @@ func TestIdempotentExecute(t *testing.T) { // "main" does not cause the output of "hello" to change. err = tmpl.ExecuteTemplate(got, "main", nil) if err != nil { - t.Errorf("unexpected error: %s", err) + t.Fatalf("unexpected error: %s", err) } // If the HTML escaper is added again to the action {{"Ladies & Gentlemen!"}}, // we would expected to see the ampersand overescaped to "&amp;". @@ -1881,6 +1881,19 @@ func TestIdempotentExecute(t *testing.T) { } } +// This covers issue #21844. +func TestAddExistingTreeError(t *testing.T) { + tmpl := Must(New("foo").Parse(`

{{.}}

`)) + tmpl, err := tmpl.AddParseTree("bar", tmpl.Tree) + if err == nil { + t.Fatalf("expected error after AddParseTree") + } + const want = `html/template: cannot add parse tree that template "foo" already references` + if got := err.Error(); got != want { + t.Errorf("got error:\n\t%q\nwant:\n\t%q\n", got, want) + } +} + func BenchmarkEscapedExecute(b *testing.B) { tmpl := Must(New("t").Parse(`{{.}}`)) var buf bytes.Buffer diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go index 6a661bf6e5d..d77aa3d7df3 100644 --- a/libgo/go/html/template/template.go +++ b/libgo/go/html/template/template.go @@ -219,6 +219,11 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error t.nameSpace.mu.Lock() defer t.nameSpace.mu.Unlock() + for _, tmpl := range t.set { + if tmpl.Tree == tree { + return nil, fmt.Errorf("html/template: cannot add parse tree that template %q already references", tmpl.Name()) + } + } text, err := t.text.AddParseTree(name, tree) if err != nil { return nil, err diff --git a/libgo/go/html/template/url.go b/libgo/go/html/template/url.go index 02123b2cccd..a0bfe7672e3 100644 --- a/libgo/go/html/template/url.go +++ b/libgo/go/html/template/url.go @@ -10,8 +10,28 @@ import ( "strings" ) -// urlFilter returns its input unless it contains an unsafe protocol in which +// urlFilter returns its input unless it contains an unsafe scheme in which // case it defangs the entire URL. +// +// Schemes that cause unintended side effects that are irreversible without user +// interaction are considered unsafe. For example, clicking on a "javascript:" +// link can immediately trigger JavaScript code execution. +// +// This filter conservatively assumes that all schemes other than the following +// are unsafe: +// * http: Navigates to a new website, and may open a new window or tab. +// These side effects can be reversed by navigating back to the +// previous website, or closing the window or tab. No irreversible +// changes will take place without further user interaction with +// the new website. +// * https: Same as http. +// * mailto: Opens an email program and starts a new draft. This side effect +// is not irreversible until the user explicitly clicks send; it +// can be undone by closing the email program. +// +// To allow URLs containing other schemes to bypass this filter, developers must +// explicitly indicate that such a URL is expected and safe by encapsulating it +// in a template.URL value. func urlFilter(args ...interface{}) string { s, t := stringify(args...) if t == contentTypeURL { diff --git a/libgo/go/image/color/color.go b/libgo/go/image/color/color.go index 0832c597293..88958391404 100644 --- a/libgo/go/image/color/color.go +++ b/libgo/go/image/color/color.go @@ -200,7 +200,7 @@ func nrgbaModel(c Color) Color { if a == 0 { return NRGBA{0, 0, 0, 0} } - // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a. + // Since Color.RGBA returns an alpha-premultiplied color, we should have r <= a && g <= a && b <= a. r = (r * 0xffff) / a g = (g * 0xffff) / a b = (b * 0xffff) / a @@ -218,7 +218,7 @@ func nrgba64Model(c Color) Color { if a == 0 { return NRGBA64{0, 0, 0, 0} } - // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a. + // Since Color.RGBA returns an alpha-premultiplied color, we should have r <= a && g <= a && b <= a. r = (r * 0xffff) / a g = (g * 0xffff) / a b = (b * 0xffff) / a @@ -312,12 +312,29 @@ func (p Palette) Index(c Color) int { // // x and y are both assumed to be in the range [0, 0xffff]. func sqDiff(x, y uint32) uint32 { - var d uint32 - if x > y { - d = x - y - } else { - d = y - x - } + // The canonical code of this function looks as follows: + // + // var d uint32 + // if x > y { + // d = x - y + // } else { + // d = y - x + // } + // return (d * d) >> 2 + // + // Language spec guarantees the following properties of unsigned integer + // values operations with respect to overflow/wrap around: + // + // > For unsigned integer values, the operations +, -, *, and << are + // > computed modulo 2n, where n is the bit width of the unsigned + // > integer's type. Loosely speaking, these unsigned integer operations + // > discard high bits upon overflow, and programs may rely on ``wrap + // > around''. + // + // Considering these properties and the fact that this function is + // called in the hot paths (x,y loops), it is reduced to the below code + // which is slightly faster. See TestSqDiff for correctness check. + d := x - y return (d * d) >> 2 } diff --git a/libgo/go/image/color/color_test.go b/libgo/go/image/color/color_test.go new file mode 100644 index 00000000000..ea66b7bef23 --- /dev/null +++ b/libgo/go/image/color/color_test.go @@ -0,0 +1,47 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package color + +import ( + "testing" + "testing/quick" +) + +func TestSqDiff(t *testing.T) { + // canonical sqDiff implementation + orig := func(x, y uint32) uint32 { + var d uint32 + if x > y { + d = uint32(x - y) + } else { + d = uint32(y - x) + } + return (d * d) >> 2 + } + testCases := []uint32{ + 0, + 1, + 2, + 0x0fffd, + 0x0fffe, + 0x0ffff, + 0x10000, + 0x10001, + 0x10002, + 0xfffffffd, + 0xfffffffe, + 0xffffffff, + } + for _, x := range testCases { + for _, y := range testCases { + if got, want := sqDiff(x, y), orig(x, y); got != want { + t.Fatalf("sqDiff(%#x, %#x): got %d, want %d", x, y, got, want) + } + } + } + if err := quick.CheckEqual(orig, sqDiff, &quick.Config{MaxCountScale: 10}); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go index a31dd427ce1..977d7c52215 100644 --- a/libgo/go/image/draw/draw.go +++ b/libgo/go/image/draw/draw.go @@ -564,12 +564,10 @@ func clamp(i int32) int32 { // // x and y are both assumed to be in the range [0, 0xffff]. func sqDiff(x, y int32) uint32 { - var d uint32 - if x > y { - d = uint32(x - y) - } else { - d = uint32(y - x) - } + // This is an optimized code relying on the overflow/wrap around + // properties of unsigned integers operations guaranteed by the language + // spec. See sqDiff from the image/color package for more details. + d := uint32(x - y) return (d * d) >> 2 } @@ -603,6 +601,18 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, quantErrorCurr = make([][4]int32, r.Dx()+2) quantErrorNext = make([][4]int32, r.Dx()+2) } + pxRGBA := func(x, y int) (r, g, b, a uint32) { return src.At(x, y).RGBA() } + // Fast paths for special cases to avoid excessive use of the color.Color + // interface which escapes to the heap but need to be discovered for + // each pixel on r. See also https://golang.org/issues/15759. + switch src0 := src.(type) { + case *image.RGBA: + pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.RGBAAt(x, y).RGBA() } + case *image.NRGBA: + pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.NRGBAAt(x, y).RGBA() } + case *image.YCbCr: + pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.YCbCrAt(x, y).RGBA() } + } // Loop over each source pixel. out := color.RGBA64{A: 0xffff} @@ -610,7 +620,7 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, for x := 0; x != r.Dx(); x++ { // er, eg and eb are the pixel's R,G,B values plus the // optional Floyd-Steinberg error. - sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA() + sr, sg, sb, sa := pxRGBA(sp.X+x, sp.Y+y) er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa) if floydSteinberg { er = clamp(er + quantErrorCurr[x+1][0]/16) diff --git a/libgo/go/image/draw/draw_test.go b/libgo/go/image/draw/draw_test.go index a58f0f49849..dea51b6bc50 100644 --- a/libgo/go/image/draw/draw_test.go +++ b/libgo/go/image/draw/draw_test.go @@ -10,6 +10,7 @@ import ( "image/png" "os" "testing" + "testing/quick" ) func eq(c0, c1 color.Color) bool { @@ -467,3 +468,47 @@ loop: } } } + +func TestSqDiff(t *testing.T) { + // This test is similar to the one from the image/color package, but + // sqDiff in this package accepts int32 instead of uint32, so test it + // for appropriate input. + + // canonical sqDiff implementation + orig := func(x, y int32) uint32 { + var d uint32 + if x > y { + d = uint32(x - y) + } else { + d = uint32(y - x) + } + return (d * d) >> 2 + } + testCases := []int32{ + 0, + 1, + 2, + 0x0fffd, + 0x0fffe, + 0x0ffff, + 0x10000, + 0x10001, + 0x10002, + 0x7ffffffd, + 0x7ffffffe, + 0x7fffffff, + -0x7ffffffd, + -0x7ffffffe, + -0x80000000, + } + for _, x := range testCases { + for _, y := range testCases { + if got, want := sqDiff(x, y), orig(x, y); got != want { + t.Fatalf("sqDiff(%#x, %#x): got %d, want %d", x, y, got, want) + } + } + } + if err := quick.CheckEqual(orig, sqDiff, &quick.Config{MaxCountScale: 10}); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go index b1335e61259..c1c9562067d 100644 --- a/libgo/go/image/gif/reader.go +++ b/libgo/go/image/gif/reader.go @@ -109,48 +109,114 @@ type decoder struct { tmp [1024]byte // must be at least 768 so we can read color table } -// blockReader parses the block structure of GIF image data, which -// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the -// reader given to the LZW decoder, which is thus immune to the -// blocking. After the LZW decoder completes, there will be a 0-byte -// block remaining (0, ()), which is consumed when checking that the -// blockReader is exhausted. +// blockReader parses the block structure of GIF image data, which comprises +// (n, (n bytes)) blocks, with 1 <= n <= 255. It is the reader given to the +// LZW decoder, which is thus immune to the blocking. After the LZW decoder +// completes, there will be a 0-byte block remaining (0, ()), which is +// consumed when checking that the blockReader is exhausted. +// +// To avoid the allocation of a bufio.Reader for the lzw Reader, blockReader +// implements io.ReadByte and buffers blocks into the decoder's "tmp" buffer. type blockReader struct { - r reader - slice []byte - err error - tmp [256]byte + d *decoder + i, j uint8 // d.tmp[i:j] contains the buffered bytes + err error } -func (b *blockReader) Read(p []byte) (int, error) { +func (b *blockReader) fill() { if b.err != nil { - return 0, b.err + return + } + b.j, b.err = readByte(b.d.r) + if b.j == 0 && b.err == nil { + b.err = io.EOF + } + if b.err != nil { + return } - if len(p) == 0 { - return 0, nil + + b.i = 0 + b.err = readFull(b.d.r, b.d.tmp[:b.j]) + if b.err != nil { + b.j = 0 } - if len(b.slice) == 0 { - var blockLen uint8 - blockLen, b.err = b.r.ReadByte() +} + +func (b *blockReader) ReadByte() (byte, error) { + if b.i == b.j { + b.fill() if b.err != nil { return 0, b.err } - if blockLen == 0 { - b.err = io.EOF - return 0, b.err - } - b.slice = b.tmp[:blockLen] - if b.err = readFull(b.r, b.slice); b.err != nil { + } + + c := b.d.tmp[b.i] + b.i++ + return c, nil +} + +// blockReader must implement io.Reader, but its Read shouldn't ever actually +// be called in practice. The compress/lzw package will only call ReadByte. +func (b *blockReader) Read(p []byte) (int, error) { + if len(p) == 0 || b.err != nil { + return 0, b.err + } + if b.i == b.j { + b.fill() + if b.err != nil { return 0, b.err } } - n := copy(p, b.slice) - b.slice = b.slice[n:] + + n := copy(p, b.d.tmp[b.i:b.j]) + b.i += uint8(n) return n, nil } +// close primarily detects whether or not a block terminator was encountered +// after reading a sequence of data sub-blocks. It allows at most one trailing +// sub-block worth of data. I.e., if some number of bytes exist in one sub-block +// following the end of LZW data, the very next sub-block must be the block +// terminator. If the very end of LZW data happened to fill one sub-block, at +// most one more sub-block of length 1 may exist before the block-terminator. +// These accomodations allow us to support GIFs created by less strict encoders. +// See https://golang.org/issue/16146. +func (b *blockReader) close() error { + if b.err == io.EOF { + // A clean block-sequence terminator was encountered while reading. + return nil + } else if b.err != nil { + // Some other error was encountered while reading. + return b.err + } + + if b.i == b.j { + // We reached the end of a sub block reading LZW data. We'll allow at + // most one more sub block of data with a length of 1 byte. + b.fill() + if b.err == io.EOF { + return nil + } else if b.err != nil { + return b.err + } else if b.j > 1 { + return errTooMuch + } + } + + // Part of a sub-block remains buffered. We expect that the next attempt to + // buffer a sub-block will reach the block terminator. + b.fill() + if b.err == io.EOF { + return nil + } else if b.err != nil { + return b.err + } + + return errTooMuch +} + // decode reads a GIF image from r and stores the result in d. -func (d *decoder) decode(r io.Reader, configOnly bool) error { +func (d *decoder) decode(r io.Reader, configOnly, keepAllFrames bool) error { // Add buffering if r does not provide ReadByte. if rr, ok := r.(reader); ok { d.r = rr @@ -178,115 +244,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { } case sImageDescriptor: - m, err := d.newImageFromDescriptor() - if err != nil { + if err = d.readImageDescriptor(keepAllFrames); err != nil { return err } - useLocalColorTable := d.imageFields&fColorTable != 0 - if useLocalColorTable { - m.Palette, err = d.readColorTable(d.imageFields) - if err != nil { - return err - } - } else { - if d.globalColorTable == nil { - return errors.New("gif: no color table") - } - m.Palette = d.globalColorTable - } - if d.hasTransparentIndex { - if !useLocalColorTable { - // Clone the global color table. - m.Palette = append(color.Palette(nil), d.globalColorTable...) - } - if ti := int(d.transparentIndex); ti < len(m.Palette) { - m.Palette[ti] = color.RGBA{} - } else { - // The transparentIndex is out of range, which is an error - // according to the spec, but Firefox and Google Chrome - // seem OK with this, so we enlarge the palette with - // transparent colors. See golang.org/issue/15059. - p := make(color.Palette, ti+1) - copy(p, m.Palette) - for i := len(m.Palette); i < len(p); i++ { - p[i] = color.RGBA{} - } - m.Palette = p - } - } - litWidth, err := readByte(d.r) - if err != nil { - return fmt.Errorf("gif: reading image data: %v", err) - } - if litWidth < 2 || litWidth > 8 { - return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth) - } - // A wonderfully Go-like piece of magic. - br := &blockReader{r: d.r} - lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth)) - defer lzwr.Close() - if err = readFull(lzwr, m.Pix); err != nil { - if err != io.ErrUnexpectedEOF { - return fmt.Errorf("gif: reading image data: %v", err) - } - return errNotEnough - } - // In theory, both lzwr and br should be exhausted. Reading from them - // should yield (0, io.EOF). - // - // The spec (Appendix F - Compression), says that "An End of - // Information code... must be the last code output by the encoder - // for an image". In practice, though, giflib (a widely used C - // library) does not enforce this, so we also accept lzwr returning - // io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF - // before the LZW decoder saw an explicit end code), provided that - // the io.ReadFull call above successfully read len(m.Pix) bytes. - // See https://golang.org/issue/9856 for an example GIF. - if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) { - if err != nil { - return fmt.Errorf("gif: reading image data: %v", err) - } - return errTooMuch - } - - // In practice, some GIFs have an extra byte in the data sub-block - // stream, which we ignore. See https://golang.org/issue/16146. - for nExtraBytes := 0; ; { - n, err := br.Read(d.tmp[:2]) - nExtraBytes += n - if nExtraBytes > 1 { - return errTooMuch - } - if err == io.EOF { - break - } - if err != nil { - return fmt.Errorf("gif: reading image data: %v", err) - } - } - - // Check that the color indexes are inside the palette. - if len(m.Palette) < 256 { - for _, pixel := range m.Pix { - if int(pixel) >= len(m.Palette) { - return errBadPixel - } - } - } - - // Undo the interlacing if necessary. - if d.imageFields&fInterlace != 0 { - uninterlace(m) - } - - d.image = append(d.image, m) - d.delay = append(d.delay, d.delayTime) - d.disposal = append(d.disposal, d.disposalMethod) - // The GIF89a spec, Section 23 (Graphic Control Extension) says: - // "The scope of this extension is the first graphic rendering block - // to follow." We therefore reset the GCE fields to zero. - d.delayTime = 0 - d.hasTransparentIndex = false case sTrailer: if len(d.image) == 0 { @@ -410,6 +370,113 @@ func (d *decoder) readGraphicControl() error { return nil } +func (d *decoder) readImageDescriptor(keepAllFrames bool) error { + m, err := d.newImageFromDescriptor() + if err != nil { + return err + } + useLocalColorTable := d.imageFields&fColorTable != 0 + if useLocalColorTable { + m.Palette, err = d.readColorTable(d.imageFields) + if err != nil { + return err + } + } else { + if d.globalColorTable == nil { + return errors.New("gif: no color table") + } + m.Palette = d.globalColorTable + } + if d.hasTransparentIndex { + if !useLocalColorTable { + // Clone the global color table. + m.Palette = append(color.Palette(nil), d.globalColorTable...) + } + if ti := int(d.transparentIndex); ti < len(m.Palette) { + m.Palette[ti] = color.RGBA{} + } else { + // The transparentIndex is out of range, which is an error + // according to the spec, but Firefox and Google Chrome + // seem OK with this, so we enlarge the palette with + // transparent colors. See golang.org/issue/15059. + p := make(color.Palette, ti+1) + copy(p, m.Palette) + for i := len(m.Palette); i < len(p); i++ { + p[i] = color.RGBA{} + } + m.Palette = p + } + } + litWidth, err := readByte(d.r) + if err != nil { + return fmt.Errorf("gif: reading image data: %v", err) + } + if litWidth < 2 || litWidth > 8 { + return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth) + } + // A wonderfully Go-like piece of magic. + br := &blockReader{d: d} + lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth)) + defer lzwr.Close() + if err = readFull(lzwr, m.Pix); err != nil { + if err != io.ErrUnexpectedEOF { + return fmt.Errorf("gif: reading image data: %v", err) + } + return errNotEnough + } + // In theory, both lzwr and br should be exhausted. Reading from them + // should yield (0, io.EOF). + // + // The spec (Appendix F - Compression), says that "An End of + // Information code... must be the last code output by the encoder + // for an image". In practice, though, giflib (a widely used C + // library) does not enforce this, so we also accept lzwr returning + // io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF + // before the LZW decoder saw an explicit end code), provided that + // the io.ReadFull call above successfully read len(m.Pix) bytes. + // See https://golang.org/issue/9856 for an example GIF. + if n, err := lzwr.Read(d.tmp[256:257]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) { + if err != nil { + return fmt.Errorf("gif: reading image data: %v", err) + } + return errTooMuch + } + + // In practice, some GIFs have an extra byte in the data sub-block + // stream, which we ignore. See https://golang.org/issue/16146. + if err := br.close(); err == errTooMuch { + return errTooMuch + } else if err != nil { + return fmt.Errorf("gif: reading image data: %v", err) + } + + // Check that the color indexes are inside the palette. + if len(m.Palette) < 256 { + for _, pixel := range m.Pix { + if int(pixel) >= len(m.Palette) { + return errBadPixel + } + } + } + + // Undo the interlacing if necessary. + if d.imageFields&fInterlace != 0 { + uninterlace(m) + } + + if keepAllFrames || len(d.image) == 0 { + d.image = append(d.image, m) + d.delay = append(d.delay, d.delayTime) + d.disposal = append(d.disposal, d.disposalMethod) + } + // The GIF89a spec, Section 23 (Graphic Control Extension) says: + // "The scope of this extension is the first graphic rendering block + // to follow." We therefore reset the GCE fields to zero. + d.delayTime = 0 + d.hasTransparentIndex = false + return nil +} + func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) { if err := readFull(d.r, d.tmp[:9]); err != nil { return nil, fmt.Errorf("gif: can't read image descriptor: %s", err) @@ -491,7 +558,7 @@ func uninterlace(m *image.Paletted) { // image as an image.Image. func Decode(r io.Reader) (image.Image, error) { var d decoder - if err := d.decode(r, false); err != nil { + if err := d.decode(r, false, false); err != nil { return nil, err } return d.image[0], nil @@ -526,7 +593,7 @@ type GIF struct { // and timing information. func DecodeAll(r io.Reader) (*GIF, error) { var d decoder - if err := d.decode(r, false); err != nil { + if err := d.decode(r, false, true); err != nil { return nil, err } gif := &GIF{ @@ -548,7 +615,7 @@ func DecodeAll(r io.Reader) (*GIF, error) { // without decoding the entire image. func DecodeConfig(r io.Reader) (image.Config, error) { var d decoder - if err := d.decode(r, true); err != nil { + if err := d.decode(r, true, false); err != nil { return image.Config{}, err } return image.Config{ diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go index 51c64b7328f..220e8f52d48 100644 --- a/libgo/go/image/gif/reader_test.go +++ b/libgo/go/image/gif/reader_test.go @@ -9,7 +9,12 @@ import ( "compress/lzw" "image" "image/color" + "image/color/palette" + "io" + "io/ioutil" "reflect" + "runtime" + "runtime/debug" "strings" "testing" ) @@ -23,6 +28,9 @@ const ( trailerStr = "\x3b" ) +// lzw.NewReader wants a io.ByteReader, this ensures we're compatible. +var _ io.ByteReader = (*blockReader)(nil) + // lzwEncode returns an LZW encoding (with 2-bit literals) of in. func lzwEncode(in []byte) []byte { b := &bytes.Buffer{} @@ -66,6 +74,9 @@ func TestDecode(t *testing.T) { {2, 1, 0, nil}, // Two extra bytes after LZW data, but inside the same data sub-block. {2, 2, 0, nil}, + // Extra data exists in the final sub-block with LZW data, AND there is + // a bogus sub-block following. + {2, 1, 1, errTooMuch}, } for _, tc := range testCases { b := &bytes.Buffer{} @@ -342,3 +353,50 @@ func TestUnexpectedEOF(t *testing.T) { } } } + +// See golang.org/issue/22237 +func TestDecodeMemoryConsumption(t *testing.T) { + const frames = 3000 + img := image.NewPaletted(image.Rectangle{Max: image.Point{1, 1}}, palette.WebSafe) + hugeGIF := &GIF{ + Image: make([]*image.Paletted, frames), + Delay: make([]int, frames), + Disposal: make([]byte, frames), + } + for i := 0; i < frames; i++ { + hugeGIF.Image[i] = img + hugeGIF.Delay[i] = 60 + } + buf := new(bytes.Buffer) + if err := EncodeAll(buf, hugeGIF); err != nil { + t.Fatal("EncodeAll:", err) + } + s0, s1 := new(runtime.MemStats), new(runtime.MemStats) + runtime.GC() + defer debug.SetGCPercent(debug.SetGCPercent(5)) + runtime.ReadMemStats(s0) + if _, err := Decode(buf); err != nil { + t.Fatal("Decode:", err) + } + runtime.ReadMemStats(s1) + if heapDiff := int64(s1.HeapAlloc - s0.HeapAlloc); heapDiff > 30<<20 { + t.Fatalf("Decode of %d frames increased heap by %dMB", frames, heapDiff>>20) + } +} + +func BenchmarkDecode(b *testing.B) { + data, err := ioutil.ReadFile("../testdata/video-001.gif") + if err != nil { + b.Fatal(err) + } + cfg, err := DecodeConfig(bytes.NewReader(data)) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(cfg.Width * cfg.Height)) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + Decode(bytes.NewReader(data)) + } +} diff --git a/libgo/go/image/gif/writer.go b/libgo/go/image/gif/writer.go index 493c7549eb2..f26af8be478 100644 --- a/libgo/go/image/gif/writer.go +++ b/libgo/go/image/gif/writer.go @@ -70,25 +70,54 @@ type blockWriter struct { e *encoder } -func (b blockWriter) Write(data []byte) (int, error) { +func (b blockWriter) setup() { + b.e.buf[0] = 0 +} + +func (b blockWriter) Flush() error { + return b.e.err +} + +func (b blockWriter) WriteByte(c byte) error { if b.e.err != nil { - return 0, b.e.err + return b.e.err } - if len(data) == 0 { - return 0, nil + + // Append c to buffered sub-block. + b.e.buf[0]++ + b.e.buf[b.e.buf[0]] = c + if b.e.buf[0] < 255 { + return nil } - total := 0 - for total < len(data) { - n := copy(b.e.buf[1:256], data[total:]) - total += n - b.e.buf[0] = uint8(n) - _, b.e.err = b.e.w.Write(b.e.buf[:n+1]) - if b.e.err != nil { - return 0, b.e.err + // Flush block + b.e.write(b.e.buf[:256]) + b.e.buf[0] = 0 + return b.e.err +} + +// blockWriter must be an io.Writer for lzw.NewWriter, but this is never +// actually called. +func (b blockWriter) Write(data []byte) (int, error) { + for i, c := range data { + if err := b.WriteByte(c); err != nil { + return i, err } } - return total, b.e.err + return len(data), nil +} + +func (b blockWriter) close() { + // Write the block terminator (0x00), either by itself, or along with a + // pending sub-block. + if b.e.buf[0] == 0 { + b.e.writeByte(0) + } else { + n := uint(b.e.buf[0]) + b.e.buf[n+1] = 0 + b.e.write(b.e.buf[:n+2]) + } + b.e.flush() } func (e *encoder) flush() { @@ -171,27 +200,44 @@ func encodeColorTable(dst []byte, p color.Palette, size int) (int, error) { if uint(size) >= uint(len(log2Lookup)) { return 0, errors.New("gif: cannot encode color table with more than 256 entries") } - n := log2Lookup[size] - for i := 0; i < n; i++ { - if i < len(p) { - c := p[i] - if c == nil { - return 0, errors.New("gif: cannot encode color table with nil entries") - } - r, g, b, _ := c.RGBA() - dst[3*i+0] = uint8(r >> 8) - dst[3*i+1] = uint8(g >> 8) - dst[3*i+2] = uint8(b >> 8) + for i, c := range p { + if c == nil { + return 0, errors.New("gif: cannot encode color table with nil entries") + } + var r, g, b uint8 + // It is most likely that the palette is full of color.RGBAs, so they + // get a fast path. + if rgba, ok := c.(color.RGBA); ok { + r, g, b = rgba.R, rgba.G, rgba.B } else { - // Pad with black. - dst[3*i+0] = 0x00 - dst[3*i+1] = 0x00 - dst[3*i+2] = 0x00 + rr, gg, bb, _ := c.RGBA() + r, g, b = uint8(rr>>8), uint8(gg>>8), uint8(bb>>8) + } + dst[3*i+0] = r + dst[3*i+1] = g + dst[3*i+2] = b + } + n := log2Lookup[size] + if n > len(p) { + // Pad with black. + fill := dst[3*len(p) : 3*n] + for i := range fill { + fill[i] = 0 } } return 3 * n, nil } +func (e *encoder) colorTablesMatch(localLen, transparentIndex int) bool { + localSize := 3 * localLen + if transparentIndex >= 0 { + trOff := 3 * transparentIndex + return bytes.Equal(e.globalColorTable[:trOff], e.localColorTable[:trOff]) && + bytes.Equal(e.globalColorTable[trOff+3:localSize], e.localColorTable[trOff+3:localSize]) + } + return bytes.Equal(e.globalColorTable[:localSize], e.localColorTable[:localSize]) +} + func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) { if e.err != nil { return @@ -251,19 +297,31 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) writeUint16(e.buf[7:9], uint16(b.Dy())) e.write(e.buf[:9]) + // To determine whether or not this frame's palette is the same as the + // global palette, we can check a couple things. First, do they actually + // point to the same []color.Color? If so, they are equal so long as the + // frame's palette is not longer than the global palette... paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n). - if ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize); err != nil { - if e.err == nil { - e.err = err - } - return - } else if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) { - // Use a local color table. - e.writeByte(fColorTable | uint8(paddedSize)) - e.write(e.localColorTable[:ct]) + if gp, ok := e.g.Config.ColorModel.(color.Palette); ok && len(pm.Palette) <= len(gp) && &gp[0] == &pm.Palette[0] { + e.writeByte(0) // Use the global color table. } else { - // Use the global color table. - e.writeByte(0) + ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize) + if err != nil { + if e.err == nil { + e.err = err + } + return + } + // This frame's palette is not the very same slice as the global + // palette, but it might be a copy, possibly with one value turned into + // transparency by DecodeAll. + if ct <= e.globalCT && e.colorTablesMatch(len(pm.Palette), transparentIndex) { + e.writeByte(0) // Use the global color table. + } else { + // Use a local color table. + e.writeByte(fColorTable | uint8(paddedSize)) + e.write(e.localColorTable[:ct]) + } } litWidth := paddedSize + 1 @@ -272,7 +330,9 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) } e.writeByte(uint8(litWidth)) // LZW Minimum Code Size. - lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth) + bw := blockWriter{e: e} + bw.setup() + lzww := lzw.NewWriter(bw, lzw.LSB, litWidth) if dx := b.Dx(); dx == pm.Stride { _, e.err = lzww.Write(pm.Pix[:dx*b.Dy()]) if e.err != nil { @@ -288,8 +348,8 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) } } } - lzww.Close() - e.writeByte(0x00) // Block Terminator. + lzww.Close() // flush to bw + bw.close() // flush to e.w } // Options are the encoding parameters. diff --git a/libgo/go/image/gif/writer_test.go b/libgo/go/image/gif/writer_test.go index 1bba9b8ece5..69042ec6743 100644 --- a/libgo/go/image/gif/writer_test.go +++ b/libgo/go/image/gif/writer_test.go @@ -64,6 +64,10 @@ func averageDelta(m0, m1 image.Image) int64 { return sum / n } +// lzw.NewWriter wants an interface which is basically the same thing as gif's +// writer interface. This ensures we're compatible. +var _ writer = blockWriter{} + var testCase = []struct { filename string tolerance int64 @@ -471,6 +475,35 @@ func TestEncodeBadPalettes(t *testing.T) { } } +func TestColorTablesMatch(t *testing.T) { + const trIdx = 100 + global := color.Palette(palette.Plan9) + if rgb := global[trIdx].(color.RGBA); rgb.R == 0 && rgb.G == 0 && rgb.B == 0 { + t.Fatalf("trIdx (%d) is already black", trIdx) + } + + // Make a copy of the palette, substituting trIdx's slot with transparent, + // just like decoder.decode. + local := append(color.Palette(nil), global...) + local[trIdx] = color.RGBA{} + + const testLen = 3 * 256 + const padded = 7 + e := new(encoder) + if l, err := encodeColorTable(e.globalColorTable[:], global, padded); err != nil || l != testLen { + t.Fatalf("Failed to encode global color table: got %d, %v; want nil, %d", l, err, testLen) + } + if l, err := encodeColorTable(e.localColorTable[:], local, padded); err != nil || l != testLen { + t.Fatalf("Failed to encode local color table: got %d, %v; want nil, %d", l, err, testLen) + } + if bytes.Equal(e.globalColorTable[:testLen], e.localColorTable[:testLen]) { + t.Fatal("Encoded color tables are equal, expected mismatch") + } + if !e.colorTablesMatch(len(local), trIdx) { + t.Fatal("colorTablesMatch() == false, expected true") + } +} + func TestEncodeCroppedSubImages(t *testing.T) { // This test means to ensure that Encode honors the Bounds and Strides of // images correctly when encoding. @@ -500,8 +533,6 @@ func TestEncodeCroppedSubImages(t *testing.T) { } func BenchmarkEncode(b *testing.B) { - b.StopTimer() - bo := image.Rect(0, 0, 640, 480) rnd := rand.New(rand.NewSource(123)) @@ -523,14 +554,14 @@ func BenchmarkEncode(b *testing.B) { } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img, nil) } } func BenchmarkQuantizedEncode(b *testing.B) { - b.StopTimer() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) bo := img.Bounds() rnd := rand.New(rand.NewSource(123)) @@ -545,7 +576,8 @@ func BenchmarkQuantizedEncode(b *testing.B) { } } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img, nil) } diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go index 77376152bc0..a62b509234e 100644 --- a/libgo/go/image/jpeg/reader_test.go +++ b/libgo/go/image/jpeg/reader_test.go @@ -323,7 +323,6 @@ func TestExtraneousData(t *testing.T) { } func benchmarkDecode(b *testing.B, filename string) { - b.StopTimer() data, err := ioutil.ReadFile(filename) if err != nil { b.Fatal(err) @@ -333,7 +332,8 @@ func benchmarkDecode(b *testing.B, filename string) { b.Fatal(err) } b.SetBytes(int64(cfg.Width * cfg.Height * 4)) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Decode(bytes.NewReader(data)) } diff --git a/libgo/go/image/jpeg/writer_test.go b/libgo/go/image/jpeg/writer_test.go index a6c056174bd..3aff7426325 100644 --- a/libgo/go/image/jpeg/writer_test.go +++ b/libgo/go/image/jpeg/writer_test.go @@ -243,7 +243,6 @@ func TestEncodeYCbCr(t *testing.T) { } func BenchmarkEncodeRGBA(b *testing.B) { - b.StopTimer() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) bo := img.Bounds() rnd := rand.New(rand.NewSource(123)) @@ -258,7 +257,8 @@ func BenchmarkEncodeRGBA(b *testing.B) { } } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() options := &Options{Quality: 90} for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img, options) @@ -266,7 +266,6 @@ func BenchmarkEncodeRGBA(b *testing.B) { } func BenchmarkEncodeYCbCr(b *testing.B) { - b.StopTimer() img := image.NewYCbCr(image.Rect(0, 0, 640, 480), image.YCbCrSubsampleRatio420) bo := img.Bounds() rnd := rand.New(rand.NewSource(123)) @@ -280,7 +279,8 @@ func BenchmarkEncodeYCbCr(b *testing.B) { } } b.SetBytes(640 * 480 * 3) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() options := &Options{Quality: 90} for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img, options) diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go index 4f043a0e424..4fbcef84b7c 100644 --- a/libgo/go/image/png/reader.go +++ b/libgo/go/image/png/reader.go @@ -157,6 +157,7 @@ func (d *decoder) parseIHDR(length uint32) error { return FormatError("invalid interlace method") } d.interlace = int(d.tmp[12]) + w := int32(binary.BigEndian.Uint32(d.tmp[0:4])) h := int32(binary.BigEndian.Uint32(d.tmp[4:8])) if w <= 0 || h <= 0 { @@ -166,6 +167,11 @@ func (d *decoder) parseIHDR(length uint32) error { if nPixels != int64(int(nPixels)) { return UnsupportedError("dimension overflow") } + // There can be up to 8 bytes per pixel, for 16 bits per channel RGBA. + if nPixels != (nPixels*8)/8 { + return UnsupportedError("dimension overflow") + } + d.cb = cbInvalid d.depth = int(d.tmp[8]) switch d.depth { diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go index cabf533adcd..66bcfcb437e 100644 --- a/libgo/go/image/png/reader_test.go +++ b/libgo/go/image/png/reader_test.go @@ -589,7 +589,7 @@ func TestUnknownChunkLengthUnderflow(t *testing.T) { } func TestGray8Transparent(t *testing.T) { - // These bytes come from https://github.com/golang/go/issues/19553 + // These bytes come from https://golang.org/issues/19553 m, err := Decode(bytes.NewReader([]byte{ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88, @@ -649,21 +649,38 @@ func TestGray8Transparent(t *testing.T) { } } +func TestDimensionOverflow(t *testing.T) { + // These bytes come from https://golang.org/issues/22304 + // + // It encodes a 2147483646 × 2147483646 (i.e. 0x7ffffffe × 0x7ffffffe) + // NRGBA image. The (width × height) per se doesn't overflow an int64, but + // (width × height × bytesPerPixel) will. + _, err := Decode(bytes.NewReader([]byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x08, 0x06, 0x00, 0x00, 0x00, 0x30, 0x57, 0xb3, + 0xfd, 0x00, 0x00, 0x00, 0x15, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x62, 0x20, 0x12, 0x8c, + 0x2a, 0xa4, 0xb3, 0x42, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x13, 0x38, 0x00, 0x15, 0x2d, 0xef, + 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + })) + if _, ok := err.(UnsupportedError); !ok { + t.Fatalf("Decode: got %v (of type %T), want non-nil error (of type png.UnsupportedError)", err, err) + } +} + func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) { - b.StopTimer() data, err := ioutil.ReadFile(filename) if err != nil { b.Fatal(err) } - s := string(data) - cfg, err := DecodeConfig(strings.NewReader(s)) + cfg, err := DecodeConfig(bytes.NewReader(data)) if err != nil { b.Fatal(err) } b.SetBytes(int64(cfg.Width * cfg.Height * bytesPerPixel)) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { - Decode(strings.NewReader(s)) + Decode(bytes.NewReader(data)) } } diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go index b1f97b1d7bf..1107ea0e7fc 100644 --- a/libgo/go/image/png/writer_test.go +++ b/libgo/go/image/png/writer_test.go @@ -121,10 +121,10 @@ func TestSubImage(t *testing.T) { } func BenchmarkEncodeGray(b *testing.B) { - b.StopTimer() img := image.NewGray(image.Rect(0, 0, 640, 480)) b.SetBytes(640 * 480 * 1) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } @@ -143,20 +143,19 @@ func (p *pool) Put(b *EncoderBuffer) { } func BenchmarkEncodeGrayWithBufferPool(b *testing.B) { - b.StopTimer() img := image.NewGray(image.Rect(0, 0, 640, 480)) e := Encoder{ BufferPool: &pool{}, } b.SetBytes(640 * 480 * 1) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { e.Encode(ioutil.Discard, img) } } func BenchmarkEncodeNRGBOpaque(b *testing.B) { - b.StopTimer() img := image.NewNRGBA(image.Rect(0, 0, 640, 480)) // Set all pixels to 0xFF alpha to force opaque mode. bo := img.Bounds() @@ -169,40 +168,40 @@ func BenchmarkEncodeNRGBOpaque(b *testing.B) { b.Fatal("expected image to be opaque") } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } } func BenchmarkEncodeNRGBA(b *testing.B) { - b.StopTimer() img := image.NewNRGBA(image.Rect(0, 0, 640, 480)) if img.Opaque() { b.Fatal("expected image not to be opaque") } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } } func BenchmarkEncodePaletted(b *testing.B) { - b.StopTimer() img := image.NewPaletted(image.Rect(0, 0, 640, 480), color.Palette{ color.RGBA{0, 0, 0, 255}, color.RGBA{255, 255, 255, 255}, }) b.SetBytes(640 * 480 * 1) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } } func BenchmarkEncodeRGBOpaque(b *testing.B) { - b.StopTimer() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) // Set all pixels to 0xFF alpha to force opaque mode. bo := img.Bounds() @@ -215,20 +214,21 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) { b.Fatal("expected image to be opaque") } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } } func BenchmarkEncodeRGBA(b *testing.B) { - b.StopTimer() img := image.NewRGBA(image.Rect(0, 0, 640, 480)) if img.Opaque() { b.Fatal("expected image not to be opaque") } b.SetBytes(640 * 480 * 4) - b.StartTimer() + b.ReportAllocs() + b.ResetTimer() for i := 0; i < b.N; i++ { Encode(ioutil.Discard, img) } diff --git a/libgo/go/internal/cpu/cpu.go b/libgo/go/internal/cpu/cpu.go index 2226b777e23..22fc561002d 100644 --- a/libgo/go/internal/cpu/cpu.go +++ b/libgo/go/internal/cpu/cpu.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package cpu implements processor feature detection -// used by the Go standard libary. +// used by the Go standard library. package cpu var X86 x86 @@ -15,11 +15,13 @@ var X86 x86 type x86 struct { _ [CacheLineSize]byte HasAES bool + HasADX bool HasAVX bool HasAVX2 bool HasBMI1 bool HasBMI2 bool HasERMS bool + HasFMA bool HasOSXSAVE bool HasPCLMULQDQ bool HasPOPCNT bool @@ -30,3 +32,46 @@ type x86 struct { HasSSE42 bool _ [CacheLineSize]byte } + +var PPC64 ppc64 + +// For ppc64x, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (darn, scv), so there are capability bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07), so we +// maintain some of the old capability checks for optional categories for +// safety. +// The struct is padded to avoid false sharing. +type ppc64 struct { + _ [CacheLineSize]byte + HasVMX bool // Vector unit (Altivec) + HasDFP bool // Decimal Floating Point unit + HasVSX bool // Vector-scalar unit + HasHTM bool // Hardware Transactional Memory + HasISEL bool // Integer select + HasVCRYPTO bool // Vector cryptography + HasHTMNOSC bool // HTM: kernel-aborted transaction in syscalls + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ [CacheLineSize]byte +} + +var ARM64 arm64 + +// The booleans in arm64 contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +type arm64 struct { + _ [CacheLineSize]byte + HasFP bool + HasASIMD bool + HasEVTSTRM bool + HasAES bool + HasPMULL bool + HasSHA1 bool + HasSHA2 bool + HasCRC32 bool + HasATOMICS bool + _ [CacheLineSize]byte +} diff --git a/libgo/go/internal/cpu/cpu_arm64.go b/libgo/go/internal/cpu/cpu_arm64.go index 078a6c3b80a..e1278a147a1 100644 --- a/libgo/go/internal/cpu/cpu_arm64.go +++ b/libgo/go/internal/cpu/cpu_arm64.go @@ -2,6 +2,44 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build arm64 + package cpu -const CacheLineSize = 32 +const CacheLineSize = 64 + +// arm64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. +// These are linknamed in runtime/os_linux_arm64.go and are initialized by +// archauxv(). +var arm64_hwcap uint +var arm64_hwcap2 uint + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + _ARM64_FEATURE_HAS_FP = (1 << 0) + _ARM64_FEATURE_HAS_ASIMD = (1 << 1) + _ARM64_FEATURE_HAS_EVTSTRM = (1 << 2) + _ARM64_FEATURE_HAS_AES = (1 << 3) + _ARM64_FEATURE_HAS_PMULL = (1 << 4) + _ARM64_FEATURE_HAS_SHA1 = (1 << 5) + _ARM64_FEATURE_HAS_SHA2 = (1 << 6) + _ARM64_FEATURE_HAS_CRC32 = (1 << 7) + _ARM64_FEATURE_HAS_ATOMICS = (1 << 8) +) + +func init() { + // HWCAP feature bits + ARM64.HasFP = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_FP) + ARM64.HasASIMD = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_ASIMD) + ARM64.HasEVTSTRM = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_EVTSTRM) + ARM64.HasAES = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_AES) + ARM64.HasPMULL = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_PMULL) + ARM64.HasSHA1 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_SHA1) + ARM64.HasSHA2 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_SHA2) + ARM64.HasCRC32 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_CRC32) + ARM64.HasATOMICS = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_ATOMICS) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/libgo/go/internal/cpu/cpu_ppc64x.go b/libgo/go/internal/cpu/cpu_ppc64x.go new file mode 100644 index 00000000000..7f093723b2f --- /dev/null +++ b/libgo/go/internal/cpu/cpu_ppc64x.go @@ -0,0 +1,54 @@ +// Copyright 2017 The Go 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 ppc64 ppc64le + +package cpu + +const CacheLineSize = 128 + +// ppc64x doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. +// These are linknamed in runtime/os_linux_ppc64x.go and are initialized by +// archauxv(). +var ppc64x_hwcap uint +var ppc64x_hwcap2 uint + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 + _PPC_FEATURE_HAS_DFP = 0x00000400 + _PPC_FEATURE_HAS_VSX = 0x00000080 + _PPC_FEATURE2_HAS_HTM = 0x40000000 + _PPC_FEATURE2_HAS_ISEL = 0x08000000 + _PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000 + _PPC_FEATURE2_HTM_NOSC = 0x01000000 + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func init() { + // HWCAP feature bits + PPC64.HasVMX = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_ALTIVEC) + PPC64.HasDFP = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_DFP) + PPC64.HasVSX = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_VSX) + + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(ppc64x_hwcap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.HasHTM = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_HTM) + PPC64.HasISEL = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_ISEL) + PPC64.HasVCRYPTO = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_VEC_CRYPTO) + PPC64.HasHTMNOSC = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HTM_NOSC) + PPC64.IsPOWER9 = isSet(ppc64x_hwcap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(ppc64x_hwcap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(ppc64x_hwcap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/libgo/go/internal/cpu/cpu_test.go b/libgo/go/internal/cpu/cpu_test.go index ab9836ac2f6..07b0243f306 100644 --- a/libgo/go/internal/cpu/cpu_test.go +++ b/libgo/go/internal/cpu/cpu_test.go @@ -25,3 +25,26 @@ func TestAVX2hasAVX(t *testing.T) { } } } + +func TestPPC64minimalFeatures(t *testing.T) { + if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { + if !cpu.PPC64.IsPOWER8 { + t.Fatalf("IsPOWER8 expected true, got false") + } + if !cpu.PPC64.HasVMX { + t.Fatalf("HasVMX expected true, got false") + } + if !cpu.PPC64.HasDFP { + t.Fatalf("HasDFP expected true, got false") + } + if !cpu.PPC64.HasVSX { + t.Fatalf("HasVSX expected true, got false") + } + if !cpu.PPC64.HasISEL { + t.Fatalf("HasISEL expected true, got false") + } + if !cpu.PPC64.HasVCRYPTO { + t.Fatalf("HasVCRYPTO expected true, got false") + } + } +} diff --git a/libgo/go/internal/cpu/cpu_x86.go b/libgo/go/internal/cpu/cpu_x86.go index 31e7084e78b..34c632f2f99 100644 --- a/libgo/go/internal/cpu/cpu_x86.go +++ b/libgo/go/internal/cpu/cpu_x86.go @@ -15,9 +15,9 @@ func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) func xgetbv() (eax, edx uint32) func init() { - maxId, _, _, _ := cpuid(0, 0) + maxID, _, _, _ := cpuid(0, 0) - if maxId < 1 { + if maxID < 1 { return } @@ -27,6 +27,7 @@ func init() { X86.HasSSE3 = isSet(0, ecx1) X86.HasPCLMULQDQ = isSet(1, ecx1) X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) X86.HasSSE41 = isSet(19, ecx1) X86.HasSSE42 = isSet(20, ecx1) X86.HasPOPCNT = isSet(23, ecx1) @@ -43,7 +44,7 @@ func init() { X86.HasAVX = isSet(28, ecx1) && osSupportsAVX - if maxId < 7 { + if maxID < 7 { return } @@ -52,6 +53,7 @@ func init() { X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX X86.HasBMI2 = isSet(8, ebx7) X86.HasERMS = isSet(9, ebx7) + X86.HasADX = isSet(19, ebx7) } func isSet(bitpos uint, value uint32) bool { diff --git a/libgo/go/internal/poll/export_windows_test.go b/libgo/go/internal/poll/export_windows_test.go new file mode 100644 index 00000000000..88ed71ad84a --- /dev/null +++ b/libgo/go/internal/poll/export_windows_test.go @@ -0,0 +1,17 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Export guts for testing on windows. +// Since testing imports os and os imports internal/poll, +// the internal/poll tests can not be in package poll. + +package poll + +var ( + LogInitFD = &logInitFD +) + +func (fd *FD) IsPartOfNetpoll() bool { + return fd.pd.runtimeCtx != 0 +} diff --git a/libgo/go/internal/poll/fd.go b/libgo/go/internal/poll/fd.go index f1454dba908..2567746106f 100644 --- a/libgo/go/internal/poll/fd.go +++ b/libgo/go/internal/poll/fd.go @@ -21,6 +21,10 @@ var ErrNetClosing = errors.New("use of closed network connection") // has been closed. var ErrFileClosing = errors.New("use of closed file") +// ErrNoDeadline is returned when a request is made to set a deadline +// on a file type that does not use the poller. +var ErrNoDeadline = errors.New("file type does not support deadline") + // Return the appropriate closing error based on isFile. func errClosing(isFile bool) error { if isFile { diff --git a/libgo/go/internal/poll/fd_poll_runtime.go b/libgo/go/internal/poll/fd_poll_runtime.go index 9de8af1598d..b91cbe40e48 100644 --- a/libgo/go/internal/poll/fd_poll_runtime.go +++ b/libgo/go/internal/poll/fd_poll_runtime.go @@ -147,11 +147,11 @@ func setDeadlineImpl(fd *FD, t time.Time, mode int) error { if err := fd.incref(); err != nil { return err } + defer fd.decref() if fd.pd.runtimeCtx == 0 { - return errors.New("file type does not support deadlines") + return ErrNoDeadline } runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode) - fd.decref() return nil } diff --git a/libgo/go/internal/poll/fd_unix.go b/libgo/go/internal/poll/fd_unix.go index 0b43a19590b..4148d40c847 100644 --- a/libgo/go/internal/poll/fd_unix.go +++ b/libgo/go/internal/poll/fd_unix.go @@ -8,6 +8,7 @@ package poll import ( "io" + "runtime" "syscall" ) @@ -26,6 +27,9 @@ type FD struct { // Writev cache. iovecs *[]syscall.Iovec + // Semaphore signaled when file is closed. + csema uint32 + // Whether this is a streaming descriptor, as opposed to a // packet-based descriptor like a UDP socket. Immutable. IsStream bool @@ -42,6 +46,7 @@ type FD struct { // This can be called multiple times on a single FD. // The net argument is a network name from the net package (e.g., "tcp"), // or "file". +// Set pollable to true if fd should be managed by runtime netpoll. func (fd *FD) Init(net string, pollable bool) error { // We don't actually care about the various network types. if net == "file" { @@ -61,6 +66,7 @@ func (fd *FD) destroy() error { fd.pd.close() err := CloseFunc(fd.Sysfd) fd.Sysfd = -1 + runtime_Semrelease(&fd.csema) return err } @@ -78,7 +84,11 @@ func (fd *FD) Close() error { fd.pd.evict() // The call to decref will call destroy if there are no other // references. - return fd.decref() + err := fd.decref() + // Wait until the descriptor is closed. If this was the only + // reference, it is already closed. + runtime_Semacquire(&fd.csema) + return err } // Shutdown wraps the shutdown network call. @@ -126,6 +136,12 @@ func (fd *FD) Read(p []byte) (int, error) { continue } } + + // On MacOS we can see EINTR here if the user + // pressed ^Z. See issue #22838. + if runtime.GOOS == "darwin" && err == syscall.EINTR { + continue + } } err = fd.eofError(n, err) return n, err @@ -402,6 +418,15 @@ func (fd *FD) WaitWrite() error { return fd.pd.waitWrite(fd.isFile) } +// WriteOnce is for testing only. It makes a single write call. +func (fd *FD) WriteOnce(p []byte) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + return syscall.Write(fd.Sysfd, p) +} + // RawControl invokes the user-defined function f for a non-IO // operation. func (fd *FD) RawControl(f func(uintptr)) error { diff --git a/libgo/go/internal/poll/fd_windows.go b/libgo/go/internal/poll/fd_windows.go index 655f9348c62..187908bc834 100644 --- a/libgo/go/internal/poll/fd_windows.go +++ b/libgo/go/internal/poll/fd_windows.go @@ -7,6 +7,7 @@ package poll import ( "errors" "internal/race" + "internal/syscall/windows" "io" "runtime" "sync" @@ -31,11 +32,40 @@ var ( // package uses CancelIoEx API, if present, otherwise it fallback // to CancelIo. -var ( - canCancelIO bool // determines if CancelIoEx API is present - skipSyncNotif bool - hasLoadSetFileCompletionNotificationModes bool -) +var canCancelIO bool // determines if CancelIoEx API is present + +// This package uses SetFileCompletionNotificationModes Windows API +// to skip calling GetQueuedCompletionStatus if an IO operation completes +// synchronously. Unfortuently SetFileCompletionNotificationModes is not +// available on Windows XP. Also there is a known bug where +// SetFileCompletionNotificationModes crashes on some systems +// (see http://support.microsoft.com/kb/2568167 for details). + +var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use + +// checkSetFileCompletionNotificationModes verifies that +// SetFileCompletionNotificationModes Windows API is present +// on the system and is safe to use. +// See http://support.microsoft.com/kb/2568167 for details. +func checkSetFileCompletionNotificationModes() { + err := syscall.LoadSetFileCompletionNotificationModes() + if err != nil { + return + } + protos := [2]int32{syscall.IPPROTO_TCP, 0} + var buf [32]syscall.WSAProtocolInfo + len := uint32(unsafe.Sizeof(buf)) + n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) + if err != nil { + return + } + for i := int32(0); i < n; i++ { + if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { + return + } + } + useSetFileCompletionNotificationModes = true +} func init() { var d syscall.WSAData @@ -44,26 +74,7 @@ func init() { initErr = e } canCancelIO = syscall.LoadCancelIoEx() == nil - hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil - if hasLoadSetFileCompletionNotificationModes { - // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed: - // http://support.microsoft.com/kb/2568167 - skipSyncNotif = true - protos := [2]int32{syscall.IPPROTO_TCP, 0} - var buf [32]syscall.WSAProtocolInfo - len := uint32(unsafe.Sizeof(buf)) - n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) - if err != nil { - skipSyncNotif = false - } else { - for i := int32(0); i < n; i++ { - if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { - skipSyncNotif = false - break - } - } - } - } + checkSetFileCompletionNotificationModes() } // operation contains superset of data necessary to perform all async IO. @@ -82,6 +93,7 @@ type operation struct { fd *FD errc chan error buf syscall.WSABuf + msg windows.WSAMsg sa syscall.Sockaddr rsa *syscall.RawSockaddrAny rsan int32 @@ -122,6 +134,22 @@ func (o *operation) ClearBufs() { o.bufs = o.bufs[:0] } +func (o *operation) InitMsg(p []byte, oob []byte) { + o.InitBuf(p) + o.msg.Buffers = &o.buf + o.msg.BufferCount = 1 + + o.msg.Name = nil + o.msg.Namelen = 0 + + o.msg.Flags = 0 + o.msg.Control.Len = uint32(len(oob)) + o.msg.Control.Buf = nil + if len(oob) != 0 { + o.msg.Control.Buf = &oob[0] + } +} + // ioSrv executes net IO requests. type ioSrv struct { req chan ioSrvReq @@ -278,6 +306,9 @@ type FD struct { readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8 readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read + // Semaphore signaled when file is closed. + csema uint32 + skipSyncNotif bool // Whether this is a streaming descriptor, as opposed to a @@ -295,11 +326,15 @@ type FD struct { isDir bool } +// logInitFD is set by tests to enable file descriptor initialization logging. +var logInitFD func(net string, fd *FD, err error) + // Init initializes the FD. The Sysfd field should already be set. // This can be called multiple times on a single FD. // The net argument is a network name from the net package (e.g., "tcp"), // or "file" or "console" or "dir". -func (fd *FD) Init(net string) (string, error) { +// Set pollable to true if fd should be managed by runtime netpoll. +func (fd *FD) Init(net string, pollable bool) (string, error) { if initErr != nil { return "", initErr } @@ -319,7 +354,8 @@ func (fd *FD) Init(net string) (string, error) { return "", errors.New("internal error: unknown network type " + net) } - if !fd.isFile && !fd.isConsole && !fd.isDir { + var err error + if pollable { // Only call init for a network socket. // This means that we don't add files to the runtime poller. // Adding files to the runtime poller can confuse matters @@ -331,16 +367,20 @@ func (fd *FD) Init(net string) (string, error) { // somehow call ExecIO, then ExecIO, and therefore the // calling method, will return an error, because // fd.pd.runtimeCtx will be 0. - if err := fd.pd.init(fd); err != nil { - return "", err - } + err = fd.pd.init(fd) + } + if logInitFD != nil { + logInitFD(net, fd, err) } - if hasLoadSetFileCompletionNotificationModes { + if err != nil { + return "", err + } + if pollable && useSetFileCompletionNotificationModes { // We do not use events, so we can skip them always. flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) // It's not safe to skip completion notifications for UDP: // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx - if skipSyncNotif && (net == "tcp" || net == "file") { + if net == "tcp" { flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS } err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags) @@ -390,6 +430,7 @@ func (fd *FD) destroy() error { err = CloseFunc(fd.Sysfd) } fd.Sysfd = syscall.InvalidHandle + runtime_Semrelease(&fd.csema) return err } @@ -401,7 +442,11 @@ func (fd *FD) Close() error { } // unblock pending reader and writer fd.pd.evict() - return fd.decref() + err := fd.decref() + // Wait until the descriptor is closed. If this was the only + // reference, it is already closed. + runtime_Semacquire(&fd.csema) + return err } // Shutdown wraps the shutdown network call. @@ -871,3 +916,77 @@ func (fd *FD) RawRead(f func(uintptr) bool) error { func (fd *FD) RawWrite(f func(uintptr) bool) error { return errors.New("not implemented") } + +func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) { + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + var raw syscall.RawSockaddrInet4 + raw.Family = syscall.AF_INET + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + for i := 0; i < len(sa.Addr); i++ { + raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil + case *syscall.SockaddrInet6: + var raw syscall.RawSockaddrInet6 + raw.Family = syscall.AF_INET6 + p := (*[2]byte)(unsafe.Pointer(&raw.Port)) + p[0] = byte(sa.Port >> 8) + p[1] = byte(sa.Port) + raw.Scope_id = sa.ZoneId + for i := 0; i < len(sa.Addr); i++ { + raw.Addr[i] = sa.Addr[i] + } + return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil + default: + return nil, 0, syscall.EWINDOWS + } +} + +// ReadMsg wraps the WSARecvMsg network call. +func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) { + if err := fd.readLock(); err != nil { + return 0, 0, 0, nil, err + } + defer fd.readUnlock() + + o := &fd.rop + o.InitMsg(p, oob) + o.rsa = new(syscall.RawSockaddrAny) + o.msg.Name = o.rsa + o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa)) + n, err := rsrv.ExecIO(o, func(o *operation) error { + return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil) + }) + err = fd.eofError(n, err) + var sa syscall.Sockaddr + if err == nil { + sa, err = o.rsa.Sockaddr() + } + return n, int(o.msg.Control.Len), int(o.msg.Flags), sa, err +} + +// WriteMsg wraps the WSASendMsg network call. +func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) { + if err := fd.writeLock(); err != nil { + return 0, 0, err + } + defer fd.writeUnlock() + + o := &fd.wop + o.InitMsg(p, oob) + if sa != nil { + rsa, len, err := sockaddrToRaw(sa) + if err != nil { + return 0, 0, err + } + o.msg.Name = (*syscall.RawSockaddrAny)(rsa) + o.msg.Namelen = len + } + n, err := wsrv.ExecIO(o, func(o *operation) error { + return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil) + }) + return n, int(o.msg.Control.Len), err +} diff --git a/libgo/go/internal/poll/fd_windows_test.go b/libgo/go/internal/poll/fd_windows_test.go new file mode 100644 index 00000000000..e3ca0e26acd --- /dev/null +++ b/libgo/go/internal/poll/fd_windows_test.go @@ -0,0 +1,111 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll_test + +import ( + "fmt" + "internal/poll" + "os" + "sync" + "syscall" + "testing" +) + +type loggedFD struct { + Net string + FD *poll.FD + Err error +} + +var ( + logMu sync.Mutex + loggedFDs map[syscall.Handle]*loggedFD +) + +func logFD(net string, fd *poll.FD, err error) { + logMu.Lock() + defer logMu.Unlock() + + loggedFDs[fd.Sysfd] = &loggedFD{ + Net: net, + FD: fd, + Err: err, + } +} + +func init() { + loggedFDs = make(map[syscall.Handle]*loggedFD) + *poll.LogInitFD = logFD +} + +func findLoggedFD(h syscall.Handle) (lfd *loggedFD, found bool) { + logMu.Lock() + defer logMu.Unlock() + + lfd, found = loggedFDs[h] + return lfd, found +} + +// checkFileIsNotPartOfNetpoll verifies that f is not managed by netpoll. +// It returns error, if check fails. +func checkFileIsNotPartOfNetpoll(f *os.File) error { + lfd, found := findLoggedFD(syscall.Handle(f.Fd())) + if !found { + return fmt.Errorf("%v fd=%v: is not found in the log", f.Name(), f.Fd()) + } + if lfd.FD.IsPartOfNetpoll() { + return fmt.Errorf("%v fd=%v: is part of netpoll, but should not be (logged: net=%v err=%v)", f.Name(), f.Fd(), lfd.Net, lfd.Err) + } + return nil +} + +func TestFileFdsAreInitialised(t *testing.T) { + exe, err := os.Executable() + if err != nil { + t.Fatal(err) + } + f, err := os.Open(exe) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + err = checkFileIsNotPartOfNetpoll(f) + if err != nil { + t.Fatal(err) + } +} + +func TestSerialFdsAreInitialised(t *testing.T) { + for _, name := range []string{"COM1", "COM2", "COM3", "COM4"} { + t.Run(name, func(t *testing.T) { + h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name), + syscall.GENERIC_READ|syscall.GENERIC_WRITE, + 0, + nil, + syscall.OPEN_EXISTING, + syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED, + 0) + if err != nil { + if errno, ok := err.(syscall.Errno); ok { + switch errno { + case syscall.ERROR_FILE_NOT_FOUND, + syscall.ERROR_ACCESS_DENIED: + t.Log("Skipping: ", err) + return + } + } + t.Fatal(err) + } + f := os.NewFile(uintptr(h), name) + defer f.Close() + + err = checkFileIsNotPartOfNetpoll(f) + if err != nil { + t.Fatal(err) + } + }) + } +} diff --git a/libgo/go/internal/poll/sendfile_windows.go b/libgo/go/internal/poll/sendfile_windows.go index c1a2d6d1765..4a15b752366 100644 --- a/libgo/go/internal/poll/sendfile_windows.go +++ b/libgo/go/internal/poll/sendfile_windows.go @@ -8,6 +8,15 @@ import "syscall" // SendFile wraps the TransmitFile call. func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) { + ft, err := syscall.GetFileType(src) + if err != nil { + return 0, err + } + // TransmitFile does not work with pipes + if ft == syscall.FILE_TYPE_PIPE { + return 0, syscall.ESPIPE + } + if err := fd.writeLock(); err != nil { return 0, err } diff --git a/libgo/go/internal/poll/sockoptip.go b/libgo/go/internal/poll/sockoptip.go index ae59b0c7627..c55a1e3c5b1 100644 --- a/libgo/go/internal/poll/sockoptip.go +++ b/libgo/go/internal/poll/sockoptip.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 aix darwin dragonfly freebsd linux netbsd openbsd windows +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package poll diff --git a/libgo/go/internal/syscall/windows/exec_windows_test.go b/libgo/go/internal/syscall/windows/exec_windows_test.go new file mode 100644 index 00000000000..94fd95b2bc5 --- /dev/null +++ b/libgo/go/internal/syscall/windows/exec_windows_test.go @@ -0,0 +1,152 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package windows_test + +import ( + "fmt" + "internal/syscall/windows" + "os" + "os/exec" + "syscall" + "testing" + "unsafe" +) + +func TestRunAtLowIntegrity(t *testing.T) { + if isWindowsXP(t) { + t.Skip("Windows XP does not support windows integrity levels") + } + + if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { + wil, err := getProcessIntegrityLevel() + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) + os.Exit(9) + return + } + fmt.Printf("%s", wil) + os.Exit(0) + return + } + + cmd := exec.Command(os.Args[0], "-test.run=TestRunAtLowIntegrity", "--") + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + + token, err := getIntegrityLevelToken(sidWilLow) + if err != nil { + t.Fatal(err) + } + defer token.Close() + + cmd.SysProcAttr = &syscall.SysProcAttr{ + Token: token, + } + + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(err) + } + + if string(out) != sidWilLow { + t.Fatalf("Child process did not run as low integrity level: %s", string(out)) + } +} + +func isWindowsXP(t *testing.T) bool { + v, err := syscall.GetVersion() + if err != nil { + t.Fatalf("GetVersion failed: %v", err) + } + major := byte(v) + return major < 6 +} + +const ( + sidWilLow = `S-1-16-4096` +) + +func getProcessIntegrityLevel() (string, error) { + procToken, err := syscall.OpenCurrentProcessToken() + if err != nil { + return "", err + } + defer procToken.Close() + + p, err := tokenGetInfo(procToken, syscall.TokenIntegrityLevel, 64) + if err != nil { + return "", err + } + + tml := (*windows.TOKEN_MANDATORY_LABEL)(p) + + sid := (*syscall.SID)(unsafe.Pointer(tml.Label.Sid)) + + return sid.String() +} + +func tokenGetInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) { + n := uint32(initSize) + for { + b := make([]byte, n) + e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) + if e == nil { + return unsafe.Pointer(&b[0]), nil + } + if e != syscall.ERROR_INSUFFICIENT_BUFFER { + return nil, e + } + if n <= uint32(len(b)) { + return nil, e + } + } +} + +func getIntegrityLevelToken(wns string) (syscall.Token, error) { + var procToken, token syscall.Token + + proc, err := syscall.GetCurrentProcess() + if err != nil { + return 0, err + } + defer syscall.CloseHandle(proc) + + err = syscall.OpenProcessToken(proc, + syscall.TOKEN_DUPLICATE| + syscall.TOKEN_ADJUST_DEFAULT| + syscall.TOKEN_QUERY| + syscall.TOKEN_ASSIGN_PRIMARY, + &procToken) + if err != nil { + return 0, err + } + defer procToken.Close() + + sid, err := syscall.StringToSid(wns) + if err != nil { + return 0, err + } + + tml := &windows.TOKEN_MANDATORY_LABEL{} + tml.Label.Attributes = windows.SE_GROUP_INTEGRITY + tml.Label.Sid = sid + + err = windows.DuplicateTokenEx(procToken, 0, nil, windows.SecurityImpersonation, + windows.TokenPrimary, &token) + if err != nil { + return 0, err + } + + err = windows.SetTokenInformation(token, + syscall.TokenIntegrityLevel, + uintptr(unsafe.Pointer(tml)), + tml.Size()) + if err != nil { + token.Close() + return 0, err + } + return token, nil +} diff --git a/libgo/go/internal/syscall/windows/mksyscall.go b/libgo/go/internal/syscall/windows/mksyscall.go index 91fa2b3b81f..23efb6a01ab 100644 --- a/libgo/go/internal/syscall/windows/mksyscall.go +++ b/libgo/go/internal/syscall/windows/mksyscall.go @@ -4,4 +4,4 @@ package windows -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go diff --git a/libgo/go/internal/syscall/windows/psapi_windows.go b/libgo/go/internal/syscall/windows/psapi_windows.go new file mode 100644 index 00000000000..b138e658a93 --- /dev/null +++ b/libgo/go/internal/syscall/windows/psapi_windows.go @@ -0,0 +1,20 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +type PROCESS_MEMORY_COUNTERS struct { + CB uint32 + PageFaultCount uint32 + PeakWorkingSetSize uintptr + WorkingSetSize uintptr + QuotaPeakPagedPoolUsage uintptr + QuotaPagedPoolUsage uintptr + QuotaPeakNonPagedPoolUsage uintptr + QuotaNonPagedPoolUsage uintptr + PagefileUsage uintptr + PeakPagefileUsage uintptr +} + +//sys GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) = psapi.GetProcessMemoryInfo diff --git a/libgo/go/internal/syscall/windows/security_windows.go b/libgo/go/internal/syscall/windows/security_windows.go index 2c145e160f7..14ea425c05b 100644 --- a/libgo/go/internal/syscall/windows/security_windows.go +++ b/libgo/go/internal/syscall/windows/security_windows.go @@ -6,6 +6,7 @@ package windows import ( "syscall" + "unsafe" ) const ( @@ -55,3 +56,28 @@ func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newst } return err } + +//sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx +//sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation + +type SID_AND_ATTRIBUTES struct { + Sid *syscall.SID + Attributes uint32 +} + +type TOKEN_MANDATORY_LABEL struct { + Label SID_AND_ATTRIBUTES +} + +func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 { + return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid) +} + +const SE_GROUP_INTEGRITY = 0x00000020 + +type TokenType uint32 + +const ( + TokenPrimary TokenType = 1 + TokenImpersonation TokenType = 2 +) diff --git a/libgo/go/internal/syscall/windows/syscall_windows.go b/libgo/go/internal/syscall/windows/syscall_windows.go index ec08a5a92c6..b531f89b62a 100644 --- a/libgo/go/internal/syscall/windows/syscall_windows.go +++ b/libgo/go/internal/syscall/windows/syscall_windows.go @@ -4,7 +4,11 @@ package windows -import "syscall" +import ( + "sync" + "syscall" + "unsafe" +) const ( ERROR_SHARING_VIOLATION syscall.Errno = 32 @@ -112,6 +116,112 @@ const ( //sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW //sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW +const ( + WSA_FLAG_OVERLAPPED = 0x01 + WSA_FLAG_NO_HANDLE_INHERIT = 0x80 + + WSAEMSGSIZE syscall.Errno = 10040 + + MSG_TRUNC = 0x0100 + MSG_CTRUNC = 0x0200 + + socket_error = uintptr(^uint32(0)) +) + +var WSAID_WSASENDMSG = syscall.GUID{ + Data1: 0xa441e712, + Data2: 0x754f, + Data3: 0x43ca, + Data4: [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}, +} + +var WSAID_WSARECVMSG = syscall.GUID{ + Data1: 0xf689d7c8, + Data2: 0x6f1f, + Data3: 0x436b, + Data4: [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}, +} + +var sendRecvMsgFunc struct { + once sync.Once + sendAddr uintptr + recvAddr uintptr + err error +} + +type WSAMsg struct { + Name *syscall.RawSockaddrAny + Namelen int32 + Buffers *syscall.WSABuf + BufferCount uint32 + Control syscall.WSABuf + Flags uint32 +} + +//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW + +func loadWSASendRecvMsg() error { + sendRecvMsgFunc.once.Do(func() { + var s syscall.Handle + s, sendRecvMsgFunc.err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) + if sendRecvMsgFunc.err != nil { + return + } + defer syscall.CloseHandle(s) + var n uint32 + sendRecvMsgFunc.err = syscall.WSAIoctl(s, + syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)), + uint32(unsafe.Sizeof(WSAID_WSARECVMSG)), + (*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)), + uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)), + &n, nil, 0) + if sendRecvMsgFunc.err != nil { + return + } + sendRecvMsgFunc.err = syscall.WSAIoctl(s, + syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, + (*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)), + uint32(unsafe.Sizeof(WSAID_WSASENDMSG)), + (*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)), + uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)), + &n, nil, 0) + }) + return sendRecvMsgFunc.err +} + +func WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, croutine *byte) error { + err := loadWSASendRecvMsg() + if err != nil { + return err + } + r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.sendAddr, 6, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return err +} + +func WSARecvMsg(fd syscall.Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *syscall.Overlapped, croutine *byte) error { + err := loadWSASendRecvMsg() + if err != nil { + return err + } + r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.recvAddr, 5, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0) + if r1 == socket_error { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return err +} + const ( ComputerNameNetBIOS = 0 ComputerNameDnsHostname = 1 @@ -165,3 +275,19 @@ type SHARE_INFO_2 struct { //sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd //sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel + +const ( + FILE_NAME_NORMALIZED = 0x0 + FILE_NAME_OPENED = 0x8 + + VOLUME_NAME_DOS = 0x0 + VOLUME_NAME_GUID = 0x1 + VOLUME_NAME_NONE = 0x4 + VOLUME_NAME_NT = 0x2 +) + +//sys GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW + +func LoadGetFinalPathNameByHandle() error { + return procGetFinalPathNameByHandleW.Find() +} diff --git a/libgo/go/internal/syscall/windows/zsyscall_windows.go b/libgo/go/internal/syscall/windows/zsyscall_windows.go index 7a2ffeeffaf..bdca80c60d3 100644 --- a/libgo/go/internal/syscall/windows/zsyscall_windows.go +++ b/libgo/go/internal/syscall/windows/zsyscall_windows.go @@ -38,24 +38,31 @@ func errnoErr(e syscall.Errno) error { var ( modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) + modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) - procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") - procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") - procMoveFileExW = modkernel32.NewProc("MoveFileExW") - procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") - procGetACP = modkernel32.NewProc("GetACP") - procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") - procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") - procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") - procNetShareAdd = modnetapi32.NewProc("NetShareAdd") - procNetShareDel = modnetapi32.NewProc("NetShareDel") - procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") - procRevertToSelf = modadvapi32.NewProc("RevertToSelf") - procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") - procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") - procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") + procMoveFileExW = modkernel32.NewProc("MoveFileExW") + procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") + procWSASocketW = modws2_32.NewProc("WSASocketW") + procGetACP = modkernel32.NewProc("GetACP") + procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") + procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") + procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") + procNetShareAdd = modnetapi32.NewProc("NetShareAdd") + procNetShareDel = modnetapi32.NewProc("NetShareDel") + procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") + procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") + procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") ) func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { @@ -103,6 +110,19 @@ func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, return } +func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func GetACP() (acp uint32) { r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) acp = uint32(r0) @@ -157,6 +177,19 @@ func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr e return } +func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func ImpersonateSelf(impersonationlevel uint32) (err error) { r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) if r1 == 0 { @@ -229,3 +262,39 @@ func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newst } return } + +func DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) { + r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/libgo/go/internal/testenv/testenv.go b/libgo/go/internal/testenv/testenv.go index 999080bcc52..87d01d20327 100644 --- a/libgo/go/internal/testenv/testenv.go +++ b/libgo/go/internal/testenv/testenv.go @@ -40,6 +40,13 @@ func Builder() string { // HasGoBuild reports whether the current system can build programs with ``go build'' // and then run them with os.StartProcess or exec.Command. func HasGoBuild() bool { + if os.Getenv("GO_GCFLAGS") != "" { + // It's too much work to require every caller of the go command + // to pass along "-gcflags="+os.Getenv("GO_GCFLAGS"). + // For now, if $GO_GCFLAGS is set, report that we simply can't + // run go build. + return false + } switch runtime.GOOS { case "android", "nacl": return false @@ -55,10 +62,13 @@ func HasGoBuild() bool { // MustHaveGoBuild checks that the current system can build programs with ``go build'' // and then run them with os.StartProcess or exec.Command. // If not, MustHaveGoBuild calls t.Skip with an explanation. -func MustHaveGoBuild(t *testing.T) { +func MustHaveGoBuild(t testing.TB) { if !testingGotools() { t.Skip("skipping test: 'go build' not available for gccgo tests") } + if os.Getenv("GO_GCFLAGS") != "" { + t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS") + } if !HasGoBuild() { t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH) } @@ -72,7 +82,7 @@ func HasGoRun() bool { // MustHaveGoRun checks that the current system can run programs with ``go run.'' // If not, MustHaveGoRun calls t.Skip with an explanation. -func MustHaveGoRun(t *testing.T) { +func MustHaveGoRun(t testing.TB) { if !testingGotools() { t.Skip("skipping test: 'go run' not available for gccgo tests") } @@ -85,7 +95,7 @@ func MustHaveGoRun(t *testing.T) { // It is a convenience wrapper around GoTool. // If the tool is unavailable GoToolPath calls t.Skip. // If the tool should be available and isn't, GoToolPath calls t.Fatal. -func GoToolPath(t *testing.T) string { +func GoToolPath(t testing.TB) string { MustHaveGoBuild(t) path, err := GoTool() if err != nil { @@ -147,7 +157,7 @@ func HasSrc() bool { // MustHaveExec checks that the current system can start new processes // using os.StartProcess or (more commonly) exec.Command. // If not, MustHaveExec calls t.Skip with an explanation. -func MustHaveExec(t *testing.T) { +func MustHaveExec(t testing.TB) { if !HasExec() { t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH) } @@ -162,7 +172,7 @@ func HasExternalNetwork() bool { // MustHaveExternalNetwork checks that the current system can use // external (non-localhost) networks. // If not, MustHaveExternalNetwork calls t.Skip with an explanation. -func MustHaveExternalNetwork(t *testing.T) { +func MustHaveExternalNetwork(t testing.TB) { if testing.Short() { t.Skipf("skipping test: no external network in -short mode") } @@ -170,8 +180,13 @@ func MustHaveExternalNetwork(t *testing.T) { var haveCGO bool +// HasCGO reports whether the current system can use cgo. +func HasCGO() bool { + return haveCGO +} + // MustHaveCGO calls t.Skip if cgo is not available. -func MustHaveCGO(t *testing.T) { +func MustHaveCGO(t testing.TB) { if !haveCGO { t.Skipf("skipping test: no cgo") } @@ -185,7 +200,7 @@ func HasSymlink() bool { // MustHaveSymlink reports whether the current system can use os.Symlink. // If not, MustHaveSymlink calls t.Skip with an explanation. -func MustHaveSymlink(t *testing.T) { +func MustHaveSymlink(t testing.TB) { ok, reason := hasSymlink() if !ok { t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason) @@ -202,7 +217,7 @@ func HasLink() bool { // MustHaveLink reports whether the current system can use os.Link. // If not, MustHaveLink calls t.Skip with an explanation. -func MustHaveLink(t *testing.T) { +func MustHaveLink(t testing.TB) { if !HasLink() { t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH) } @@ -210,14 +225,38 @@ func MustHaveLink(t *testing.T) { var flaky = flag.Bool("flaky", false, "run known-flaky tests too") -func SkipFlaky(t *testing.T, issue int) { +func SkipFlaky(t testing.TB, issue int) { + t.Helper() if !*flaky { t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue) } } -func SkipFlakyNet(t *testing.T) { +func SkipFlakyNet(t testing.TB) { + t.Helper() if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v { t.Skip("skipping test on builder known to have frequent network failures") } } + +// CleanCmdEnv will fill cmd.Env with the environment, excluding certain +// variables that could modify the behavior of the Go tools such as +// GODEBUG and GOTRACEBACK. +func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd { + if cmd.Env != nil { + panic("environment already set") + } + for _, env := range os.Environ() { + // Exclude GODEBUG from the environment to prevent its output + // from breaking tests that are trying to parse other command output. + if strings.HasPrefix(env, "GODEBUG=") { + continue + } + // Exclude GOTRACEBACK for the same reason. + if strings.HasPrefix(env, "GOTRACEBACK=") { + continue + } + cmd.Env = append(cmd.Env, env) + } + return cmd +} diff --git a/libgo/go/internal/trace/parser.go b/libgo/go/internal/trace/parser.go index 1dd3ef15090..a774bf14c96 100644 --- a/libgo/go/internal/trace/parser.go +++ b/libgo/go/internal/trace/parser.go @@ -12,11 +12,25 @@ import ( "math/rand" "os" "os/exec" + "path/filepath" + "runtime" "strconv" "strings" _ "unsafe" ) +func goCmd() string { + var exeSuffix string + if runtime.GOOS == "windows" { + exeSuffix = ".exe" + } + path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix) + if _, err := os.Stat(path); err == nil { + return path + } + return "go" +} + // Event describes one event in the trace. type Event struct { Off int // offset in input file (for debugging and error reporting) @@ -31,7 +45,7 @@ type Event struct { SArgs []string // event-type-specific string args // linked event (can be nil), depends on event type: // for GCStart: the GCStop - // for GCScanStart: the GCScanDone + // for GCSTWStart: the GCSTWDone // for GCSweepStart: the GCSweepDone // for GoCreate: first GoStart of the created goroutine // for GoStart/GoStartLabel: the associated GoEnd, GoBlock or other blocking event @@ -128,7 +142,7 @@ func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]stri return } switch ver { - case 1005, 1007, 1008, 1009: + case 1005, 1007, 1008, 1009, 1010: // Note: When adding a new version, add canned traces // from the old version to the test suite using mkcanned.bash. break @@ -270,8 +284,9 @@ func parseHeader(buf []byte) (int, error) { // It does analyze and verify per-event-type arguments. func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (events []*Event, stacks map[uint64][]*Frame, err error) { var ticksPerSec, lastSeq, lastTs int64 - var lastG, timerGoid uint64 + var lastG uint64 var lastP int + timerGoids := make(map[uint64]bool) lastGs := make(map[int]uint64) // last goroutine running on P stacks = make(map[uint64][]*Frame) batches := make(map[int][]*Event) // events by P @@ -308,7 +323,7 @@ func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (even return } case EvTimerGoroutine: - timerGoid = raw.args[0] + timerGoids[raw.args[0]] = true case EvStack: if len(raw.args) < 2 { err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want at least 2, got %v", @@ -373,7 +388,18 @@ func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (even if raw.typ == EvGoStartLabel { e.SArgs = []string{strings[e.Args[2]]} } - case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone: + case EvGCSTWStart: + e.G = 0 + switch e.Args[0] { + case 0: + e.SArgs = []string{"mark termination"} + case 1: + e.SArgs = []string{"sweep termination"} + default: + err = fmt.Errorf("unknown STW kind %d", e.Args[0]) + return + } + case EvGCStart, EvGCDone, EvGCSTWDone: e.G = 0 case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt, EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv, @@ -420,7 +446,7 @@ func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (even for _, ev := range events { ev.Ts = int64(float64(ev.Ts-minTs) * freq) // Move timers and syscalls to separate fake Ps. - if timerGoid != 0 && ev.G == timerGoid && ev.Type == EvGoUnblock { + if timerGoids[ev.G] && ev.Type == EvGoUnblock { ev.P = TimerP } if ev.Type == EvGoSysExit { @@ -511,14 +537,14 @@ func postProcessTrace(ver int, events []*Event) error { type pdesc struct { running bool g uint64 - evScan *Event + evSTW *Event evSweep *Event } gs := make(map[uint64]gdesc) ps := make(map[int]pdesc) gs[0] = gdesc{state: gRunning} - var evGC *Event + var evGC, evSTW *Event checkRunning := func(p pdesc, g gdesc, ev *Event, allowG0 bool) error { name := EventDescriptions[ev.Type].Name @@ -565,17 +591,27 @@ func postProcessTrace(ver int, events []*Event) error { } evGC.Link = ev evGC = nil - case EvGCScanStart: - if p.evScan != nil { - return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) - } - p.evScan = ev - case EvGCScanDone: - if p.evScan == nil { - return fmt.Errorf("bogus scanning end (offset %v, time %v)", ev.Off, ev.Ts) - } - p.evScan.Link = ev - p.evScan = nil + case EvGCSTWStart: + evp := &evSTW + if ver < 1010 { + // Before 1.10, EvGCSTWStart was per-P. + evp = &p.evSTW + } + if *evp != nil { + return fmt.Errorf("previous STW is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) + } + *evp = ev + case EvGCSTWDone: + evp := &evSTW + if ver < 1010 { + // Before 1.10, EvGCSTWDone was per-P. + evp = &p.evSTW + } + if *evp == nil { + return fmt.Errorf("bogus STW end (offset %v, time %v)", ev.Off, ev.Ts) + } + (*evp).Link = ev + *evp = nil case EvGCSweepStart: if p.evSweep != nil { return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) @@ -735,7 +771,7 @@ func symbolize(events []*Event, bin string) error { } // Start addr2line. - cmd := exec.Command("go", "tool", "addr2line", bin) + cmd := exec.Command(goCmd(), "tool", "addr2line", bin) in, err := cmd.StdinPipe() if err != nil { return fmt.Errorf("failed to pipe addr2line stdin: %v", err) @@ -864,6 +900,10 @@ func argNum(raw rawEvent, ver int) int { if ver < 1007 { narg-- // 1.7 added an additional seq arg } + case EvGCSTWStart: + if ver < 1010 { + narg-- // 1.10 added an argument + } } return narg } @@ -883,8 +923,8 @@ const ( EvProcStop = 6 // stop of P [timestamp] EvGCStart = 7 // GC start [timestamp, seq, stack id] EvGCDone = 8 // GC done [timestamp] - EvGCScanStart = 9 // GC mark termination start [timestamp] - EvGCScanDone = 10 // GC mark termination done [timestamp] + EvGCSTWStart = 9 // GC mark termination start [timestamp, kind] + EvGCSTWDone = 10 // GC mark termination done [timestamp] EvGCSweepStart = 11 // GC sweep start [timestamp, stack id] EvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] @@ -937,8 +977,8 @@ var EventDescriptions = [EvCount]struct { EvProcStop: {"ProcStop", 1005, false, []string{}}, EvGCStart: {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {} EvGCDone: {"GCDone", 1005, false, []string{}}, - EvGCScanStart: {"GCScanStart", 1005, false, []string{}}, - EvGCScanDone: {"GCScanDone", 1005, false, []string{}}, + EvGCSTWStart: {"GCSTWStart", 1005, false, []string{"kind"}}, // <= 1.9, args was {} (implicitly {0}) + EvGCSTWDone: {"GCSTWDone", 1005, false, []string{}}, EvGCSweepStart: {"GCSweepStart", 1005, true, []string{}}, EvGCSweepDone: {"GCSweepDone", 1005, false, []string{"swept", "reclaimed"}}, // before 1.9, format was {} EvGoCreate: {"GoCreate", 1005, true, []string{"g", "stack"}}, diff --git a/libgo/go/io/example_test.go b/libgo/go/io/example_test.go index af478537267..edcd0086f5b 100644 --- a/libgo/go/io/example_test.go +++ b/libgo/go/io/example_test.go @@ -243,3 +243,19 @@ func ExampleMultiWriter() { // some io.Reader stream to be read // some io.Reader stream to be read } + +func ExamplePipe() { + r, w := io.Pipe() + + go func() { + fmt.Fprint(w, "some text to be read\n") + w.Close() + }() + + buf := new(bytes.Buffer) + buf.ReadFrom(r) + fmt.Print(buf.String()) + + // Output: + // some text to be read +} diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go index 28dab08e46c..27482de62ee 100644 --- a/libgo/go/io/io.go +++ b/libgo/go/io/io.go @@ -385,8 +385,16 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { if rt, ok := dst.(ReaderFrom); ok { return rt.ReadFrom(src) } + size := 32 * 1024 + if l, ok := src.(*LimitedReader); ok && int64(size) > l.N { + if l.N < 1 { + size = 1 + } else { + size = int(l.N) + } + } if buf == nil { - buf = make([]byte, 32*1024) + buf = make([]byte, size) } for { nr, er := src.Read(buf) diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go index 877e8392e27..0e4ce612400 100644 --- a/libgo/go/io/io_test.go +++ b/libgo/go/io/io_test.go @@ -32,6 +32,21 @@ func TestCopy(t *testing.T) { } } +func TestCopyNegative(t *testing.T) { + rb := new(Buffer) + wb := new(Buffer) + rb.WriteString("hello") + Copy(wb, &LimitedReader{R: rb, N: -1}) + if wb.String() != "" { + t.Errorf("Copy on LimitedReader with N<0 copied data") + } + + CopyN(wb, rb, -1) + if wb.String() != "" { + t.Errorf("CopyN with N<0 copied data") + } +} + func TestCopyBuffer(t *testing.T) { rb := new(Buffer) wb := new(Buffer) @@ -156,6 +171,30 @@ func TestCopyNWriteTo(t *testing.T) { } } +func BenchmarkCopyNSmall(b *testing.B) { + bs := bytes.Repeat([]byte{0}, 512+1) + rd := bytes.NewReader(bs) + buf := new(Buffer) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + CopyN(buf, rd, 512) + rd.Reset(bs) + } +} + +func BenchmarkCopyNLarge(b *testing.B) { + bs := bytes.Repeat([]byte{0}, (32*1024)+1) + rd := bytes.NewReader(bs) + buf := new(Buffer) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + CopyN(buf, rd, 32*1024) + rd.Reset(bs) + } +} + type noReadFrom struct { w Writer } diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go index f0da6168305..674b2701db1 100644 --- a/libgo/go/io/ioutil/ioutil.go +++ b/libgo/go/io/ioutil/ioutil.go @@ -16,7 +16,7 @@ import ( // readAll reads from r until an error or EOF and returns the data it read // from the internal buffer allocated with a specified capacity. func readAll(r io.Reader, capacity int64) (b []byte, err error) { - buf := bytes.NewBuffer(make([]byte, 0, capacity)) + var buf bytes.Buffer // If the buffer overflows, we will get bytes.ErrTooLarge. // Return that as an error. Any other panic remains. defer func() { @@ -30,6 +30,9 @@ func readAll(r io.Reader, capacity int64) (b []byte, err error) { panic(e) } }() + if int64(int(capacity)) == capacity { + buf.Grow(int(capacity)) + } _, err = buf.ReadFrom(r) return buf.Bytes(), err } @@ -54,20 +57,20 @@ func ReadFile(filename string) ([]byte, error) { defer f.Close() // It's a good but not certain bet that FileInfo will tell us exactly how much to // read, so let's try it but be prepared for the answer to be wrong. - var n int64 + var n int64 = bytes.MinRead if fi, err := f.Stat(); err == nil { - // Don't preallocate a huge buffer, just in case. - if size := fi.Size(); size < 1e9 { + // As initial capacity for readAll, use Size + a little extra in case Size + // is zero, and to avoid another allocation after Read has filled the + // buffer. The readAll call will read into its allocated internal buffer + // cheaply. If the size was wrong, we'll either waste some space off the end + // or reallocate as needed, but in the overwhelmingly common case we'll get + // it just right. + if size := fi.Size() + bytes.MinRead; size > n { n = size } } - // As initial capacity for readAll, use n + a little extra in case Size is zero, - // and to avoid another allocation after Read has filled the buffer. The readAll - // call will read into its allocated internal buffer cheaply. If the size was - // wrong, we'll either waste some space off the end or reallocate as needed, but - // in the overwhelmingly common case we'll get it just right. - return readAll(f, n+bytes.MinRead) + return readAll(f, n) } // WriteFile writes data to a file named by filename. diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go index d784846862c..65f99099ca7 100644 --- a/libgo/go/io/multi.go +++ b/libgo/go/io/multi.go @@ -95,8 +95,18 @@ func (t *multiWriter) WriteString(s string) (n int, err error) { // MultiWriter creates a writer that duplicates its writes to all the // provided writers, similar to the Unix tee(1) command. +// +// Each write is written to each listed writer, one at a time. +// If a listed writer returns an error, that overall write operation +// stops and returns the error; it does not continue down the list. func MultiWriter(writers ...Writer) Writer { - w := make([]Writer, len(writers)) - copy(w, writers) - return &multiWriter{w} + allWriters := make([]Writer, 0, len(writers)) + for _, w := range writers { + if mw, ok := w.(*multiWriter); ok { + allWriters = append(allWriters, mw.writers...) + } else { + allWriters = append(allWriters, w) + } + } + return &multiWriter{allWriters} } diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go index fef3e00fbcd..4acc51abea2 100644 --- a/libgo/go/io/multi_test.go +++ b/libgo/go/io/multi_test.go @@ -143,6 +143,55 @@ func testMultiWriter(t *testing.T, sink interface { } } +// writerFunc is an io.Writer implemented by the underlying func. +type writerFunc func(p []byte) (int, error) + +func (f writerFunc) Write(p []byte) (int, error) { + return f(p) +} + +// Test that MultiWriter properly flattens chained multiWriters, +func TestMultiWriterSingleChainFlatten(t *testing.T) { + pc := make([]uintptr, 1000) // 1000 should fit the full stack + n := runtime.Callers(0, pc) + var myDepth = callDepth(pc[:n]) + var writeDepth int // will contain the depth from which writerFunc.Writer was called + var w Writer = MultiWriter(writerFunc(func(p []byte) (int, error) { + n := runtime.Callers(1, pc) + writeDepth += callDepth(pc[:n]) + return 0, nil + })) + + mw := w + // chain a bunch of multiWriters + for i := 0; i < 100; i++ { + mw = MultiWriter(w) + } + + mw = MultiWriter(w, mw, w, mw) + mw.Write(nil) // don't care about errors, just want to check the call-depth for Write + + if writeDepth != 4*(myDepth+2) { // 2 should be multiWriter.Write and writerFunc.Write + t.Errorf("multiWriter did not flatten chained multiWriters: expected writeDepth %d, got %d", + 4*(myDepth+2), writeDepth) + } +} + +func TestMultiWriterError(t *testing.T) { + f1 := writerFunc(func(p []byte) (int, error) { + return len(p) / 2, ErrShortWrite + }) + f2 := writerFunc(func(p []byte) (int, error) { + t.Errorf("MultiWriter called f2.Write") + return len(p), nil + }) + w := MultiWriter(f1, f2) + n, err := w.Write(make([]byte, 100)) + if n != 50 || err != ErrShortWrite { + t.Errorf("Write = %d, %v, want 50, ErrShortWrite", n, err) + } +} + // Test that MultiReader copies the input slice and is insulated from future modification. func TestMultiReaderCopy(t *testing.T) { slice := []Reader{strings.NewReader("hello world")} diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go index b6e7755f64c..4efaf2f8e48 100644 --- a/libgo/go/io/pipe.go +++ b/libgo/go/io/pipe.go @@ -10,110 +10,107 @@ package io import ( "errors" "sync" + "sync/atomic" ) +// atomicError is a type-safe atomic value for errors. +// We use a struct{ error } to ensure consistent use of a concrete type. +type atomicError struct{ v atomic.Value } + +func (a *atomicError) Store(err error) { + a.v.Store(struct{ error }{err}) +} +func (a *atomicError) Load() error { + err, _ := a.v.Load().(struct{ error }) + return err.error +} + // ErrClosedPipe is the error used for read or write operations on a closed pipe. var ErrClosedPipe = errors.New("io: read/write on closed pipe") // A pipe is the shared pipe structure underlying PipeReader and PipeWriter. type pipe struct { - rl sync.Mutex // gates readers one at a time - wl sync.Mutex // gates writers one at a time - l sync.Mutex // protects remaining fields - data []byte // data remaining in pending write - rwait sync.Cond // waiting reader - wwait sync.Cond // waiting writer - rerr error // if reader closed, error to give writes - werr error // if writer closed, error to give reads -} - -func (p *pipe) read(b []byte) (n int, err error) { - // One reader at a time. - p.rl.Lock() - defer p.rl.Unlock() - - p.l.Lock() - defer p.l.Unlock() - for { - if p.rerr != nil { - return 0, ErrClosedPipe - } - if p.data != nil { - break - } - if p.werr != nil { - return 0, p.werr - } - p.rwait.Wait() - } - n = copy(b, p.data) - p.data = p.data[n:] - if len(p.data) == 0 { - p.data = nil - p.wwait.Signal() - } - return + wrMu sync.Mutex // Serializes Write operations + wrCh chan []byte + rdCh chan int + + once sync.Once // Protects closing done + done chan struct{} + rerr atomicError + werr atomicError } -var zero [0]byte +func (p *pipe) Read(b []byte) (n int, err error) { + select { + case <-p.done: + return 0, p.readCloseError() + default: + } -func (p *pipe) write(b []byte) (n int, err error) { - // pipe uses nil to mean not available - if b == nil { - b = zero[:] + select { + case bw := <-p.wrCh: + nr := copy(b, bw) + p.rdCh <- nr + return nr, nil + case <-p.done: + return 0, p.readCloseError() } +} - // One writer at a time. - p.wl.Lock() - defer p.wl.Unlock() +func (p *pipe) readCloseError() error { + rerr := p.rerr.Load() + if werr := p.werr.Load(); rerr == nil && werr != nil { + return werr + } + return ErrClosedPipe +} - p.l.Lock() - defer p.l.Unlock() - if p.werr != nil { +func (p *pipe) CloseRead(err error) error { + if err == nil { err = ErrClosedPipe - return } - p.data = b - p.rwait.Signal() - for { - if p.data == nil { - break - } - if p.rerr != nil { - err = p.rerr - break - } - if p.werr != nil { - err = ErrClosedPipe - break + p.rerr.Store(err) + p.once.Do(func() { close(p.done) }) + return nil +} + +func (p *pipe) Write(b []byte) (n int, err error) { + select { + case <-p.done: + return 0, p.writeCloseError() + default: + p.wrMu.Lock() + defer p.wrMu.Unlock() + } + + for once := true; once || len(b) > 0; once = false { + select { + case p.wrCh <- b: + nw := <-p.rdCh + b = b[nw:] + n += nw + case <-p.done: + return n, p.writeCloseError() } - p.wwait.Wait() } - n = len(b) - len(p.data) - p.data = nil // in case of rerr or werr - return + return n, nil } -func (p *pipe) rclose(err error) { - if err == nil { - err = ErrClosedPipe +func (p *pipe) writeCloseError() error { + werr := p.werr.Load() + if rerr := p.rerr.Load(); werr == nil && rerr != nil { + return rerr } - p.l.Lock() - defer p.l.Unlock() - p.rerr = err - p.rwait.Signal() - p.wwait.Signal() + return ErrClosedPipe } -func (p *pipe) wclose(err error) { +func (p *pipe) CloseWrite(err error) error { if err == nil { err = EOF } - p.l.Lock() - defer p.l.Unlock() - p.werr = err - p.rwait.Signal() - p.wwait.Signal() + p.werr.Store(err) + p.once.Do(func() { close(p.done) }) + return nil } // A PipeReader is the read half of a pipe. @@ -127,7 +124,7 @@ type PipeReader struct { // If the write end is closed with an error, that error is // returned as err; otherwise err is EOF. func (r *PipeReader) Read(data []byte) (n int, err error) { - return r.p.read(data) + return r.p.Read(data) } // Close closes the reader; subsequent writes to the @@ -139,8 +136,7 @@ func (r *PipeReader) Close() error { // CloseWithError closes the reader; subsequent writes // to the write half of the pipe will return the error err. func (r *PipeReader) CloseWithError(err error) error { - r.p.rclose(err) - return nil + return r.p.CloseRead(err) } // A PipeWriter is the write half of a pipe. @@ -154,7 +150,7 @@ type PipeWriter struct { // If the read end is closed with an error, that err is // returned as err; otherwise err is ErrClosedPipe. func (w *PipeWriter) Write(data []byte) (n int, err error) { - return w.p.write(data) + return w.p.Write(data) } // Close closes the writer; subsequent reads from the @@ -169,8 +165,7 @@ func (w *PipeWriter) Close() error { // // CloseWithError always returns nil. func (w *PipeWriter) CloseWithError(err error) error { - w.p.wclose(err) - return nil + return w.p.CloseWrite(err) } // Pipe creates a synchronous in-memory pipe. @@ -189,10 +184,10 @@ func (w *PipeWriter) CloseWithError(err error) error { // Parallel calls to Read and parallel calls to Write are also safe: // the individual calls will be gated sequentially. func Pipe() (*PipeReader, *PipeWriter) { - p := new(pipe) - p.rwait.L = &p.l - p.wwait.L = &p.l - r := &PipeReader{p} - w := &PipeWriter{p} - return r, w + p := &pipe{ + wrCh: make(chan []byte), + rdCh: make(chan int), + done: make(chan struct{}), + } + return &PipeReader{p}, &PipeWriter{p} } diff --git a/libgo/go/io/pipe_test.go b/libgo/go/io/pipe_test.go index 95930e86a4e..f18b1c45f8b 100644 --- a/libgo/go/io/pipe_test.go +++ b/libgo/go/io/pipe_test.go @@ -5,8 +5,11 @@ package io_test import ( + "bytes" "fmt" . "io" + "sort" + "strings" "testing" "time" ) @@ -312,3 +315,109 @@ func TestWriteAfterWriterClose(t *testing.T) { t.Errorf("got: %q; want: %q", writeErr, ErrClosedPipe) } } + +func TestPipeCloseError(t *testing.T) { + type testError1 struct{ error } + type testError2 struct{ error } + + r, w := Pipe() + r.CloseWithError(testError1{}) + if _, err := w.Write(nil); err != (testError1{}) { + t.Errorf("Write error: got %T, want testError1", err) + } + r.CloseWithError(testError2{}) + if _, err := w.Write(nil); err != (testError2{}) { + t.Errorf("Write error: got %T, want testError2", err) + } + + r, w = Pipe() + w.CloseWithError(testError1{}) + if _, err := r.Read(nil); err != (testError1{}) { + t.Errorf("Read error: got %T, want testError1", err) + } + w.CloseWithError(testError2{}) + if _, err := r.Read(nil); err != (testError2{}) { + t.Errorf("Read error: got %T, want testError2", err) + } +} + +func TestPipeConcurrent(t *testing.T) { + const ( + input = "0123456789abcdef" + count = 8 + readSize = 2 + ) + + t.Run("Write", func(t *testing.T) { + r, w := Pipe() + + for i := 0; i < count; i++ { + go func() { + time.Sleep(time.Millisecond) // Increase probability of race + if n, err := w.Write([]byte(input)); n != len(input) || err != nil { + t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input)) + } + }() + } + + buf := make([]byte, count*len(input)) + for i := 0; i < len(buf); i += readSize { + if n, err := r.Read(buf[i : i+readSize]); n != readSize || err != nil { + t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize) + } + } + + // Since each Write is fully gated, if multiple Read calls were needed, + // the contents of Write should still appear together in the output. + got := string(buf) + want := strings.Repeat(input, count) + if got != want { + t.Errorf("got: %q; want: %q", got, want) + } + }) + + t.Run("Read", func(t *testing.T) { + r, w := Pipe() + + c := make(chan []byte, count*len(input)/readSize) + for i := 0; i < cap(c); i++ { + go func() { + time.Sleep(time.Millisecond) // Increase probability of race + buf := make([]byte, readSize) + if n, err := r.Read(buf); n != readSize || err != nil { + t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize) + } + c <- buf + }() + } + + for i := 0; i < count; i++ { + if n, err := w.Write([]byte(input)); n != len(input) || err != nil { + t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input)) + } + } + + // Since each read is independent, the only guarantee about the output + // is that it is a permutation of the input in readSized groups. + got := make([]byte, 0, count*len(input)) + for i := 0; i < cap(c); i++ { + got = append(got, (<-c)...) + } + got = sortBytesInGroups(got, readSize) + want := bytes.Repeat([]byte(input), count) + want = sortBytesInGroups(want, readSize) + if string(got) != string(want) { + t.Errorf("got: %q; want: %q", got, want) + } + }) +} + +func sortBytesInGroups(b []byte, n int) []byte { + var groups [][]byte + for len(b) > 0 { + groups = append(groups, b[:n]) + b = b[n:] + } + sort.Slice(groups, func(i, j int) bool { return bytes.Compare(groups[i], groups[j]) < 0 }) + return bytes.Join(groups, nil) +} diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go index 587904b11c4..2b7c57fdfe5 100644 --- a/libgo/go/log/log.go +++ b/libgo/go/log/log.go @@ -24,16 +24,16 @@ import ( ) // These flags define which text to prefix to each log entry generated by the Logger. +// Bits are or'ed together to control what's printed. +// There is no control over the order they appear (the order listed +// here) or the format they present (as described in the comments). +// The prefix is followed by a colon only when Llongfile or Lshortfile +// is specified. +// For example, flags Ldate | Ltime (or LstdFlags) produce, +// 2009/01/23 01:23:23 message +// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce, +// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message const ( - // Bits or'ed together to control what's printed. - // There is no control over the order they appear (the order listed - // here) or the format they present (as described in the comments). - // The prefix is followed by a colon only when Llongfile or Lshortfile - // is specified. - // For example, flags Ldate | Ltime (or LstdFlags) produce, - // 2009/01/23 01:23:23 message - // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce, - // 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message Ldate = 1 << iota // the date in the local time zone: 2009/01/23 Ltime // the time in the local time zone: 01:23:23 Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime. @@ -147,11 +147,7 @@ func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) { // provided for generality, although at the moment on all pre-defined // paths it will be 2. func (l *Logger) Output(calldepth int, s string) error { - // Get time early if we need it. - var now time.Time - if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 { - now = time.Now() - } + now := time.Now() // get this early. var file string var line int l.mu.Lock() diff --git a/libgo/go/log/log_test.go b/libgo/go/log/log_test.go index 966fdf306bc..adc15e7e8ed 100644 --- a/libgo/go/log/log_test.go +++ b/libgo/go/log/log_test.go @@ -88,6 +88,17 @@ func TestOutput(t *testing.T) { } } +func TestOutputRace(t *testing.T) { + var b bytes.Buffer + l := New(&b, "", 0) + for i := 0; i < 100; i++ { + go func() { + l.SetFlags(0) + }() + l.Output(0, "") + } +} + func TestFlagAndPrefixSetting(t *testing.T) { var b bytes.Buffer l := New(&b, "Test:", LstdFlags) diff --git a/libgo/go/log/syslog/syslog_unix.go b/libgo/go/log/syslog/syslog_unix.go index 356b98d18ed..53cbf502436 100644 --- a/libgo/go/log/syslog/syslog_unix.go +++ b/libgo/go/log/syslog/syslog_unix.go @@ -20,9 +20,7 @@ func unixSyslog() (conn serverConn, err error) { for _, network := range logTypes { for _, path := range logPaths { conn, err := net.Dial(network, path) - if err != nil { - continue - } else { + if err == nil { return &netConn{conn: conn, local: true}, nil } } diff --git a/libgo/go/math/abs.go b/libgo/go/math/abs.go index 1b7c7c1820c..d74a090be8c 100644 --- a/libgo/go/math/abs.go +++ b/libgo/go/math/abs.go @@ -18,14 +18,5 @@ func Abs(x float64) float64 { } func abs(x float64) float64 { - // TODO: once golang.org/issue/13095 is fixed, change this to: - // return Float64frombits(Float64bits(x) &^ (1 << 63)) - // But for now, this generates better code and can also be inlined: - if x < 0 { - return -x - } - if x == 0 { - return 0 // return correctly abs(-0) - } - return x + return Float64frombits(Float64bits(x) &^ (1 << 63)) } diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go index 39a3a4986b8..0412c19e579 100644 --- a/libgo/go/math/all_test.go +++ b/libgo/go/math/all_test.go @@ -8,6 +8,7 @@ import ( "fmt" . "math" "testing" + "unsafe" ) var vf = []float64{ @@ -210,6 +211,18 @@ var erfc = []float64{ 7.9630075582117758758440411e-01, 1.7806938696800922672994468e+00, } +var erfinv = []float64{ + 4.746037673358033586786350696e-01, + 8.559054432692110956388764172e-01, + -2.45427830571707336251331946e-02, + -4.78116683518973366268905506e-01, + 1.479804430319470983648120853e+00, + 2.654485787128896161882650211e-01, + 5.027444534221520197823192493e-01, + 2.466703532707627818954585670e-01, + 1.632011465103005426240343116e-01, + -1.06672334642196900710000389e+00, +} var exp = []float64{ 1.4533071302642137507696589e+02, 2.2958822575694449002537581e+03, @@ -516,6 +529,18 @@ var remainder = []float64{ 8.734595415957246977711748e-01, 1.314075231424398637614104e+00, } +var round = []float64{ + 5, + 8, + Copysign(0, -1), + -5, + 10, + 3, + 5, + 3, + 2, + -9, +} var signbit = []bool{ false, false, @@ -941,6 +966,40 @@ var erfcSC = []float64{ NaN(), } +var vferfinvSC = []float64{ + 1, + -1, + 0, + Inf(-1), + Inf(1), + NaN(), +} +var erfinvSC = []float64{ + Inf(+1), + Inf(-1), + 0, + NaN(), + NaN(), + NaN(), +} + +var vferfcinvSC = []float64{ + 0, + 2, + 1, + Inf(1), + Inf(-1), + NaN(), +} +var erfcinvSC = []float64{ + Inf(+1), + Inf(-1), + 0, + NaN(), + NaN(), + NaN(), +} + var vfexpSC = []float64{ Inf(-1), -2000, @@ -952,6 +1011,7 @@ var vfexpSC = []float64{ // Issue 18912 1.48852223e+09, 1.4885222e+09, + 1, } var expSC = []float64{ 0, @@ -962,6 +1022,7 @@ var expSC = []float64{ Inf(1), Inf(1), Inf(1), + 2.718281828459045, } var vfexp2SC = []float64{ @@ -1368,6 +1429,8 @@ var vfldexpSC = []fi{ {Inf(-1), 0}, {Inf(-1), -1024}, {NaN(), -1024}, + {10, int(1) << (uint64(unsafe.Sizeof(0)-1) * 8)}, + {10, -(int(1) << (uint64(unsafe.Sizeof(0)-1) * 8))}, } var ldexpSC = []float64{ 0, @@ -1381,6 +1444,8 @@ var ldexpSC = []float64{ Inf(-1), Inf(-1), NaN(), + Inf(1), + 0, } var vflgammaSC = []float64{ @@ -1581,6 +1646,17 @@ var vfpowSC = [][2]float64{ {NaN(), 1}, {NaN(), Pi}, {NaN(), NaN()}, + + // Issue #7394 overflow checks + {2, float64(1 << 32)}, + {2, -float64(1 << 32)}, + {-2, float64(1<<32 + 1)}, + {1 / 2, float64(1 << 45)}, + {1 / 2, -float64(1 << 45)}, + {Nextafter(1, 2), float64(1 << 63)}, + {Nextafter(1, -2), float64(1 << 63)}, + {Nextafter(-1, 2), float64(1 << 63)}, + {Nextafter(-1, -2), float64(1 << 63)}, } var powSC = []float64{ 0, // pow(-Inf, -Pi) @@ -1642,6 +1718,17 @@ var powSC = []float64{ NaN(), // pow(NaN, 1) NaN(), // pow(NaN, +Pi) NaN(), // pow(NaN, NaN) + + // Issue #7394 overflow checks + Inf(1), // pow(2, float64(1 << 32)) + 0, // pow(2, -float64(1 << 32)) + Inf(-1), // pow(-2, float64(1<<32 + 1)) + 0, // pow(1/2, float64(1 << 45)) + Inf(1), // pow(1/2, -float64(1 << 45)) + Inf(1), // pow(Nextafter(1, 2), float64(1 << 63)) + 0, // pow(Nextafter(1, -2), float64(1 << 63)) + 0, // pow(Nextafter(-1, 2), float64(1 << 63)) + Inf(1), // pow(Nextafter(-1, -2), float64(1 << 63)) } var vfpow10SC = []int{ @@ -1680,6 +1767,37 @@ var pow10SC = []float64{ Inf(1), // pow10(MaxInt32) } +var vfroundSC = [][2]float64{ + {0, 0}, + {1.390671161567e-309, 0}, // denormal + {0.49999999999999994, 0}, // 0.5-epsilon + {0.5, 1}, + {0.5000000000000001, 1}, // 0.5+epsilon + {-1.5, -2}, + {-2.5, -3}, + {NaN(), NaN()}, + {Inf(1), Inf(1)}, + {2251799813685249.5, 2251799813685250}, // 1 bit fraction + {2251799813685250.5, 2251799813685251}, + {4503599627370495.5, 4503599627370496}, // 1 bit fraction, rounding to 0 bit fraction + {4503599627370497, 4503599627370497}, // large integer +} +var vfroundEvenSC = [][2]float64{ + {0, 0}, + {1.390671161567e-309, 0}, // denormal + {0.49999999999999994, 0}, // 0.5-epsilon + {0.5, 0}, + {0.5000000000000001, 1}, // 0.5+epsilon + {-1.5, -2}, + {-2.5, -2}, + {NaN(), NaN()}, + {Inf(1), Inf(1)}, + {2251799813685249.5, 2251799813685250}, // 1 bit fraction + {2251799813685250.5, 2251799813685250}, + {4503599627370495.5, 4503599627370496}, // 1 bit fraction, rounding to 0 bit fraction + {4503599627370497, 4503599627370497}, // large integer +} + var vfsignbitSC = []float64{ Inf(-1), Copysign(0, -1), @@ -2093,6 +2211,54 @@ func TestErfc(t *testing.T) { } } +func TestErfinv(t *testing.T) { + for i := 0; i < len(vf); i++ { + a := vf[i] / 10 + if f := Erfinv(a); !veryclose(erfinv[i], f) { + t.Errorf("Erfinv(%g) = %g, want %g", a, f, erfinv[i]) + } + } + for i := 0; i < len(vferfinvSC); i++ { + if f := Erfinv(vferfinvSC[i]); !alike(erfinvSC[i], f) { + t.Errorf("Erfinv(%g) = %g, want %g", vferfinvSC[i], f, erfinvSC[i]) + } + } + for x := -0.9; x <= 0.90; x += 1e-2 { + if f := Erf(Erfinv(x)); !close(x, f) { + t.Errorf("Erf(Erfinv(%g)) = %g, want %g", x, f, x) + } + } + for x := -0.9; x <= 0.90; x += 1e-2 { + if f := Erfinv(Erf(x)); !close(x, f) { + t.Errorf("Erfinv(Erf(%g)) = %g, want %g", x, f, x) + } + } +} + +func TestErfcinv(t *testing.T) { + for i := 0; i < len(vf); i++ { + a := 1.0 - (vf[i] / 10) + if f := Erfcinv(a); !veryclose(erfinv[i], f) { + t.Errorf("Erfcinv(%g) = %g, want %g", a, f, erfinv[i]) + } + } + for i := 0; i < len(vferfcinvSC); i++ { + if f := Erfcinv(vferfcinvSC[i]); !alike(erfcinvSC[i], f) { + t.Errorf("Erfcinv(%g) = %g, want %g", vferfcinvSC[i], f, erfcinvSC[i]) + } + } + for x := 0.1; x <= 1.9; x += 1e-2 { + if f := Erfc(Erfcinv(x)); !close(x, f) { + t.Errorf("Erfc(Erfcinv(%g)) = %g, want %g", x, f, x) + } + } + for x := 0.1; x <= 1.9; x += 1e-2 { + if f := Erfcinv(Erfc(x)); !close(x, f) { + t.Errorf("Erfcinv(Erfc(%g)) = %g, want %g", x, f, x) + } + } +} + func TestExp(t *testing.T) { testExp(t, Exp, "Exp") testExp(t, ExpGo, "ExpGo") @@ -2590,6 +2756,32 @@ func TestRemainder(t *testing.T) { } } +func TestRound(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := Round(vf[i]); !alike(round[i], f) { + t.Errorf("Round(%g) = %g, want %g", vf[i], f, round[i]) + } + } + for i := 0; i < len(vfroundSC); i++ { + if f := Round(vfroundSC[i][0]); !alike(vfroundSC[i][1], f) { + t.Errorf("Round(%g) = %g, want %g", vfroundSC[i][0], f, vfroundSC[i][1]) + } + } +} + +func TestRoundToEven(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := RoundToEven(vf[i]); !alike(round[i], f) { + t.Errorf("RoundToEven(%g) = %g, want %g", vf[i], f, round[i]) + } + } + for i := 0; i < len(vfroundEvenSC); i++ { + if f := RoundToEven(vfroundEvenSC[i][0]); !alike(vfroundEvenSC[i][1], f) { + t.Errorf("RoundToEven(%g) = %g, want %g", vfroundEvenSC[i][0], f, vfroundEvenSC[i][1]) + } + } +} + func TestSignbit(t *testing.T) { for i := 0; i < len(vf); i++ { if f := Signbit(vf[i]); signbit[i] != f { @@ -2906,10 +3098,12 @@ func BenchmarkCeil(b *testing.B) { GlobalF = x } +var copysignNeg = -1.0 + func BenchmarkCopysign(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { - x = Copysign(.5, -1) + x = Copysign(.5, copysignNeg) } GlobalF = x } @@ -2946,6 +3140,22 @@ func BenchmarkErfc(b *testing.B) { GlobalF = x } +func BenchmarkErfinv(b *testing.B) { + x := 0.0 + for i := 0; i < b.N; i++ { + x = Erfinv(.5) + } + GlobalF = x +} + +func BenchmarkErfcinv(b *testing.B) { + x := 0.0 + for i := 0; i < b.N; i++ { + x = Erfcinv(.5) + } + GlobalF = x +} + func BenchmarkExp(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { @@ -2986,10 +3196,12 @@ func BenchmarkExp2Go(b *testing.B) { GlobalF = x } +var absPos = .5 + func BenchmarkAbs(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { - x = Abs(.5) + x = Abs(absPos) } GlobalF = x @@ -2998,7 +3210,7 @@ func BenchmarkAbs(b *testing.B) { func BenchmarkDim(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { - x = Dim(10, 3) + x = Dim(GlobalF, x) } GlobalF = x } @@ -3221,6 +3433,24 @@ func BenchmarkPow10Neg(b *testing.B) { GlobalF = x } +var roundNeg = float64(-2.5) + +func BenchmarkRound(b *testing.B) { + x := 0.0 + for i := 0; i < b.N; i++ { + x = Round(roundNeg) + } + GlobalF = x +} + +func BenchmarkRoundToEven(b *testing.B) { + x := 0.0 + for i := 0; i < b.N; i++ { + x = RoundToEven(roundNeg) + } + GlobalF = x +} + func BenchmarkRemainder(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { @@ -3229,10 +3459,12 @@ func BenchmarkRemainder(b *testing.B) { GlobalF = x } +var signbitPos = 2.5 + func BenchmarkSignbit(b *testing.B) { x := false for i := 0; i < b.N; i++ { - x = Signbit(2.5) + x = Signbit(signbitPos) } GlobalB = x } diff --git a/libgo/go/math/big/calibrate_test.go b/libgo/go/math/big/calibrate_test.go index f69ffbf5cf1..2b96e74a658 100644 --- a/libgo/go/math/big/calibrate_test.go +++ b/libgo/go/math/big/calibrate_test.go @@ -2,13 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Calibration used to determine thresholds for using +// different algorithms. Ideally, this would be converted +// to go generate to create thresholds.go + // This file prints execution times for the Mul benchmark // given different Karatsuba thresholds. The result may be // used to manually fine-tune the threshold constant. The // results are somewhat fragile; use repeated runs to get // a clear picture. -// Usage: go test -run=TestCalibrate -calibrate +// Calculates lower and upper thresholds for when basicSqr +// is faster than standard multiplication. + +// Usage: go test -run=TestCalibrate -v -calibrate package big @@ -21,6 +28,27 @@ import ( var calibrate = flag.Bool("calibrate", false, "run calibration test") +func TestCalibrate(t *testing.T) { + if *calibrate { + computeKaratsubaThresholds() + + // compute basicSqrThreshold where overhead becomes negligible + minSqr := computeSqrThreshold(10, 30, 1, 3) + // compute karatsubaSqrThreshold where karatsuba is faster + maxSqr := computeSqrThreshold(300, 500, 10, 3) + if minSqr != 0 { + fmt.Printf("found basicSqrThreshold = %d\n", minSqr) + } else { + fmt.Println("no basicSqrThreshold found") + } + if maxSqr != 0 { + fmt.Printf("found karatsubaSqrThreshold = %d\n", maxSqr) + } else { + fmt.Println("no karatsubaSqrThreshold found") + } + } +} + func karatsubaLoad(b *testing.B) { BenchmarkMul(b) } @@ -34,7 +62,7 @@ func measureKaratsuba(th int) time.Duration { return time.Duration(res.NsPerOp()) } -func computeThresholds() { +func computeKaratsubaThresholds() { fmt.Printf("Multiplication times for varying Karatsuba thresholds\n") fmt.Printf("(run repeatedly for good results)\n") @@ -81,8 +109,56 @@ func computeThresholds() { } } -func TestCalibrate(t *testing.T) { - if *calibrate { - computeThresholds() +func measureBasicSqr(words, nruns int, enable bool) time.Duration { + // more runs for better statistics + initBasicSqr, initKaratsubaSqr := basicSqrThreshold, karatsubaSqrThreshold + + if enable { + // set thresholds to use basicSqr at this number of words + basicSqrThreshold, karatsubaSqrThreshold = words-1, words+1 + } else { + // set thresholds to disable basicSqr for any number of words + basicSqrThreshold, karatsubaSqrThreshold = -1, -1 + } + + var testval int64 + for i := 0; i < nruns; i++ { + res := testing.Benchmark(func(b *testing.B) { benchmarkNatSqr(b, words) }) + testval += res.NsPerOp() + } + testval /= int64(nruns) + + basicSqrThreshold, karatsubaSqrThreshold = initBasicSqr, initKaratsubaSqr + + return time.Duration(testval) +} + +func computeSqrThreshold(from, to, step, nruns int) int { + fmt.Println("Calibrating thresholds for basicSqr via benchmarks of z.mul(x,x)") + fmt.Printf("Looking for a timing difference for x between %d - %d words by %d step\n", from, to, step) + var initPos bool + var threshold int + for i := from; i <= to; i += step { + baseline := measureBasicSqr(i, nruns, false) + testval := measureBasicSqr(i, nruns, true) + pos := baseline > testval + delta := baseline - testval + percent := delta * 100 / baseline + fmt.Printf("words = %3d deltaT = %10s (%4d%%) is basicSqr better: %v", i, delta, percent, pos) + if i == from { + initPos = pos + } + if threshold == 0 && pos != initPos { + threshold = i + fmt.Printf(" threshold found") + } + fmt.Println() + + } + if threshold != 0 { + fmt.Printf("Found threshold = %d between %d - %d\n", threshold, from, to) + } else { + fmt.Printf("Found NO threshold between %d - %d\n", from, to) } + return threshold } diff --git a/libgo/go/math/big/decimal.go b/libgo/go/math/big/decimal.go index 2dfa032c776..ae9ffb5db6a 100644 --- a/libgo/go/math/big/decimal.go +++ b/libgo/go/math/big/decimal.go @@ -20,7 +20,7 @@ package big // A decimal represents an unsigned floating-point number in decimal representation. -// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= d.mant < 1, +// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.1 <= d.mant < 1, // with the most-significant mantissa digit at index 0. For the zero decimal, the // mantissa length and exponent are 0. // The zero value for decimal represents a ready-to-use 0.0. diff --git a/libgo/go/math/big/float.go b/libgo/go/math/big/float.go index 7e11f1aff58..c042854ebaa 100644 --- a/libgo/go/math/big/float.go +++ b/libgo/go/math/big/float.go @@ -415,8 +415,9 @@ func (z *Float) round(sbit uint) { // bits > z.prec: mantissa too large => round r := uint(bits - z.prec - 1) // rounding bit position; r >= 0 rbit := z.mant.bit(r) & 1 // rounding bit; be safe and ensure it's a single bit - if sbit == 0 { - // TODO(gri) if rbit != 0 we don't need to compute sbit for some rounding modes (optimization) + // The sticky bit is only needed for rounding ToNearestEven + // or when the rounding bit is zero. Avoid computation otherwise. + if sbit == 0 && (rbit == 0 || z.mode == ToNearestEven) { sbit = z.mant.sticky(r) } sbit &= 1 // be safe and ensure it's a single bit @@ -1310,8 +1311,11 @@ func (z *Float) umul(x, y *Float) { // TODO(gri) Optimize this for the common case. e := int64(x.exp) + int64(y.exp) - z.mant = z.mant.mul(x.mant, y.mant) - + if x == y { + z.mant = z.mant.sqr(x.mant) + } else { + z.mant = z.mant.mul(x.mant, y.mant) + } z.setExpAndRound(e-fnorm(z.mant), 0) } diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go index 62f7fc53203..0eda9cd4e12 100644 --- a/libgo/go/math/big/int.go +++ b/libgo/go/math/big/int.go @@ -153,6 +153,11 @@ func (z *Int) Mul(x, y *Int) *Int { // x * (-y) == -(x * y) // (-x) * y == -(x * y) // (-x) * (-y) == x * y + if x == y { + z.abs = z.abs.sqr(x.abs) + z.neg = false + return z + } z.abs = z.abs.mul(x.abs, y.abs) z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign return z @@ -324,6 +329,16 @@ func (x *Int) Cmp(y *Int) (r int) { return } +// CmpAbs compares the absolute values of x and y and returns: +// +// -1 if |x| < |y| +// 0 if |x| == |y| +// +1 if |x| > |y| +// +func (x *Int) CmpAbs(y *Int) int { + return x.abs.cmp(y.abs) +} + // low32 returns the least significant 32 bits of x. func low32(x nat) uint32 { if len(x) == 0 { @@ -384,16 +399,26 @@ func (x *Int) IsUint64() bool { // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. // +// For bases <= 36, lower and upper case letters are considered the same: +// The letters 'a' to 'z' and 'A' to 'Z' represent digit values 10 to 35. +// For bases > 36, the upper case letters 'A' to 'Z' represent the digit +// values 36 to 61. +// func (z *Int) SetString(s string, base int) (*Int, bool) { - r := strings.NewReader(s) + return z.setFromScanner(strings.NewReader(s), base) +} + +// setFromScanner implements SetString given an io.BytesScanner. +// For documentation see comments of SetString. +func (z *Int) setFromScanner(r io.ByteScanner, base int) (*Int, bool) { if _, _, err := z.scan(r, base); err != nil { return nil, false } - // entire string must have been consumed + // entire content must have been consumed if _, err := r.ReadByte(); err != io.EOF { return nil, false } - return z, true // err == io.EOF => scan consumed all of s + return z, true // err == io.EOF => scan consumed all content of r } // SetBytes interprets buf as the bytes of a big-endian unsigned @@ -447,7 +472,7 @@ func (z *Int) Exp(x, y, m *Int) *Int { // GCD sets z to the greatest common divisor of a and b, which both must // be > 0, and returns z. -// If x and y are not nil, GCD sets x and y such that z = a*x + b*y. +// If x or y are not nil, GCD sets their value such that z = a*x + b*y. // If either a or b is <= 0, GCD sets z = x = y = 0. func (z *Int) GCD(x, y, a, b *Int) *Int { if a.Sign() <= 0 || b.Sign() <= 0 { @@ -461,17 +486,14 @@ func (z *Int) GCD(x, y, a, b *Int) *Int { return z } if x == nil && y == nil { - return z.binaryGCD(a, b) + return z.lehmerGCD(a, b) } A := new(Int).Set(a) B := new(Int).Set(b) X := new(Int) - Y := new(Int).SetInt64(1) - lastX := new(Int).SetInt64(1) - lastY := new(Int) q := new(Int) temp := new(Int) @@ -484,15 +506,8 @@ func (z *Int) GCD(x, y, a, b *Int) *Int { temp.Set(X) X.Mul(X, q) - X.neg = !X.neg - X.Add(X, lastX) + X.Sub(lastX, X) lastX.Set(temp) - - temp.Set(Y) - Y.Mul(Y, q) - Y.neg = !Y.neg - Y.Add(Y, lastY) - lastY.Set(temp) } if x != nil { @@ -500,74 +515,139 @@ func (z *Int) GCD(x, y, a, b *Int) *Int { } if y != nil { - *y = *lastY + // y = (z - a*x)/b + y.Mul(a, lastX) + y.Sub(A, y) + y.Div(y, b) } *z = *A return z } -// binaryGCD sets z to the greatest common divisor of a and b, which both must -// be > 0, and returns z. -// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm B. -func (z *Int) binaryGCD(a, b *Int) *Int { - u := z - v := new(Int) - - // use one Euclidean iteration to ensure that u and v are approx. the same size - switch { - case len(a.abs) > len(b.abs): - // must set v before u since u may be alias for a or b (was issue #11284) - v.Rem(a, b) - u.Set(b) - case len(a.abs) < len(b.abs): - v.Rem(b, a) - u.Set(a) - default: - v.Set(b) - u.Set(a) - } - // a, b must not be used anymore (may be aliases with u) - - // v might be 0 now - if len(v.abs) == 0 { - return u +// lehmerGCD sets z to the greatest common divisor of a and b, +// which both must be > 0, and returns z. +// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm L. +// This implementation uses the improved condition by Collins requiring only one +// quotient and avoiding the possibility of single Word overflow. +// See Jebelean, "Improving the multiprecision Euclidean algorithm", +// Design and Implementation of Symbolic Computation Systems, pp 45-58. +func (z *Int) lehmerGCD(a, b *Int) *Int { + // ensure a >= b + if a.abs.cmp(b.abs) < 0 { + a, b = b, a } - // u > 0 && v > 0 - // determine largest k such that u = u' << k, v = v' << k - k := u.abs.trailingZeroBits() - if vk := v.abs.trailingZeroBits(); vk < k { - k = vk - } - u.Rsh(u, k) - v.Rsh(v, k) + // don't destroy incoming values of a and b + B := new(Int).Set(b) // must be set first in case b is an alias of z + A := z.Set(a) - // determine t (we know that u > 0) + // temp variables for multiprecision update t := new(Int) - if u.abs[0]&1 != 0 { - // u is odd - t.Neg(v) - } else { - t.Set(u) - } + r := new(Int) + s := new(Int) + w := new(Int) + + // loop invariant A >= B + for len(B.abs) > 1 { + // initialize the digits + var a1, a2, u0, u1, u2, v0, v1, v2 Word + + m := len(B.abs) // m >= 2 + n := len(A.abs) // n >= m >= 2 + + // extract the top Word of bits from A and B + h := nlz(A.abs[n-1]) + a1 = (A.abs[n-1] << h) | (A.abs[n-2] >> (_W - h)) + // B may have implicit zero words in the high bits if the lengths differ + switch { + case n == m: + a2 = (B.abs[n-1] << h) | (B.abs[n-2] >> (_W - h)) + case n == m+1: + a2 = (B.abs[n-2] >> (_W - h)) + default: + a2 = 0 + } + + // Since we are calculating with full words to avoid overflow, + // we use 'even' to track the sign of the cosequences. + // For even iterations: u0, v1 >= 0 && u1, v0 <= 0 + // For odd iterations: u0, v1 <= 0 && u1, v0 >= 0 + // The first iteration starts with k=1 (odd). + even := false + // variables to track the cosequences + u0, u1, u2 = 0, 1, 0 + v0, v1, v2 = 0, 0, 1 + + // Calculate the quotient and cosequences using Collins' stopping condition. + // Note that overflow of a Word is not possible when computing the remainder + // sequence and cosequences since the cosequence size is bounded by the input size. + // See section 4.2 of Jebelean for details. + for a2 >= v2 && a1-a2 >= v1+v2 { + q := a1 / a2 + a1, a2 = a2, a1-q*a2 + u0, u1, u2 = u1, u2, u1+q*u2 + v0, v1, v2 = v1, v2, v1+q*v2 + even = !even + } + + // multiprecision step + if v0 != 0 { + // simulate the effect of the single precision steps using the cosequences + // A = u0*A + v0*B + // B = u1*A + v1*B + + t.abs = t.abs.setWord(u0) + s.abs = s.abs.setWord(v0) + t.neg = !even + s.neg = even + + t.Mul(A, t) + s.Mul(B, s) + + r.abs = r.abs.setWord(u1) + w.abs = w.abs.setWord(v1) + r.neg = even + w.neg = !even + + r.Mul(A, r) + w.Mul(B, w) + + A.Add(t, s) + B.Add(r, w) - for len(t.abs) > 0 { - // reduce t - t.Rsh(t, t.abs.trailingZeroBits()) - if t.neg { - v, t = t, v - v.neg = len(v.abs) > 0 && !v.neg // 0 has no sign } else { - u, t = t, u + // single-digit calculations failed to simluate any quotients + // do a standard Euclidean step + t.Rem(A, B) + A, B, t = B, t, A } - t.Sub(u, v) } - return z.Lsh(u, k) + if len(B.abs) > 0 { + // standard Euclidean algorithm base case for B a single Word + if len(A.abs) > 1 { + // A is longer than a single Word + t.Rem(A, B) + A, B, t = B, t, A + } + if len(B.abs) > 0 { + // A and B are both a single Word + a1, a2 := A.abs[0], B.abs[0] + for a2 != 0 { + a1, a2 = a2, a1%a2 + } + A.abs[0] = a1 + } + } + *z = *A + return z } // Rand sets z to a pseudo-random number in [0, n) and returns z. +// +// As this uses the math/rand package, it must not be used for +// security-sensitive work. Use crypto/rand.Int instead. func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int { z.neg = false if n.neg || len(n.abs) == 0 { @@ -659,10 +739,9 @@ func Jacobi(x, y *Int) int { // to calculate the square root of any quadratic residue mod p quickly for 3 // mod 4 primes. func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int { - z.Set(p) // z = p - z.Add(z, intOne) // z = p + 1 - z.Rsh(z, 2) // z = (p + 1) / 4 - z.Exp(x, z, p) // z = x^z mod p + e := new(Int).Add(p, intOne) // e = p + 1 + e.Rsh(e, 2) // e = (p + 1) / 4 + z.Exp(x, e, p) // z = x^e mod p return z } diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go index 42e810b3b81..270fec6b369 100644 --- a/libgo/go/math/big/int_test.go +++ b/libgo/go/math/big/int_test.go @@ -7,6 +7,7 @@ package big import ( "bytes" "encoding/hex" + "fmt" "math/rand" "strconv" "strings" @@ -674,6 +675,37 @@ func checkGcd(aBytes, bBytes []byte) bool { return x.Cmp(d) == 0 } +// euclidGCD is a reference implementation of Euclid's GCD +// algorithm for testing against optimized algorithms. +// Requirements: a, b > 0 +func euclidGCD(a, b *Int) *Int { + + A := new(Int).Set(a) + B := new(Int).Set(b) + t := new(Int) + + for len(B.abs) > 0 { + // A, B = B, A % B + t.Rem(A, B) + A, B, t = B, t, A + } + return A +} + +func checkLehmerGcd(aBytes, bBytes []byte) bool { + a := new(Int).SetBytes(aBytes) + b := new(Int).SetBytes(bBytes) + + if a.Sign() <= 0 || b.Sign() <= 0 { + return true // can only test positive arguments + } + + d := new(Int).lehmerGCD(a, b) + d0 := euclidGCD(a, b) + + return d.Cmp(d0) == 0 +} + var gcdTests = []struct { d, x, y, a, b string }{ @@ -707,38 +739,28 @@ func testGcd(t *testing.T, d, x, y, a, b *Int) { D := new(Int).GCD(X, Y, a, b) if D.Cmp(d) != 0 { - t.Errorf("GCD(%s, %s): got d = %s, want %s", a, b, D, d) + t.Errorf("GCD(%s, %s, %s, %s): got d = %s, want %s", x, y, a, b, D, d) } if x != nil && X.Cmp(x) != 0 { - t.Errorf("GCD(%s, %s): got x = %s, want %s", a, b, X, x) + t.Errorf("GCD(%s, %s, %s, %s): got x = %s, want %s", x, y, a, b, X, x) } if y != nil && Y.Cmp(y) != 0 { - t.Errorf("GCD(%s, %s): got y = %s, want %s", a, b, Y, y) - } - - // binaryGCD requires a > 0 && b > 0 - if a.Sign() <= 0 || b.Sign() <= 0 { - return - } - - D.binaryGCD(a, b) - if D.Cmp(d) != 0 { - t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d) + t.Errorf("GCD(%s, %s, %s, %s): got y = %s, want %s", x, y, a, b, Y, y) } // check results in presence of aliasing (issue #11284) a2 := new(Int).Set(a) b2 := new(Int).Set(b) - a2.binaryGCD(a2, b2) // result is same as 1st argument + a2.GCD(X, Y, a2, b2) // result is same as 1st argument if a2.Cmp(d) != 0 { - t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d) + t.Errorf("aliased z = a GCD(%s, %s, %s, %s): got d = %s, want %s", x, y, a, b, a2, d) } a2 = new(Int).Set(a) b2 = new(Int).Set(b) - b2.binaryGCD(a2, b2) // result is same as 2nd argument + b2.GCD(X, Y, a2, b2) // result is same as 2nd argument if b2.Cmp(d) != 0 { - t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d) + t.Errorf("aliased z = b GCD(%s, %s, %s, %s): got d = %s, want %s", x, y, a, b, b2, d) } } @@ -759,6 +781,10 @@ func TestGcd(t *testing.T) { if err := quick.Check(checkGcd, nil); err != nil { t.Error(err) } + + if err := quick.Check(checkLehmerGcd, nil); err != nil { + t.Error(err) + } } type intShiftTest struct { @@ -903,6 +929,63 @@ func TestLshRsh(t *testing.T) { } } +// Entries must be sorted by value in ascending order. +var cmpAbsTests = []string{ + "0", + "1", + "2", + "10", + "10000000", + "2783678367462374683678456387645876387564783686583485", + "2783678367462374683678456387645876387564783686583486", + "32957394867987420967976567076075976570670947609750670956097509670576075067076027578341538", +} + +func TestCmpAbs(t *testing.T) { + values := make([]*Int, len(cmpAbsTests)) + var prev *Int + for i, s := range cmpAbsTests { + x, ok := new(Int).SetString(s, 0) + if !ok { + t.Fatalf("SetString(%s, 0) failed", s) + } + if prev != nil && prev.Cmp(x) >= 0 { + t.Fatal("cmpAbsTests entries not sorted in ascending order") + } + values[i] = x + prev = x + } + + for i, x := range values { + for j, y := range values { + // try all combinations of signs for x, y + for k := 0; k < 4; k++ { + var a, b Int + a.Set(x) + b.Set(y) + if k&1 != 0 { + a.Neg(&a) + } + if k&2 != 0 { + b.Neg(&b) + } + + got := a.CmpAbs(&b) + want := 0 + switch { + case i > j: + want = 1 + case i < j: + want = -1 + } + if got != want { + t.Errorf("absCmp |%s|, |%s|: got %d; want %d", &a, &b, got, want) + } + } + } + } +} + var int64Tests = []string{ // int64 "0", @@ -1383,6 +1466,12 @@ func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool { t.Errorf("ModSqrt returned inconsistent value %s", z) } + // test x aliasing z + z = sqrtChk.ModSqrt(sqrtChk.Set(sq), mod) + if z != &sqrtChk || z.Cmp(sqrt) != 0 { + t.Errorf("ModSqrt returned inconsistent value %s", z) + } + // make sure we actually got a square root if sqrt.Cmp(elt) == 0 { return true // we found the "desired" square root @@ -1536,6 +1625,26 @@ func TestSqrt(t *testing.T) { } } +// We can't test this together with the other Exp tests above because +// it requires a different receiver setup. +func TestIssue22830(t *testing.T) { + one := new(Int).SetInt64(1) + base, _ := new(Int).SetString("84555555300000000000", 10) + mod, _ := new(Int).SetString("66666670001111111111", 10) + want, _ := new(Int).SetString("17888885298888888889", 10) + + var tests = []int64{ + 0, 1, -1, + } + + for _, n := range tests { + m := NewInt(n) + if got := m.Exp(base, one, mod); got.Cmp(want) != 0 { + t.Errorf("(%v).Exp(%s, 1, %s) = %s, want %s", n, base, mod, got, want) + } + } +} + func BenchmarkSqrt(b *testing.B) { n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10) b.ResetTimer() @@ -1544,3 +1653,24 @@ func BenchmarkSqrt(b *testing.B) { t.Sqrt(n) } } + +func benchmarkIntSqr(b *testing.B, nwords int) { + x := new(Int) + x.abs = rndNat(nwords) + t := new(Int) + b.ResetTimer() + for i := 0; i < b.N; i++ { + t.Mul(x, x) + } +} + +func BenchmarkIntSqr(b *testing.B) { + for _, n := range sqrBenchSizes { + if isRaceBuilder && n > 1e3 { + continue + } + b.Run(fmt.Sprintf("%d", n), func(b *testing.B) { + benchmarkIntSqr(b, n) + }) + } +} diff --git a/libgo/go/math/big/intconv.go b/libgo/go/math/big/intconv.go index 91a62ce04e1..6cca827c8e3 100644 --- a/libgo/go/math/big/intconv.go +++ b/libgo/go/math/big/intconv.go @@ -12,16 +12,11 @@ import ( "io" ) -// TODO(gri) Should rename itoa to utoa (there's no sign). That -// would permit the introduction of itoa which is like utoa but -// reserves a byte for a possible sign that's passed in. That -// would permit Int.Text to be implemented w/o the need for -// string copy if the number is negative. - // Text returns the string representation of x in the given base. -// Base must be between 2 and 36, inclusive. The result uses the -// lower-case letters 'a' to 'z' for digit values >= 10. No base -// prefix (such as "0x") is added to the string. +// Base must be between 2 and 62, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values 10 to 35, and +// the upper-case letters 'A' to 'Z' for digit values 36 to 61. +// No prefix (such as "0x") is added to the string. func (x *Int) Text(base int) string { if x == nil { return "" diff --git a/libgo/go/math/big/intconv_test.go b/libgo/go/math/big/intconv_test.go index 514208145fd..2e01ee327dd 100644 --- a/libgo/go/math/big/intconv_test.go +++ b/libgo/go/math/big/intconv_test.go @@ -56,6 +56,10 @@ var stringTests = []struct { {"-0b111", "-7", 0, -7, true}, {"0b1001010111", "599", 0, 0x257, true}, {"1001010111", "1001010111", 2, 0x257, true}, + {"A", "a", 36, 10, true}, + {"A", "A", 37, 36, true}, + {"ABCXYZ", "abcxyz", 36, 623741435, true}, + {"ABCXYZ", "ABCXYZ", 62, 33536793425, true}, } func TestIntText(t *testing.T) { @@ -135,8 +139,16 @@ func TestGetString(t *testing.T) { } } - if got := fmt.Sprintf(format(test.base), z); got != test.out { - t.Errorf("#%db got %s; want %s", i, got, test.out) + f := format(test.base) + got := fmt.Sprintf(f, z) + if f == "%d" { + if got != fmt.Sprintf("%d", test.val) { + t.Errorf("#%db got %s; want %d", i, got, test.val) + } + } else { + if got != test.out { + t.Errorf("#%dc got %s; want %s", i, got, test.out) + } } } } diff --git a/libgo/go/math/big/intmarsh.go b/libgo/go/math/big/intmarsh.go index ee1e4143ed9..c1422e27107 100644 --- a/libgo/go/math/big/intmarsh.go +++ b/libgo/go/math/big/intmarsh.go @@ -6,7 +6,10 @@ package big -import "fmt" +import ( + "bytes" + "fmt" +) // Gob codec version. Permits backward-compatible changes to the encoding. const intGobVersion byte = 1 @@ -52,8 +55,7 @@ func (x *Int) MarshalText() (text []byte, err error) { // UnmarshalText implements the encoding.TextUnmarshaler interface. func (z *Int) UnmarshalText(text []byte) error { - // TODO(gri): get rid of the []byte/string conversion - if _, ok := z.SetString(string(text), 0); !ok { + if _, ok := z.setFromScanner(bytes.NewReader(text), 0); !ok { return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) } return nil diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 889eacb90f0..3bb818f5f25 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -249,7 +249,7 @@ func karatsubaSub(z, x nat, n int) { // Operands that are shorter than karatsubaThreshold are multiplied using // "grade school" multiplication; for longer operands the Karatsuba algorithm // is used. -var karatsubaThreshold int = 40 // computed by calibrate.go +var karatsubaThreshold = 40 // computed by calibrate_test.go // karatsuba multiplies x and y and leaves the result in z. // Both x and y must have the same length n and n must be a @@ -473,6 +473,61 @@ func (z nat) mul(x, y nat) nat { return z.norm() } +// basicSqr sets z = x*x and is asymptotically faster than basicMul +// by about a factor of 2, but slower for small arguments due to overhead. +// Requirements: len(x) > 0, len(z) >= 2*len(x) +// The (non-normalized) result is placed in z[0 : 2 * len(x)]. +func basicSqr(z, x nat) { + n := len(x) + t := make(nat, 2*n) // temporary variable to hold the products + z[1], z[0] = mulWW(x[0], x[0]) // the initial square + for i := 1; i < n; i++ { + d := x[i] + // z collects the squares x[i] * x[i] + z[2*i+1], z[2*i] = mulWW(d, d) + // t collects the products x[i] * x[j] where j < i + t[2*i] = addMulVVW(t[i:2*i], x[0:i], d) + } + t[2*n-1] = shlVU(t[1:2*n-1], t[1:2*n-1], 1) // double the j < i products + addVV(z, z, t) // combine the result +} + +// Operands that are shorter than basicSqrThreshold are squared using +// "grade school" multiplication; for operands longer than karatsubaSqrThreshold +// the Karatsuba algorithm is used. +var basicSqrThreshold = 20 // computed by calibrate_test.go +var karatsubaSqrThreshold = 400 // computed by calibrate_test.go + +// z = x*x +func (z nat) sqr(x nat) nat { + n := len(x) + switch { + case n == 0: + return z[:0] + case n == 1: + d := x[0] + z = z.make(2) + z[1], z[0] = mulWW(d, d) + return z.norm() + } + + if alias(z, x) { + z = nil // z is an alias for x - cannot reuse + } + z = z.make(2 * n) + + if n < basicSqrThreshold { + basicMul(z, x, x) + return z.norm() + } + if n < karatsubaSqrThreshold { + basicSqr(z, x) + return z.norm() + } + + return z.mul(x, x) +} + // mulRange computes the product of all the unsigned integers in the // range [a, b] inclusively. If a > b (empty range), the result is 1. func (z nat) mulRange(a, b uint64) nat { @@ -566,8 +621,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { // determine if z can be reused // TODO(gri) should find a better solution - this if statement // is very costly (see e.g. time pidigits -s -n 10000) - if alias(z, uIn) || alias(z, v) { - z = nil // z is an alias for uIn or v - cannot reuse + if alias(z, u) || alias(z, uIn) || alias(z, v) { + z = nil // z is an alias for u or uIn or v - cannot reuse } q = z.make(m + 1) @@ -936,7 +991,7 @@ func (z nat) expNN(x, y, m nat) nat { // otherwise the arguments would alias. var zz, r nat for j := 0; j < w; j++ { - zz = zz.mul(z, z) + zz = zz.sqr(z) zz, z = z, zz if v&mask != 0 { @@ -956,7 +1011,7 @@ func (z nat) expNN(x, y, m nat) nat { v = y[i] for j := 0; j < _W; j++ { - zz = zz.mul(z, z) + zz = zz.sqr(z) zz, z = z, zz if v&mask != 0 { @@ -989,7 +1044,7 @@ func (z nat) expNNWindowed(x, y, m nat) nat { powers[1] = x for i := 2; i < 1< 1e3 { + continue + } + b.Run(fmt.Sprintf("%d", n), func(b *testing.B) { + benchmarkNatSqr(b, n) + }) + } +} diff --git a/libgo/go/math/big/natconv.go b/libgo/go/math/big/natconv.go index 25a345ef0e5..21ccbd6cfaf 100644 --- a/libgo/go/math/big/natconv.go +++ b/libgo/go/math/big/natconv.go @@ -15,13 +15,14 @@ import ( "sync" ) -const digits = "0123456789abcdefghijklmnopqrstuvwxyz" +const digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -// Note: MaxBase = len(digits), but it must remain a rune constant +// Note: MaxBase = len(digits), but it must remain an untyped rune constant // for API compatibility. // MaxBase is the largest number base accepted for string conversions. -const MaxBase = 'z' - 'a' + 10 + 1 +const MaxBase = 10 + ('z' - 'a' + 1) + ('Z' - 'A' + 1) +const maxBaseSmall = 10 + ('z' - 'a' + 1) // maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M. // For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word. @@ -59,11 +60,11 @@ func pow(x Word, n int) (p Word) { // It returns the corresponding natural number res, the actual base b, // a digit count, and a read or syntax error err, if any. // -// number = [ prefix ] mantissa . -// prefix = "0" [ "x" | "X" | "b" | "B" ] . -// mantissa = digits | digits "." [ digits ] | "." digits . -// digits = digit { digit } . -// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . +// number = [ prefix ] mantissa . +// prefix = "0" [ "x" | "X" | "b" | "B" ] . +// mantissa = digits | digits "." [ digits ] | "." digits . +// digits = digit { digit } . +// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . // // Unless fracOk is set, the base argument must be 0 or a value between // 2 and MaxBase. If fracOk is set, the base argument must be one of @@ -80,6 +81,11 @@ func pow(x Word, n int) (p Word) { // is permitted. The result value is computed as if there were no period // present; and the count value is used to determine the fractional part. // +// For bases <= 36, lower and upper case letters are considered the same: +// The letters 'a' to 'z' and 'A' to 'Z' represent digit values 10 to 35. +// For bases > 36, the upper case letters 'A' to 'Z' represent the digit +// values 36 to 61. +// // A result digit count > 0 corresponds to the number of (non-prefix) digits // parsed. A digit count <= 0 indicates the presence of a period (if fracOk // is set, only), and -count is the number of fractional digits found. @@ -173,7 +179,11 @@ func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count in case 'a' <= ch && ch <= 'z': d1 = Word(ch - 'a' + 10) case 'A' <= ch && ch <= 'Z': - d1 = Word(ch - 'A' + 10) + if b <= maxBaseSmall { + d1 = Word(ch - 'A' + 10) + } else { + d1 = Word(ch - 'A' + maxBaseSmall) + } default: d1 = MaxBase + 1 } @@ -469,7 +479,7 @@ func divisors(m int, b Word, ndigits int, bb Word) []divisor { table[0].bbb = nat(nil).expWW(bb, Word(leafSize)) table[0].ndigits = ndigits * leafSize } else { - table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb) + table[i].bbb = nat(nil).sqr(table[i-1].bbb) table[i].ndigits = 2 * table[i-1].ndigits } diff --git a/libgo/go/math/big/natconv_test.go b/libgo/go/math/big/natconv_test.go index 898a39fc2c2..9f38bd94bba 100644 --- a/libgo/go/math/big/natconv_test.go +++ b/libgo/go/math/big/natconv_test.go @@ -13,6 +13,12 @@ import ( "testing" ) +func TestMaxBase(t *testing.T) { + if MaxBase != len(digits) { + t.Fatalf("%d != %d", MaxBase, len(digits)) + } +} + // log2 computes the integer binary logarithm of x. // The result is the integer n for which 2^n <= x < 2^(n+1). // If x == 0, the result is -1. @@ -61,6 +67,7 @@ var strTests = []struct { {nat{0xdeadbeef}, 16, "deadbeef"}, {nat{0x229be7}, 17, "1a2b3c"}, {nat{0x309663e6}, 32, "o9cov6"}, + {nat{0x309663e6}, 62, "TakXI"}, } func TestString(t *testing.T) { @@ -110,6 +117,7 @@ var natScanTests = []struct { {s: "?"}, {base: 10}, {base: 36}, + {base: 62}, {s: "?", base: 10}, {s: "0x"}, {s: "345", base: 2}, @@ -124,6 +132,7 @@ var natScanTests = []struct { {"0", 0, false, nil, 10, 1, true, 0}, {"0", 10, false, nil, 10, 1, true, 0}, {"0", 36, false, nil, 36, 1, true, 0}, + {"0", 62, false, nil, 62, 1, true, 0}, {"1", 0, false, nat{1}, 10, 1, true, 0}, {"1", 10, false, nat{1}, 10, 1, true, 0}, {"0 ", 0, false, nil, 10, 1, true, ' '}, @@ -135,8 +144,11 @@ var natScanTests = []struct { {"03271", 0, false, nat{03271}, 8, 4, true, 0}, {"10ab", 0, false, nat{10}, 10, 2, true, 'a'}, {"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0}, + {"A", 36, false, nat{10}, 36, 1, true, 0}, + {"A", 37, false, nat{36}, 37, 1, true, 0}, {"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0}, - {"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'}, + {"XYZ?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'}, + {"XYZ?", 62, false, nat{(59*62+60)*62 + 61}, 62, 3, true, '?'}, {"0x", 16, false, nil, 16, 1, true, 'x'}, {"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0}, {"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0}, diff --git a/libgo/go/math/big/prime.go b/libgo/go/math/big/prime.go index 3e9690e55e6..848affbf5bf 100644 --- a/libgo/go/math/big/prime.go +++ b/libgo/go/math/big/prime.go @@ -108,7 +108,7 @@ NextRandom: continue } for j := uint(1); j < k; j++ { - y = y.mul(y, y) + y = y.sqr(y) quotient, y = quotient.div(y, y, n) if y.cmp(nm1) == 0 { continue NextRandom @@ -194,7 +194,7 @@ func (n nat) probablyPrimeLucas() bool { // If n is a non-square we expect to find a d in just a few attempts on average. // After 40 attempts, take a moment to check if n is indeed a square. t1 = t1.sqrt(n) - t1 = t1.mul(t1, t1) + t1 = t1.sqr(t1) if t1.cmp(n) == 0 { return false } @@ -259,7 +259,7 @@ func (n nat) probablyPrimeLucas() bool { t1 = t1.sub(t1, natP) t2, vk = t2.div(vk, t1, n) // V(k'+1) = V(2k+2) = V(k+1)² - 2. - t1 = t1.mul(vk1, vk1) + t1 = t1.sqr(vk1) t1 = t1.add(t1, nm2) t2, vk1 = t2.div(vk1, t1, n) } else { @@ -270,7 +270,7 @@ func (n nat) probablyPrimeLucas() bool { t1 = t1.sub(t1, natP) t2, vk1 = t2.div(vk1, t1, n) // V(k') = V(2k) = V(k)² - 2 - t1 = t1.mul(vk, vk) + t1 = t1.sqr(vk) t1 = t1.add(t1, nm2) t2, vk = t2.div(vk, t1, n) } @@ -312,7 +312,7 @@ func (n nat) probablyPrimeLucas() bool { } // k' = 2k // V(k') = V(2k) = V(k)² - 2 - t1 = t1.mul(vk, vk) + t1 = t1.sqr(vk) t1 = t1.sub(t1, natTwo) t2, vk = t2.div(vk, t1, n) } diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go index 56ce33d8826..b33fc696adf 100644 --- a/libgo/go/math/big/rat.go +++ b/libgo/go/math/big/rat.go @@ -422,7 +422,7 @@ func (z *Rat) norm() *Rat { neg := z.a.neg z.a.neg = false z.b.neg = false - if f := NewInt(0).binaryGCD(&z.a, &z.b); f.Cmp(intOne) != 0 { + if f := NewInt(0).lehmerGCD(&z.a, &z.b); f.Cmp(intOne) != 0 { z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs) z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs) if z.b.abs.cmp(natOne) == 0 { @@ -490,6 +490,13 @@ func (z *Rat) Sub(x, y *Rat) *Rat { // Mul sets z to the product x*y and returns z. func (z *Rat) Mul(x, y *Rat) *Rat { + if x == y { + // a squared Rat is positive and can't be reduced + z.a.neg = false + z.a.abs = z.a.abs.sqr(x.a.abs) + z.b.abs = z.b.abs.sqr(x.b.abs) + return z + } z.a.Mul(&x.a, &y.a) z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs) return z.norm() diff --git a/libgo/go/math/big/ratconv.go b/libgo/go/math/big/ratconv.go index 4bc6ef7e806..157d8d006d4 100644 --- a/libgo/go/math/big/ratconv.go +++ b/libgo/go/math/big/ratconv.go @@ -202,6 +202,11 @@ func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err err // String returns a string representation of x in the form "a/b" (even if b == 1). func (x *Rat) String() string { + return string(x.marshal()) +} + +// marshal implements String returning a slice of bytes +func (x *Rat) marshal() []byte { var buf []byte buf = x.a.Append(buf, 10) buf = append(buf, '/') @@ -210,7 +215,7 @@ func (x *Rat) String() string { } else { buf = append(buf, '1') } - return string(buf) + return buf } // RatString returns a string representation of x in the form "a/b" if b != 1, diff --git a/libgo/go/math/big/ratmarsh.go b/libgo/go/math/big/ratmarsh.go index b82e8d4ae8d..fbc7b6002d9 100644 --- a/libgo/go/math/big/ratmarsh.go +++ b/libgo/go/math/big/ratmarsh.go @@ -59,8 +59,10 @@ func (z *Rat) GobDecode(buf []byte) error { // MarshalText implements the encoding.TextMarshaler interface. func (x *Rat) MarshalText() (text []byte, err error) { - // TODO(gri): get rid of the []byte/string conversion - return []byte(x.RatString()), nil + if x.IsInt() { + return x.a.MarshalText() + } + return x.marshal(), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. diff --git a/libgo/go/math/big/sqrt.go b/libgo/go/math/big/sqrt.go new file mode 100644 index 00000000000..00433cfe7a7 --- /dev/null +++ b/libgo/go/math/big/sqrt.go @@ -0,0 +1,151 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import "math" + +var ( + half = NewFloat(0.5) + two = NewFloat(2.0) + three = NewFloat(3.0) +) + +// Sqrt sets z to the rounded square root of x, and returns it. +// +// If z's precision is 0, it is changed to x's precision before the +// operation. Rounding is performed according to z's precision and +// rounding mode. +// +// The function panics if z < 0. The value of z is undefined in that +// case. +func (z *Float) Sqrt(x *Float) *Float { + if debugFloat { + x.validate() + } + + if z.prec == 0 { + z.prec = x.prec + } + + if x.Sign() == -1 { + // following IEEE754-2008 (section 7.2) + panic(ErrNaN{"square root of negative operand"}) + } + + // handle ±0 and +∞ + if x.form != finite { + z.acc = Exact + z.form = x.form + z.neg = x.neg // IEEE754-2008 requires √±0 = ±0 + return z + } + + // MantExp sets the argument's precision to the receiver's, and + // when z.prec > x.prec this will lower z.prec. Restore it after + // the MantExp call. + prec := z.prec + b := x.MantExp(z) + z.prec = prec + + // Compute √(z·2**b) as + // √( z)·2**(½b) if b is even + // √(2z)·2**(⌊½b⌋) if b > 0 is odd + // √(½z)·2**(⌈½b⌉) if b < 0 is odd + switch b % 2 { + case 0: + // nothing to do + case 1: + z.Mul(two, z) + case -1: + z.Mul(half, z) + } + // 0.25 <= z < 2.0 + + // Solving x² - z = 0 directly requires a Quo call, but it's + // faster for small precisions. + // + // Solving 1/x² - z = 0 avoids the Quo call and is much faster for + // high precisions. + // + // 128bit precision is an empirically chosen threshold. + if z.prec <= 128 { + z.sqrtDirect(z) + } else { + z.sqrtInverse(z) + } + + // re-attach halved exponent + return z.SetMantExp(z, b/2) +} + +// Compute √x (up to prec 128) by solving +// t² - x = 0 +// for t, starting with a 53 bits precision guess from math.Sqrt and +// then using at most two iterations of Newton's method. +func (z *Float) sqrtDirect(x *Float) { + // let + // f(t) = t² - x + // then + // g(t) = f(t)/f'(t) = ½(t² - x)/t + // and the next guess is given by + // t2 = t - g(t) = ½(t² + x)/t + u := new(Float) + ng := func(t *Float) *Float { + u.prec = t.prec + u.Mul(t, t) // u = t² + u.Add(u, x) // = t² + x + u.Mul(half, u) // = ½(t² + x) + return t.Quo(u, t) // = ½(t² + x)/t + } + + xf, _ := x.Float64() + sq := NewFloat(math.Sqrt(xf)) + + switch { + case z.prec > 128: + panic("sqrtDirect: only for z.prec <= 128") + case z.prec > 64: + sq.prec *= 2 + sq = ng(sq) + fallthrough + default: + sq.prec *= 2 + sq = ng(sq) + } + + z.Set(sq) +} + +// Compute √x (to z.prec precision) by solving +// 1/t² - x = 0 +// for t (using Newton's method), and then inverting. +func (z *Float) sqrtInverse(x *Float) { + // let + // f(t) = 1/t² - x + // then + // g(t) = f(t)/f'(t) = -½t(1 - xt²) + // and the next guess is given by + // t2 = t - g(t) = ½t(3 - xt²) + u := new(Float) + ng := func(t *Float) *Float { + u.prec = t.prec + u.Mul(t, t) // u = t² + u.Mul(x, u) // = xt² + u.Sub(three, u) // = 3 - xt² + u.Mul(t, u) // = t(3 - xt²) + return t.Mul(half, u) // = ½t(3 - xt²) + } + + xf, _ := x.Float64() + sqi := NewFloat(1 / math.Sqrt(xf)) + for prec := z.prec + 32; sqi.prec < prec; { + sqi.prec *= 2 + sqi = ng(sqi) + } + // sqi = 1/√x + + // x/√x = √x + z.Mul(x, sqi) +} diff --git a/libgo/go/math/big/sqrt_test.go b/libgo/go/math/big/sqrt_test.go new file mode 100644 index 00000000000..86595a5f1e9 --- /dev/null +++ b/libgo/go/math/big/sqrt_test.go @@ -0,0 +1,131 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "fmt" + "math" + "math/rand" + "runtime" + "testing" +) + +// TestFloatSqrt64 tests that Float.Sqrt of numbers with 53bit mantissa +// behaves like float math.Sqrt. +func TestFloatSqrt64(t *testing.T) { + // This test fails for gccgo on 386 with a one ULP difference, + // presumably due to the use of extended precision floating + // point. + if runtime.Compiler == "gccgo" && runtime.GOARCH == "386" { + t.Skip("skipping on gccgo for 386; gets a one ULP difference") + } + + for i := 0; i < 1e5; i++ { + r := rand.Float64() + + got := new(Float).SetPrec(53) + got.Sqrt(NewFloat(r)) + want := NewFloat(math.Sqrt(r)) + if got.Cmp(want) != 0 { + t.Fatalf("Sqrt(%g) =\n got %g;\nwant %g", r, got, want) + } + } +} + +func TestFloatSqrt(t *testing.T) { + for _, test := range []struct { + x string + want string + }{ + // Test values were generated on Wolfram Alpha using query + // 'sqrt(N) to 350 digits' + // 350 decimal digits give up to 1000 binary digits. + {"0.03125", "0.17677669529663688110021109052621225982120898442211850914708496724884155980776337985629844179095519659187673077886403712811560450698134215158051518713749197892665283324093819909447499381264409775757143376369499645074628431682460775184106467733011114982619404115381053858929018135497032545349940642599871090667456829147610370507757690729404938184321879"}, + {"0.125", "0.35355339059327376220042218105242451964241796884423701829416993449768311961552675971259688358191039318375346155772807425623120901396268430316103037427498395785330566648187639818894998762528819551514286752738999290149256863364921550368212935466022229965238808230762107717858036270994065090699881285199742181334913658295220741015515381458809876368643757"}, + {"0.5", "0.70710678118654752440084436210484903928483593768847403658833986899536623923105351942519376716382078636750692311545614851246241802792536860632206074854996791570661133296375279637789997525057639103028573505477998580298513726729843100736425870932044459930477616461524215435716072541988130181399762570399484362669827316590441482031030762917619752737287514"}, + {"2.0", "1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079896872533965463318088296406206152583523950547457503"}, + {"3.0", "1.7320508075688772935274463415058723669428052538103806280558069794519330169088000370811461867572485756756261414154067030299699450949989524788116555120943736485280932319023055820679748201010846749232650153123432669033228866506722546689218379712270471316603678615880190499865373798593894676503475065760507566183481296061009476021871903250831458295239598"}, + {"4.0", "2.0"}, + + {"1p512", "1p256"}, + {"4p1024", "2p512"}, + {"9p2048", "3p1024"}, + + {"1p-1024", "1p-512"}, + {"4p-2048", "2p-1024"}, + {"9p-4096", "3p-2048"}, + } { + for _, prec := range []uint{24, 53, 64, 65, 100, 128, 129, 200, 256, 400, 600, 800, 1000} { + x := new(Float).SetPrec(prec) + x.Parse(test.x, 10) + + got := new(Float).SetPrec(prec).Sqrt(x) + want := new(Float).SetPrec(prec) + want.Parse(test.want, 10) + if got.Cmp(want) != 0 { + t.Errorf("prec = %d, Sqrt(%v) =\ngot %g;\nwant %g", + prec, test.x, got, want) + } + + // Square test. + // If got holds the square root of x to precision p, then + // got = √x + k + // for some k such that |k| < 2**(-p). Thus, + // got² = (√x + k)² = x + 2k√n + k² + // and the error must satisfy + // err = |got² - x| ≈ | 2k√n | < 2**(-p+1)*√n + // Ignoring the k² term for simplicity. + + // err = |got² - x| + // (but do intermediate steps with 32 guard digits to + // avoid introducing spurious rounding-related errors) + sq := new(Float).SetPrec(prec+32).Mul(got, got) + diff := new(Float).Sub(sq, x) + err := diff.Abs(diff).SetPrec(prec) + + // maxErr = 2**(-p+1)*√x + one := new(Float).SetPrec(prec).SetInt64(1) + maxErr := new(Float).Mul(new(Float).SetMantExp(one, -int(prec)+1), got) + + if err.Cmp(maxErr) >= 0 { + t.Errorf("prec = %d, Sqrt(%v) =\ngot err %g;\nwant maxErr %g", + prec, test.x, err, maxErr) + } + } + } +} + +func TestFloatSqrtSpecial(t *testing.T) { + for _, test := range []struct { + x *Float + want *Float + }{ + {NewFloat(+0), NewFloat(+0)}, + {NewFloat(-0), NewFloat(-0)}, + {NewFloat(math.Inf(+1)), NewFloat(math.Inf(+1))}, + } { + got := new(Float).Sqrt(test.x) + if got.neg != test.want.neg || got.form != test.want.form { + t.Errorf("Sqrt(%v) = %v (neg: %v); want %v (neg: %v)", + test.x, got, got.neg, test.want, test.want.neg) + } + } + +} + +// Benchmarks + +func BenchmarkFloatSqrt(b *testing.B) { + for _, prec := range []uint{64, 128, 256, 1e3, 1e4, 1e5, 1e6} { + x := NewFloat(2) + z := new(Float).SetPrec(prec) + b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) { + b.ReportAllocs() + for n := 0; n < b.N; n++ { + z.Sqrt(x) + } + }) + } +} diff --git a/libgo/go/math/bits.go b/libgo/go/math/bits.go index d85ee9cb137..77bcdbe1ce6 100644 --- a/libgo/go/math/bits.go +++ b/libgo/go/math/bits.go @@ -8,9 +8,12 @@ const ( uvnan = 0x7FF8000000000001 uvinf = 0x7FF0000000000000 uvneginf = 0xFFF0000000000000 + uvone = 0x3FF0000000000000 mask = 0x7FF shift = 64 - 11 - 1 bias = 1023 + signMask = 1 << 63 + fracMask = 1<= 0, negative infinity if sign < 0. diff --git a/libgo/go/math/bits/example_test.go b/libgo/go/math/bits/example_test.go index 78750da15d2..dfe7ece6ff7 100644 --- a/libgo/go/math/bits/example_test.go +++ b/libgo/go/math/bits/example_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. +// Code generated by go run make_examples.go. DO NOT EDIT. + // +build ignore package bits_test @@ -11,70 +13,194 @@ import ( "math/bits" ) +func ExampleLeadingZeros8() { + fmt.Printf("LeadingZeros8(%08b) = %d\n", 1, bits.LeadingZeros8(1)) + // Output: + // LeadingZeros8(00000001) = 7 +} + func ExampleLeadingZeros16() { - fmt.Println(bits.LeadingZeros16(0)) - fmt.Println(bits.LeadingZeros16(1)) - fmt.Println(bits.LeadingZeros16(256)) - fmt.Println(bits.LeadingZeros16(65535)) + fmt.Printf("LeadingZeros16(%016b) = %d\n", 1, bits.LeadingZeros16(1)) // Output: - // 16 - // 15 - // 7 - // 0 + // LeadingZeros16(0000000000000001) = 15 } func ExampleLeadingZeros32() { - fmt.Println(bits.LeadingZeros32(0)) - fmt.Println(bits.LeadingZeros32(1)) + fmt.Printf("LeadingZeros32(%032b) = %d\n", 1, bits.LeadingZeros32(1)) // Output: - // 32 - // 31 + // LeadingZeros32(00000000000000000000000000000001) = 31 } func ExampleLeadingZeros64() { - fmt.Println(bits.LeadingZeros64(0)) - fmt.Println(bits.LeadingZeros64(1)) + fmt.Printf("LeadingZeros64(%064b) = %d\n", 1, bits.LeadingZeros64(1)) // Output: - // 64 - // 63 + // LeadingZeros64(0000000000000000000000000000000000000000000000000000000000000001) = 63 } -func ExampleOnesCount() { - fmt.Printf("%b\n", 14) - fmt.Println(bits.OnesCount(14)) +func ExampleTrailingZeros8() { + fmt.Printf("TrailingZeros8(%08b) = %d\n", 14, bits.TrailingZeros8(14)) // Output: - // 1110 - // 3 + // TrailingZeros8(00001110) = 1 +} + +func ExampleTrailingZeros16() { + fmt.Printf("TrailingZeros16(%016b) = %d\n", 14, bits.TrailingZeros16(14)) + // Output: + // TrailingZeros16(0000000000001110) = 1 +} + +func ExampleTrailingZeros32() { + fmt.Printf("TrailingZeros32(%032b) = %d\n", 14, bits.TrailingZeros32(14)) + // Output: + // TrailingZeros32(00000000000000000000000000001110) = 1 +} + +func ExampleTrailingZeros64() { + fmt.Printf("TrailingZeros64(%064b) = %d\n", 14, bits.TrailingZeros64(14)) + // Output: + // TrailingZeros64(0000000000000000000000000000000000000000000000000000000000001110) = 1 } func ExampleOnesCount8() { - fmt.Printf("%b\n", 14) - fmt.Println(bits.OnesCount8(14)) + fmt.Printf("OnesCount8(%08b) = %d\n", 14, bits.OnesCount8(14)) // Output: - // 1110 - // 3 + // OnesCount8(00001110) = 3 } func ExampleOnesCount16() { - fmt.Printf("%b\n", 14) - fmt.Println(bits.OnesCount16(14)) + fmt.Printf("OnesCount16(%016b) = %d\n", 14, bits.OnesCount16(14)) // Output: - // 1110 - // 3 + // OnesCount16(0000000000001110) = 3 } func ExampleOnesCount32() { - fmt.Printf("%b\n", 14) - fmt.Println(bits.OnesCount32(14)) + fmt.Printf("OnesCount32(%032b) = %d\n", 14, bits.OnesCount32(14)) // Output: - // 1110 - // 3 + // OnesCount32(00000000000000000000000000001110) = 3 } func ExampleOnesCount64() { - fmt.Printf("%b\n", 14) - fmt.Println(bits.OnesCount64(14)) + fmt.Printf("OnesCount64(%064b) = %d\n", 14, bits.OnesCount64(14)) + // Output: + // OnesCount64(0000000000000000000000000000000000000000000000000000000000001110) = 3 +} + +func ExampleRotateLeft8() { + fmt.Printf("%08b\n", 15) + fmt.Printf("%08b\n", bits.RotateLeft8(15, 2)) + fmt.Printf("%08b\n", bits.RotateLeft8(15, -2)) + // Output: + // 00001111 + // 00111100 + // 11000011 +} + +func ExampleRotateLeft16() { + fmt.Printf("%016b\n", 15) + fmt.Printf("%016b\n", bits.RotateLeft16(15, 2)) + fmt.Printf("%016b\n", bits.RotateLeft16(15, -2)) + // Output: + // 0000000000001111 + // 0000000000111100 + // 1100000000000011 +} + +func ExampleRotateLeft32() { + fmt.Printf("%032b\n", 15) + fmt.Printf("%032b\n", bits.RotateLeft32(15, 2)) + fmt.Printf("%032b\n", bits.RotateLeft32(15, -2)) + // Output: + // 00000000000000000000000000001111 + // 00000000000000000000000000111100 + // 11000000000000000000000000000011 +} + +func ExampleRotateLeft64() { + fmt.Printf("%064b\n", 15) + fmt.Printf("%064b\n", bits.RotateLeft64(15, 2)) + fmt.Printf("%064b\n", bits.RotateLeft64(15, -2)) + // Output: + // 0000000000000000000000000000000000000000000000000000000000001111 + // 0000000000000000000000000000000000000000000000000000000000111100 + // 1100000000000000000000000000000000000000000000000000000000000011 +} + +func ExampleReverse8() { + fmt.Printf("%08b\n", 19) + fmt.Printf("%08b\n", bits.Reverse8(19)) + // Output: + // 00010011 + // 11001000 +} + +func ExampleReverse16() { + fmt.Printf("%016b\n", 19) + fmt.Printf("%016b\n", bits.Reverse16(19)) + // Output: + // 0000000000010011 + // 1100100000000000 +} + +func ExampleReverse32() { + fmt.Printf("%032b\n", 19) + fmt.Printf("%032b\n", bits.Reverse32(19)) + // Output: + // 00000000000000000000000000010011 + // 11001000000000000000000000000000 +} + +func ExampleReverse64() { + fmt.Printf("%064b\n", 19) + fmt.Printf("%064b\n", bits.Reverse64(19)) + // Output: + // 0000000000000000000000000000000000000000000000000000000000010011 + // 1100100000000000000000000000000000000000000000000000000000000000 +} + +func ExampleReverseBytes16() { + fmt.Printf("%016b\n", 15) + fmt.Printf("%016b\n", bits.ReverseBytes16(15)) + // Output: + // 0000000000001111 + // 0000111100000000 +} + +func ExampleReverseBytes32() { + fmt.Printf("%032b\n", 15) + fmt.Printf("%032b\n", bits.ReverseBytes32(15)) + // Output: + // 00000000000000000000000000001111 + // 00001111000000000000000000000000 +} + +func ExampleReverseBytes64() { + fmt.Printf("%064b\n", 15) + fmt.Printf("%064b\n", bits.ReverseBytes64(15)) + // Output: + // 0000000000000000000000000000000000000000000000000000000000001111 + // 0000111100000000000000000000000000000000000000000000000000000000 +} + +func ExampleLen8() { + fmt.Printf("Len8(%08b) = %d\n", 8, bits.Len8(8)) + // Output: + // Len8(00001000) = 4 +} + +func ExampleLen16() { + fmt.Printf("Len16(%016b) = %d\n", 8, bits.Len16(8)) + // Output: + // Len16(0000000000001000) = 4 +} + +func ExampleLen32() { + fmt.Printf("Len32(%032b) = %d\n", 8, bits.Len32(8)) + // Output: + // Len32(00000000000000000000000000001000) = 4 +} + +func ExampleLen64() { + fmt.Printf("Len64(%064b) = %d\n", 8, bits.Len64(8)) // Output: - // 1110 - // 3 + // Len64(0000000000000000000000000000000000000000000000000000000000001000) = 4 } diff --git a/libgo/go/math/bits/make_examples.go b/libgo/go/math/bits/make_examples.go new file mode 100644 index 00000000000..cd81cd6c4db --- /dev/null +++ b/libgo/go/math/bits/make_examples.go @@ -0,0 +1,112 @@ +// Copyright 2017 The Go 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 program generates example_test.go. + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "math/bits" +) + +const header = `// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by go run make_examples.go. DO NOT EDIT. + +package bits_test + +import ( + "fmt" + "math/bits" +) +` + +func main() { + w := bytes.NewBuffer([]byte(header)) + + for _, e := range []struct { + name string + in int + out [4]interface{} + out2 [4]interface{} + }{ + { + name: "LeadingZeros", + in: 1, + out: [4]interface{}{bits.LeadingZeros8(1), bits.LeadingZeros16(1), bits.LeadingZeros32(1), bits.LeadingZeros64(1)}, + }, + { + name: "TrailingZeros", + in: 14, + out: [4]interface{}{bits.TrailingZeros8(14), bits.TrailingZeros16(14), bits.TrailingZeros32(14), bits.TrailingZeros64(14)}, + }, + { + name: "OnesCount", + in: 14, + out: [4]interface{}{bits.OnesCount8(14), bits.OnesCount16(14), bits.OnesCount32(14), bits.OnesCount64(14)}, + }, + { + name: "RotateLeft", + in: 15, + out: [4]interface{}{bits.RotateLeft8(15, 2), bits.RotateLeft16(15, 2), bits.RotateLeft32(15, 2), bits.RotateLeft64(15, 2)}, + out2: [4]interface{}{bits.RotateLeft8(15, -2), bits.RotateLeft16(15, -2), bits.RotateLeft32(15, -2), bits.RotateLeft64(15, -2)}, + }, + { + name: "Reverse", + in: 19, + out: [4]interface{}{bits.Reverse8(19), bits.Reverse16(19), bits.Reverse32(19), bits.Reverse64(19)}, + }, + { + name: "ReverseBytes", + in: 15, + out: [4]interface{}{nil, bits.ReverseBytes16(15), bits.ReverseBytes32(15), bits.ReverseBytes64(15)}, + }, + { + name: "Len", + in: 8, + out: [4]interface{}{bits.Len8(8), bits.Len16(8), bits.Len32(8), bits.Len64(8)}, + }, + } { + for i, size := range []int{8, 16, 32, 64} { + if e.out[i] == nil { + continue // function doesn't exist + } + f := fmt.Sprintf("%s%d", e.name, size) + fmt.Fprintf(w, "\nfunc Example%s() {\n", f) + switch e.name { + case "RotateLeft", "Reverse", "ReverseBytes": + fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", %d)\n", size, e.in) + if e.name == "RotateLeft" { + fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, 2))\n", size, f, e.in) + fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, -2))\n", size, f, e.in) + } else { + fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d))\n", size, f, e.in) + } + fmt.Fprintf(w, "\t// Output:\n") + fmt.Fprintf(w, "\t// %0*b\n", size, e.in) + fmt.Fprintf(w, "\t// %0*b\n", size, e.out[i]) + if e.name == "RotateLeft" && e.out2[i] != nil { + fmt.Fprintf(w, "\t// %0*b\n", size, e.out2[i]) + } + default: + fmt.Fprintf(w, "\tfmt.Printf(\"%s(%%0%db) = %%d\\n\", %d, bits.%s(%d))\n", f, size, e.in, f, e.in) + fmt.Fprintf(w, "\t// Output:\n") + fmt.Fprintf(w, "\t// %s(%0*b) = %d\n", f, size, e.in, e.out[i]) + } + fmt.Fprintf(w, "}\n") + } + } + + if err := ioutil.WriteFile("example_test.go", w.Bytes(), 0666); err != nil { + log.Fatal(err) + } +} diff --git a/libgo/go/math/cmplx/asin.go b/libgo/go/math/cmplx/asin.go index 61880a257d4..062f324ce2c 100644 --- a/libgo/go/math/cmplx/asin.go +++ b/libgo/go/math/cmplx/asin.go @@ -49,11 +49,8 @@ import "math" // Asin returns the inverse sine of x. func Asin(x complex128) complex128 { - if imag(x) == 0 { - if math.Abs(real(x)) > 1 { - return complex(math.Pi/2, 0) // DOMAIN error - } - return complex(math.Asin(real(x)), 0) + if imag(x) == 0 && math.Abs(real(x)) <= 1 { + return complex(math.Asin(real(x)), imag(x)) } ct := complex(-imag(x), real(x)) // i * x xx := x * x @@ -65,12 +62,8 @@ func Asin(x complex128) complex128 { // Asinh returns the inverse hyperbolic sine of x. func Asinh(x complex128) complex128 { - // TODO check range - if imag(x) == 0 { - if math.Abs(real(x)) > 1 { - return complex(math.Pi/2, 0) // DOMAIN error - } - return complex(math.Asinh(real(x)), 0) + if imag(x) == 0 && math.Abs(real(x)) <= 1 { + return complex(math.Asinh(real(x)), imag(x)) } xx := x * x x1 := complex(1+real(xx), imag(xx)) // 1 + x*x @@ -140,10 +133,6 @@ func Acosh(x complex128) complex128 { // Atan returns the inverse tangent of x. func Atan(x complex128) complex128 { - if real(x) == 0 && imag(x) > 1 { - return NaN() - } - x2 := real(x) * real(x) a := 1 - x2 - imag(x)*imag(x) if a == 0 { diff --git a/libgo/go/math/cmplx/cmath_test.go b/libgo/go/math/cmplx/cmath_test.go index 7a5c485a310..8d705622fd4 100644 --- a/libgo/go/math/cmplx/cmath_test.go +++ b/libgo/go/math/cmplx/cmath_test.go @@ -435,6 +435,24 @@ var tanhSC = []complex128{ NaN(), } +// branch cut continuity checks +// points on each axis at |z| > 1 are checked for one-sided continuity from both the positive and negative side +// all possible branch cuts for the elementary functions are at one of these points + +var zero = 0.0 +var eps = 1.0 / (1 << 53) + +var branchPoints = [][2]complex128{ + {complex(2.0, zero), complex(2.0, eps)}, + {complex(2.0, -zero), complex(2.0, -eps)}, + {complex(-2.0, zero), complex(-2.0, eps)}, + {complex(-2.0, -zero), complex(-2.0, -eps)}, + {complex(zero, 2.0), complex(eps, 2.0)}, + {complex(-zero, 2.0), complex(-eps, 2.0)}, + {complex(zero, -2.0), complex(eps, -2.0)}, + {complex(-zero, -2.0), complex(-eps, -2.0)}, +} + // functions borrowed from pkg/math/all_test.go func tolerance(a, b, e float64) bool { d := a - b @@ -508,6 +526,11 @@ func TestAcos(t *testing.T) { t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Acos(pt[0]), Acos(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Acos(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestAcosh(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -520,6 +543,11 @@ func TestAcosh(t *testing.T) { t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Acosh(pt[0]), Acosh(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Acosh(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestAsin(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -532,6 +560,11 @@ func TestAsin(t *testing.T) { t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Asin(pt[0]), Asin(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Asin(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestAsinh(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -544,6 +577,11 @@ func TestAsinh(t *testing.T) { t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Asinh(pt[0]), Asinh(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Asinh(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestAtan(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -556,6 +594,11 @@ func TestAtan(t *testing.T) { t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Atan(pt[0]), Atan(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Atan(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestAtanh(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -568,6 +611,11 @@ func TestAtanh(t *testing.T) { t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Atanh(pt[0]), Atanh(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Atanh(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestConj(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -635,6 +683,11 @@ func TestLog(t *testing.T) { t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Log(pt[0]), Log(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Log(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestLog10(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -685,6 +738,11 @@ func TestPow(t *testing.T) { t.Errorf("Pow(%g, %g) = %g, want %g", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Pow(pt[0], 0.1), Pow(pt[1], 0.1); !cVeryclose(f0, f1) { + t.Errorf("Pow(%g, 0.1) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestRect(t *testing.T) { for i := 0; i < len(vc); i++ { @@ -733,6 +791,11 @@ func TestSqrt(t *testing.T) { t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i]) } } + for _, pt := range branchPoints { + if f0, f1 := Sqrt(pt[0]), Sqrt(pt[1]); !cVeryclose(f0, f1) { + t.Errorf("Sqrt(%g) not continuous, got %g want %g", pt[0], f0, f1) + } + } } func TestTan(t *testing.T) { for i := 0; i < len(vc); i++ { diff --git a/libgo/go/math/cmplx/sqrt.go b/libgo/go/math/cmplx/sqrt.go index 72f81e907cf..0fbdcdedd36 100644 --- a/libgo/go/math/cmplx/sqrt.go +++ b/libgo/go/math/cmplx/sqrt.go @@ -57,13 +57,14 @@ import "math" // 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 { + // Ensure that imag(r) has the same sign as imag(x) for imag(x) == signed zero. if real(x) == 0 { - return complex(0, 0) + return complex(0, imag(x)) } if real(x) < 0 { - return complex(0, math.Sqrt(-real(x))) + return complex(0, math.Copysign(math.Sqrt(-real(x)), imag(x))) } - return complex(math.Sqrt(real(x)), 0) + return complex(math.Sqrt(real(x)), imag(x)) } if real(x) == 0 { if imag(x) < 0 { diff --git a/libgo/go/math/const.go b/libgo/go/math/const.go index 20b70653b46..0fc8715dd07 100644 --- a/libgo/go/math/const.go +++ b/libgo/go/math/const.go @@ -9,18 +9,18 @@ package math // Mathematical constants. const ( - E = 2.71828182845904523536028747135266249775724709369995957496696763 // http://oeis.org/A001113 - Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // http://oeis.org/A000796 - Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // http://oeis.org/A001622 + E = 2.71828182845904523536028747135266249775724709369995957496696763 // https://oeis.org/A001113 + Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // https://oeis.org/A000796 + Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // https://oeis.org/A001622 - Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // http://oeis.org/A002193 - SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // http://oeis.org/A019774 - SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // http://oeis.org/A002161 - SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // http://oeis.org/A139339 + Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // https://oeis.org/A002193 + SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // https://oeis.org/A019774 + SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // https://oeis.org/A002161 + SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // https://oeis.org/A139339 - Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // http://oeis.org/A002162 + Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // https://oeis.org/A002162 Log2E = 1 / Ln2 - Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // http://oeis.org/A002392 + Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // https://oeis.org/A002392 Log10E = 1 / Ln10 ) diff --git a/libgo/go/math/dim.go b/libgo/go/math/dim.go index 37ab5388073..cf06f30d562 100644 --- a/libgo/go/math/dim.go +++ b/libgo/go/math/dim.go @@ -11,11 +11,18 @@ package math // Dim(-Inf, -Inf) = NaN // Dim(x, NaN) = Dim(NaN, x) = NaN func Dim(x, y float64) float64 { - return dim(x, y) -} - -func dim(x, y float64) float64 { - return max(x-y, 0) + // The special cases result in NaN after the subtraction: + // +Inf - +Inf = NaN + // -Inf - -Inf = NaN + // NaN - y = NaN + // x - NaN = NaN + v := x - y + if v <= 0 { + // v is negative or 0 + return 0 + } + // v is positive or NaN + return v } // Max returns the larger of x or y. diff --git a/libgo/go/math/erfinv.go b/libgo/go/math/erfinv.go new file mode 100644 index 00000000000..21b5578c84f --- /dev/null +++ b/libgo/go/math/erfinv.go @@ -0,0 +1,127 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +/* + Inverse of the floating-point error function. +*/ + +// This implementation is based on the rational approximation +// of percentage points of normal distribution available from +// http://www.jstor.org/stable/2347330. + +const ( + // Coefficients for approximation to erf in |x| <= 0.85 + a0 = 1.1975323115670912564578e0 + a1 = 4.7072688112383978012285e1 + a2 = 6.9706266534389598238465e2 + a3 = 4.8548868893843886794648e3 + a4 = 1.6235862515167575384252e4 + a5 = 2.3782041382114385731252e4 + a6 = 1.1819493347062294404278e4 + a7 = 8.8709406962545514830200e2 + b0 = 1.0000000000000000000e0 + b1 = 4.2313330701600911252e1 + b2 = 6.8718700749205790830e2 + b3 = 5.3941960214247511077e3 + b4 = 2.1213794301586595867e4 + b5 = 3.9307895800092710610e4 + b6 = 2.8729085735721942674e4 + b7 = 5.2264952788528545610e3 + // Coefficients for approximation to erf in 0.85 < |x| <= 1-2*exp(-25) + c0 = 1.42343711074968357734e0 + c1 = 4.63033784615654529590e0 + c2 = 5.76949722146069140550e0 + c3 = 3.64784832476320460504e0 + c4 = 1.27045825245236838258e0 + c5 = 2.41780725177450611770e-1 + c6 = 2.27238449892691845833e-2 + c7 = 7.74545014278341407640e-4 + d0 = 1.4142135623730950488016887e0 + d1 = 2.9036514445419946173133295e0 + d2 = 2.3707661626024532365971225e0 + d3 = 9.7547832001787427186894837e-1 + d4 = 2.0945065210512749128288442e-1 + d5 = 2.1494160384252876777097297e-2 + d6 = 7.7441459065157709165577218e-4 + d7 = 1.4859850019840355905497876e-9 + // Coefficients for approximation to erf in 1-2*exp(-25) < |x| < 1 + e0 = 6.65790464350110377720e0 + e1 = 5.46378491116411436990e0 + e2 = 1.78482653991729133580e0 + e3 = 2.96560571828504891230e-1 + e4 = 2.65321895265761230930e-2 + e5 = 1.24266094738807843860e-3 + e6 = 2.71155556874348757815e-5 + e7 = 2.01033439929228813265e-7 + f0 = 1.414213562373095048801689e0 + f1 = 8.482908416595164588112026e-1 + f2 = 1.936480946950659106176712e-1 + f3 = 2.103693768272068968719679e-2 + f4 = 1.112800997078859844711555e-3 + f5 = 2.611088405080593625138020e-5 + f6 = 2.010321207683943062279931e-7 + f7 = 2.891024605872965461538222e-15 +) + +// Erfinv returns the inverse error function of x. +// +// Special cases are: +// Erfinv(1) = +Inf +// Erfinv(-1) = -Inf +// Erfinv(x) = NaN if x < -1 or x > 1 +// Erfinv(NaN) = NaN +func Erfinv(x float64) float64 { + // special cases + if IsNaN(x) || x <= -1 || x >= 1 { + if x == -1 || x == 1 { + return Inf(int(x)) + } + return NaN() + } + + sign := false + if x < 0 { + x = -x + sign = true + } + + var ans float64 + if x <= 0.85 { // |x| <= 0.85 + r := 0.180625 - 0.25*x*x + z1 := ((((((a7*r+a6)*r+a5)*r+a4)*r+a3)*r+a2)*r+a1)*r + a0 + z2 := ((((((b7*r+b6)*r+b5)*r+b4)*r+b3)*r+b2)*r+b1)*r + b0 + ans = (x * z1) / z2 + } else { + var z1, z2 float64 + r := Sqrt(Ln2 - Log(1.0-x)) + if r <= 5.0 { + r -= 1.6 + z1 = ((((((c7*r+c6)*r+c5)*r+c4)*r+c3)*r+c2)*r+c1)*r + c0 + z2 = ((((((d7*r+d6)*r+d5)*r+d4)*r+d3)*r+d2)*r+d1)*r + d0 + } else { + r -= 5.0 + z1 = ((((((e7*r+e6)*r+e5)*r+e4)*r+e3)*r+e2)*r+e1)*r + e0 + z2 = ((((((f7*r+f6)*r+f5)*r+f4)*r+f3)*r+f2)*r+f1)*r + f0 + } + ans = z1 / z2 + } + + if sign { + return -ans + } + return ans +} + +// Erfcinv returns the inverse of Erfc(x). +// +// Special cases are: +// Erfcinv(0) = +Inf +// Erfcinv(2) = -Inf +// Erfcinv(x) = NaN if x < 0 or x > 2 +// Erfcinv(NaN) = NaN +func Erfcinv(x float64) float64 { + return Erfinv(1 - x) +} diff --git a/libgo/go/math/example_test.go b/libgo/go/math/example_test.go index 12e9876730e..feaf9d82525 100644 --- a/libgo/go/math/example_test.go +++ b/libgo/go/math/example_test.go @@ -9,6 +9,77 @@ import ( "math" ) +func ExampleAcos() { + fmt.Printf("%.2f", math.Acos(1)) + // Output: 0.00 +} + +func ExampleAcosh() { + fmt.Printf("%.2f", math.Acosh(1)) + // Output: 0.00 +} + +func ExampleAsin() { + fmt.Printf("%.2f", math.Asin(0)) + // Output: 0.00 +} + +func ExampleAsinh() { + fmt.Printf("%.2f", math.Asinh(0)) + // Output: 0.00 +} + +func ExampleAtan() { + fmt.Printf("%.2f", math.Atan(0)) + // Output: 0.00 +} + +func ExampleAtan2() { + fmt.Printf("%.2f", math.Atan2(0, 0)) + // Output: 0.00 +} + +func ExampleAtanh() { + fmt.Printf("%.2f", math.Atanh(0)) + // Output: 0.00 +} + +func ExampleCos() { + fmt.Printf("%.2f", math.Cos(math.Pi/2)) + // Output: 0.00 +} + +func ExampleCosh() { + fmt.Printf("%.2f", math.Cosh(0)) + // Output: 1.00 +} + +func ExampleSin() { + fmt.Printf("%.2f", math.Sin(math.Pi)) + // Output: 0.00 +} + +func ExampleSincos() { + sin, cos := math.Sincos(0) + fmt.Printf("%.2f, %.2f", sin, cos) + // Output: 0.00, 1.00 +} + +func ExampleSinh() { + fmt.Printf("%.2f", math.Sinh(0)) + // Output: 0.00 +} + +func ExampleTan() { + fmt.Printf("%.2f", math.Tan(0)) + // Output: 0.00 +} + +func ExampleTanh() { + fmt.Printf("%.2f", math.Tanh(0)) + // Output: 0.00 +} + func ExampleSqrt() { const ( a = 3 diff --git a/libgo/go/math/exp.go b/libgo/go/math/exp.go index cbc955d01e4..f3d3cb6dbba 100644 --- a/libgo/go/math/exp.go +++ b/libgo/go/math/exp.go @@ -50,7 +50,7 @@ func Exp(x float64) float64 { // the interval [0,0.34658]: // Write // R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... -// We use a special Remes algorithm on [0,0.34658] to generate +// We use a special Remez algorithm on [0,0.34658] to generate // a polynomial of degree 5 to approximate R. The maximum error // of this polynomial approximation is bounded by 2**-59. In // other words, @@ -183,7 +183,7 @@ func exp2(x float64) float64 { // exp1 returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2. func expmulti(hi, lo float64, k int) float64 { const ( - P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */ + P1 = 1.66666666666666657415e-01 /* 0x3FC55555; 0x55555555 */ P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */ P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */ P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */ diff --git a/libgo/go/math/exp_asm.go b/libgo/go/math/exp_asm.go new file mode 100644 index 00000000000..298420faeaf --- /dev/null +++ b/libgo/go/math/exp_asm.go @@ -0,0 +1,12 @@ +// Copyright 2017 The Go 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 +// +build ignore + +package math + +import "internal/cpu" + +var useFMA = cpu.X86.HasAVX && cpu.X86.HasFMA diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go index 74940436f92..9c6e0809f3f 100644 --- a/libgo/go/math/expm1.go +++ b/libgo/go/math/expm1.go @@ -214,33 +214,33 @@ func expm1(x float64) float64 { r1 := 1 + hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))) t := 3 - r1*hfx e := hxs * ((r1 - t) / (6.0 - x*t)) - if k != 0 { - e = (x*(e-c) - c) - e -= hxs - switch { - case k == -1: - return 0.5*(x-e) - 0.5 - case k == 1: - if x < -0.25 { - return -2 * (e - (x + 0.5)) - } - return 1 + 2*(x-e) - case k <= -2 || k > 56: // suffice to return exp(x)-1 - y := 1 - (e - x) - y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent - return y - 1 - } - if k < 20 { - t := Float64frombits(0x3ff0000000000000 - (0x20000000000000 >> uint(k))) // t=1-2**-k - y := t - (e - x) - y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent - return y + if k == 0 { + return x - (x*e - hxs) // c is 0 + } + e = (x*(e-c) - c) + e -= hxs + switch { + case k == -1: + return 0.5*(x-e) - 0.5 + case k == 1: + if x < -0.25 { + return -2 * (e - (x + 0.5)) } - t := Float64frombits(uint64(0x3ff-k) << 52) // 2**-k - y := x - (e + t) - y++ + return 1 + 2*(x-e) + case k <= -2 || k > 56: // suffice to return exp(x)-1 + y := 1 - (e - x) + y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent + return y - 1 + } + if k < 20 { + t := Float64frombits(0x3ff0000000000000 - (0x20000000000000 >> uint(k))) // t=1-2**-k + y := t - (e - x) y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent return y } - return x - (x*e - hxs) // c is 0 + t = Float64frombits(uint64(0x3ff-k) << 52) // 2**-k + y := x - (e + t) + y++ + y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent + return y } diff --git a/libgo/go/math/floor.go b/libgo/go/math/floor.go index c40be417152..9115968c74a 100644 --- a/libgo/go/math/floor.go +++ b/libgo/go/math/floor.go @@ -1,4 +1,4 @@ -// Copyright 2009-2010 The Go Authors. All rights reserved. +// 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. @@ -69,3 +69,78 @@ func trunc(x float64) float64 { d, _ := Modf(x) return d } + +// Round returns the nearest integer, rounding half away from zero. +// +// Special cases are: +// Round(±0) = ±0 +// Round(±Inf) = ±Inf +// Round(NaN) = NaN +func Round(x float64) float64 { + // Round is a faster implementation of: + // + // func Round(x float64) float64 { + // t := Trunc(x) + // if Abs(x-t) >= 0.5 { + // return t + Copysign(1, x) + // } + // return t + // } + bits := Float64bits(x) + e := uint(bits>>shift) & mask + if e < bias { + // Round abs(x) < 1 including denormals. + bits &= signMask // +-0 + if e == bias-1 { + bits |= uvone // +-1 + } + } else if e < bias+shift { + // Round any abs(x) >= 1 containing a fractional component [0,1). + // + // Numbers with larger exponents are returned unchanged since they + // must be either an integer, infinity, or NaN. + const half = 1 << (shift - 1) + e -= bias + bits += half >> e + bits &^= fracMask >> e + } + return Float64frombits(bits) +} + +// RoundToEven returns the nearest integer, rounding ties to even. +// +// Special cases are: +// RoundToEven(±0) = ±0 +// RoundToEven(±Inf) = ±Inf +// RoundToEven(NaN) = NaN +func RoundToEven(x float64) float64 { + // RoundToEven is a faster implementation of: + // + // func RoundToEven(x float64) float64 { + // t := math.Trunc(x) + // odd := math.Remainder(t, 2) != 0 + // if d := math.Abs(x - t); d > 0.5 || (d == 0.5 && odd) { + // return t + math.Copysign(1, x) + // } + // return t + // } + bits := Float64bits(x) + e := uint(bits>>shift) & mask + if e >= bias { + // Round abs(x) >= 1. + // - Large numbers without fractional components, infinity, and NaN are unchanged. + // - Add 0.499.. or 0.5 before truncating depending on whether the truncated + // number is even or odd (respectively). + const halfMinusULP = (1 << (shift - 1)) - 1 + e -= bias + bits += (halfMinusULP + (bits>>(shift-e))&1) >> e + bits &^= fracMask >> e + } else if e == bias-1 && bits&fracMask != 0 { + // Round 0.5 < abs(x) < 1. + bits = bits&signMask | uvone // +-1 + } else { + // Round abs(x) <= 0.5 including denormals. + bits &= signMask // +-0 + } + return Float64frombits(bits) +} diff --git a/libgo/go/math/pow.go b/libgo/go/math/pow.go index 7ba426f48bc..e255ee41466 100644 --- a/libgo/go/math/pow.go +++ b/libgo/go/math/pow.go @@ -99,7 +99,16 @@ func pow(x, y float64) float64 { return NaN() } if yi >= 1<<63 { - return Exp(y * Log(x)) + // yi is a large even int that will lead to overflow (or underflow to 0) + // for all x except -1 (x == 1 was handled earlier) + switch { + case x == -1: + return 1 + case (Abs(x) < 1) == (y > 0): + return 0 + default: + return Inf(1) + } } // ans = a1 * 2**ae (= 1 for now). @@ -121,6 +130,15 @@ func pow(x, y float64) float64 { // accumulate powers of two into exp. x1, xe := Frexp(x) for i := int64(yi); i != 0; i >>= 1 { + if xe < -1<<12 || 1<<12 < xe { + // catch xe before it overflows the left shift below + // Since i !=0 it has at least one bit still set, so ae will accumulate xe + // on at least one more iteration, ae += xe is a lower bound on ae + // the lower bound on ae exceeds the size of a float64 exp + // so the final call to Ldexp will produce under/overflow (0/Inf) + ae += xe + break + } if i&1 == 1 { a1 *= x1 ae += xe diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go index fe99c948ac2..957bebdddd6 100644 --- a/libgo/go/math/rand/rand.go +++ b/libgo/go/math/rand/rand.go @@ -135,6 +135,30 @@ func (r *Rand) Int31n(n int32) int32 { return v % n } +// int31n returns, as an int32, a non-negative pseudo-random number in [0,n). +// n must be > 0, but int31n does not check this; the caller must ensure it. +// int31n exists because Int31n is inefficient, but Go 1 compatibility +// requires that the stream of values produced by math/rand remain unchanged. +// int31n can thus only be used internally, by newly introduced APIs. +// +// For implementation details, see: +// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction +// https://lemire.me/blog/2016/06/30/fast-random-shuffling +func (r *Rand) int31n(n int32) int32 { + v := r.Uint32() + prod := uint64(v) * uint64(n) + low := uint32(prod) + if low < uint32(n) { + thresh := uint32(-n) % uint32(n) + for low < thresh { + v = r.Uint32() + prod = uint64(v) * uint64(n) + low = uint32(prod) + } + } + return int32(prod >> 32) +} + // Intn returns, as an int, a non-negative pseudo-random number in [0,n). // It panics if n <= 0. func (r *Rand) Intn(n int) int { @@ -202,6 +226,31 @@ func (r *Rand) Perm(n int) []int { return m } +// Shuffle pseudo-randomizes the order of elements. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func (r *Rand) Shuffle(n int, swap func(i, j int)) { + if n < 0 { + panic("invalid argument to Shuffle") + } + + // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + // Shuffle really ought not be called with n that doesn't fit in 32 bits. + // Not only will it take a very long time, but with 2³¹! possible permutations, + // there's no way that any PRNG can have a big enough internal state to + // generate even a minuscule percentage of the possible permutations. + // Nevertheless, the right API signature accepts an int n, so handle it as best we can. + i := n - 1 + for ; i > 1<<31-1-1; i-- { + j := int(r.Int63n(int64(i + 1))) + swap(i, j) + } + for ; i > 0; i-- { + j := int(r.int31n(int32(i + 1))) + swap(i, j) + } +} + // Read generates len(p) random bytes and writes them into p. It // always returns len(p) and a nil error. // Read should not be called concurrently with any other Rand method. @@ -288,6 +337,11 @@ func Float32() float32 { return globalRand.Float32() } // from the default Source. func Perm(n int) []int { return globalRand.Perm(n) } +// Shuffle pseudo-randomizes the order of elements using the default Source. +// n is the number of elements. Shuffle panics if n < 0. +// swap swaps the elements with indexes i and j. +func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) } + // Read generates len(p) random bytes from the default Source and // writes them into p. It always returns len(p) and a nil error. // Read, unlike the Rand.Read method, is safe for concurrent use. diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go index bf509e06bec..e663b84f9fc 100644 --- a/libgo/go/math/rand/rand_test.go +++ b/libgo/go/math/rand/rand_test.go @@ -53,7 +53,7 @@ func (this *statsResults) checkSimilarDistribution(expected *statsResults) error fmt.Println(s) return errors.New(s) } - if !nearEqual(this.stddev, expected.stddev, 0, expected.maxError) { + if !nearEqual(this.stddev, expected.stddev, expected.closeEnough, expected.maxError) { s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", this.stddev, expected.stddev, expected.closeEnough, expected.maxError) fmt.Println(s) return errors.New(s) @@ -74,6 +74,7 @@ func getStatsResults(samples []float64) *statsResults { } func checkSampleDistribution(t *testing.T, samples []float64, expected *statsResults) { + t.Helper() actual := getStatsResults(samples) err := actual.checkSimilarDistribution(expected) if err != nil { @@ -82,6 +83,7 @@ func checkSampleDistribution(t *testing.T, samples []float64, expected *statsRes } func checkSampleSliceDistributions(t *testing.T, samples []float64, nslices int, expected *statsResults) { + t.Helper() chunk := len(samples) / nslices for i := 0; i < nslices; i++ { low := i * chunk @@ -374,7 +376,7 @@ func testReadUniformity(t *testing.T, n int, seed int64) { // Expect a uniform distribution of byte values, which lie in [0, 255]. var ( mean = 255.0 / 2 - stddev = math.Sqrt(255.0 * 255.0 / 12.0) + stddev = 256.0 / math.Sqrt(12.0) errorScale = stddev / math.Sqrt(float64(n)) ) @@ -448,6 +450,113 @@ func TestReadSeedReset(t *testing.T) { } } +func TestShuffleSmall(t *testing.T) { + // Check that Shuffle allows n=0 and n=1, but that swap is never called for them. + r := New(NewSource(1)) + for n := 0; n <= 1; n++ { + r.Shuffle(n, func(i, j int) { t.Fatalf("swap called, n=%d i=%d j=%d", n, i, j) }) + } +} + +// encodePerm converts from a permuted slice of length n, such as Perm generates, to an int in [0, n!). +// See https://en.wikipedia.org/wiki/Lehmer_code. +// encodePerm modifies the input slice. +func encodePerm(s []int) int { + // Convert to Lehmer code. + for i, x := range s { + r := s[i+1:] + for j, y := range r { + if y > x { + r[j]-- + } + } + } + // Convert to int in [0, n!). + m := 0 + fact := 1 + for i := len(s) - 1; i >= 0; i-- { + m += s[i] * fact + fact *= len(s) - i + } + return m +} + +// TestUniformFactorial tests several ways of generating a uniform value in [0, n!). +func TestUniformFactorial(t *testing.T) { + r := New(NewSource(testSeeds[0])) + top := 6 + if testing.Short() { + top = 4 + } + for n := 3; n <= top; n++ { + t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { + // Calculate n!. + nfact := 1 + for i := 2; i <= n; i++ { + nfact *= i + } + + // Test a few different ways to generate a uniform distribution. + p := make([]int, n) // re-usable slice for Shuffle generator + tests := [...]struct { + name string + fn func() int + }{ + {name: "Int31n", fn: func() int { return int(r.Int31n(int32(nfact))) }}, + {name: "int31n", fn: func() int { return int(r.int31n(int32(nfact))) }}, + {name: "Perm", fn: func() int { return encodePerm(r.Perm(n)) }}, + {name: "Shuffle", fn: func() int { + // Generate permutation using Shuffle. + for i := range p { + p[i] = i + } + r.Shuffle(n, func(i, j int) { p[i], p[j] = p[j], p[i] }) + return encodePerm(p) + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Gather chi-squared values and check that they follow + // the expected normal distribution given n!-1 degrees of freedom. + // See https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test and + // https://www.johndcook.com/Beautiful_Testing_ch10.pdf. + nsamples := 10 * nfact + if nsamples < 200 { + nsamples = 200 + } + samples := make([]float64, nsamples) + for i := range samples { + // Generate some uniformly distributed values and count their occurrences. + const iters = 1000 + counts := make([]int, nfact) + for i := 0; i < iters; i++ { + counts[test.fn()]++ + } + // Calculate chi-squared and add to samples. + want := iters / float64(nfact) + var χ2 float64 + for _, have := range counts { + err := float64(have) - want + χ2 += err * err + } + χ2 /= want + samples[i] = χ2 + } + + // Check that our samples approximate the appropriate normal distribution. + dof := float64(nfact - 1) + expected := &statsResults{mean: dof, stddev: math.Sqrt(2 * dof)} + errorScale := max(1.0, expected.stddev) + expected.closeEnough = 0.10 * errorScale + expected.maxError = 0.08 // TODO: What is the right value here? See issue 21211. + checkSampleDistribution(t, samples, expected) + }) + } + }) + } +} + // Benchmarks func BenchmarkInt63Threadsafe(b *testing.B) { @@ -512,6 +621,30 @@ func BenchmarkPerm30(b *testing.B) { } } +func BenchmarkPerm30ViaShuffle(b *testing.B) { + r := New(NewSource(1)) + for n := b.N; n > 0; n-- { + p := make([]int, 30) + for i := range p { + p[i] = i + } + r.Shuffle(30, func(i, j int) { p[i], p[j] = p[j], p[i] }) + } +} + +// BenchmarkShuffleOverhead uses a minimal swap function +// to measure just the shuffling overhead. +func BenchmarkShuffleOverhead(b *testing.B) { + r := New(NewSource(1)) + for n := b.N; n > 0; n-- { + r.Shuffle(52, func(i, j int) { + if i < 0 || i >= 52 || j < 0 || j >= 52 { + b.Fatalf("bad swap(%d, %d)", i, j) + } + }) + } +} + func BenchmarkRead3(b *testing.B) { r := New(NewSource(1)) buf := make([]byte, 3) diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go index 5557672b3d0..426d417da23 100644 --- a/libgo/go/mime/mediatype.go +++ b/libgo/go/mime/mediatype.go @@ -171,8 +171,9 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e for key, pieceMap := range continuation { singlePartKey := key + "*" if v, ok := pieceMap[singlePartKey]; ok { - decv := decode2231Enc(v) - params[key] = decv + if decv, ok := decode2231Enc(v); ok { + params[key] = decv + } continue } @@ -186,16 +187,18 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e continue } encodedPart := simplePart + "*" - if v, ok := pieceMap[encodedPart]; ok { - valid = true - if n == 0 { - buf.WriteString(decode2231Enc(v)) - } else { - decv, _ := percentHexUnescape(v) + v, ok := pieceMap[encodedPart] + if !ok { + break + } + valid = true + if n == 0 { + if decv, ok := decode2231Enc(v); ok { buf.WriteString(decv) } } else { - break + decv, _ := percentHexUnescape(v) + buf.WriteString(decv) } } if valid { @@ -206,21 +209,27 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e return } -func decode2231Enc(v string) string { +func decode2231Enc(v string) (string, bool) { sv := strings.SplitN(v, "'", 3) if len(sv) != 3 { - return "" + return "", false } // TODO: ignoring lang in sv[1] for now. If anybody needs it we'll // need to decide how to expose it in the API. But I'm not sure // anybody uses it in practice. charset := strings.ToLower(sv[0]) + if len(charset) == 0 { + return "", false + } if charset != "us-ascii" && charset != "utf-8" { // TODO: unsupported encoding - return "" + return "", false + } + encv, err := percentHexUnescape(sv[2]) + if err != nil { + return "", false } - encv, _ := percentHexUnescape(sv[2]) - return encv + return encv, true } func isNotTokenChar(r rune) bool { diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go index 3ba8ee18d5d..88d742f0aab 100644 --- a/libgo/go/mime/mediatype_test.go +++ b/libgo/go/mime/mediatype_test.go @@ -139,79 +139,248 @@ func TestParseMediaType(t *testing.T) { // Tests from http://greenbytes.de/tech/tc2231/ // Note: Backslash escape handling is a bit loose, like MSIE. - // TODO(bradfitz): add the rest of the tests from that site. + + // #attonly + {`attachment`, + "attachment", + m()}, + // #attonlyucase + {`ATTACHMENT`, + "attachment", + m()}, + // #attwithasciifilename + {`attachment; filename="foo.html"`, + "attachment", + m("filename", "foo.html")}, + // #attwithasciifilename25 + {`attachment; filename="0000000000111111111122222"`, + "attachment", + m("filename", "0000000000111111111122222")}, + // #attwithasciifilename35 + {`attachment; filename="00000000001111111111222222222233333"`, + "attachment", + m("filename", "00000000001111111111222222222233333")}, + // #attwithasciifnescapedchar {`attachment; filename="f\oo.html"`, "attachment", m("filename", "f\\oo.html")}, + // #attwithasciifnescapedquote {`attachment; filename="\"quoting\" tested.html"`, "attachment", m("filename", `"quoting" tested.html`)}, + // #attwithquotedsemicolon {`attachment; filename="Here's a semicolon;.html"`, "attachment", m("filename", "Here's a semicolon;.html")}, + // #attwithfilenameandextparam + {`attachment; foo="bar"; filename="foo.html"`, + "attachment", + m("foo", "bar", "filename", "foo.html")}, + // #attwithfilenameandextparamescaped {`attachment; foo="\"\\";filename="foo.html"`, "attachment", m("foo", "\"\\", "filename", "foo.html")}, + // #attwithasciifilenameucase + {`attachment; FILENAME="foo.html"`, + "attachment", + m("filename", "foo.html")}, + // #attwithasciifilenamenq {`attachment; filename=foo.html`, "attachment", m("filename", "foo.html")}, + // #attwithasciifilenamenqs {`attachment; filename=foo.html ;`, "attachment", m("filename", "foo.html")}, + // #attwithfntokensq {`attachment; filename='foo.html'`, "attachment", m("filename", "'foo.html'")}, + // #attwithisofnplain + {`attachment; filename="foo-ä.html"`, + "attachment", + m("filename", "foo-ä.html")}, + // #attwithutf8fnplain + {`attachment; filename="foo-ä.html"`, + "attachment", + m("filename", "foo-ä.html")}, + // #attwithfnrawpctenca {`attachment; filename="foo-%41.html"`, "attachment", m("filename", "foo-%41.html")}, + // #attwithfnusingpct + {`attachment; filename="50%.html"`, + "attachment", + m("filename", "50%.html")}, + // #attwithfnrawpctencaq {`attachment; filename="foo-%\41.html"`, "attachment", m("filename", "foo-%\\41.html")}, + // #attwithnamepct + {`attachment; name="foo-%41.html"`, + "attachment", + m("name", "foo-%41.html")}, + // #attwithfilenamepctandiso + {`attachment; name="ä-%41.html"`, + "attachment", + m("name", "ä-%41.html")}, + // #attwithfnrawpctenclong + {`attachment; filename="foo-%c3%a4-%e2%82%ac.html"`, + "attachment", + m("filename", "foo-%c3%a4-%e2%82%ac.html")}, + // #attwithasciifilenamews1 + {`attachment; filename ="foo.html"`, + "attachment", + m("filename", "foo.html")}, + // #attmissingdisposition {`filename=foo.html`, "", m()}, + // #attmissingdisposition2 {`x=y; filename=foo.html`, "", m()}, + // #attmissingdisposition3 {`"foo; filename=bar;baz"; filename=qux`, "", m()}, + // #attmissingdisposition4 + {`filename=foo.html, filename=bar.html`, + "", m()}, + // #emptydisposition + {`; filename=foo.html`, + "", m()}, + // #doublecolon + {`: inline; attachment; filename=foo.html`, + "", m()}, + // #attandinline {`inline; attachment; filename=foo.html`, "", m()}, + // #attandinline2 + {`attachment; inline; filename=foo.html`, + "", m()}, + // #attbrokenquotedfn {`attachment; filename="foo.html".txt`, "", m()}, + // #attbrokenquotedfn2 {`attachment; filename="bar`, "", m()}, + // #attbrokenquotedfn3 + {`attachment; filename=foo"bar;baz"qux`, + "", m()}, + // #attmultinstances + {`attachment; filename=foo.html, attachment; filename=bar.html`, + "", m()}, + // #attmissingdelim + {`attachment; foo=foo filename=bar`, + "", m()}, + // #attmissingdelim2 + {`attachment; filename=bar foo=foo`, + "", m()}, + // #attmissingdelim3 + {`attachment filename=bar`, + "", m()}, + // #attreversed + {`filename=foo.html; attachment`, + "", m()}, + // #attconfusedparam + {`attachment; xfilename=foo.html`, + "attachment", + m("xfilename", "foo.html")}, + // #attcdate {`attachment; creation-date="Wed, 12 Feb 1997 16:29:51 -0500"`, "attachment", m("creation-date", "Wed, 12 Feb 1997 16:29:51 -0500")}, + // #attmdate + {`attachment; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"`, + "attachment", + m("modification-date", "Wed, 12 Feb 1997 16:29:51 -0500")}, + // #dispext {`foobar`, "foobar", m()}, + // #dispextbadfn + {`attachment; example="filename=example.txt"`, + "attachment", + m("example", "filename=example.txt")}, + // #attwithfn2231utf8 + {`attachment; filename*=UTF-8''foo-%c3%a4-%e2%82%ac.html`, + "attachment", + m("filename", "foo-ä-€.html")}, + // #attwithfn2231noc + {`attachment; filename*=''foo-%c3%a4-%e2%82%ac.html`, + "attachment", + m()}, + // #attwithfn2231utf8comp + {`attachment; filename*=UTF-8''foo-a%cc%88.html`, + "attachment", + m("filename", "foo-ä.html")}, + // #attwithfn2231ws2 + {`attachment; filename*= UTF-8''foo-%c3%a4.html`, + "attachment", + m("filename", "foo-ä.html")}, + // #attwithfn2231ws3 {`attachment; filename* =UTF-8''foo-%c3%a4.html`, "attachment", m("filename", "foo-ä.html")}, + // #attwithfn2231quot + {`attachment; filename*="UTF-8''foo-%c3%a4.html"`, + "attachment", + m("filename", "foo-ä.html")}, + // #attwithfn2231quot2 + {`attachment; filename*="foo%20bar.html"`, + "attachment", + m()}, + // #attwithfn2231singleqmissing + {`attachment; filename*=UTF-8'foo-%c3%a4.html`, + "attachment", + m()}, + // #attwithfn2231nbadpct1 + {`attachment; filename*=UTF-8''foo%`, + "attachment", + m()}, + // #attwithfn2231nbadpct2 + {`attachment; filename*=UTF-8''f%oo.html`, + "attachment", + m()}, + // #attwithfn2231dpct {`attachment; filename*=UTF-8''A-%2541.html`, "attachment", m("filename", "A-%41.html")}, + // #attfncont {`attachment; filename*0="foo."; filename*1="html"`, "attachment", m("filename", "foo.html")}, + // #attfncontenc {`attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=".html"`, "attachment", m("filename", "foo-ä.html")}, + // #attfncontlz {`attachment; filename*0="foo"; filename*01="bar"`, "attachment", m("filename", "foo")}, + // #attfncontnc {`attachment; filename*0="foo"; filename*2="bar"`, "attachment", m("filename", "foo")}, - {`attachment; filename*1="foo"; filename*2="bar"`, + // #attfnconts1 + {`attachment; filename*1="foo."; filename*2="html"`, "attachment", m()}, + // #attfncontord {`attachment; filename*1="bar"; filename*0="foo"`, "attachment", m("filename", "foobar")}, + // #attfnboth {`attachment; filename="foo-ae.html"; filename*=UTF-8''foo-%c3%a4.html`, "attachment", m("filename", "foo-ä.html")}, + // #attfnboth2 {`attachment; filename*=UTF-8''foo-%c3%a4.html; filename="foo-ae.html"`, "attachment", m("filename", "foo-ä.html")}, + // #attfnboth3 + {`attachment; filename*0*=ISO-8859-15''euro-sign%3d%a4; filename*=ISO-8859-1''currency-sign%3d%a4`, + "attachment", + m()}, + // #attnewandfn + {`attachment; foobar=x; filename="foo.html"`, + "attachment", + m("foobar", "x", "filename", "foo.html")}, // Browsers also just send UTF-8 directly without RFC 2231, // at least when the source page is served with UTF-8. @@ -265,6 +434,16 @@ var badMediaTypeTests = []badMediaTypeTest{ "application/pdf", "mime: invalid media parameter"}, {"bogus/", "", "mime: expected token after slash"}, {"bogus/bogus", "", "mime: unexpected content after media subtype"}, + // Tests from http://greenbytes.de/tech/tc2231/ + {`"attachment"`, "attachment", "mime: no media type"}, + {"attachment; filename=foo,bar.html", "attachment", "mime: invalid media parameter"}, + {"attachment; ;filename=foo", "attachment", "mime: invalid media parameter"}, + {"attachment; filename=foo bar.html", "attachment", "mime: invalid media parameter"}, + {`attachment; filename="foo.html"; filename="bar.html"`, "attachment", "mime: duplicate parameter name"}, + {"attachment; filename=foo[1](2).html", "attachment", "mime: invalid media parameter"}, + {"attachment; filename=foo-ä.html", "attachment", "mime: invalid media parameter"}, + {"attachment; filename=foo-ä.html", "attachment", "mime: invalid media parameter"}, + {`attachment; filename *=UTF-8''foo-%c3%a4.html`, "attachment", "mime: invalid media parameter"}, } func TestParseMediaTypeBogus(t *testing.T) { diff --git a/libgo/go/mime/multipart/formdata.go b/libgo/go/mime/multipart/formdata.go index 832d0ad6936..2a4ebdd4a06 100644 --- a/libgo/go/mime/multipart/formdata.go +++ b/libgo/go/mime/multipart/formdata.go @@ -58,7 +58,8 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { var b bytes.Buffer - if filename == "" { + _, hasContentTypeHeader := p.Header["Content-Type"] + if !hasContentTypeHeader && filename == "" { // value, store as string in memory n, err := io.CopyN(&b, p, maxValueBytes+1) if err != nil && err != io.EOF { diff --git a/libgo/go/mime/multipart/formdata_test.go b/libgo/go/mime/multipart/formdata_test.go index 979ae5c4e10..69333d3d0de 100644 --- a/libgo/go/mime/multipart/formdata_test.go +++ b/libgo/go/mime/multipart/formdata_test.go @@ -38,6 +38,23 @@ func TestReadForm(t *testing.T) { fd.Close() } +func TestReadFormWithNamelessFile(t *testing.T) { + b := strings.NewReader(strings.Replace(messageWithFileWithoutName, "\n", "\r\n", -1)) + r := NewReader(b, boundary) + f, err := r.ReadForm(25) + if err != nil { + t.Fatal("ReadForm:", err) + } + defer f.RemoveAll() + + fd := testFile(t, f.File["hiddenfile"][0], "", filebContents) + if _, ok := fd.(sectionReadCloser); !ok { + t.Errorf("file has unexpected underlying type %T", fd) + } + fd.Close() + +} + func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File { if fh.Filename != efn { t.Errorf("filename = %q, want %q", fh.Filename, efn) @@ -68,6 +85,15 @@ const ( boundary = `MyBoundary` ) +const messageWithFileWithoutName = ` +--MyBoundary +Content-Disposition: form-data; name="hiddenfile"; filename="" +Content-Type: text/plain + +` + filebContents + ` +--MyBoundary-- +` + const message = ` --MyBoundary Content-Disposition: form-data; name="filea"; filename="filea.txt" diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go index 0de3ff8bebd..5866d384820 100644 --- a/libgo/go/net/cgo_unix.go +++ b/libgo/go/net/cgo_unix.go @@ -12,7 +12,6 @@ package net #include #include #include -#include #include #include */ diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go index a892bf1e140..13fa9faacb5 100644 --- a/libgo/go/net/dial_test.go +++ b/libgo/go/net/dial_test.go @@ -161,6 +161,8 @@ func dialClosedPort() (actual, expected time.Duration) { // but other platforms should be instantaneous. if runtime.GOOS == "windows" { expected = 1500 * time.Millisecond + } else if runtime.GOOS == "darwin" { + expected = 150 * time.Millisecond } else { expected = 95 * time.Millisecond } diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index c2156b255e5..e5f8da156a2 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -52,7 +52,7 @@ func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) } func (fd *netFD) init() error { - errcall, err := fd.pfd.Init(fd.net) + errcall, err := fd.pfd.Init(fd.net, true) if errcall != "" { err = wrapSyscallError(errcall, err) } @@ -223,17 +223,21 @@ func (fd *netFD) accept() (*netFD, error) { return netfd, nil } +func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { + n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob) + runtime.KeepAlive(fd) + return n, oobn, flags, sa, wrapSyscallError("wsarecvmsg", err) +} + +func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { + n, oobn, err = fd.pfd.WriteMsg(p, oob, sa) + runtime.KeepAlive(fd) + return n, oobn, wrapSyscallError("wsasendmsg", err) +} + // Unimplemented functions. func (fd *netFD) dup() (*os.File, error) { // TODO: Implement this return nil, syscall.EWINDOWS } - -func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { - return 0, 0, 0, nil, syscall.EWINDOWS -} - -func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { - return 0, 0, syscall.EWINDOWS -} diff --git a/libgo/go/net/hook_windows.go b/libgo/go/net/hook_windows.go index 4e64dcef517..ab8656cbbf3 100644 --- a/libgo/go/net/hook_windows.go +++ b/libgo/go/net/hook_windows.go @@ -5,6 +5,7 @@ package net import ( + "internal/syscall/windows" "syscall" "time" ) @@ -13,7 +14,8 @@ var ( testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 // Placeholders for socket system calls. - socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket - connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect - listenFunc func(syscall.Handle, int) error = syscall.Listen + socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + listenFunc func(syscall.Handle, int) error = syscall.Listen ) diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go index 5d6c9cfe190..f850e2fccfd 100644 --- a/libgo/go/net/hosts_test.go +++ b/libgo/go/net/hosts_test.go @@ -150,7 +150,7 @@ func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) { func TestHostCacheModification(t *testing.T) { // Ensure that programs can't modify the internals of the host cache. - // See https://github.com/golang/go/issues/14212. + // See https://golang.org/issues/14212. defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) testHookHostsPath = "testdata/ipv4-hosts" diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index 4c9084ae512..6f6024ed4d8 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -127,7 +127,10 @@ type RoundTripper interface { // authentication, or cookies. // // RoundTrip should not modify the request, except for - // consuming and closing the Request's Body. + // consuming and closing the Request's Body. RoundTrip may + // read fields of the request in a separate goroutine. Callers + // should not mutate the request until the Response's Body has + // been closed. // // RoundTrip must always close the body, including on errors, // but depending on the implementation may do so in a separate @@ -536,12 +539,22 @@ func (c *Client) Do(req *Request) (*Response, error) { resp.closeBody() return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err)) } + host := "" + if req.Host != "" && req.Host != req.URL.Host { + // If the caller specified a custom Host header and the + // redirect location is relative, preserve the Host header + // through the redirect. See issue #22233. + if u, _ := url.Parse(loc); u != nil && !u.IsAbs() { + host = req.Host + } + } ireq := reqs[0] req = &Request{ Method: redirectMethod, Response: resp, URL: u, Header: make(Header), + Host: host, Cancel: ireq.Cancel, ctx: ireq.ctx, } @@ -750,7 +763,7 @@ func PostForm(url string, data url.Values) (resp *Response, err error) { // with data's keys and values URL-encoded as the request body. // // The Content-Type header is set to application/x-www-form-urlencoded. -// To set other headers, use NewRequest and DefaultClient.Do. +// To set other headers, use NewRequest and Client.Do. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. @@ -843,16 +856,8 @@ func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { // directly, we don't know their scope, so we assume // it's for *.domain.com. - // TODO(bradfitz): once issue 16142 is fixed, make - // this code use those URL accessors, and consider - // "http://foo.com" and "http://foo.com:80" as - // equivalent? - - // TODO(bradfitz): better hostname canonicalization, - // at least once we figure out IDNA/Punycode (issue - // 13835). - ihost := strings.ToLower(initial.Host) - dhost := strings.ToLower(dest.Host) + ihost := canonicalAddr(initial) + dhost := canonicalAddr(dest) return isDomainOrSubdomain(dhost, ihost) } // All other headers are copied: diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index b9a1c31e43a..eea3b16fb3b 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -1426,7 +1426,7 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) { c.Get("http://dummy.tld") } -// Issue 4800: copy (some) headers when Client follows a redirect +// Issue 4800: copy (some) headers when Client follows a redirect. func TestClientCopyHeadersOnRedirect(t *testing.T) { const ( ua = "some-agent/1.2" @@ -1487,6 +1487,76 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) { } } +// Issue 22233: copy host when Client follows a relative redirect. +func TestClientCopyHostOnRedirect(t *testing.T) { + // Virtual hostname: should not receive any request. + virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + t.Errorf("Virtual host received request %v", r.URL) + w.WriteHeader(403) + io.WriteString(w, "should not see this response") + })) + defer virtual.Close() + virtualHost := strings.TrimPrefix(virtual.URL, "http://") + t.Logf("Virtual host is %v", virtualHost) + + // Actual hostname: should not receive any request. + const wantBody = "response body" + var tsURL string + var tsHost string + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + switch r.URL.Path { + case "/": + // Relative redirect. + if r.Host != virtualHost { + t.Errorf("Serving /: Request.Host = %#v; want %#v", r.Host, virtualHost) + w.WriteHeader(404) + return + } + w.Header().Set("Location", "/hop") + w.WriteHeader(302) + case "/hop": + // Absolute redirect. + if r.Host != virtualHost { + t.Errorf("Serving /hop: Request.Host = %#v; want %#v", r.Host, virtualHost) + w.WriteHeader(404) + return + } + w.Header().Set("Location", tsURL+"/final") + w.WriteHeader(302) + case "/final": + if r.Host != tsHost { + t.Errorf("Serving /final: Request.Host = %#v; want %#v", r.Host, tsHost) + w.WriteHeader(404) + return + } + w.WriteHeader(200) + io.WriteString(w, wantBody) + default: + t.Errorf("Serving unexpected path %q", r.URL.Path) + w.WriteHeader(404) + } + })) + defer ts.Close() + tsURL = ts.URL + tsHost = strings.TrimPrefix(ts.URL, "http://") + t.Logf("Server host is %v", tsHost) + + c := ts.Client() + req, _ := NewRequest("GET", ts.URL, nil) + req.Host = virtualHost + resp, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + t.Fatal(resp.Status) + } + if got, err := ioutil.ReadAll(resp.Body); err != nil || string(got) != wantBody { + t.Errorf("body = %q; want %q", got, wantBody) + } +} + // Issue 17494: cookies should be altered when Client follows redirects. func TestClientAltersCookiesOnRedirect(t *testing.T) { cookieMap := func(cs []*Cookie) map[string][]string { @@ -1599,8 +1669,12 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) { {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true}, {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false}, - // TODO(bradfitz): make this test work, once issue 16142 is fixed: - // {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, + {"www-authenticate", "http://foo.com/", "https://foo.com/", false}, + {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, + {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true}, + {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true}, + {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true}, + {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", false}, } for i, tt := range tests { u0, err := url.Parse(tt.initialURL) diff --git a/libgo/go/net/http/clientserver_test.go b/libgo/go/net/http/clientserver_test.go index 20feaa70ff6..c8d9fab8b7a 100644 --- a/libgo/go/net/http/clientserver_test.go +++ b/libgo/go/net/http/clientserver_test.go @@ -1145,27 +1145,6 @@ func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) { } } -// Tests that we support bogus under-100 HTTP statuses, because we historically -// have. This might change at some point, but not yet in Go 1.6. -func TestBogusStatusWorks_h1(t *testing.T) { testBogusStatusWorks(t, h1Mode) } -func TestBogusStatusWorks_h2(t *testing.T) { testBogusStatusWorks(t, h2Mode) } -func testBogusStatusWorks(t *testing.T, h2 bool) { - defer afterTest(t) - const code = 7 - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { - w.WriteHeader(code) - })) - defer cst.close() - - res, err := cst.c.Get(cst.ts.URL) - if err != nil { - t.Fatal(err) - } - if res.StatusCode != code { - t.Errorf("StatusCode = %d; want %d", res.StatusCode, code) - } -} - func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, "boom") } func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, "boom") } func TestInterruptWithPanic_nil_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, nil) } @@ -1412,3 +1391,40 @@ func TestBadResponseAfterReadingBody(t *testing.T) { t.Errorf("closes = %d; want 1", closes) } } + +func TestWriteHeader0_h1(t *testing.T) { testWriteHeader0(t, h1Mode) } +func TestWriteHeader0_h2(t *testing.T) { testWriteHeader0(t, h2Mode) } +func testWriteHeader0(t *testing.T, h2 bool) { + defer afterTest(t) + gotpanic := make(chan bool, 1) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + defer close(gotpanic) + defer func() { + if e := recover(); e != nil { + got := fmt.Sprintf("%T, %v", e, e) + want := "string, invalid WriteHeader code 0" + if got != want { + t.Errorf("unexpected panic value:\n got: %v\nwant: %v\n", got, want) + } + gotpanic <- true + + // Set an explicit 503. This also tests that the WriteHeader call panics + // before it recorded that an explicit value was set and that bogus + // value wasn't stuck. + w.WriteHeader(503) + } + }() + w.WriteHeader(0) + })) + defer cst.close() + res, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != 503 { + t.Errorf("Response: %v %q; want 503", res.StatusCode, res.Status) + } + if !<-gotpanic { + t.Error("expected panic in handler") + } +} diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go index cf522488c15..38b1b3630e2 100644 --- a/libgo/go/net/http/cookie.go +++ b/libgo/go/net/http/cookie.go @@ -208,7 +208,6 @@ func readCookies(h Header, filter string) []*Cookie { continue } // Per-line attributes - parsedPairs := 0 for i := 0; i < len(parts); i++ { parts[i] = strings.TrimSpace(parts[i]) if len(parts[i]) == 0 { @@ -229,7 +228,6 @@ func readCookies(h Header, filter string) []*Cookie { continue } cookies = append(cookies, &Cookie{Name: name, Value: val}) - parsedPairs++ } } return cookies diff --git a/libgo/go/net/http/example_test.go b/libgo/go/net/http/example_test.go index 1774795d379..9de0893e873 100644 --- a/libgo/go/net/http/example_test.go +++ b/libgo/go/net/http/example_test.go @@ -5,11 +5,14 @@ package http_test import ( + "context" "fmt" "io" "io/ioutil" "log" "net/http" + "os" + "os/signal" ) func ExampleHijacker() { @@ -109,3 +112,28 @@ func ExampleResponseWriter_trailers() { w.Header().Set("AtEnd3", "value 3") // These will appear as trailers. }) } + +func ExampleServer_Shutdown() { + var srv http.Server + + idleConnsClosed := make(chan struct{}) + go func() { + sigint := make(chan os.Signal, 1) + signal.Notify(sigint, os.Interrupt) + <-sigint + + // We received an interrupt signal, shut down. + if err := srv.Shutdown(context.Background()); err != nil { + // Error from closing listeners, or context timeout: + log.Printf("HTTP server Shutdown: %v", err) + } + close(idleConnsClosed) + }() + + if err := srv.ListenAndServe(); err != http.ErrServerClosed { + // Error starting or closing listener: + log.Printf("HTTP server ListenAndServe: %v", err) + } + + <-idleConnsClosed +} diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go index 2ef145e5342..1825acd9be7 100644 --- a/libgo/go/net/http/export_test.go +++ b/libgo/go/net/http/export_test.go @@ -63,9 +63,14 @@ func SetPendingDialHooks(before, after func()) { func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn } func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { + ctx, cancel := context.WithCancel(context.Background()) + go func() { + <-ch + cancel() + }() return &timeoutHandler{ handler: handler, - testTimeout: ch, + testContext: ctx, // (no body) } } @@ -206,3 +211,9 @@ func (s *Server) ExportAllConnsIdle() bool { func (r *Request) WithT(t *testing.T) *Request { return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf)) } + +func ExportSetH2GoawayTimeout(d time.Duration) (restore func()) { + old := http2goAwayTimeout + http2goAwayTimeout = d + return func() { http2goAwayTimeout = old } +} diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go index 5819334b5f4..ecad14ac1e4 100644 --- a/libgo/go/net/http/fs.go +++ b/libgo/go/net/http/fs.go @@ -98,12 +98,10 @@ type File interface { Stat() (os.FileInfo, error) } -func dirList(w ResponseWriter, f File) { +func dirList(w ResponseWriter, r *Request, f File) { dirs, err := f.Readdir(-1) if err != nil { - // TODO: log err.Error() to the Server.ErrorLog, once it's possible - // for a handler to get at its Server via the ResponseWriter. See - // Issue 12438. + logf(r, "http: error reading directory: %v", err) Error(w, "Error reading directory", StatusInternalServerError) return } @@ -319,7 +317,7 @@ func scanETag(s string) (etag string, remain string) { // Character values allowed in ETags. case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80: case c == '"': - return string(s[:i+1]), s[i+1:] + return s[:i+1], s[i+1:] default: return "", "" } @@ -445,7 +443,7 @@ func checkIfModifiedSince(r *Request, modtime time.Time) condResult { } func checkIfRange(w ResponseWriter, r *Request, modtime time.Time) condResult { - if r.Method != "GET" { + if r.Method != "GET" && r.Method != "HEAD" { return condNone } ir := r.Header.get("If-Range") @@ -532,10 +530,8 @@ func checkPreconditions(w ResponseWriter, r *Request, modtime time.Time) (done b } rangeHeader = r.Header.get("Range") - if rangeHeader != "" { - if checkIfRange(w, r, modtime) == condFalse { - rangeHeader = "" - } + if rangeHeader != "" && checkIfRange(w, r, modtime) == condFalse { + rangeHeader = "" } return false, rangeHeader } @@ -615,7 +611,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec return } w.Header().Set("Last-Modified", d.ModTime().UTC().Format(TimeFormat)) - dirList(w, f) + dirList(w, r, f) return } diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index f6eab0fcc31..fb8f9fe4c5c 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -895,6 +895,17 @@ func TestServeContent(t *testing.T) { wantContentRange: "bytes 0-4/8", wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT", }, + "range_with_modtime_mismatch": { + file: "testdata/style.css", + modtime: time.Date(2014, 6, 25, 17, 12, 18, 0 /* nanos */, time.UTC), + reqHeader: map[string]string{ + "Range": "bytes=0-4", + "If-Range": "Wed, 25 Jun 2014 17:12:19 GMT", + }, + wantStatus: StatusOK, + wantContentType: "text/css; charset=utf-8", + wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT", + }, "range_with_modtime_nanos": { file: "testdata/style.css", modtime: time.Date(2014, 6, 25, 17, 12, 18, 123 /* nanos */, time.UTC), @@ -937,8 +948,7 @@ func TestServeContent(t *testing.T) { reqHeader: map[string]string{ "If-Match": `"B"`, }, - wantStatus: 412, - wantContentType: "text/plain; charset=utf-8", + wantStatus: 412, }, "ifmatch_fails_on_weak_etag": { file: "testdata/style.css", @@ -946,8 +956,7 @@ func TestServeContent(t *testing.T) { reqHeader: map[string]string{ "If-Match": `W/"A"`, }, - wantStatus: 412, - wantContentType: "text/plain; charset=utf-8", + wantStatus: 412, }, "if_unmodified_since_true": { file: "testdata/style.css", @@ -965,9 +974,8 @@ func TestServeContent(t *testing.T) { reqHeader: map[string]string{ "If-Unmodified-Since": htmlModTime.Add(-2 * time.Second).UTC().Format(TimeFormat), }, - wantStatus: 412, - wantContentType: "text/plain; charset=utf-8", - wantLastMod: htmlModTime.UTC().Format(TimeFormat), + wantStatus: 412, + wantLastMod: htmlModTime.UTC().Format(TimeFormat), }, } for testName, tt := range tests { @@ -982,40 +990,46 @@ func TestServeContent(t *testing.T) { } else { content = tt.content } + for _, method := range []string{"GET", "HEAD"} { + //restore content in case it is consumed by previous method + if content, ok := content.(*strings.Reader); ok { + content.Seek(io.SeekStart, 0) + } - servec <- serveParam{ - name: filepath.Base(tt.file), - content: content, - modtime: tt.modtime, - etag: tt.serveETag, - contentType: tt.serveContentType, - } - req, err := NewRequest("GET", ts.URL, nil) - if err != nil { - t.Fatal(err) - } - for k, v := range tt.reqHeader { - req.Header.Set(k, v) - } + servec <- serveParam{ + name: filepath.Base(tt.file), + content: content, + modtime: tt.modtime, + etag: tt.serveETag, + contentType: tt.serveContentType, + } + req, err := NewRequest(method, ts.URL, nil) + if err != nil { + t.Fatal(err) + } + for k, v := range tt.reqHeader { + req.Header.Set(k, v) + } - c := ts.Client() - res, err := c.Do(req) - if err != nil { - t.Fatal(err) - } - io.Copy(ioutil.Discard, res.Body) - res.Body.Close() - if res.StatusCode != tt.wantStatus { - t.Errorf("test %q: status = %d; want %d", testName, res.StatusCode, tt.wantStatus) - } - if g, e := res.Header.Get("Content-Type"), tt.wantContentType; g != e { - t.Errorf("test %q: content-type = %q, want %q", testName, g, e) - } - if g, e := res.Header.Get("Content-Range"), tt.wantContentRange; g != e { - t.Errorf("test %q: content-range = %q, want %q", testName, g, e) - } - if g, e := res.Header.Get("Last-Modified"), tt.wantLastMod; g != e { - t.Errorf("test %q: last-modified = %q, want %q", testName, g, e) + c := ts.Client() + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + io.Copy(ioutil.Discard, res.Body) + res.Body.Close() + if res.StatusCode != tt.wantStatus { + t.Errorf("test %q using %q: got status = %d; want %d", testName, method, res.StatusCode, tt.wantStatus) + } + if g, e := res.Header.Get("Content-Type"), tt.wantContentType; g != e { + t.Errorf("test %q using %q: got content-type = %q, want %q", testName, method, g, e) + } + if g, e := res.Header.Get("Content-Range"), tt.wantContentRange; g != e { + t.Errorf("test %q using %q: got content-range = %q, want %q", testName, method, g, e) + } + if g, e := res.Header.Get("Last-Modified"), tt.wantLastMod; g != e { + t.Errorf("test %q using %q: got last-modified = %q, want %q", testName, method, g, e) + } } } } diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go index 373f55098a3..f5a95084d24 100644 --- a/libgo/go/net/http/h2_bundle.go +++ b/libgo/go/net/http/h2_bundle.go @@ -30,6 +30,7 @@ import ( "io/ioutil" "log" "math" + mathrand "math/rand" "net" "net/http/httptrace" "net/textproto" @@ -3909,12 +3910,15 @@ func http2ConfigureServer(s *Server, conf *http2Server) error { } else if s.TLSConfig.CipherSuites != nil { // If they already provided a CipherSuite list, return // an error if it has a bad order or is missing - // ECDHE_RSA_WITH_AES_128_GCM_SHA256. - const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. haveRequired := false sawBad := false for i, cs := range s.TLSConfig.CipherSuites { - if cs == requiredCipher { + switch cs { + case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + // Alternative MTI cipher to not discourage ECDSA-only servers. + // See http://golang.org/cl/30721 for further information. + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: haveRequired = true } if http2isBadCipher(cs) { @@ -3924,7 +3928,7 @@ func http2ConfigureServer(s *Server, conf *http2Server) error { } } if !haveRequired { - return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") + return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.") } } @@ -4341,7 +4345,7 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{ if err == nil { return } - if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) { + if err == io.EOF || err == io.ErrUnexpectedEOF || http2isClosedConnError(err) || err == http2errPrefaceTimeout { // Boring, expected errors. sc.vlogf(format, args...) } else { @@ -4545,8 +4549,13 @@ func (sc *http2serverConn) serve() { } } - if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame { - return + // Start the shutdown timer after sending a GOAWAY. When sending GOAWAY + // with no error code (graceful shutdown), don't start the timer until + // all open streams have been completed. + sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame + gracefulShutdownComplete := sc.goAwayCode == http2ErrCodeNo && sc.curOpenStreams() == 0 + if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != http2ErrCodeNo || gracefulShutdownComplete) { + sc.shutDownIn(http2goAwayTimeout) } } } @@ -4583,8 +4592,11 @@ func (sc *http2serverConn) sendServeMsg(msg interface{}) { } } -// readPreface reads the ClientPreface greeting from the peer -// or returns an error on timeout or an invalid greeting. +var http2errPrefaceTimeout = errors.New("timeout waiting for client preface") + +// readPreface reads the ClientPreface greeting from the peer or +// returns errPrefaceTimeout on timeout, or an error if the greeting +// is invalid. func (sc *http2serverConn) readPreface() error { errc := make(chan error, 1) go func() { @@ -4602,7 +4614,7 @@ func (sc *http2serverConn) readPreface() error { defer timer.Stop() select { case <-timer.C: - return errors.New("timeout waiting for client preface") + return http2errPrefaceTimeout case err := <-errc: if err == nil { if http2VerboseLogs { @@ -4912,30 +4924,31 @@ func (sc *http2serverConn) startGracefulShutdown() { sc.shutdownOnce.Do(func() { sc.sendServeMsg(http2gracefulShutdownMsg) }) } +// After sending GOAWAY, the connection will close after goAwayTimeout. +// If we close the connection immediately after sending GOAWAY, there may +// be unsent data in our kernel receive buffer, which will cause the kernel +// to send a TCP RST on close() instead of a FIN. This RST will abort the +// connection immediately, whether or not the client had received the GOAWAY. +// +// Ideally we should delay for at least 1 RTT + epsilon so the client has +// a chance to read the GOAWAY and stop sending messages. Measuring RTT +// is hard, so we approximate with 1 second. See golang.org/issue/18701. +// +// This is a var so it can be shorter in tests, where all requests uses the +// loopback interface making the expected RTT very small. +// +// TODO: configurable? +var http2goAwayTimeout = 1 * time.Second + func (sc *http2serverConn) startGracefulShutdownInternal() { - sc.goAwayIn(http2ErrCodeNo, 0) + sc.goAway(http2ErrCodeNo) } func (sc *http2serverConn) goAway(code http2ErrCode) { - sc.serveG.check() - var forceCloseIn time.Duration - if code != http2ErrCodeNo { - forceCloseIn = 250 * time.Millisecond - } else { - // TODO: configurable - forceCloseIn = 1 * time.Second - } - sc.goAwayIn(code, forceCloseIn) -} - -func (sc *http2serverConn) goAwayIn(code http2ErrCode, forceCloseIn time.Duration) { sc.serveG.check() if sc.inGoAway { return } - if forceCloseIn != 0 { - sc.shutDownIn(forceCloseIn) - } sc.inGoAway = true sc.needToSendGoAway = true sc.goAwayCode = code @@ -6004,7 +6017,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { clen = strconv.Itoa(len(p)) } _, hasContentType := rws.snapHeader["Content-Type"] - if !hasContentType && http2bodyAllowedForStatus(rws.status) { + if !hasContentType && http2bodyAllowedForStatus(rws.status) && len(p) > 0 { ctype = DetectContentType(p) } var date string @@ -6172,7 +6185,26 @@ func (w *http2responseWriter) Header() Header { return rws.handlerHeader } +// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode. +func http2checkWriteHeaderCode(code int) { + // Issue 22880: require valid WriteHeader status codes. + // For now we only enforce that it's three digits. + // In the future we might block things over 599 (600 and above aren't defined + // at http://httpwg.org/specs/rfc7231.html#status.codes) + // and we might block under 200 (once we have more mature 1xx support). + // But for now any three digits. + // + // We used to send "HTTP/1.1 000 0" on the wire in responses but there's + // no equivalent bogus thing we can realistically send in HTTP/2, + // so we'll consistently panic instead and help people find their bugs + // early. (We can't return an error from WriteHeader even if we wanted to.) + if code < 100 || code > 999 { + panic(fmt.Sprintf("invalid WriteHeader code %v", code)) + } +} + func (w *http2responseWriter) WriteHeader(code int) { + http2checkWriteHeaderCode(code) rws := w.rws if rws == nil { panic("WriteHeader called after Handler finished") @@ -6605,7 +6637,7 @@ type http2Transport struct { // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to // send in the initial settings frame. It is how many bytes - // of response headers are allow. Unlike the http2 spec, zero here + // of response headers are allowed. Unlike the http2 spec, zero here // means to use a default limit (currently 10MB). If you actually // want to advertise an ulimited value to the peer, Transport // interprets the highest possible value here (0xffffffff or 1<<32-1) @@ -6683,15 +6715,17 @@ type http2ClientConn struct { goAwayDebug string // goAway frame's debug data, retained as a string streams map[uint32]*http2clientStream // client-initiated nextStreamID uint32 + pendingRequests int // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams pings map[[8]byte]chan struct{} // in flight ping data to notification channel bw *bufio.Writer br *bufio.Reader fr *http2Framer lastActive time.Time // Settings from peer: (also guarded by mu) - maxFrameSize uint32 - maxConcurrentStreams uint32 - initialWindowSize uint32 + maxFrameSize uint32 + maxConcurrentStreams uint32 + peerMaxHeaderListSize uint64 + initialWindowSize uint32 hbuf bytes.Buffer // HPACK encoder writes into this henc *hpack.Encoder @@ -6735,35 +6769,45 @@ type http2clientStream struct { resTrailer *Header // client's Response.Trailer } -// awaitRequestCancel runs in its own goroutine and waits for the user -// to cancel a RoundTrip request, its context to expire, or for the -// request to be done (any way it might be removed from the cc.streams -// map: peer reset, successful completion, TCP connection breakage, -// etc) -func (cs *http2clientStream) awaitRequestCancel(req *Request) { +// awaitRequestCancel waits for the user to cancel a request or for the done +// channel to be signaled. A non-nil error is returned only if the request was +// canceled. +func http2awaitRequestCancel(req *Request, done <-chan struct{}) error { ctx := http2reqContext(req) if req.Cancel == nil && ctx.Done() == nil { - return + return nil } select { case <-req.Cancel: - cs.cancelStream() - cs.bufPipe.CloseWithError(http2errRequestCanceled) + return http2errRequestCanceled case <-ctx.Done(): + return ctx.Err() + case <-done: + return nil + } +} + +// awaitRequestCancel waits for the user to cancel a request, its context to +// expire, or for the request to be done (any way it might be removed from the +// cc.streams map: peer reset, successful completion, TCP connection breakage, +// etc). If the request is canceled, then cs will be canceled and closed. +func (cs *http2clientStream) awaitRequestCancel(req *Request) { + if err := http2awaitRequestCancel(req, cs.done); err != nil { cs.cancelStream() - cs.bufPipe.CloseWithError(ctx.Err()) - case <-cs.done: + cs.bufPipe.CloseWithError(err) } } func (cs *http2clientStream) cancelStream() { - cs.cc.mu.Lock() + cc := cs.cc + cc.mu.Lock() didReset := cs.didReset cs.didReset = true - cs.cc.mu.Unlock() + cc.mu.Unlock() if !didReset { - cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) + cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) + cc.forgetStreamID(cs.ID) } } @@ -6780,6 +6824,13 @@ func (cs *http2clientStream) checkResetOrDone() error { } } +func (cs *http2clientStream) getStartedWrite() bool { + cc := cs.cc + cc.mu.Lock() + defer cc.mu.Unlock() + return cs.startedWrite +} + func (cs *http2clientStream) abortRequestBodyWrite(err error) { if err == nil { panic("nil error") @@ -6848,17 +6899,28 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res } addr := http2authorityAddr(req.URL.Scheme, req.URL.Host) - for { + for retry := 0; ; retry++ { cc, err := t.connPool().GetClientConn(req, addr) if err != nil { t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err) return nil, err } http2traceGotConn(req, cc) - res, err := cc.RoundTrip(req) - if err != nil { - if req, err = http2shouldRetryRequest(req, err); err == nil { - continue + res, gotErrAfterReqBodyWrite, err := cc.roundTrip(req) + if err != nil && retry <= 6 { + if req, err = http2shouldRetryRequest(req, err, gotErrAfterReqBodyWrite); err == nil { + // After the first retry, do exponential backoff with 10% jitter. + if retry == 0 { + continue + } + backoff := float64(uint(1) << (uint(retry) - 1)) + backoff += backoff * (0.1 * mathrand.Float64()) + select { + case <-time.After(time.Second * time.Duration(backoff)): + continue + case <-http2reqContext(req).Done(): + return nil, http2reqContext(req).Err() + } } } if err != nil { @@ -6879,43 +6941,50 @@ func (t *http2Transport) CloseIdleConnections() { } var ( - http2errClientConnClosed = errors.New("http2: client conn is closed") - http2errClientConnUnusable = errors.New("http2: client conn not usable") - - http2errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY") - http2errClientConnGotGoAwayAfterSomeReqBody = errors.New("http2: Transport received Server's graceful shutdown GOAWAY; some request body already written") + http2errClientConnClosed = errors.New("http2: client conn is closed") + http2errClientConnUnusable = errors.New("http2: client conn not usable") + http2errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY") ) // shouldRetryRequest is called by RoundTrip when a request fails to get // response headers. It is always called with a non-nil error. // It returns either a request to retry (either the same request, or a // modified clone), or an error if the request can't be replayed. -func http2shouldRetryRequest(req *Request, err error) (*Request, error) { - switch err { - default: +func http2shouldRetryRequest(req *Request, err error, afterBodyWrite bool) (*Request, error) { + if !http2canRetryError(err) { return nil, err - case http2errClientConnUnusable, http2errClientConnGotGoAway: + } + if !afterBodyWrite { return req, nil - case http2errClientConnGotGoAwayAfterSomeReqBody: - // If the Body is nil (or http.NoBody), it's safe to reuse - // this request and its Body. - if req.Body == nil || http2reqBodyIsNoBody(req.Body) { - return req, nil - } - // Otherwise we depend on the Request having its GetBody - // func defined. - getBody := http2reqGetBody(req) // Go 1.8: getBody = req.GetBody - if getBody == nil { - return nil, errors.New("http2: Transport: peer server initiated graceful shutdown after some of Request.Body was written; define Request.GetBody to avoid this error") - } - body, err := getBody() - if err != nil { - return nil, err - } - newReq := *req - newReq.Body = body - return &newReq, nil } + // If the Body is nil (or http.NoBody), it's safe to reuse + // this request and its Body. + if req.Body == nil || http2reqBodyIsNoBody(req.Body) { + return req, nil + } + // Otherwise we depend on the Request having its GetBody + // func defined. + getBody := http2reqGetBody(req) // Go 1.8: getBody = req.GetBody + if getBody == nil { + return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", err) + } + body, err := getBody() + if err != nil { + return nil, err + } + newReq := *req + newReq.Body = body + return &newReq, nil +} + +func http2canRetryError(err error) bool { + if err == http2errClientConnUnusable || err == http2errClientConnGotGoAway { + return true + } + if se, ok := err.(http2StreamError); ok { + return se.Code == http2ErrCodeRefusedStream + } + return false } func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) { @@ -6993,17 +7062,18 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) { cc := &http2ClientConn{ - t: t, - tconn: c, - readerDone: make(chan struct{}), - nextStreamID: 1, - maxFrameSize: 16 << 10, // spec default - initialWindowSize: 65535, // spec default - maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough. - streams: make(map[uint32]*http2clientStream), - singleUse: singleUse, - wantSettingsAck: true, - pings: make(map[[8]byte]chan struct{}), + t: t, + tconn: c, + readerDone: make(chan struct{}), + nextStreamID: 1, + maxFrameSize: 16 << 10, // spec default + initialWindowSize: 65535, // spec default + maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough. + peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead. + streams: make(map[uint32]*http2clientStream), + singleUse: singleUse, + wantSettingsAck: true, + pings: make(map[[8]byte]chan struct{}), } if d := t.idleConnTimeout(); d != 0 { cc.idleTimeout = d @@ -7079,6 +7149,8 @@ func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) { } } +// CanTakeNewRequest reports whether the connection can take a new request, +// meaning it has not been closed or received or sent a GOAWAY. func (cc *http2ClientConn) CanTakeNewRequest() bool { cc.mu.Lock() defer cc.mu.Unlock() @@ -7090,8 +7162,7 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool { return false } return cc.goAway == nil && !cc.closed && - int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) && - cc.nextStreamID < math.MaxInt32 + int64(cc.nextStreamID)+int64(cc.pendingRequests) < math.MaxInt32 } // onIdleTimeout is called from a time.AfterFunc goroutine. It will @@ -7223,8 +7294,13 @@ func http2actualContentLength(req *Request) int64 { } func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { + resp, _, err := cc.roundTrip(req) + return resp, err +} + +func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterReqBodyWrite bool, err error) { if err := http2checkConnHeaders(req); err != nil { - return nil, err + return nil, false, err } if cc.idleTimer != nil { cc.idleTimer.Stop() @@ -7232,15 +7308,14 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { trailers, err := http2commaSeparatedTrailers(req) if err != nil { - return nil, err + return nil, false, err } hasTrailers := trailers != "" cc.mu.Lock() - cc.lastActive = time.Now() - if cc.closed || !cc.canTakeNewRequestLocked() { + if err := cc.awaitOpenSlotForRequest(req); err != nil { cc.mu.Unlock() - return nil, http2errClientConnUnusable + return nil, false, err } body := req.Body @@ -7274,7 +7349,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen) if err != nil { cc.mu.Unlock() - return nil, err + return nil, false, err } cs := cc.newStream() @@ -7286,7 +7361,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cc.wmu.Lock() endStream := !hasBody && !hasTrailers - werr := cc.writeHeaders(cs.ID, endStream, hdrs) + werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) cc.wmu.Unlock() http2traceWroteHeaders(cs.trace) cc.mu.Unlock() @@ -7300,7 +7375,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { // Don't bother sending a RST_STREAM (our write already failed; // no need to keep writing) http2traceWroteRequest(cs.trace, werr) - return nil, werr + return nil, false, werr } var respHeaderTimer <-chan time.Time @@ -7319,7 +7394,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { bodyWritten := false ctx := http2reqContext(req) - handleReadLoopResponse := func(re http2resAndError) (*Response, error) { + handleReadLoopResponse := func(re http2resAndError) (*Response, bool, error) { res := re.res if re.err != nil || res.StatusCode > 299 { // On error or status code 3xx, 4xx, 5xx, etc abort any @@ -7335,19 +7410,12 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { cs.abortRequestBodyWrite(http2errStopReqBodyWrite) } if re.err != nil { - if re.err == http2errClientConnGotGoAway { - cc.mu.Lock() - if cs.startedWrite { - re.err = http2errClientConnGotGoAwayAfterSomeReqBody - } - cc.mu.Unlock() - } cc.forgetStreamID(cs.ID) - return nil, re.err + return nil, cs.getStartedWrite(), re.err } res.Request = req res.TLS = cc.tlsState - return res, nil + return res, false, nil } for { @@ -7355,42 +7423,42 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { case re := <-readLoopResCh: return handleReadLoopResponse(re) case <-respHeaderTimer: - cc.forgetStreamID(cs.ID) if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } - return nil, http2errTimeout + cc.forgetStreamID(cs.ID) + return nil, cs.getStartedWrite(), http2errTimeout case <-ctx.Done(): select { case re := <-readLoopResCh: return handleReadLoopResponse(re) default: } - cc.forgetStreamID(cs.ID) if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } - return nil, ctx.Err() + cc.forgetStreamID(cs.ID) + return nil, cs.getStartedWrite(), ctx.Err() case <-req.Cancel: select { case re := <-readLoopResCh: return handleReadLoopResponse(re) default: } - cc.forgetStreamID(cs.ID) if !hasBody || bodyWritten { cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) } else { bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel) } - return nil, http2errRequestCanceled + cc.forgetStreamID(cs.ID) + return nil, cs.getStartedWrite(), http2errRequestCanceled case <-cs.peerReset: select { case re := <-readLoopResCh: @@ -7400,7 +7468,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { // processResetStream already removed the // stream from the streams map; no need for // forgetStreamID. - return nil, cs.resetErr + return nil, cs.getStartedWrite(), cs.resetErr case err := <-bodyWriter.resc: // Prefer the read loop's response, if available. Issue 16102. select { @@ -7409,7 +7477,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { default: } if err != nil { - return nil, err + return nil, cs.getStartedWrite(), err } bodyWritten = true if d := cc.responseHeaderTimeout(); d != 0 { @@ -7421,14 +7489,52 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { } } +// awaitOpenSlotForRequest waits until len(streams) < maxConcurrentStreams. +// Must hold cc.mu. +func (cc *http2ClientConn) awaitOpenSlotForRequest(req *Request) error { + var waitingForConn chan struct{} + var waitingForConnErr error // guarded by cc.mu + for { + cc.lastActive = time.Now() + if cc.closed || !cc.canTakeNewRequestLocked() { + return http2errClientConnUnusable + } + if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) { + if waitingForConn != nil { + close(waitingForConn) + } + return nil + } + // Unfortunately, we cannot wait on a condition variable and channel at + // the same time, so instead, we spin up a goroutine to check if the + // request is canceled while we wait for a slot to open in the connection. + if waitingForConn == nil { + waitingForConn = make(chan struct{}) + go func() { + if err := http2awaitRequestCancel(req, waitingForConn); err != nil { + cc.mu.Lock() + waitingForConnErr = err + cc.cond.Broadcast() + cc.mu.Unlock() + } + }() + } + cc.pendingRequests++ + cc.cond.Wait() + cc.pendingRequests-- + if waitingForConnErr != nil { + return waitingForConnErr + } + } +} + // requires cc.wmu be held -func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error { +func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error { first := true // first frame written (HEADERS is first, then CONTINUATION) - frameSize := int(cc.maxFrameSize) for len(hdrs) > 0 && cc.werr == nil { chunk := hdrs - if len(chunk) > frameSize { - chunk = chunk[:frameSize] + if len(chunk) > maxFrameSize { + chunk = chunk[:maxFrameSize] } hdrs = hdrs[len(chunk):] endHeaders := len(hdrs) == 0 @@ -7536,17 +7642,26 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos var trls []byte if hasTrailers { cc.mu.Lock() - defer cc.mu.Unlock() - trls = cc.encodeTrailers(req) + trls, err = cc.encodeTrailers(req) + cc.mu.Unlock() + if err != nil { + cc.writeStreamReset(cs.ID, http2ErrCodeInternal, err) + cc.forgetStreamID(cs.ID) + return err + } } + cc.mu.Lock() + maxFrameSize := int(cc.maxFrameSize) + cc.mu.Unlock() + cc.wmu.Lock() defer cc.wmu.Unlock() // Two ways to send END_STREAM: either with trailers, or // with an empty DATA frame. if len(trls) > 0 { - err = cc.writeHeaders(cs.ID, true, trls) + err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls) } else { err = cc.fr.WriteData(cs.ID, true, nil) } @@ -7640,62 +7755,86 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail } } - // 8.1.2.3 Request Pseudo-Header Fields - // The :path pseudo-header field includes the path and query parts of the - // target URI (the path-absolute production and optionally a '?' character - // followed by the query production (see Sections 3.3 and 3.4 of - // [RFC3986]). - cc.writeHeader(":authority", host) - cc.writeHeader(":method", req.Method) - if req.Method != "CONNECT" { - cc.writeHeader(":path", path) - cc.writeHeader(":scheme", req.URL.Scheme) - } - if trailers != "" { - cc.writeHeader("trailer", trailers) - } - - var didUA bool - for k, vv := range req.Header { - lowKey := strings.ToLower(k) - switch lowKey { - case "host", "content-length": - // Host is :authority, already sent. - // Content-Length is automatic, set below. - continue - case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive": - // Per 8.1.2.2 Connection-Specific Header - // Fields, don't send connection-specific - // fields. We have already checked if any - // are error-worthy so just ignore the rest. - continue - case "user-agent": - // Match Go's http1 behavior: at most one - // User-Agent. If set to nil or empty string, - // then omit it. Otherwise if not mentioned, - // include the default (below). - didUA = true - if len(vv) < 1 { + enumerateHeaders := func(f func(name, value string)) { + // 8.1.2.3 Request Pseudo-Header Fields + // The :path pseudo-header field includes the path and query parts of the + // target URI (the path-absolute production and optionally a '?' character + // followed by the query production (see Sections 3.3 and 3.4 of + // [RFC3986]). + f(":authority", host) + f(":method", req.Method) + if req.Method != "CONNECT" { + f(":path", path) + f(":scheme", req.URL.Scheme) + } + if trailers != "" { + f("trailer", trailers) + } + + var didUA bool + for k, vv := range req.Header { + if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") { + // Host is :authority, already sent. + // Content-Length is automatic, set below. continue - } - vv = vv[:1] - if vv[0] == "" { + } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") || + strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") || + strings.EqualFold(k, "keep-alive") { + // Per 8.1.2.2 Connection-Specific Header + // Fields, don't send connection-specific + // fields. We have already checked if any + // are error-worthy so just ignore the rest. continue + } else if strings.EqualFold(k, "user-agent") { + // Match Go's http1 behavior: at most one + // User-Agent. If set to nil or empty string, + // then omit it. Otherwise if not mentioned, + // include the default (below). + didUA = true + if len(vv) < 1 { + continue + } + vv = vv[:1] + if vv[0] == "" { + continue + } + + } + + for _, v := range vv { + f(k, v) } } - for _, v := range vv { - cc.writeHeader(lowKey, v) + if http2shouldSendReqContentLength(req.Method, contentLength) { + f("content-length", strconv.FormatInt(contentLength, 10)) + } + if addGzipHeader { + f("accept-encoding", "gzip") + } + if !didUA { + f("user-agent", http2defaultUserAgent) } } - if http2shouldSendReqContentLength(req.Method, contentLength) { - cc.writeHeader("content-length", strconv.FormatInt(contentLength, 10)) - } - if addGzipHeader { - cc.writeHeader("accept-encoding", "gzip") - } - if !didUA { - cc.writeHeader("user-agent", http2defaultUserAgent) + + // Do a first pass over the headers counting bytes to ensure + // we don't exceed cc.peerMaxHeaderListSize. This is done as a + // separate pass before encoding the headers to prevent + // modifying the hpack state. + hlSize := uint64(0) + enumerateHeaders(func(name, value string) { + hf := hpack.HeaderField{Name: name, Value: value} + hlSize += uint64(hf.Size()) + }) + + if hlSize > cc.peerMaxHeaderListSize { + return nil, http2errRequestHeaderListSize } + + // Header list size is ok. Write the headers. + enumerateHeaders(func(name, value string) { + cc.writeHeader(strings.ToLower(name), value) + }) + return cc.hbuf.Bytes(), nil } @@ -7722,17 +7861,29 @@ func http2shouldSendReqContentLength(method string, contentLength int64) bool { } // requires cc.mu be held. -func (cc *http2ClientConn) encodeTrailers(req *Request) []byte { +func (cc *http2ClientConn) encodeTrailers(req *Request) ([]byte, error) { cc.hbuf.Reset() + + hlSize := uint64(0) + for k, vv := range req.Trailer { + for _, v := range vv { + hf := hpack.HeaderField{Name: k, Value: v} + hlSize += uint64(hf.Size()) + } + } + if hlSize > cc.peerMaxHeaderListSize { + return nil, http2errRequestHeaderListSize + } + for k, vv := range req.Trailer { - // Transfer-Encoding, etc.. have already been filter at the + // Transfer-Encoding, etc.. have already been filtered at the // start of RoundTrip lowKey := strings.ToLower(k) for _, v := range vv { cc.writeHeader(lowKey, v) } } - return cc.hbuf.Bytes() + return cc.hbuf.Bytes(), nil } func (cc *http2ClientConn) writeHeader(name, value string) { @@ -7780,7 +7931,9 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr cc.idleTimer.Reset(cc.idleTimeout) } close(cs.done) - cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl + // Wake up checkResetOrDone via clientStream.awaitFlowControl and + // wake up RoundTrip if there is a pending request. + cc.cond.Broadcast() } return cs } @@ -7788,17 +7941,12 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. type http2clientConnReadLoop struct { cc *http2ClientConn - activeRes map[uint32]*http2clientStream // keyed by streamID closeWhenIdle bool } // readLoop runs in its own goroutine and reads and dispatches frames. func (cc *http2ClientConn) readLoop() { - rl := &http2clientConnReadLoop{ - cc: cc, - activeRes: make(map[uint32]*http2clientStream), - } - + rl := &http2clientConnReadLoop{cc: cc} defer rl.cleanup() cc.readerErr = rl.run() if ce, ok := cc.readerErr.(http2ConnectionError); ok { @@ -7853,10 +8001,8 @@ func (rl *http2clientConnReadLoop) cleanup() { } else if err == io.EOF { err = io.ErrUnexpectedEOF } - for _, cs := range rl.activeRes { - cs.bufPipe.CloseWithError(err) - } for _, cs := range cc.streams { + cs.bufPipe.CloseWithError(err) // no-op if already closed select { case cs.resc <- http2resAndError{err: err}: default: @@ -7879,8 +8025,9 @@ func (rl *http2clientConnReadLoop) run() error { cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) } if se, ok := err.(http2StreamError); ok { - if cs := cc.streamByID(se.StreamID, true /*ended; remove it*/); cs != nil { + if cs := cc.streamByID(se.StreamID, false); cs != nil { cs.cc.writeStreamReset(cs.ID, se.Code, err) + cs.cc.forgetStreamID(cs.ID) if se.Cause == nil { se.Cause = cc.fr.errDetail } @@ -7933,7 +8080,7 @@ func (rl *http2clientConnReadLoop) run() error { } return err } - if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 { + if rl.closeWhenIdle && gotReply && maybeIdle { cc.closeIfIdle() } } @@ -7941,13 +8088,31 @@ func (rl *http2clientConnReadLoop) run() error { func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error { cc := rl.cc - cs := cc.streamByID(f.StreamID, f.StreamEnded()) + cs := cc.streamByID(f.StreamID, false) if cs == nil { // We'd get here if we canceled a request while the // server had its response still in flight. So if this // was just something we canceled, ignore it. return nil } + if f.StreamEnded() { + // Issue 20521: If the stream has ended, streamByID() causes + // clientStream.done to be closed, which causes the request's bodyWriter + // to be closed with an errStreamClosed, which may be received by + // clientConn.RoundTrip before the result of processing these headers. + // Deferring stream closure allows the header processing to occur first. + // clientConn.RoundTrip may still receive the bodyWriter error first, but + // the fix for issue 16102 prioritises any response. + // + // Issue 22413: If there is no request body, we should close the + // stream before writing to cs.resc so that the stream is closed + // immediately once RoundTrip returns. + if cs.req.Body != nil { + defer cc.forgetStreamID(f.StreamID) + } else { + cc.forgetStreamID(f.StreamID) + } + } if !cs.firstByte { if cs.trace != nil { // TODO(bradfitz): move first response byte earlier, @@ -7971,6 +8136,7 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro } // Any other error type is a stream error. cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err) + cc.forgetStreamID(cs.ID) cs.resc <- http2resAndError{err: err} return nil // return nil from process* funcs to keep conn alive } @@ -7978,9 +8144,6 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro // (nil, nil) special case. See handleResponse docs. return nil } - if res.Body != http2noBody { - rl.activeRes[cs.ID] = cs - } cs.resTrailer = &res.Trailer cs.resc <- http2resAndError{res: res} return nil @@ -8000,11 +8163,11 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http status := f.PseudoValue("status") if status == "" { - return nil, errors.New("missing status pseudo header") + return nil, errors.New("malformed response from server: missing status pseudo header") } statusCode, err := strconv.Atoi(status) if err != nil { - return nil, errors.New("malformed non-numeric status pseudo header") + return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header") } if statusCode == 100 { @@ -8202,6 +8365,7 @@ func (b http2transportResponseBody) Close() error { } cs.bufPipe.BreakWithError(http2errClosedResponseBody) + cc.forgetStreamID(cs.ID) return nil } @@ -8236,7 +8400,23 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error { } return nil } + if !cs.firstByte { + cc.logf("protocol error: received DATA before a HEADERS frame") + rl.endStreamError(cs, http2StreamError{ + StreamID: f.StreamID, + Code: http2ErrCodeProtocol, + }) + return nil + } if f.Length > 0 { + if cs.req.Method == "HEAD" && len(data) > 0 { + cc.logf("protocol error: received DATA on a HEAD request") + rl.endStreamError(cs, http2StreamError{ + StreamID: f.StreamID, + Code: http2ErrCodeProtocol, + }) + return nil + } // Check connection-level flow control. cc.mu.Lock() if cs.inflow.available() >= int32(f.Length) { @@ -8298,11 +8478,10 @@ func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err err err = io.EOF code = cs.copyTrailers } - cs.bufPipe.closeWithErrorAndCode(err, code) - delete(rl.activeRes, cs.ID) if http2isConnectionCloseRequest(cs.req) { rl.closeWhenIdle = true } + cs.bufPipe.closeWithErrorAndCode(err, code) select { case cs.resc <- http2resAndError{err: err}: @@ -8350,6 +8529,8 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error cc.maxFrameSize = s.Val case http2SettingMaxConcurrentStreams: cc.maxConcurrentStreams = s.Val + case http2SettingMaxHeaderListSize: + cc.peerMaxHeaderListSize = uint64(s.Val) case http2SettingInitialWindowSize: // Values above the maximum flow-control // window size of 2^31-1 MUST be treated as a @@ -8427,7 +8608,6 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er cs.bufPipe.CloseWithError(err) cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl } - delete(rl.activeRes, cs.ID) return nil } @@ -8516,6 +8696,7 @@ func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, var ( http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") + http2errRequestHeaderListSize = errors.New("http2: request header list larger than peer's advertised limit") http2errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers") ) @@ -8741,11 +8922,7 @@ type http2writeGoAway struct { func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error { err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil) - if p.code != 0 { - ctx.Flush() // ignore error: we're hanging up on them anyway - time.Sleep(50 * time.Millisecond) - ctx.CloseConn() - } + ctx.Flush() // ignore error: we're hanging up on them anyway return err } diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go index 832169247fe..622ad289636 100644 --- a/libgo/go/net/http/header.go +++ b/libgo/go/net/http/header.go @@ -156,6 +156,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { v = textproto.TrimString(v) for _, s := range []string{kv.key, ": ", v, "\r\n"} { if _, err := ws.WriteString(s); err != nil { + headerSorterPool.Put(sorter) return err } } diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go index f881020fef7..5703a7fb866 100644 --- a/libgo/go/net/http/httputil/dump_test.go +++ b/libgo/go/net/http/httputil/dump_test.go @@ -27,7 +27,6 @@ type dumpTest struct { } var dumpTests = []dumpTest{ - // HTTP/1.1 => chunked coding; body; empty trailer { Req: http.Request{ @@ -214,7 +213,6 @@ func TestDumpRequest(t *testing.T) { t.Fatalf("Test %d: unsupported Body of %T", i, tt.Body) } } - setBody() if tt.Req.Header == nil { tt.Req.Header = make(http.Header) } diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go index 0d514f529ba..aa22d5a2fdd 100644 --- a/libgo/go/net/http/httputil/reverseproxy.go +++ b/libgo/go/net/http/httputil/reverseproxy.go @@ -169,15 +169,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { p.Director(outreq) outreq.Close = false - // Remove hop-by-hop headers listed in the "Connection" header. - // See RFC 2616, section 14.10. - if c := outreq.Header.Get("Connection"); c != "" { - for _, f := range strings.Split(c, ",") { - if f = strings.TrimSpace(f); f != "" { - outreq.Header.Del(f) - } - } - } + removeConnectionHeaders(outreq.Header) // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent @@ -199,32 +191,30 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } res, err := transport.RoundTrip(outreq) - if err != nil { - p.logf("http: proxy error: %v", err) - rw.WriteHeader(http.StatusBadGateway) - return - } - - // Remove hop-by-hop headers listed in the - // "Connection" header of the response. - if c := res.Header.Get("Connection"); c != "" { - for _, f := range strings.Split(c, ",") { - if f = strings.TrimSpace(f); f != "" { - res.Header.Del(f) - } + if res == nil { + res = &http.Response{ + StatusCode: http.StatusBadGateway, + Body: http.NoBody, } } + removeConnectionHeaders(res.Header) + for _, h := range hopHeaders { res.Header.Del(h) } if p.ModifyResponse != nil { - if err := p.ModifyResponse(res); err != nil { + if err != nil { p.logf("http: proxy error: %v", err) - rw.WriteHeader(http.StatusBadGateway) - return } + err = p.ModifyResponse(res) + } + if err != nil { + p.logf("http: proxy error: %v", err) + rw.WriteHeader(http.StatusBadGateway) + res.Body.Close() + return } copyHeader(rw.Header(), res.Header) @@ -265,6 +255,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } +// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h. +// See RFC 2616, section 14.10. +func removeConnectionHeaders(h http.Header) { + if c := h.Get("Connection"); c != "" { + for _, f := range strings.Split(c, ",") { + if f = strings.TrimSpace(f); f != "" { + h.Del(f) + } + } + } +} + func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) { if p.FlushInterval != 0 { if wf, ok := dst.(writeFlusher); ok { diff --git a/libgo/go/net/http/httputil/reverseproxy_test.go b/libgo/go/net/http/httputil/reverseproxy_test.go index 37a9992375d..822828e5c0d 100644 --- a/libgo/go/net/http/httputil/reverseproxy_test.go +++ b/libgo/go/net/http/httputil/reverseproxy_test.go @@ -631,6 +631,35 @@ func TestReverseProxyModifyResponse(t *testing.T) { } } +// Issue 21255. Test ModifyResponse when an error from transport.RoundTrip +// occurs, and that the proxy returns StatusOK. +func TestReverseProxyModifyResponse_OnError(t *testing.T) { + // Always returns an error + errBackend := httptest.NewUnstartedServer(nil) + errBackend.Config.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + defer errBackend.Close() + + rpURL, _ := url.Parse(errBackend.URL) + rproxy := NewSingleHostReverseProxy(rpURL) + rproxy.ModifyResponse = func(resp *http.Response) error { + // Will be set for a non-nil error + resp.StatusCode = http.StatusOK + return nil + } + + frontend := httptest.NewServer(rproxy) + defer frontend.Close() + + resp, err := http.Get(frontend.URL) + if err != nil { + t.Fatalf("failed to reach proxy: %v", err) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("err != nil: got res.StatusCode %d; expected %d", resp.StatusCode, http.StatusOK) + } + resp.Body.Close() +} + // Issue 16659: log errors from short read func TestReverseProxy_CopyBuffer(t *testing.T) { backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -769,3 +798,47 @@ type roundTripperFunc func(req *http.Request) (*http.Response, error) func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return fn(req) } + +func TestModifyResponseClosesBody(t *testing.T) { + req, _ := http.NewRequest("GET", "http://foo.tld/", nil) + req.RemoteAddr = "1.2.3.4:56789" + closeCheck := new(checkCloser) + logBuf := new(bytes.Buffer) + outErr := errors.New("ModifyResponse error") + rp := &ReverseProxy{ + Director: func(req *http.Request) {}, + Transport: &staticTransport{&http.Response{ + StatusCode: 200, + Body: closeCheck, + }}, + ErrorLog: log.New(logBuf, "", 0), + ModifyResponse: func(*http.Response) error { + return outErr + }, + } + rec := httptest.NewRecorder() + rp.ServeHTTP(rec, req) + res := rec.Result() + if g, e := res.StatusCode, http.StatusBadGateway; g != e { + t.Errorf("got res.StatusCode %d; expected %d", g, e) + } + if !closeCheck.closed { + t.Errorf("body should have been closed") + } + if g, e := logBuf.String(), outErr.Error(); !strings.Contains(g, e) { + t.Errorf("ErrorLog %q does not contain %q", g, e) + } +} + +type checkCloser struct { + closed bool +} + +func (cc *checkCloser) Close() error { + cc.closed = true + return nil +} + +func (cc *checkCloser) Read(b []byte) (int, error) { + return len(b), nil +} diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go index 12c7599ab0f..21992d62da2 100644 --- a/libgo/go/net/http/pprof/pprof.go +++ b/libgo/go/net/http/pprof/pprof.go @@ -69,11 +69,11 @@ import ( ) func init() { - http.Handle("/debug/pprof/", http.HandlerFunc(Index)) - http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline)) - http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile)) - http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol)) - http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace)) + http.HandleFunc("/debug/pprof/", Index) + http.HandleFunc("/debug/pprof/cmdline", Cmdline) + http.HandleFunc("/debug/pprof/profile", Profile) + http.HandleFunc("/debug/pprof/symbol", Symbol) + http.HandleFunc("/debug/pprof/trace", Trace) } // Cmdline responds with the running program's diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index 28a148b9acb..22a9c2ef4b2 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -453,6 +453,14 @@ Content-Length: 4 abc`)}, {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1 Host: foo +Content-Length: 5`)}, + + // golang.org/issue/22464 + {"leading_space_in_header", reqBytes(`HEAD / HTTP/1.1 + Host: foo +Content-Length: 5`)}, + {"leading_tab_in_header", reqBytes(`HEAD / HTTP/1.1 +\tHost: foo Content-Length: 5`)}, } diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 13f367c1a8f..870af85e04a 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -490,8 +490,8 @@ var errMissingHost = errors.New("http: Request.Write on Request with no Host or // extraHeaders may be nil // waitForContinue may be nil -func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) { - trace := httptrace.ContextClientTrace(req.Context()) +func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) { + trace := httptrace.ContextClientTrace(r.Context()) if trace != nil && trace.WroteRequest != nil { defer func() { trace.WroteRequest(httptrace.WroteRequestInfo{ @@ -504,12 +504,12 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai // is not given, use the host from the request URL. // // Clean the host, in case it arrives with unexpected stuff in it. - host := cleanHost(req.Host) + host := cleanHost(r.Host) if host == "" { - if req.URL == nil { + if r.URL == nil { return errMissingHost } - host = cleanHost(req.URL.Host) + host = cleanHost(r.URL.Host) } // According to RFC 6874, an HTTP client, proxy, or other @@ -517,10 +517,10 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai // to an outgoing URI. host = removeZone(host) - ruri := req.URL.RequestURI() - if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { - ruri = req.URL.Scheme + "://" + host + ruri - } else if req.Method == "CONNECT" && req.URL.Path == "" { + ruri := r.URL.RequestURI() + if usingProxy && r.URL.Scheme != "" && r.URL.Opaque == "" { + ruri = r.URL.Scheme + "://" + host + ruri + } else if r.Method == "CONNECT" && r.URL.Path == "" { // CONNECT requests normally give just the host and port, not a full URL. ruri = host } @@ -536,7 +536,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai w = bw } - _, err = fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri) + _, err = fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(r.Method, "GET"), ruri) if err != nil { return err } @@ -550,8 +550,8 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai // Use the defaultUserAgent unless the Header contains one, which // may be blank to not send the header. userAgent := defaultUserAgent - if _, ok := req.Header["User-Agent"]; ok { - userAgent = req.Header.Get("User-Agent") + if _, ok := r.Header["User-Agent"]; ok { + userAgent = r.Header.Get("User-Agent") } if userAgent != "" { _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent) @@ -561,7 +561,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai } // Process Body,ContentLength,Close,Trailer - tw, err := newTransferWriter(req) + tw, err := newTransferWriter(r) if err != nil { return err } @@ -570,7 +570,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai return err } - err = req.Header.WriteSubset(w, reqWriteExcludeHeader) + err = r.Header.WriteSubset(w, reqWriteExcludeHeader) if err != nil { return err } @@ -603,7 +603,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai trace.Wait100Continue() } if !waitForContinue() { - req.closeBody() + r.closeBody() return nil } } diff --git a/libgo/go/net/http/response.go b/libgo/go/net/http/response.go index 0357b605023..4c614bfab0b 100644 --- a/libgo/go/net/http/response.go +++ b/libgo/go/net/http/response.go @@ -27,6 +27,9 @@ var respExcludeHeader = map[string]bool{ // Response represents the response from an HTTP request. // +// The Client and Transport return Responses from servers once +// the response headers have been received. The response body +// is streamed on demand as the Body field is read. type Response struct { Status string // e.g. "200 OK" StatusCode int // e.g. 200 @@ -47,6 +50,10 @@ type Response struct { // Body represents the response body. // + // The response body is streamed on demand as the Body field + // is read. If the network connection fails or the server + // terminates the response, Body.Read calls return an error. + // // The http Client and Transport guarantee that Body is always // non-nil, even on responses without a body or responses with // a zero-length body. It is the caller's responsibility to diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go index f1a50bd5989..1ea19619fee 100644 --- a/libgo/go/net/http/response_test.go +++ b/libgo/go/net/http/response_test.go @@ -816,7 +816,6 @@ func TestReadResponseErrors(t *testing.T) { type testCase struct { name string // optional, defaults to in in string - header Header wantErr interface{} // nil, err value, or string substring } @@ -842,22 +841,21 @@ func TestReadResponseErrors(t *testing.T) { } } - contentLength := func(status, body string, wantErr interface{}, header Header) testCase { + contentLength := func(status, body string, wantErr interface{}) testCase { return testCase{ name: fmt.Sprintf("status %q %q", status, body), in: fmt.Sprintf("HTTP/1.1 %s\r\n%s", status, body), wantErr: wantErr, - header: header, } } errMultiCL := "message cannot contain multiple Content-Length headers" tests := []testCase{ - {"", "", nil, io.ErrUnexpectedEOF}, - {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", nil, io.ErrUnexpectedEOF}, - {"", "HTTP/1.1", nil, "malformed HTTP response"}, - {"", "HTTP/2.0", nil, "malformed HTTP response"}, + {"", "", io.ErrUnexpectedEOF}, + {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", io.ErrUnexpectedEOF}, + {"", "HTTP/1.1", "malformed HTTP response"}, + {"", "HTTP/2.0", "malformed HTTP response"}, status("20X Unknown", true), status("abcd Unknown", true), status("二百/两百 OK", true), @@ -883,18 +881,22 @@ func TestReadResponseErrors(t *testing.T) { version("HTTP/1", true), version("http/1.1", true), - contentLength("200 OK", "Content-Length: 10\r\nContent-Length: 7\r\n\r\nGopher hey\r\n", errMultiCL, nil), - contentLength("200 OK", "Content-Length: 7\r\nContent-Length: 7\r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"7"}}), - contentLength("201 OK", "Content-Length: 0\r\nContent-Length: 7\r\n\r\nGophers\r\n", errMultiCL, nil), - contentLength("300 OK", "Content-Length: 0\r\nContent-Length: 0 \r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"0"}}), - contentLength("200 OK", "Content-Length:\r\nContent-Length:\r\n\r\nGophers\r\n", nil, nil), - contentLength("206 OK", "Content-Length:\r\nContent-Length: 0 \r\nConnection: close\r\n\r\nGophers\r\n", errMultiCL, nil), + contentLength("200 OK", "Content-Length: 10\r\nContent-Length: 7\r\n\r\nGopher hey\r\n", errMultiCL), + contentLength("200 OK", "Content-Length: 7\r\nContent-Length: 7\r\n\r\nGophers\r\n", nil), + contentLength("201 OK", "Content-Length: 0\r\nContent-Length: 7\r\n\r\nGophers\r\n", errMultiCL), + contentLength("300 OK", "Content-Length: 0\r\nContent-Length: 0 \r\n\r\nGophers\r\n", nil), + contentLength("200 OK", "Content-Length:\r\nContent-Length:\r\n\r\nGophers\r\n", nil), + contentLength("206 OK", "Content-Length:\r\nContent-Length: 0 \r\nConnection: close\r\n\r\nGophers\r\n", errMultiCL), // multiple content-length headers for 204 and 304 should still be checked - contentLength("204 OK", "Content-Length: 7\r\nContent-Length: 8\r\n\r\n", errMultiCL, nil), - contentLength("204 OK", "Content-Length: 3\r\nContent-Length: 3\r\n\r\n", nil, nil), - contentLength("304 OK", "Content-Length: 880\r\nContent-Length: 1\r\n\r\n", errMultiCL, nil), - contentLength("304 OK", "Content-Length: 961\r\nContent-Length: 961\r\n\r\n", nil, nil), + contentLength("204 OK", "Content-Length: 7\r\nContent-Length: 8\r\n\r\n", errMultiCL), + contentLength("204 OK", "Content-Length: 3\r\nContent-Length: 3\r\n\r\n", nil), + contentLength("304 OK", "Content-Length: 880\r\nContent-Length: 1\r\n\r\n", errMultiCL), + contentLength("304 OK", "Content-Length: 961\r\nContent-Length: 961\r\n\r\n", nil), + + // golang.org/issue/22464 + {"leading space in header", "HTTP/1.1 200 OK\r\n Content-type: text/html\r\nFoo: bar\r\n\r\n", "malformed MIME"}, + {"leading tab in header", "HTTP/1.1 200 OK\r\n\tContent-type: text/html\r\nFoo: bar\r\n\r\n", "malformed MIME"}, } for i, tt := range tests { diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 7137599c42e..1ffa4115009 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -461,6 +461,68 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) { } } +// Test that the special cased "/route" redirect +// implicitly created by a registered "/route/" +// properly sets the query string in the redirect URL. +// See Issue 17841. +func TestServeWithSlashRedirectKeepsQueryString(t *testing.T) { + setParallel(t) + defer afterTest(t) + + writeBackQuery := func(w ResponseWriter, r *Request) { + fmt.Fprintf(w, "%s", r.URL.RawQuery) + } + + mux := NewServeMux() + mux.HandleFunc("/testOne", writeBackQuery) + mux.HandleFunc("/testTwo/", writeBackQuery) + mux.HandleFunc("/testThree", writeBackQuery) + mux.HandleFunc("/testThree/", func(w ResponseWriter, r *Request) { + fmt.Fprintf(w, "%s:bar", r.URL.RawQuery) + }) + + ts := httptest.NewServer(mux) + defer ts.Close() + + tests := [...]struct { + path string + method string + want string + statusOk bool + }{ + 0: {"/testOne?this=that", "GET", "this=that", true}, + 1: {"/testTwo?foo=bar", "GET", "foo=bar", true}, + 2: {"/testTwo?a=1&b=2&a=3", "GET", "a=1&b=2&a=3", true}, + 3: {"/testTwo?", "GET", "", true}, + 4: {"/testThree?foo", "GET", "foo", true}, + 5: {"/testThree/?foo", "GET", "foo:bar", true}, + 6: {"/testThree?foo", "CONNECT", "foo", true}, + 7: {"/testThree/?foo", "CONNECT", "foo:bar", true}, + + // canonicalization or not + 8: {"/testOne/foo/..?foo", "GET", "foo", true}, + 9: {"/testOne/foo/..?foo", "CONNECT", "404 page not found\n", false}, + } + + for i, tt := range tests { + req, _ := NewRequest(tt.method, ts.URL+tt.path, nil) + res, err := ts.Client().Do(req) + if err != nil { + continue + } + slurp, _ := ioutil.ReadAll(res.Body) + res.Body.Close() + if !tt.statusOk { + if got, want := res.StatusCode, 404; got != want { + t.Errorf("#%d: Status = %d; want = %d", i, got, want) + } + } + if got, want := string(slurp), tt.want; got != want { + t.Errorf("#%d: Body = %q; want = %q", i, got, want) + } + } +} + func BenchmarkServeMux(b *testing.B) { type test struct { @@ -624,12 +686,8 @@ func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) { req = req.WithContext(ctx) r, err := c.Do(req) - select { - case <-ctx.Done(): - if ctx.Err() == context.DeadlineExceeded { - t.Fatalf("http2 Get #%d response timed out", i) - } - default: + if ctx.Err() == context.DeadlineExceeded { + t.Fatalf("http2 Get #%d response timed out", i) } if err != nil { t.Fatalf("http2 Get #%d: %v", i, err) @@ -2376,6 +2434,14 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) { } } +// https://golang.org/issues/22084 +func TestTimeoutHandlerPanicRecovery(t *testing.T) { + wrapper := func(h Handler) Handler { + return TimeoutHandler(h, time.Second, "") + } + testHandlerPanic(t, false, false, wrapper, "intentional death for testing") +} + func TestRedirectBadPath(t *testing.T) { // This used to crash. It's not valid input (bad path), but it // shouldn't crash. @@ -2436,6 +2502,37 @@ func TestRedirect(t *testing.T) { } } +// Test that Content-Type header is set for GET and HEAD requests. +func TestRedirectContentTypeAndBody(t *testing.T) { + var tests = []struct { + method string + wantCT string + wantBody string + }{ + {MethodGet, "text/html; charset=utf-8", "Found.\n\n"}, + {MethodHead, "text/html; charset=utf-8", ""}, + {MethodPost, "", ""}, + {MethodDelete, "", ""}, + {"foo", "", ""}, + } + for _, tt := range tests { + req := httptest.NewRequest(tt.method, "http://example.com/qux/", nil) + rec := httptest.NewRecorder() + Redirect(rec, req, "/foo", 302) + if got, want := rec.Header().Get("Content-Type"), tt.wantCT; got != want { + t.Errorf("Redirect(%q) generated Content-Type header %q; want %q", tt.method, got, want) + } + resp := rec.Result() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if got, want := string(body), tt.wantBody; got != want { + t.Errorf("Redirect(%q) generated Body %q; want %q", tt.method, got, want) + } + } +} + // TestZeroLengthPostAndResponse exercises an optimization done by the Transport: // when there is no body (either because the method doesn't permit a body, or an // explicit Content-Length of zero is present), then the transport can re-use the @@ -2489,22 +2586,22 @@ func testZeroLengthPostAndResponse(t *testing.T, h2 bool) { } } -func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil) } -func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil) } +func TestHandlerPanicNil_h1(t *testing.T) { testHandlerPanic(t, false, h1Mode, nil, nil) } +func TestHandlerPanicNil_h2(t *testing.T) { testHandlerPanic(t, false, h2Mode, nil, nil) } func TestHandlerPanic_h1(t *testing.T) { - testHandlerPanic(t, false, h1Mode, "intentional death for testing") + testHandlerPanic(t, false, h1Mode, nil, "intentional death for testing") } func TestHandlerPanic_h2(t *testing.T) { - testHandlerPanic(t, false, h2Mode, "intentional death for testing") + testHandlerPanic(t, false, h2Mode, nil, "intentional death for testing") } func TestHandlerPanicWithHijack(t *testing.T) { // Only testing HTTP/1, and our http2 server doesn't support hijacking. - testHandlerPanic(t, true, h1Mode, "intentional death for testing") + testHandlerPanic(t, true, h1Mode, nil, "intentional death for testing") } -func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) { +func testHandlerPanic(t *testing.T, withHijack, h2 bool, wrapper func(Handler) Handler, panicValue interface{}) { defer afterTest(t) // Unlike the other tests that set the log output to ioutil.Discard // to quiet the output, this test uses a pipe. The pipe serves three @@ -2527,7 +2624,7 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) defer log.SetOutput(os.Stderr) defer pw.Close() - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + var handler Handler = HandlerFunc(func(w ResponseWriter, r *Request) { if withHijack { rwc, _, err := w.(Hijacker).Hijack() if err != nil { @@ -2536,7 +2633,11 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) defer rwc.Close() } panic(panicValue) - })) + }) + if wrapper != nil { + handler = wrapper(handler) + } + cst := newClientServerTest(t, h2, handler) defer cst.close() // Do a blocking read on the log output pipe so its logging @@ -2691,15 +2792,28 @@ func testRequestLimit(t *testing.T, h2 bool) { req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i)) } res, err := cst.c.Do(req) - if err != nil { + if res != nil { + defer res.Body.Close() + } + if h2 { + // In HTTP/2, the result depends on a race. If the client has received the + // server's SETTINGS before RoundTrip starts sending the request, then RoundTrip + // will fail with an error. Otherwise, the client should receive a 431 from the + // server. + if err == nil && res.StatusCode != 431 { + t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status) + } + } else { + // In HTTP/1, we expect a 431 from the server. // Some HTTP clients may fail on this undefined behavior (server replying and // closing the connection while the request is still being written), but // we do support it (at least currently), so we expect a response below. - t.Fatalf("Do: %v", err) - } - defer res.Body.Close() - if res.StatusCode != 431 { - t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status) + if err != nil { + t.Fatalf("Do: %v", err) + } + if res.StatusCode != 431 { + t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status) + } } } @@ -3325,9 +3439,6 @@ func TestHeaderToWire(t *testing.T) { handler: func(rw ResponseWriter, r *Request) { }, check: func(got string) error { - if !strings.Contains(got, "Content-Type: text/plain") { - return errors.New("wrong content-type; want text/plain") - } if !strings.Contains(got, "Content-Length: 0") { return errors.New("want 0 content-length") } @@ -5336,7 +5447,11 @@ func TestServerCloseDeadlock(t *testing.T) { func TestServerKeepAlivesEnabled_h1(t *testing.T) { testServerKeepAlivesEnabled(t, h1Mode) } func TestServerKeepAlivesEnabled_h2(t *testing.T) { testServerKeepAlivesEnabled(t, h2Mode) } func testServerKeepAlivesEnabled(t *testing.T, h2 bool) { - setParallel(t) + if h2 { + restore := ExportSetH2GoawayTimeout(10 * time.Millisecond) + defer restore() + } + // Not parallel: messes with global variable. (http2goAwayTimeout) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "%v", r.RemoteAddr) diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index 2fa8ab23d8a..3fa66601649 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -179,7 +179,7 @@ type Hijacker interface { // The returned bufio.Reader may contain unprocessed buffered // data from the client. // - // After a call to Hijack, the original Request.Body should + // After a call to Hijack, the original Request.Body must // not be used. Hijack() (net.Conn, *bufio.ReadWriter, error) } @@ -729,6 +729,9 @@ func (cr *connReader) Read(p []byte) (n int, err error) { cr.lock() if cr.inRead { cr.unlock() + if cr.conn.hijacked() { + panic("invalid Body.Read call. After hijacked, the original Request must not be used") + } panic("invalid concurrent Body.Read call") } if cr.hitReadLimit() { @@ -1043,7 +1046,25 @@ func (w *response) Header() Header { // well read them) const maxPostHandlerReadBytes = 256 << 10 +func checkWriteHeaderCode(code int) { + // Issue 22880: require valid WriteHeader status codes. + // For now we only enforce that it's three digits. + // In the future we might block things over 599 (600 and above aren't defined + // at http://httpwg.org/specs/rfc7231.html#status.codes) + // and we might block under 200 (once we have more mature 1xx support). + // But for now any three digits. + // + // We used to send "HTTP/1.1 000 0" on the wire in responses but there's + // no equivalent bogus thing we can realistically send in HTTP/2, + // so we'll consistently panic instead and help people find their bugs + // early. (We can't return an error from WriteHeader even if we wanted to.) + if code < 100 || code > 999 { + panic(fmt.Sprintf("invalid WriteHeader code %v", code)) + } +} + func (w *response) WriteHeader(code int) { + checkWriteHeaderCode(code) if w.conn.hijacked() { w.conn.server.logf("http: response.WriteHeader on hijacked connection") return @@ -1210,7 +1231,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { } } - // Check for a explicit (and valid) Content-Length header. + // Check for an explicit (and valid) Content-Length header. hasCL := w.contentLength != -1 if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) { @@ -1308,7 +1329,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { if bodyAllowedForStatus(code) { // If no content type, apply sniffing algorithm to body. _, haveType := header["Content-Type"] - if !haveType && !hasTE { + if !haveType && !hasTE && len(p) > 0 { setHeader.contentType = DetectContentType(p) } } else { @@ -1337,7 +1358,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { } else if hasCL { delHeader("Transfer-Encoding") } else if w.req.ProtoAtLeast(1, 1) { - // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no + // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no // content-length has been provided. The connection must be closed after the // reply is written, and no chunking is to be done. This is the setup // recommended in the Server-Sent Events candidate recommendation 11, @@ -2014,6 +2035,9 @@ func Redirect(w ResponseWriter, r *Request, url string, code int) { } w.Header().Set("Location", hexEscapeNonASCII(url)) + if r.Method == "GET" || r.Method == "HEAD" { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + } w.WriteHeader(code) // RFC 2616 recommends that a short note "SHOULD" be included in the @@ -2105,9 +2129,8 @@ type ServeMux struct { } type muxEntry struct { - explicit bool - h Handler - pattern string + h Handler + pattern string } // NewServeMux allocates and returns a new ServeMux. @@ -2185,6 +2208,31 @@ func (mux *ServeMux) match(path string) (h Handler, pattern string) { return } +// redirectToPathSlash determines if the given path needs appending "/" to it. +// This occurs when a handler for path + "/" was already registered, but +// not for path itself. If the path needs appending to, it creates a new +// URL, setting the path to u.Path + "/" and returning true to indicate so. +func (mux *ServeMux) redirectToPathSlash(path string, u *url.URL) (*url.URL, bool) { + if !mux.shouldRedirect(path) { + return u, false + } + path = path + "/" + u = &url.URL{Path: path, RawQuery: u.RawQuery} + return u, true +} + +// shouldRedirect reports whether the given path should be redirected to +// path+"/". This should happen if a handler is registered for path+"/" but +// not path -- see comments at ServeMux. +func (mux *ServeMux) shouldRedirect(path string) bool { + if _, exist := mux.m[path]; exist { + return false + } + n := len(path) + _, exist := mux.m[path+"/"] + return n > 0 && path[n-1] != '/' && exist +} + // Handler returns the handler to use for the given request, // consulting r.Method, r.Host, and r.URL.Path. It always returns // a non-nil handler. If the path is not in its canonical form, the @@ -2204,6 +2252,13 @@ func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { // CONNECT requests are not canonicalized. if r.Method == "CONNECT" { + // If r.URL.Path is /tree and its handler is not registered, + // the /tree -> /tree/ redirect applies to CONNECT requests + // but the path canonicalization does not. + if u, ok := mux.redirectToPathSlash(r.URL.Path, r.URL); ok { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path + } + return mux.handler(r.Host, r.URL.Path) } @@ -2211,6 +2266,13 @@ func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { // before passing to mux.handler. host := stripHostPort(r.Host) path := cleanPath(r.URL.Path) + + // If the given path is /tree and its handler is not registered, + // redirect for /tree/. + if u, ok := mux.redirectToPathSlash(path, r.URL); ok { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path + } + if path != r.URL.Path { _, pattern = mux.handler(host, path) url := *r.URL @@ -2261,40 +2323,23 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { defer mux.mu.Unlock() if pattern == "" { - panic("http: invalid pattern " + pattern) + panic("http: invalid pattern") } if handler == nil { panic("http: nil handler") } - if mux.m[pattern].explicit { + if _, exist := mux.m[pattern]; exist { panic("http: multiple registrations for " + pattern) } if mux.m == nil { mux.m = make(map[string]muxEntry) } - mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern} + mux.m[pattern] = muxEntry{h: handler, pattern: pattern} if pattern[0] != '/' { mux.hosts = true } - - // Helpful behavior: - // If pattern is /tree/, insert an implicit permanent redirect for /tree. - // It can be overridden by an explicit registration. - n := len(pattern) - if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { - // If pattern contains a host name, strip it and use remaining - // path for redirect. - path := pattern - if pattern[0] != '/' { - // In pattern, at least the last character is a '/', so - // strings.Index can't be -1. - path = pattern[strings.Index(pattern, "/"):] - } - url := &url.URL{Path: path} - mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern} - } } // HandleFunc registers the handler function for the given pattern. @@ -2323,7 +2368,7 @@ func Serve(l net.Listener, handler Handler) error { return srv.Serve(l) } -// Serve accepts incoming HTTPS connections on the listener l, +// ServeTLS accepts incoming HTTPS connections on the listener l, // creating a new service goroutine for each. The service goroutines // read requests and then call handler to reply to them. // @@ -2396,9 +2441,9 @@ type Server struct { 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. + // connections, unexpected behavior from handlers, and + // underlying FileSystem errors. + // If nil, logging is done via the log package's standard logger. ErrorLog *log.Logger disableKeepAlives int32 // accessed atomically. @@ -2483,7 +2528,8 @@ var shutdownPollInterval = 500 * time.Millisecond // Shutdown does not attempt to close nor wait for hijacked // connections such as WebSockets. The caller of Shutdown should // separately notify such long-lived connections of shutdown and wait -// for them to close, if desired. +// for them to close, if desired. See RegisterOnShutdown for a way to +// register shutdown notification functions. func (srv *Server) Shutdown(ctx context.Context) error { atomic.AddInt32(&srv.inShutdown, 1) defer atomic.AddInt32(&srv.inShutdown, -1) @@ -2732,7 +2778,7 @@ func (srv *Server) Serve(l net.Listener) error { // server's certificate, any intermediates, and the CA's certificate. // // For HTTP/2 support, srv.TLSConfig should be initialized to the -// provided listener's TLS Config before calling Serve. If +// provided listener's TLS Config before calling ServeTLS. If // srv.TLSConfig is non-nil and doesn't include the string "h2" in // Config.NextProtos, HTTP/2 support is not enabled. // @@ -2849,6 +2895,18 @@ func (s *Server) logf(format string, args ...interface{}) { } } +// logf prints to the ErrorLog of the *Server associated with request r +// via ServerContextKey. If there's no associated server, or if ErrorLog +// is nil, logging is done via the log package's standard logger. +func logf(r *Request, format string, args ...interface{}) { + s, _ := r.Context().Value(ServerContextKey).(*Server) + if s != nil && 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. @@ -2940,6 +2998,8 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { return err } + defer ln.Close() + return srv.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, certFile, keyFile) } @@ -3015,9 +3075,9 @@ type timeoutHandler struct { body string dt time.Duration - // When set, no timer will be created and this channel will + // When set, no context will be created and this context will // be used instead. - testTimeout <-chan time.Time + testContext context.Context } func (h *timeoutHandler) errorBody() string { @@ -3028,22 +3088,31 @@ func (h *timeoutHandler) errorBody() string { } func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { - var t *time.Timer - timeout := h.testTimeout - if timeout == nil { - t = time.NewTimer(h.dt) - timeout = t.C + ctx := h.testContext + if ctx == nil { + var cancelCtx context.CancelFunc + ctx, cancelCtx = context.WithTimeout(r.Context(), h.dt) + defer cancelCtx() } + r = r.WithContext(ctx) done := make(chan struct{}) tw := &timeoutWriter{ w: w, h: make(Header), } + panicChan := make(chan interface{}, 1) go func() { + defer func() { + if p := recover(); p != nil { + panicChan <- p + } + }() h.handler.ServeHTTP(tw, r) close(done) }() select { + case p := <-panicChan: + panic(p) case <-done: tw.mu.Lock() defer tw.mu.Unlock() @@ -3056,10 +3125,7 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { } w.WriteHeader(tw.code) w.Write(tw.wbuf.Bytes()) - if t != nil { - t.Stop() - } - case <-timeout: + case <-ctx.Done(): tw.mu.Lock() defer tw.mu.Unlock() w.WriteHeader(StatusServiceUnavailable) @@ -3095,6 +3161,7 @@ func (tw *timeoutWriter) Write(p []byte) (int, error) { } func (tw *timeoutWriter) WriteHeader(code int) { + checkWriteHeaderCode(code) tw.mu.Lock() defer tw.mu.Unlock() if tw.timedOut || tw.wroteHeader { @@ -3116,10 +3183,10 @@ type tcpKeepAliveListener struct { *net.TCPListener } -func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { +func (ln tcpKeepAliveListener) Accept() (net.Conn, error) { tc, err := ln.AcceptTCP() if err != nil { - return + return nil, err } tc.SetKeepAlive(true) tc.SetKeepAlivePeriod(3 * time.Minute) diff --git a/libgo/go/net/http/sniff.go b/libgo/go/net/http/sniff.go index ecc65e4de64..365a36c79ef 100644 --- a/libgo/go/net/http/sniff.go +++ b/libgo/go/net/http/sniff.go @@ -91,6 +91,7 @@ var sniffSignatures = []sniffSig{ ct: "image/webp", }, &exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"}, + &maskedSig{ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"), pat: []byte("RIFF\x00\x00\x00\x00WAVE"), @@ -126,6 +127,20 @@ var sniffSignatures = []sniffSig{ pat: []byte("RIFF\x00\x00\x00\x00AVI "), ct: "video/avi", }, + + // Fonts + &maskedSig{ + // 34 NULL bytes followed by the string "LP" + pat: []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4C\x50"), + // 34 NULL bytes followed by \xF\xF + mask: []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"), + ct: "application/vnd.ms-fontobject", + }, + &exactSig{[]byte("\x00\x01\x00\x00"), "application/font-ttf"}, + &exactSig{[]byte("OTTO"), "application/font-off"}, + &exactSig{[]byte("ttcf"), "application/font-cff"}, + &exactSig{[]byte("wOFF"), "application/font-woff"}, + &exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"}, &exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"}, &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"}, diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go index 24f1298e5d9..bf1f6be41b1 100644 --- a/libgo/go/net/http/sniff_test.go +++ b/libgo/go/net/http/sniff_test.go @@ -55,6 +55,17 @@ var sniffTests = []struct { {"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"}, {"AVI video #1", []byte("RIFF,O\n\x00AVI LISTÀ"), "video/avi"}, {"AVI video #2", []byte("RIFF,\n\x00\x00AVI LISTÀ"), "video/avi"}, + + // Font types. + // {"MS.FontObject", []byte("\x00\x00")}, + {"TTF sample I", []byte("\x00\x01\x00\x00\x00\x17\x01\x00\x00\x04\x01\x60\x4f"), "application/font-ttf"}, + {"TTF sample II", []byte("\x00\x01\x00\x00\x00\x0e\x00\x80\x00\x03\x00\x60\x46"), "application/font-ttf"}, + + {"OTTO sample I", []byte("\x4f\x54\x54\x4f\x00\x0e\x00\x80\x00\x03\x00\x60\x42\x41\x53\x45"), "application/font-off"}, + + {"woff sample I", []byte("\x77\x4f\x46\x46\x00\x01\x00\x00\x00\x00\x30\x54\x00\x0d\x00\x00"), "application/font-woff"}, + // Woff2 is not yet recognized, change this test once mime-sniff working group adds woff2 + {"woff2 not recognized", []byte("\x77\x4f\x46\x32\x00\x01\x00\x00\x00"), "application/octet-stream"}, } func TestDetectContentType(t *testing.T) { @@ -88,8 +99,17 @@ func testServerContentType(t *testing.T, h2 bool) { t.Errorf("%v: %v", tt.desc, err) continue } - if ct := resp.Header.Get("Content-Type"); ct != tt.contentType { - t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, tt.contentType) + // DetectContentType is defined to return + // text/plain; charset=utf-8 for an empty body, + // but as of Go 1.10 the HTTP server has been changed + // to return no content-type at all for an empty body. + // Adjust the expectation here. + wantContentType := tt.contentType + if len(tt.data) == 0 { + wantContentType = "" + } + if ct := resp.Header.Get("Content-Type"); ct != wantContentType { + t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, wantContentType) } data, err := ioutil.ReadAll(resp.Body) if err != nil { diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index 8faff2d74a6..a400a6abb1f 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -497,7 +497,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { // or close connection when finished, since multipart is not supported yet switch { case chunked(t.TransferEncoding): - if noResponseBodyExpected(t.RequestMethod) { + if noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode) { t.Body = NoBody } else { t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close} @@ -663,9 +663,8 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, return -1, err } return n, nil - } else { - header.Del("Content-Length") } + header.Del("Content-Length") if isRequest { // RFC 2616 neither explicitly permits nor forbids an diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 6a89392a996..45e3fd2eba7 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -1016,6 +1016,69 @@ func (d oneConnDialer) Dial(network, addr string) (net.Conn, error) { } } +// The connect method and the transport can both specify a TLS +// Host name. The transport's name takes precedence if present. +func chooseTLSHost(cm connectMethod, t *Transport) string { + tlsHost := "" + if t.TLSClientConfig != nil { + tlsHost = t.TLSClientConfig.ServerName + } + if tlsHost == "" { + tlsHost = cm.tlsHost() + } + return tlsHost +} + +// Add TLS to a persistent connection, i.e. negotiate a TLS session. If pconn is already a TLS +// tunnel, this function establishes a nested TLS session inside the encrypted channel. +// The remote endpoint's name may be overridden by TLSClientConfig.ServerName. +func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) error { + // Initiate TLS and check remote host name against certificate. + cfg := cloneTLSConfig(pconn.t.TLSClientConfig) + if cfg.ServerName == "" { + cfg.ServerName = name + } + plainConn := pconn.conn + tlsConn := tls.Client(plainConn, cfg) + errc := make(chan error, 2) + var timer *time.Timer // for canceling TLS handshake + if d := pconn.t.TLSHandshakeTimeout; d != 0 { + timer = time.AfterFunc(d, func() { + errc <- tlsHandshakeTimeoutError{} + }) + } + go func() { + if trace != nil && trace.TLSHandshakeStart != nil { + trace.TLSHandshakeStart() + } + err := tlsConn.Handshake() + if timer != nil { + timer.Stop() + } + errc <- err + }() + if err := <-errc; err != nil { + plainConn.Close() + if trace != nil && trace.TLSHandshakeDone != nil { + trace.TLSHandshakeDone(tls.ConnectionState{}, err) + } + return err + } + if !cfg.InsecureSkipVerify { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + plainConn.Close() + return err + } + } + cs := tlsConn.ConnectionState() + if trace != nil && trace.TLSHandshakeDone != nil { + trace.TLSHandshakeDone(cs, nil) + } + pconn.tlsState = &cs + pconn.conn = tlsConn + return nil +} + func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) { pconn := &persistConn{ t: t, @@ -1027,15 +1090,21 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon writeLoopDone: make(chan struct{}), } trace := httptrace.ContextClientTrace(ctx) - tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil - if tlsDial { + wrapErr := func(err error) error { + if cm.proxyURL != nil { + // Return a typed error, per Issue 16997 + return &net.OpError{Op: "proxyconnect", Net: "tcp", Err: err} + } + return err + } + if cm.scheme() == "https" && t.DialTLS != nil { var err error pconn.conn, err = t.DialTLS("tcp", cm.addr()) if err != nil { - return nil, err + return nil, wrapErr(err) } if pconn.conn == nil { - return nil, errors.New("net/http: Transport.DialTLS returned (nil, nil)") + return nil, wrapErr(errors.New("net/http: Transport.DialTLS returned (nil, nil)")) } if tc, ok := pconn.conn.(*tls.Conn); ok { // Handshake here, in case DialTLS didn't. TLSNextProto below @@ -1059,13 +1128,18 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon } else { conn, err := t.dial(ctx, "tcp", cm.addr()) if err != nil { - if cm.proxyURL != nil { - // Return a typed error, per Issue 16997: - err = &net.OpError{Op: "proxyconnect", Net: "tcp", Err: err} - } - return nil, err + return nil, wrapErr(err) } pconn.conn = conn + if cm.scheme() == "https" { + var firstTLSHost string + if firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != nil { + return nil, wrapErr(err) + } + if err = pconn.addTLS(firstTLSHost, trace); err != nil { + return nil, wrapErr(err) + } + } } // Proxy setup. @@ -1125,54 +1199,17 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon if resp.StatusCode != 200 { f := strings.SplitN(resp.Status, " ", 2) conn.Close() + if len(f) < 2 { + return nil, errors.New("unknown status code") + } return nil, errors.New(f[1]) } } - if cm.targetScheme == "https" && !tlsDial { - // Initiate TLS and check remote host name against certificate. - cfg := cloneTLSConfig(t.TLSClientConfig) - if cfg.ServerName == "" { - cfg.ServerName = cm.tlsHost() - } - plainConn := pconn.conn - tlsConn := tls.Client(plainConn, cfg) - errc := make(chan error, 2) - var timer *time.Timer // for canceling TLS handshake - if d := t.TLSHandshakeTimeout; d != 0 { - timer = time.AfterFunc(d, func() { - errc <- tlsHandshakeTimeoutError{} - }) - } - go func() { - if trace != nil && trace.TLSHandshakeStart != nil { - trace.TLSHandshakeStart() - } - err := tlsConn.Handshake() - if timer != nil { - timer.Stop() - } - errc <- err - }() - if err := <-errc; err != nil { - plainConn.Close() - if trace != nil && trace.TLSHandshakeDone != nil { - trace.TLSHandshakeDone(tls.ConnectionState{}, err) - } + if cm.proxyURL != nil && cm.targetScheme == "https" { + if err := pconn.addTLS(cm.tlsHost(), trace); err != nil { return nil, err } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - plainConn.Close() - return nil, err - } - } - cs := tlsConn.ConnectionState() - if trace != nil && trace.TLSHandshakeDone != nil { - trace.TLSHandshakeDone(cs, nil) - } - pconn.tlsState = &cs - pconn.conn = tlsConn } if s := pconn.tlsState; s != nil && s.NegotiatedProtocolIsMutual && s.NegotiatedProtocol != "" { @@ -1224,8 +1261,8 @@ func useProxy(addr string) bool { } } - no_proxy := noProxyEnv.Get() - if no_proxy == "*" { + noProxy := noProxyEnv.Get() + if noProxy == "*" { return false } @@ -1234,7 +1271,7 @@ func useProxy(addr string) bool { addr = addr[:strings.LastIndex(addr, ":")] } - for _, p := range strings.Split(no_proxy, ",") { + for _, p := range strings.Split(noProxy, ",") { p = strings.ToLower(strings.TrimSpace(p)) if len(p) == 0 { continue @@ -1266,21 +1303,24 @@ func useProxy(addr string) bool { // // A connect method may be of the following types: // -// Cache key form Description -// ----------------- ------------------------- -// |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 -// socks5://proxy.com|http|foo.com socks5 to proxy, then http to foo.com -// socks5://proxy.com|https|foo.com socks5 to proxy, then https to foo.com -// -// Note: no support to https to the proxy yet. +// Cache key form Description +// ----------------- ------------------------- +// |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 +// socks5://proxy.com|http|foo.com socks5 to proxy, then http to foo.com +// socks5://proxy.com|https|foo.com socks5 to proxy, then https to foo.com +// https://proxy.com|https|foo.com https to proxy, then CONNECT to foo.com +// https://proxy.com|http https to proxy, http to anywhere after that // type connectMethod struct { proxyURL *url.URL // nil for no proxy, else full proxy URL targetScheme string // "http" or "https" - targetAddr string // Not used if http proxy + http targetScheme (4th example in table) + // If proxyURL specifies an http or https proxy, and targetScheme is http (not https), + // then targetAddr is not included in the connect method key, because the socket can + // be reused for different targetAddr values. + targetAddr string } func (cm *connectMethod) key() connectMethodKey { @@ -1288,7 +1328,7 @@ func (cm *connectMethod) key() connectMethodKey { targetAddr := cm.targetAddr if cm.proxyURL != nil { proxyStr = cm.proxyURL.String() - if strings.HasPrefix(cm.proxyURL.Scheme, "http") && cm.targetScheme == "http" { + if (cm.proxyURL.Scheme == "http" || cm.proxyURL.Scheme == "https") && cm.targetScheme == "http" { targetAddr = "" } } @@ -1299,6 +1339,14 @@ func (cm *connectMethod) key() connectMethodKey { } } +// scheme returns the first hop scheme: http, https, or socks5 +func (cm *connectMethod) scheme() string { + if cm.proxyURL != nil { + return cm.proxyURL.Scheme + } + return cm.targetScheme +} + // addr returns the first hop "host:port" to which we need to TCP connect. func (cm *connectMethod) addr() string { if cm.proxyURL != nil { @@ -1616,6 +1664,7 @@ func (pc *persistConn) readLoop() { body: resp.Body, earlyCloseFn: func() error { waitForBodyRead <- false + <-eofc // will be closed by deferred call at the end of the function return nil }, @@ -2021,8 +2070,8 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err // a t.Logf func. See export_test.go's Request.WithT method. type tLogKey struct{} -func (r *transportRequest) logf(format string, args ...interface{}) { - if logf, ok := r.Request.Context().Value(tLogKey{}).(func(string, ...interface{})); ok { +func (tr *transportRequest) logf(format string, args ...interface{}) { + if logf, ok := tr.Request.Context().Value(tLogKey{}).(func(string, ...interface{})); ok { logf(time.Now().Format(time.RFC3339Nano)+": "+format, args...) } } diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index 27b55dca2f3..55880774256 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -124,6 +124,34 @@ func (tcs *testConnSet) check(t *testing.T) { } } +func TestReuseRequest(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Write([]byte("{}")) + })) + defer ts.Close() + + c := ts.Client() + req, _ := NewRequest("GET", ts.URL, nil) + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + err = res.Body.Close() + if err != nil { + t.Fatal(err) + } + + res, err = c.Do(req) + if err != nil { + t.Fatal(err) + } + err = res.Body.Close() + if err != nil { + t.Fatal(err) + } +} + // Two subsequent requests and verify their response is the same. // The response from the server is our own IP:port func TestTransportKeepAlives(t *testing.T) { @@ -933,14 +961,10 @@ func TestTransportExpect100Continue(t *testing.T) { func TestSocks5Proxy(t *testing.T) { defer afterTest(t) ch := make(chan string, 1) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - ch <- "real server" - })) - defer ts.Close() l := newLocalListener(t) defer l.Close() - go func() { - defer close(ch) + defer close(ch) + proxy := func(t *testing.T) { s, err := l.Accept() if err != nil { t.Errorf("socks5 proxy Accept(): %v", err) @@ -975,7 +999,8 @@ func TestSocks5Proxy(t *testing.T) { case 4: ipLen = 16 default: - t.Fatalf("socks5 proxy second read: unexpected address type %v", buf[4]) + t.Errorf("socks5 proxy second read: unexpected address type %v", buf[4]) + return } if _, err := io.ReadFull(s, buf[4:ipLen+6]); err != nil { t.Errorf("socks5 proxy address read: %v", err) @@ -988,71 +1013,196 @@ func TestSocks5Proxy(t *testing.T) { t.Errorf("socks5 proxy connect write: %v", err) return } - done := make(chan struct{}) - srv := &Server{Handler: HandlerFunc(func(w ResponseWriter, r *Request) { - done <- struct{}{} - })} - srv.Serve(&oneConnListener{conn: s}) - <-done - srv.Shutdown(context.Background()) ch <- fmt.Sprintf("proxy for %s:%d", ip, port) - }() - pu, err := url.Parse("socks5://" + l.Addr().String()) - if err != nil { - t.Fatal(err) - } - c := ts.Client() - c.Transport.(*Transport).Proxy = ProxyURL(pu) - if _, err := c.Head(ts.URL); err != nil { - t.Error(err) - } - var got string - select { - case got = <-ch: - case <-time.After(5 * time.Second): - t.Fatal("timeout connecting to socks5 proxy") + // Implement proxying. + targetHost := net.JoinHostPort(ip.String(), strconv.Itoa(int(port))) + targetConn, err := net.Dial("tcp", targetHost) + if err != nil { + t.Errorf("net.Dial failed") + return + } + go io.Copy(targetConn, s) + io.Copy(s, targetConn) // Wait for the client to close the socket. + targetConn.Close() } - tsu, err := url.Parse(ts.URL) + + pu, err := url.Parse("socks5://" + l.Addr().String()) if err != nil { t.Fatal(err) } - want := "proxy for " + tsu.Host - if got != want { - t.Errorf("got %q, want %q", got, want) + + sentinelHeader := "X-Sentinel" + sentinelValue := "12345" + h := HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set(sentinelHeader, sentinelValue) + }) + for _, useTLS := range []bool{false, true} { + t.Run(fmt.Sprintf("useTLS=%v", useTLS), func(t *testing.T) { + var ts *httptest.Server + if useTLS { + ts = httptest.NewTLSServer(h) + } else { + ts = httptest.NewServer(h) + } + go proxy(t) + c := ts.Client() + c.Transport.(*Transport).Proxy = ProxyURL(pu) + r, err := c.Head(ts.URL) + if err != nil { + t.Fatal(err) + } + if r.Header.Get(sentinelHeader) != sentinelValue { + t.Errorf("Failed to retrieve sentinel value") + } + var got string + select { + case got = <-ch: + case <-time.After(5 * time.Second): + t.Fatal("timeout connecting to socks5 proxy") + } + ts.Close() + tsu, err := url.Parse(ts.URL) + if err != nil { + t.Fatal(err) + } + want := "proxy for " + tsu.Host + if got != want { + t.Errorf("got %q, want %q", got, want) + } + }) } } func TestTransportProxy(t *testing.T) { defer afterTest(t) - ch := make(chan string, 1) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - ch <- "real server" - })) - defer ts.Close() - proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - ch <- "proxy for " + r.URL.String() - })) - defer proxy.Close() + testCases := []struct{ httpsSite, httpsProxy bool }{ + {false, false}, + {false, true}, + {true, false}, + {true, true}, + } + for _, testCase := range testCases { + httpsSite := testCase.httpsSite + httpsProxy := testCase.httpsProxy + t.Run(fmt.Sprintf("httpsSite=%v, httpsProxy=%v", httpsSite, httpsProxy), func(t *testing.T) { + siteCh := make(chan *Request, 1) + h1 := HandlerFunc(func(w ResponseWriter, r *Request) { + siteCh <- r + }) + proxyCh := make(chan *Request, 1) + h2 := HandlerFunc(func(w ResponseWriter, r *Request) { + proxyCh <- r + // Implement an entire CONNECT proxy + if r.Method == "CONNECT" { + hijacker, ok := w.(Hijacker) + if !ok { + t.Errorf("hijack not allowed") + return + } + clientConn, _, err := hijacker.Hijack() + if err != nil { + t.Errorf("hijacking failed") + return + } + res := &Response{ + StatusCode: StatusOK, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(Header), + } + + targetConn, err := net.Dial("tcp", r.URL.Host) + if err != nil { + t.Errorf("net.Dial(%q) failed: %v", r.URL.Host, err) + return + } + + if err := res.Write(clientConn); err != nil { + t.Errorf("Writing 200 OK failed: %v", err) + return + } + + go io.Copy(targetConn, clientConn) + go func() { + io.Copy(clientConn, targetConn) + targetConn.Close() + }() + } + }) + var ts *httptest.Server + if httpsSite { + ts = httptest.NewTLSServer(h1) + } else { + ts = httptest.NewServer(h1) + } + var proxy *httptest.Server + if httpsProxy { + proxy = httptest.NewTLSServer(h2) + } else { + proxy = httptest.NewServer(h2) + } - pu, err := url.Parse(proxy.URL) - if err != nil { - t.Fatal(err) - } - c := ts.Client() - c.Transport.(*Transport).Proxy = ProxyURL(pu) - if _, err := c.Head(ts.URL); err != nil { - t.Error(err) - } - var got string - select { - case got = <-ch: - case <-time.After(5 * time.Second): - t.Fatal("timeout connecting to http proxy") - } - want := "proxy for " + ts.URL + "/" - if got != want { - t.Errorf("got %q, want %q", got, want) + pu, err := url.Parse(proxy.URL) + if err != nil { + t.Fatal(err) + } + + // If neither server is HTTPS or both are, then c may be derived from either. + // If only one server is HTTPS, c must be derived from that server in order + // to ensure that it is configured to use the fake root CA from testcert.go. + c := proxy.Client() + if httpsSite { + c = ts.Client() + } + + c.Transport.(*Transport).Proxy = ProxyURL(pu) + if _, err := c.Head(ts.URL); err != nil { + t.Error(err) + } + var got *Request + select { + case got = <-proxyCh: + case <-time.After(5 * time.Second): + t.Fatal("timeout connecting to http proxy") + } + c.Transport.(*Transport).CloseIdleConnections() + ts.Close() + proxy.Close() + if httpsSite { + // First message should be a CONNECT, asking for a socket to the real server, + if got.Method != "CONNECT" { + t.Errorf("Wrong method for secure proxying: %q", got.Method) + } + gotHost := got.URL.Host + pu, err := url.Parse(ts.URL) + if err != nil { + t.Fatal("Invalid site URL") + } + if wantHost := pu.Host; gotHost != wantHost { + t.Errorf("Got CONNECT host %q, want %q", gotHost, wantHost) + } + + // The next message on the channel should be from the site's server. + next := <-siteCh + if next.Method != "HEAD" { + t.Errorf("Wrong method at destination: %s", next.Method) + } + if nextURL := next.URL.String(); nextURL != "/" { + t.Errorf("Wrong URL at destination: %s", nextURL) + } + } else { + if got.Method != "HEAD" { + t.Errorf("Wrong method for destination: %q", got.Method) + } + gotURL := got.URL.String() + wantURL := ts.URL + "/" + if gotURL != wantURL { + t.Errorf("Got URL %q, want %q", gotURL, wantURL) + } + } + }) } } @@ -4118,3 +4268,100 @@ var rgz = []byte{ 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00, 0x00, 0x00, } + +// Ensure that a missing status doesn't make the server panic +// See Issue https://golang.org/issues/21701 +func TestMissingStatusNoPanic(t *testing.T) { + t.Parallel() + + const want = "unknown status code" + + ln := newLocalListener(t) + addr := ln.Addr().String() + shutdown := make(chan bool, 1) + done := make(chan bool) + fullAddrURL := fmt.Sprintf("http://%s", addr) + raw := "HTTP/1.1 400\r\n" + + "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" + + "Content-Type: text/html; charset=utf-8\r\n" + + "Content-Length: 10\r\n" + + "Last-Modified: Wed, 30 Aug 2017 19:02:02 GMT\r\n" + + "Vary: Accept-Encoding\r\n\r\n" + + "Aloha Olaa" + + go func() { + defer func() { + ln.Close() + close(done) + }() + + conn, _ := ln.Accept() + if conn != nil { + io.WriteString(conn, raw) + ioutil.ReadAll(conn) + conn.Close() + } + }() + + proxyURL, err := url.Parse(fullAddrURL) + if err != nil { + t.Fatalf("proxyURL: %v", err) + } + + tr := &Transport{Proxy: ProxyURL(proxyURL)} + + req, _ := NewRequest("GET", "https://golang.org/", nil) + res, err, panicked := doFetchCheckPanic(tr, req) + if panicked { + t.Error("panicked, expecting an error") + } + if res != nil && res.Body != nil { + io.Copy(ioutil.Discard, res.Body) + res.Body.Close() + } + + if err == nil || !strings.Contains(err.Error(), want) { + t.Errorf("got=%v want=%q", err, want) + } + + close(shutdown) + <-done +} + +func doFetchCheckPanic(tr *Transport, req *Request) (res *Response, err error, panicked bool) { + defer func() { + if r := recover(); r != nil { + panicked = true + } + }() + res, err = tr.RoundTrip(req) + return +} + +// Issue 22330: do not allow the response body to be read when the status code +// forbids a response body. +func TestNoBodyOnChunked304Response(t *testing.T) { + defer afterTest(t) + cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { + conn, buf, _ := w.(Hijacker).Hijack() + buf.Write([]byte("HTTP/1.1 304 NOT MODIFIED\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n")) + buf.Flush() + conn.Close() + })) + defer cst.close() + + // Our test server above is sending back bogus data after the + // response (the "0\r\n\r\n" part), which causes the Transport + // code to log spam. Disable keep-alives so we never even try + // to reuse the connection. + cst.tr.DisableKeepAlives = true + + res, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + + if res.Body != NoBody { + t.Errorf("Unexpected body on 304 response") + } +} diff --git a/libgo/go/net/internal/socktest/sys_windows.go b/libgo/go/net/internal/socktest/sys_windows.go index 2e3d2bc7fce..8c1c862f33c 100644 --- a/libgo/go/net/internal/socktest/sys_windows.go +++ b/libgo/go/net/internal/socktest/sys_windows.go @@ -4,7 +4,10 @@ package socktest -import "syscall" +import ( + "internal/syscall/windows" + "syscall" +) // Socket wraps syscall.Socket. func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { @@ -38,6 +41,38 @@ func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error return s, nil } +// WSASocket wraps syscall.WSASocket. +func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { + sw.once.Do(sw.init) + + so := &Status{Cookie: cookie(int(family), int(sotype), int(proto))} + sw.fmu.RLock() + f, _ := sw.fltab[FilterSocket] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return syscall.InvalidHandle, err + } + s, so.Err = windows.WSASocket(family, sotype, proto, protinfo, group, flags) + if err = af.apply(so); err != nil { + if so.Err == nil { + syscall.Closesocket(s) + } + return syscall.InvalidHandle, err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).OpenFailed++ + return syscall.InvalidHandle, so.Err + } + nso := sw.addLocked(s, int(family), int(sotype), int(proto)) + sw.stats.getLocked(nso.Cookie).Opened++ + return s, nil +} + // Closesocket wraps syscall.Closesocket. func (sw *Switch) Closesocket(s syscall.Handle) (err error) { so := sw.sockso(s) diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go index c4b54f00c4e..72cbc394337 100644 --- a/libgo/go/net/iprawsock.go +++ b/libgo/go/net/iprawsock.go @@ -21,7 +21,7 @@ import ( // change the behavior of these methods; use Read or ReadMsgIP // instead. -// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgIP and +// BUG(mikio): On NaCl and Plan 9, the ReadMsgIP and // WriteMsgIP methods of IPConn are not implemented. // BUG(mikio): On Windows, the File method of IPConn is not diff --git a/libgo/go/net/listen_test.go b/libgo/go/net/listen_test.go index 21ad4462f68..96624f98ce5 100644 --- a/libgo/go/net/listen_test.go +++ b/libgo/go/net/listen_test.go @@ -13,6 +13,7 @@ import ( "runtime" "syscall" "testing" + "time" ) func (ln *TCPListener) port() string { @@ -696,3 +697,35 @@ func multicastRIBContains(ip IP) (bool, error) { } return false, nil } + +// Issue 21856. +func TestClosingListener(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + addr := ln.Addr() + + go func() { + for { + c, err := ln.Accept() + if err != nil { + return + } + c.Close() + } + }() + + // Let the goroutine start. We don't sleep long: if the + // goroutine doesn't start, the test will pass without really + // testing anything, which is OK. + time.Sleep(time.Millisecond) + + ln.Close() + + ln2, err := Listen("tcp", addr.String()) + if err != nil { + t.Fatal(err) + } + ln2.Close() +} diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go index f81e220fc8c..1037b81a3be 100644 --- a/libgo/go/net/lookup_plan9.go +++ b/libgo/go/net/lookup_plan9.go @@ -198,7 +198,7 @@ func (*Resolver) lookupPort(ctx context.Context, network, service string) (port func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) { lines, err := queryDNS(ctx, name, "cname") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") { + if stringsHasSuffix(err.Error(), "dns failure") || stringsHasSuffix(err.Error(), "resource does not exist; negrcode 0") { cname = name + "." err = nil } diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go index 68a7abe95df..e3bf114a8e2 100644 --- a/libgo/go/net/lookup_test.go +++ b/libgo/go/net/lookup_test.go @@ -9,7 +9,9 @@ import ( "context" "fmt" "internal/testenv" + "reflect" "runtime" + "sort" "strings" "testing" "time" @@ -303,6 +305,28 @@ func TestLookupGoogleHost(t *testing.T) { } } +func TestLookupLongTXT(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; see https://golang.org/issue/22857") + } + if testenv.Builder() == "" { + testenv.MustHaveExternalNetwork(t) + } + + txts, err := LookupTXT("golang.rsc.io") + if err != nil { + t.Fatal(err) + } + sort.Strings(txts) + want := []string{ + strings.Repeat("abcdefghijklmnopqrstuvwxyABCDEFGHJIKLMNOPQRSTUVWXY", 10), + "gophers rule", + } + if !reflect.DeepEqual(txts, want) { + t.Fatalf("LookupTXT golang.rsc.io incorrect\nhave %q\nwant %q", txts, want) + } +} + var lookupGoogleIPTests = []struct { name string }{ diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go index 0036d89d150..ac1f9b431ac 100644 --- a/libgo/go/net/lookup_windows.go +++ b/libgo/go/net/lookup_windows.go @@ -279,10 +279,11 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) { txts := make([]string, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) { d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0])) + s := "" for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] { - s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:]) - txts = append(txts, s) + s += syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:]) } + txts = append(txts, s) } return txts, nil } diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go index 45a995ec720..4f3184f3e8a 100644 --- a/libgo/go/net/mail/message.go +++ b/libgo/go/net/mail/message.go @@ -10,10 +10,10 @@ extended by RFC 6532. Notable divergences: * Obsolete address formats are not parsed, including addresses with embedded route information. - * Group addresses are not parsed. * The full range of spacing (the CFWS syntax element) is not supported, such as breaking addresses across lines. * No unicode normalization is performed. + * The special characters ()[]:;@\, are allowed to appear unquoted in names. */ package mail @@ -190,7 +190,7 @@ func (a *Address) String() string { // Add quotes if needed quoteLocal := false for i, r := range local { - if isAtext(r, false) { + if isAtext(r, false, false) { continue } if r == '.' { @@ -247,13 +247,15 @@ func (p *addrParser) parseAddressList() ([]*Address, error) { var list []*Address for { p.skipSpace() - addr, err := p.parseAddress() + addrs, err := p.parseAddress(true) if err != nil { return nil, err } - list = append(list, addr) + list = append(list, addrs...) - p.skipSpace() + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } if p.empty() { break } @@ -265,36 +267,55 @@ func (p *addrParser) parseAddressList() ([]*Address, error) { } func (p *addrParser) parseSingleAddress() (*Address, error) { - addr, err := p.parseAddress() + addrs, err := p.parseAddress(true) if err != nil { return nil, err } - p.skipSpace() + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } if !p.empty() { return nil, fmt.Errorf("mail: expected single address, got %q", p.s) } - return addr, nil + if len(addrs) == 0 { + return nil, errors.New("mail: empty group") + } + if len(addrs) > 1 { + return nil, errors.New("mail: group with multiple addresses") + } + return addrs[0], nil } // parseAddress parses a single RFC 5322 address at the start of p. -func (p *addrParser) parseAddress() (addr *Address, err error) { +func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) { debug.Printf("parseAddress: %q", p.s) p.skipSpace() if p.empty() { return nil, errors.New("mail: no address") } - // address = name-addr / addr-spec - // TODO(dsymonds): Support parsing group address. + // address = mailbox / group + // mailbox = name-addr / addr-spec + // group = display-name ":" [group-list] ";" [CFWS] // addr-spec has a more restricted grammar than name-addr, // so try parsing it first, and fallback to name-addr. // TODO(dsymonds): Is this really correct? spec, err := p.consumeAddrSpec() if err == nil { - return &Address{ + var displayName string + p.skipSpace() + if !p.empty() && p.peek() == '(' { + displayName, err = p.consumeDisplayNameComment() + if err != nil { + return nil, err + } + } + + return []*Address{{ + Name: displayName, Address: spec, - }, err + }}, err } debug.Printf("parseAddress: not an addr-spec: %v", err) debug.Printf("parseAddress: state is now %q", p.s) @@ -309,8 +330,13 @@ func (p *addrParser) parseAddress() (addr *Address, err error) { } debug.Printf("parseAddress: displayName=%q", displayName) - // angle-addr = "<" addr-spec ">" p.skipSpace() + if handleGroup { + if p.consume(':') { + return p.consumeGroupList() + } + } + // angle-addr = "<" addr-spec ">" if !p.consume('<') { return nil, errors.New("mail: no angle-addr") } @@ -323,10 +349,42 @@ func (p *addrParser) parseAddress() (addr *Address, err error) { } debug.Printf("parseAddress: spec=%q", spec) - return &Address{ + return []*Address{{ Name: displayName, Address: spec, - }, nil + }}, nil +} + +func (p *addrParser) consumeGroupList() ([]*Address, error) { + var group []*Address + // handle empty group. + p.skipSpace() + if p.consume(';') { + p.skipCFWS() + return group, nil + } + + for { + p.skipSpace() + // embedded groups not allowed. + addrs, err := p.parseAddress(false) + if err != nil { + return nil, err + } + group = append(group, addrs...) + + if !p.skipCFWS() { + return nil, errors.New("mail: misformatted parenthetical comment") + } + if p.consume(';') { + p.skipCFWS() + break + } + if !p.consume(',') { + return nil, errors.New("mail: expected comma") + } + } + return group, nil } // consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p. @@ -482,20 +540,20 @@ Loop: // consumeAtom parses an RFC 5322 atom at the start of p. // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. -// If permissive is true, consumeAtom will not fail on -// leading/trailing/double dots in the atom (see golang.org/issue/4938). +// If permissive is true, consumeAtom will not fail on: +// - leading/trailing/double dots in the atom (see golang.org/issue/4938) +// - special characters (RFC 5322 3.2.3) except '<', '>', ':' and '"' (see golang.org/issue/21018) func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { i := 0 Loop: for { r, size := utf8.DecodeRuneInString(p.s[i:]) - switch { case size == 1 && r == utf8.RuneError: return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s) - case size == 0 || !isAtext(r, dot): + case size == 0 || !isAtext(r, dot, permissive): break Loop default: @@ -522,6 +580,30 @@ Loop: return atom, nil } +func (p *addrParser) consumeDisplayNameComment() (string, error) { + if !p.consume('(') { + return "", errors.New("mail: comment does not start with (") + } + comment, ok := p.consumeComment() + if !ok { + return "", errors.New("mail: misformatted parenthetical comment") + } + + // TODO(stapelberg): parse quoted-string within comment + words := strings.FieldsFunc(comment, func(r rune) bool { return r == ' ' || r == '\t' }) + for idx, word := range words { + decoded, isEncoded, err := p.decodeRFC2047Word(word) + if err != nil { + return "", err + } + if isEncoded { + words[idx] = decoded + } + } + + return strings.Join(words, " "), nil +} + func (p *addrParser) consume(c byte) bool { if p.empty() || p.peek() != c { return false @@ -547,6 +629,51 @@ func (p *addrParser) len() int { return len(p.s) } +// skipCFWS skips CFWS as defined in RFC5322. +func (p *addrParser) skipCFWS() bool { + p.skipSpace() + + for { + if !p.consume('(') { + break + } + + if _, ok := p.consumeComment(); !ok { + return false + } + + p.skipSpace() + } + + return true +} + +func (p *addrParser) consumeComment() (string, bool) { + // '(' already consumed. + depth := 1 + + var comment string + for { + if p.empty() || depth == 0 { + break + } + + if p.peek() == '\\' && p.len() > 1 { + p.s = p.s[1:] + } else if p.peek() == '(' { + depth++ + } else if p.peek() == ')' { + depth-- + } + if depth > 0 { + comment += p.s[:1] + } + p.s = p.s[1:] + } + + return comment, depth == 0 +} + func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) { if p.dec != nil { word, err = p.dec.Decode(s) @@ -580,12 +707,18 @@ func (e charsetError) Error() string { // isAtext reports whether r is an RFC 5322 atext character. // If dot is true, period is included. -func isAtext(r rune, dot bool) bool { +// If permissive is true, RFC 5322 3.2.3 specials is included, +// except '<', '>', ':' and '"'. +func isAtext(r rune, dot, permissive bool) bool { switch r { case '.': return dot - case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials + // RFC 5322 3.2.3. specials + case '(', ')', '[', ']', ';', '@', '\\', ',': + return permissive + + case '<', '>', '"', ':': return false } return isVchar(r) diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go index 2106a0b97d6..b19da52c423 100644 --- a/libgo/go/net/mail/message_test.go +++ b/libgo/go/net/mail/message_test.go @@ -129,14 +129,21 @@ func TestAddressParsingError(t *testing.T) { text string wantErrText string }{ - 0: {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= ", "charset not supported"}, - 1: {"a@gmail.com b@gmail.com", "expected single address"}, - 2: {string([]byte{0xed, 0xa0, 0x80}) + " ", "invalid utf-8 in address"}, - 3: {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" ", "invalid utf-8 in quoted-string"}, - 4: {"\"\\" + string([]byte{0x80}) + "\" ", "invalid utf-8 in quoted-string"}, - 5: {"\"\x00\" ", "bad character in quoted-string"}, - 6: {"\"\\\x00\" ", "bad character in quoted-string"}, - 7: {"John Doe", "no angle-addr"}, + 0: {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= ", "charset not supported"}, + 1: {"a@gmail.com b@gmail.com", "expected single address"}, + 2: {string([]byte{0xed, 0xa0, 0x80}) + " ", "invalid utf-8 in address"}, + 3: {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" ", "invalid utf-8 in quoted-string"}, + 4: {"\"\\" + string([]byte{0x80}) + "\" ", "invalid utf-8 in quoted-string"}, + 5: {"\"\x00\" ", "bad character in quoted-string"}, + 6: {"\"\\\x00\" ", "bad character in quoted-string"}, + 7: {"John Doe", "no angle-addr"}, + 8: {``, "missing @ in addr-spec"}, + 9: {`John Doe `, "missing @ in addr-spec"}, + 10: {"cfws@example.com (", "misformatted parenthetical comment"}, + 11: {"empty group: ;", "empty group"}, + 12: {"root group: embed group: null@example.com;", "no angle-addr"}, + 13: {"group not closed: null@example.com", "expected comma"}, + 14: {"group: first@example.com, second@example.com;", "group with multiple addresses"}, } for i, tc := range mustErrTestCases { @@ -175,6 +182,34 @@ func TestAddressParsing(t *testing.T) { Address: "john.q.public@example.com", }}, }, + { + `"John (middle) Doe" `, + []*Address{{ + Name: "John (middle) Doe", + Address: "jdoe@machine.example", + }}, + }, + { + `John (middle) Doe `, + []*Address{{ + Name: "John (middle) Doe", + Address: "jdoe@machine.example", + }}, + }, + { + `John !@M@! Doe `, + []*Address{{ + Name: "John !@M@! Doe", + Address: "jdoe@machine.example", + }}, + }, + { + `"John Doe" `, + []*Address{{ + Name: "John Doe", + Address: "jdoe@machine.example", + }}, + }, { `Mary Smith , jdoe@example.org, Who? `, []*Address{ @@ -203,9 +238,62 @@ func TestAddressParsing(t *testing.T) { }, }, }, + // RFC 5322, Appendix A.6.1 + { + `Joe Q. Public `, + []*Address{{ + Name: "Joe Q. Public", + Address: "john.q.public@example.com", + }}, + }, // RFC 5322, Appendix A.1.3 - // TODO(dsymonds): Group addresses. - + { + `group1: groupaddr1@example.com;`, + []*Address{ + { + Name: "", + Address: "groupaddr1@example.com", + }, + }, + }, + { + `empty group: ;`, + []*Address(nil), + }, + { + `A Group:Ed Jones ,joe@where.test,John ;`, + []*Address{ + { + Name: "Ed Jones", + Address: "c@a.test", + }, + { + Name: "", + Address: "joe@where.test", + }, + { + Name: "John", + Address: "jdoe@one.test", + }, + }, + }, + { + `Group1: ;, Group 2: addr2@example.com;, John `, + []*Address{ + { + Name: "", + Address: "addr1@example.com", + }, + { + Name: "", + Address: "addr2@example.com", + }, + { + Name: "John", + Address: "addr3@example.com", + }, + }, + }, // RFC 2047 "Q"-encoded ISO-8859-1 address. { `=?iso-8859-1?q?J=F6rg_Doe?= `, @@ -336,6 +424,89 @@ func TestAddressParsing(t *testing.T) { }, }, }, + // CFWS + { + ` (CFWS (cfws)) (another comment)`, + []*Address{ + { + Name: "", + Address: "cfws@example.com", + }, + }, + }, + { + ` () (another comment), (another)`, + []*Address{ + { + Name: "", + Address: "cfws@example.com", + }, + { + Name: "", + Address: "cfws2@example.com", + }, + }, + }, + // Comment as display name + { + `john@example.com (John Doe)`, + []*Address{ + { + Name: "John Doe", + Address: "john@example.com", + }, + }, + }, + // Comment and display name + { + `John Doe (Joey)`, + []*Address{ + { + Name: "John Doe", + Address: "john@example.com", + }, + }, + }, + // Comment as display name, no space + { + `john@example.com(John Doe)`, + []*Address{ + { + Name: "John Doe", + Address: "john@example.com", + }, + }, + }, + // Comment as display name, Q-encoded + { + `asjo@example.com (Adam =?utf-8?Q?Sj=C3=B8gren?=)`, + []*Address{ + { + Name: "Adam Sjøgren", + Address: "asjo@example.com", + }, + }, + }, + // Comment as display name, Q-encoded and tab-separated + { + `asjo@example.com (Adam =?utf-8?Q?Sj=C3=B8gren?=)`, + []*Address{ + { + Name: "Adam Sjøgren", + Address: "asjo@example.com", + }, + }, + }, + // Nested comment as display name, Q-encoded + { + `asjo@example.com (Adam =?utf-8?Q?Sj=C3=B8gren?= (Debian))`, + []*Address{ + { + Name: "Adam Sjøgren (Debian)", + Address: "asjo@example.com", + }, + }, + }, } for _, test := range tests { if len(test.exp) == 1 { diff --git a/libgo/go/net/main_windows_test.go b/libgo/go/net/main_windows_test.go index f38a3a0d668..07f21b72eb1 100644 --- a/libgo/go/net/main_windows_test.go +++ b/libgo/go/net/main_windows_test.go @@ -9,6 +9,7 @@ import "internal/poll" var ( // Placeholders for saving original socket system calls. origSocket = socketFunc + origWSASocket = wsaSocketFunc origClosesocket = poll.CloseFunc origConnect = connectFunc origConnectEx = poll.ConnectExFunc @@ -18,6 +19,7 @@ var ( func installTestHooks() { socketFunc = sw.Socket + wsaSocketFunc = sw.WSASocket poll.CloseFunc = sw.Closesocket connectFunc = sw.Connect poll.ConnectExFunc = sw.ConnectEx @@ -27,6 +29,7 @@ func installTestHooks() { func uninstallTestHooks() { socketFunc = origSocket + wsaSocketFunc = origWSASocket poll.CloseFunc = origClosesocket connectFunc = origConnect poll.ConnectExFunc = origConnectEx diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go index b270159cd88..a2d9245348c 100644 --- a/libgo/go/net/parse.go +++ b/libgo/go/net/parse.go @@ -69,7 +69,7 @@ func open(name string) (*file, error) { if err != nil { return nil, err } - return &file{fd, make([]byte, 0, os.Getpagesize()), false}, nil + return &file{fd, make([]byte, 0, 64*1024), false}, nil } func stat(name string) (mtime time.Time, size int64, err error) { diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go index 37e552f54e5..9177fc40364 100644 --- a/libgo/go/net/pipe.go +++ b/libgo/go/net/pipe.go @@ -5,63 +5,239 @@ package net import ( - "errors" "io" + "sync" "time" ) +// pipeDeadline is an abstraction for handling timeouts. +type pipeDeadline struct { + mu sync.Mutex // Guards timer and cancel + timer *time.Timer + cancel chan struct{} // Must be non-nil +} + +func makePipeDeadline() pipeDeadline { + return pipeDeadline{cancel: make(chan struct{})} +} + +// set sets the point in time when the deadline will time out. +// A timeout event is signaled by closing the channel returned by waiter. +// Once a timeout has occurred, the deadline can be refreshed by specifying a +// t value in the future. +// +// A zero value for t prevents timeout. +func (d *pipeDeadline) set(t time.Time) { + d.mu.Lock() + defer d.mu.Unlock() + + if d.timer != nil && !d.timer.Stop() { + <-d.cancel // Wait for the timer callback to finish and close cancel + } + d.timer = nil + + // Time is zero, then there is no deadline. + closed := isClosedChan(d.cancel) + if t.IsZero() { + if closed { + d.cancel = make(chan struct{}) + } + return + } + + // Time in the future, setup a timer to cancel in the future. + if dur := time.Until(t); dur > 0 { + if closed { + d.cancel = make(chan struct{}) + } + d.timer = time.AfterFunc(dur, func() { + close(d.cancel) + }) + return + } + + // Time in the past, so close immediately. + if !closed { + close(d.cancel) + } +} + +// wait returns a channel that is closed when the deadline is exceeded. +func (d *pipeDeadline) wait() chan struct{} { + d.mu.Lock() + defer d.mu.Unlock() + return d.cancel +} + +func isClosedChan(c <-chan struct{}) bool { + select { + case <-c: + return true + default: + return false + } +} + +type timeoutError struct{} + +func (timeoutError) Error() string { return "deadline exceeded" } +func (timeoutError) Timeout() bool { return true } +func (timeoutError) Temporary() bool { return true } + +type pipeAddr struct{} + +func (pipeAddr) Network() string { return "pipe" } +func (pipeAddr) String() string { return "pipe" } + +type pipe struct { + wrMu sync.Mutex // Serialize Write operations + + // Used by local Read to interact with remote Write. + // Successful receive on rdRx is always followed by send on rdTx. + rdRx <-chan []byte + rdTx chan<- int + + // Used by local Write to interact with remote Read. + // Successful send on wrTx is always followed by receive on wrRx. + wrTx chan<- []byte + wrRx <-chan int + + once sync.Once // Protects closing localDone + localDone chan struct{} + remoteDone <-chan struct{} + + readDeadline pipeDeadline + writeDeadline pipeDeadline +} + // Pipe creates a synchronous, in-memory, full duplex // network connection; both ends implement the Conn interface. // Reads on one end are matched with writes on the other, // copying data directly between the two; there is no internal // buffering. func Pipe() (Conn, Conn) { - r1, w1 := io.Pipe() - r2, w2 := io.Pipe() - - return &pipe{r1, w2}, &pipe{r2, w1} -} + cb1 := make(chan []byte) + cb2 := make(chan []byte) + cn1 := make(chan int) + cn2 := make(chan int) + done1 := make(chan struct{}) + done2 := make(chan struct{}) -type pipe struct { - *io.PipeReader - *io.PipeWriter + p1 := &pipe{ + rdRx: cb1, rdTx: cn1, + wrTx: cb2, wrRx: cn2, + localDone: done1, remoteDone: done2, + readDeadline: makePipeDeadline(), + writeDeadline: makePipeDeadline(), + } + p2 := &pipe{ + rdRx: cb2, rdTx: cn2, + wrTx: cb1, wrRx: cn1, + localDone: done2, remoteDone: done1, + readDeadline: makePipeDeadline(), + writeDeadline: makePipeDeadline(), + } + return p1, p2 } -type pipeAddr int +func (*pipe) LocalAddr() Addr { return pipeAddr{} } +func (*pipe) RemoteAddr() Addr { return pipeAddr{} } -func (pipeAddr) Network() string { - return "pipe" +func (p *pipe) Read(b []byte) (int, error) { + n, err := p.read(b) + if err != nil && err != io.EOF && err != io.ErrClosedPipe { + err = &OpError{Op: "read", Net: "pipe", Err: err} + } + return n, err } -func (pipeAddr) String() string { - return "pipe" -} +func (p *pipe) read(b []byte) (n int, err error) { + switch { + case isClosedChan(p.localDone): + return 0, io.ErrClosedPipe + case isClosedChan(p.remoteDone): + return 0, io.EOF + case isClosedChan(p.readDeadline.wait()): + return 0, timeoutError{} + } -func (p *pipe) Close() error { - err := p.PipeReader.Close() - err1 := p.PipeWriter.Close() - if err == nil { - err = err1 + select { + case bw := <-p.rdRx: + nr := copy(b, bw) + p.rdTx <- nr + return nr, nil + case <-p.localDone: + return 0, io.ErrClosedPipe + case <-p.remoteDone: + return 0, io.EOF + case <-p.readDeadline.wait(): + return 0, timeoutError{} } - return err } -func (p *pipe) LocalAddr() Addr { - return pipeAddr(0) +func (p *pipe) Write(b []byte) (int, error) { + n, err := p.write(b) + if err != nil && err != io.ErrClosedPipe { + err = &OpError{Op: "write", Net: "pipe", Err: err} + } + return n, err } -func (p *pipe) RemoteAddr() Addr { - return pipeAddr(0) +func (p *pipe) write(b []byte) (n int, err error) { + switch { + case isClosedChan(p.localDone): + return 0, io.ErrClosedPipe + case isClosedChan(p.remoteDone): + return 0, io.ErrClosedPipe + case isClosedChan(p.writeDeadline.wait()): + return 0, timeoutError{} + } + + p.wrMu.Lock() // Ensure entirety of b is written together + defer p.wrMu.Unlock() + for once := true; once || len(b) > 0; once = false { + select { + case p.wrTx <- b: + nw := <-p.wrRx + b = b[nw:] + n += nw + case <-p.localDone: + return n, io.ErrClosedPipe + case <-p.remoteDone: + return n, io.ErrClosedPipe + case <-p.writeDeadline.wait(): + return n, timeoutError{} + } + } + return n, nil } func (p *pipe) SetDeadline(t time.Time) error { - return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} + if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { + return io.ErrClosedPipe + } + p.readDeadline.set(t) + p.writeDeadline.set(t) + return nil } func (p *pipe) SetReadDeadline(t time.Time) error { - return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} + if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { + return io.ErrClosedPipe + } + p.readDeadline.set(t) + return nil } func (p *pipe) SetWriteDeadline(t time.Time) error { - return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} + if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) { + return io.ErrClosedPipe + } + p.writeDeadline.set(t) + return nil +} + +func (p *pipe) Close() error { + p.once.Do(func() { close(p.localDone) }) + return nil } diff --git a/libgo/go/net/pipe_test.go b/libgo/go/net/pipe_test.go index e3172d882fb..84a71b756bc 100644 --- a/libgo/go/net/pipe_test.go +++ b/libgo/go/net/pipe_test.go @@ -2,54 +2,48 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package net +package net_test import ( - "bytes" "io" + "net" "testing" + "time" + + "golang_org/x/net/nettest" ) -func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) { - n, err := w.Write(data) - if err != nil { - t.Error(err) - } - if n != len(data) { - t.Errorf("short write: %d != %d", n, len(data)) - } - c <- 0 +func TestPipe(t *testing.T) { + nettest.TestConn(t, func() (c1, c2 net.Conn, stop func(), err error) { + c1, c2 = net.Pipe() + stop = func() { + c1.Close() + c2.Close() + } + return + }) } -func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) { - buf := make([]byte, len(data)+10) - n, err := r.Read(buf) - if err != wantErr { - t.Error(err) - return +func TestPipeCloseError(t *testing.T) { + c1, c2 := net.Pipe() + c1.Close() + + if _, err := c1.Read(nil); err != io.ErrClosedPipe { + t.Errorf("c1.Read() = %v, want io.ErrClosedPipe", err) } - if n != len(data) || !bytes.Equal(buf[0:n], data) { - t.Errorf("bad read: got %q", buf[0:n]) - return + if _, err := c1.Write(nil); err != io.ErrClosedPipe { + t.Errorf("c1.Write() = %v, want io.ErrClosedPipe", err) + } + if err := c1.SetDeadline(time.Time{}); err != io.ErrClosedPipe { + t.Errorf("c1.SetDeadline() = %v, want io.ErrClosedPipe", err) + } + if _, err := c2.Read(nil); err != io.EOF { + t.Errorf("c2.Read() = %v, want io.EOF", err) + } + if _, err := c2.Write(nil); err != io.ErrClosedPipe { + t.Errorf("c2.Write() = %v, want io.ErrClosedPipe", err) + } + if err := c2.SetDeadline(time.Time{}); err != io.ErrClosedPipe { + t.Errorf("c2.SetDeadline() = %v, want io.ErrClosedPipe", err) } -} - -// TestPipe tests a simple read/write/close sequence. -// Assumes that the underlying io.Pipe implementation -// is solid and we're just testing the net wrapping. -func TestPipe(t *testing.T) { - c := make(chan int) - cli, srv := Pipe() - go checkPipeWrite(t, cli, []byte("hello, world"), c) - checkPipeRead(t, srv, []byte("hello, world"), nil) - <-c - go checkPipeWrite(t, srv, []byte("line 2"), c) - checkPipeRead(t, cli, []byte("line 2"), nil) - <-c - go checkPipeWrite(t, cli, []byte("a third line"), c) - checkPipeRead(t, srv, []byte("a third line"), nil) - <-c - go srv.Close() - checkPipeRead(t, cli, nil, io.EOF) - cli.Close() } diff --git a/libgo/go/net/platform_test.go b/libgo/go/net/platform_test.go index 5841ca35a00..8e7d9151dee 100644 --- a/libgo/go/net/platform_test.go +++ b/libgo/go/net/platform_test.go @@ -43,9 +43,12 @@ func testableNetwork(network string) bool { case "unixpacket": switch runtime.GOOS { case "android", "darwin", "nacl", "plan9", "windows": - fallthrough - case "freebsd": // FreeBSD 8 and below don't support unixpacket return false + case "netbsd": + // It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown. + if runtime.GOARCH == "386" { + return false + } } } switch ss[0] { @@ -149,12 +152,19 @@ func testableListenArgs(network, address, client string) bool { return true } -var condFatalf = func() func(*testing.T, string, ...interface{}) { - // A few APIs, File, Read/WriteMsg{UDP,IP}, are not - // implemented yet on both Plan 9 and Windows. +func condFatalf(t *testing.T, network string, format string, args ...interface{}) { + t.Helper() + // A few APIs like File and Read/WriteMsg{UDP,IP} are not + // fully implemented yet on Plan 9 and Windows. switch runtime.GOOS { - case "plan9", "windows": - return (*testing.T).Logf + case "windows": + if network == "file+net" { + t.Logf(format, args...) + return + } + case "plan9": + t.Logf(format, args...) + return } - return (*testing.T).Fatalf -}() + t.Fatalf(format, args...) +} diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go index 8e1321afa44..32e76286193 100644 --- a/libgo/go/net/port.go +++ b/libgo/go/net/port.go @@ -4,12 +4,12 @@ package net -// parsePort parses service as a decimal interger and returns the +// parsePort parses service as a decimal integer and returns the // corresponding value as port. It is the caller's responsibility to // parse service as a non-decimal integer when needsLookup is true. // // Some system resolvers will return a valid port number when given a number -// over 65536 (see https://github.com/golang/go/issues/11715). Alas, the parser +// over 65536 (see https://golang.org/issues/11715). Alas, the parser // can't bail early on numbers > 65536. Therefore reasonably large/small // numbers are parsed in full and rejected if invalid. func parsePort(service string) (port int, needsLookup bool) { diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go index 23589d3ca87..05c45d02b9a 100644 --- a/libgo/go/net/protoconn_test.go +++ b/libgo/go/net/protoconn_test.go @@ -54,7 +54,7 @@ func TestTCPListenerSpecificMethods(t *testing.T) { } if f, err := ln.File(); err != nil { - condFatalf(t, "%v", err) + condFatalf(t, "file+net", "%v", err) } else { f.Close() } @@ -139,14 +139,14 @@ func TestUDPConnSpecificMethods(t *testing.T) { t.Fatal(err) } if _, _, err := c.WriteMsgUDP(wb, nil, c.LocalAddr().(*UDPAddr)); err != nil { - condFatalf(t, "%v", err) + condFatalf(t, c.LocalAddr().Network(), "%v", err) } if _, _, _, _, err := c.ReadMsgUDP(rb, nil); err != nil { - condFatalf(t, "%v", err) + condFatalf(t, c.LocalAddr().Network(), "%v", err) } if f, err := c.File(); err != nil { - condFatalf(t, "%v", err) + condFatalf(t, "file+net", "%v", err) } else { f.Close() } @@ -184,7 +184,7 @@ func TestIPConnSpecificMethods(t *testing.T) { c.SetWriteBuffer(2048) if f, err := c.File(); err != nil { - condFatalf(t, "%v", err) + condFatalf(t, "file+net", "%v", err) } else { f.Close() } diff --git a/libgo/go/net/rawconn.go b/libgo/go/net/rawconn.go index d67be644a34..2399c9f31dd 100644 --- a/libgo/go/net/rawconn.go +++ b/libgo/go/net/rawconn.go @@ -60,3 +60,19 @@ func (c *rawConn) Write(f func(uintptr) bool) error { func newRawConn(fd *netFD) (*rawConn, error) { return &rawConn{fd: fd}, nil } + +type rawListener struct { + rawConn +} + +func (l *rawListener) Read(func(uintptr) bool) error { + return syscall.EINVAL +} + +func (l *rawListener) Write(func(uintptr) bool) error { + return syscall.EINVAL +} + +func newRawListener(fd *netFD) (*rawListener, error) { + return &rawListener{rawConn{fd: fd}}, nil +} diff --git a/libgo/go/net/rawconn_unix_test.go b/libgo/go/net/rawconn_unix_test.go index 294249ba5d1..913ad865951 100644 --- a/libgo/go/net/rawconn_unix_test.go +++ b/libgo/go/net/rawconn_unix_test.go @@ -92,3 +92,53 @@ func TestRawConn(t *testing.T) { t.Fatal("should fail") } } + +func TestRawConnListener(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + cc, err := ln.(*TCPListener).SyscallConn() + if err != nil { + t.Fatal(err) + } + + called := false + op := func(uintptr) bool { + called = true + return true + } + + err = cc.Write(op) + if err == nil { + t.Error("Write should return an error") + } + if called { + t.Error("Write shouldn't call op") + } + + called = false + err = cc.Read(op) + if err == nil { + t.Error("Read should return an error") + } + if called { + t.Error("Read shouldn't call op") + } + + var operr error + fn := func(s uintptr) { + _, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR) + } + err = cc.Control(fn) + if err != nil || operr != nil { + t.Fatal(err, operr) + } + ln.Close() + err = cc.Control(fn) + if err == nil { + t.Fatal("Control after Close should fail") + } +} diff --git a/libgo/go/net/rawconn_windows_test.go b/libgo/go/net/rawconn_windows_test.go index 5fb6de75393..2ee12c35963 100644 --- a/libgo/go/net/rawconn_windows_test.go +++ b/libgo/go/net/rawconn_windows_test.go @@ -7,6 +7,7 @@ package net import ( "syscall" "testing" + "unsafe" ) func TestRawConn(t *testing.T) { @@ -34,3 +35,55 @@ func TestRawConn(t *testing.T) { t.Fatal("should fail") } } + +func TestRawConnListener(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + cc, err := ln.(*TCPListener).SyscallConn() + if err != nil { + t.Fatal(err) + } + + called := false + op := func(uintptr) bool { + called = true + return true + } + + err = cc.Write(op) + if err == nil { + t.Error("Write should return an error") + } + if called { + t.Error("Write shouldn't call op") + } + + called = false + err = cc.Read(op) + if err == nil { + t.Error("Read should return an error") + } + if called { + t.Error("Read shouldn't call op") + } + + var operr error + fn := func(s uintptr) { + var v, l int32 + l = int32(unsafe.Sizeof(v)) + operr = syscall.Getsockopt(syscall.Handle(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, (*byte)(unsafe.Pointer(&v)), &l) + } + err = cc.Control(fn) + if err != nil || operr != nil { + t.Fatal(err, operr) + } + ln.Close() + err = cc.Control(fn) + if err == nil { + t.Fatal("Control after Close should fail") + } +} diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go index 29aae7ee7ff..a0212926037 100644 --- a/libgo/go/net/rpc/server.go +++ b/libgo/go/net/rpc/server.go @@ -372,7 +372,10 @@ func (m *methodType) NumCalls() (n uint) { return n } -func (s *service) call(server *Server, sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) { +func (s *service) call(server *Server, sending *sync.Mutex, wg *sync.WaitGroup, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) { + if wg != nil { + defer wg.Done() + } mtype.Lock() mtype.numCalls++ mtype.Unlock() @@ -456,6 +459,7 @@ func (server *Server) ServeConn(conn io.ReadWriteCloser) { // decode requests and encode responses. func (server *Server) ServeCodec(codec ServerCodec) { sending := new(sync.Mutex) + wg := new(sync.WaitGroup) for { service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec) if err != nil { @@ -472,8 +476,12 @@ func (server *Server) ServeCodec(codec ServerCodec) { } continue } - go service.call(server, sending, mtype, req, argv, replyv, codec) + wg.Add(1) + go service.call(server, sending, wg, mtype, req, argv, replyv, codec) } + // We've seen that there are no more requests. + // Wait for responses to be sent before closing codec. + wg.Wait() codec.Close() } @@ -493,7 +501,7 @@ func (server *Server) ServeRequest(codec ServerCodec) error { } return err } - service.call(server, sending, mtype, req, argv, replyv, codec) + service.call(server, sending, nil, mtype, req, argv, replyv, codec) return nil } diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go index fb97f82a2f7..e5d7fe0c8f5 100644 --- a/libgo/go/net/rpc/server_test.go +++ b/libgo/go/net/rpc/server_test.go @@ -75,6 +75,11 @@ func (t *Arith) Error(args *Args, reply *Reply) error { panic("ERROR") } +func (t *Arith) SleepMilli(args *Args, reply *Reply) error { + time.Sleep(time.Duration(args.A) * time.Millisecond) + return nil +} + type hidden int func (t *hidden) Exported(args Args, reply *Reply) error { @@ -693,6 +698,53 @@ func TestAcceptExitAfterListenerClose(t *testing.T) { newServer.Accept(l) } +func TestShutdown(t *testing.T) { + var l net.Listener + l, _ = listenTCP() + ch := make(chan net.Conn, 1) + go func() { + defer l.Close() + c, err := l.Accept() + if err != nil { + t.Error(err) + } + ch <- c + }() + c, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + t.Fatal(err) + } + c1 := <-ch + if c1 == nil { + t.Fatal(err) + } + + newServer := NewServer() + newServer.Register(new(Arith)) + go newServer.ServeConn(c1) + + args := &Args{7, 8} + reply := new(Reply) + client := NewClient(c) + err = client.Call("Arith.Add", args, reply) + if err != nil { + t.Fatal(err) + } + + // On an unloaded system 10ms is usually enough to fail 100% of the time + // with a broken server. On a loaded system, a broken server might incorrectly + // be reported as passing, but we're OK with that kind of flakiness. + // If the code is correct, this test will never fail, regardless of timeout. + args.A = 10 // 10 ms + done := make(chan *Call, 1) + call := client.Go("Arith.SleepMilli", args, reply, done) + c.(*net.TCPConn).CloseWrite() + <-done + if call.Error != nil { + t.Fatal(err) + } +} + func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { once.Do(startServer) client, err := dial() diff --git a/libgo/go/net/smtp/auth.go b/libgo/go/net/smtp/auth.go index 3f1339ebc56..fd1a472f930 100644 --- a/libgo/go/net/smtp/auth.go +++ b/libgo/go/net/smtp/auth.go @@ -44,26 +44,29 @@ type plainAuth struct { } // PlainAuth returns an Auth that implements the PLAIN authentication -// mechanism as defined in RFC 4616. -// The returned Auth uses the given username and password to authenticate -// on TLS connections to host and act as identity. Usually identity will be -// left blank to act as username. +// mechanism as defined in RFC 4616. The returned Auth uses the given +// username and password to authenticate to host and act as identity. +// Usually identity should be the empty string, to act as username. +// +// PlainAuth will only send the credentials if the connection is using TLS +// or is connected to localhost. Otherwise authentication will fail with an +// error, without sending the credentials. func PlainAuth(identity, username, password, host string) Auth { return &plainAuth{identity, username, password, host} } +func isLocalhost(name string) bool { + return name == "localhost" || name == "127.0.0.1" || name == "::1" +} + func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) { - if !server.TLS { - advertised := false - for _, mechanism := range server.Auth { - if mechanism == "PLAIN" { - advertised = true - break - } - } - if !advertised { - return "", nil, errors.New("unencrypted connection") - } + // Must have TLS, or else localhost server. + // Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo. + // In particular, it doesn't matter if the server advertises PLAIN auth. + // That might just be the attacker saying + // "it's ok, you can trust me with your password." + if !server.TLS && !isLocalhost(server.Name) { + return "", nil, errors.New("unencrypted connection") } if server.Name != a.host { return "", nil, errors.New("wrong host name") diff --git a/libgo/go/net/smtp/smtp.go b/libgo/go/net/smtp/smtp.go index 28472e447b5..cf699e6be82 100644 --- a/libgo/go/net/smtp/smtp.go +++ b/libgo/go/net/smtp/smtp.go @@ -67,6 +67,7 @@ func NewClient(conn net.Conn, host string) (*Client, error) { return nil, err } c := &Client{Text: text, conn: conn, serverName: host, localName: "localhost"} + _, c.tls = conn.(*tls.Conn) return c, nil } @@ -93,6 +94,9 @@ func (c *Client) hello() error { // automatically otherwise. If Hello is called, it must be called before // any of the other methods. func (c *Client) Hello(localName string) error { + if err := validateLine(localName); err != nil { + return err + } if c.didHello { return errors.New("smtp: Hello called after other methods") } @@ -179,6 +183,9 @@ func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) { // does not necessarily indicate an invalid address. Many servers // will not verify addresses for security reasons. func (c *Client) Verify(addr string) error { + if err := validateLine(addr); err != nil { + return err + } if err := c.hello(); err != nil { return err } @@ -237,6 +244,9 @@ func (c *Client) Auth(a Auth) error { // parameter. // This initiates a mail transaction and is followed by one or more Rcpt calls. func (c *Client) Mail(from string) error { + if err := validateLine(from); err != nil { + return err + } if err := c.hello(); err != nil { return err } @@ -254,6 +264,9 @@ func (c *Client) Mail(from string) error { // A call to Rcpt must be preceded by a call to Mail and may be followed by // a Data call or another Rcpt call. func (c *Client) Rcpt(to string) error { + if err := validateLine(to); err != nil { + return err + } _, _, err := c.cmd(25, "RCPT TO:<%s>", to) return err } @@ -304,6 +317,14 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests // functionality. Higher-level packages exist outside of the standard // library. func SendMail(addr string, a Auth, from string, to []string, msg []byte) error { + if err := validateLine(from); err != nil { + return err + } + for _, recp := range to { + if err := validateLine(recp); err != nil { + return err + } + } c, err := Dial(addr) if err != nil { return err @@ -377,6 +398,16 @@ func (c *Client) Reset() error { return err } +// Noop sends the NOOP command to the server. It does nothing but check +// that the connection to the server is okay. +func (c *Client) Noop() error { + if err := c.hello(); err != nil { + return err + } + _, _, err := c.cmd(250, "NOOP") + return err +} + // Quit sends the QUIT command and closes the connection to the server. func (c *Client) Quit() error { if err := c.hello(); err != nil { @@ -388,3 +419,11 @@ func (c *Client) Quit() error { } return c.Text.Close() } + +// validateLine checks to see if a line has CR or LF as per RFC 5321 +func validateLine(line string) error { + if strings.ContainsAny(line, "\n\r") { + return errors.New("smtp: A line must not contain CR or LF") + } + return nil +} diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go index 9dbe3eb9ecb..d489922597e 100644 --- a/libgo/go/net/smtp/smtp_test.go +++ b/libgo/go/net/smtp/smtp_test.go @@ -62,29 +62,41 @@ testLoop: } func TestAuthPlain(t *testing.T) { - auth := PlainAuth("foo", "bar", "baz", "servername") tests := []struct { - server *ServerInfo - err string + authName string + server *ServerInfo + err string }{ { - server: &ServerInfo{Name: "servername", TLS: true}, + authName: "servername", + server: &ServerInfo{Name: "servername", TLS: true}, }, { - // Okay; explicitly advertised by server. - server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, + // OK to use PlainAuth on localhost without TLS + authName: "localhost", + server: &ServerInfo{Name: "localhost", TLS: false}, }, { - server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, - err: "unencrypted connection", + // NOT OK on non-localhost, even if server says PLAIN is OK. + // (We don't know that the server is the real server.) + authName: "servername", + server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, + err: "unencrypted connection", }, { - server: &ServerInfo{Name: "attacker", TLS: true}, - err: "wrong host name", + authName: "servername", + server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, + err: "unencrypted connection", + }, + { + authName: "servername", + server: &ServerInfo{Name: "attacker", TLS: true}, + err: "wrong host name", }, } for i, tt := range tests { + auth := PlainAuth("foo", "bar", "baz", tt.authName) _, _, err := auth.Start(tt.server) got := "" if err != nil { @@ -182,6 +194,9 @@ func TestBasic(t *testing.T) { if err := c.Verify("user1@gmail.com"); err == nil { t.Fatalf("First VRFY: expected no verification") } + if err := c.Verify("user2@gmail.com>\r\nDATA\r\nAnother injected message body\r\n.\r\nQUIT\r\n"); err == nil { + t.Fatalf("VRFY should have failed due to a message injection attempt") + } if err := c.Verify("user2@gmail.com"); err != nil { t.Fatalf("Second VRFY: expected verification, got %s", err) } @@ -193,6 +208,12 @@ func TestBasic(t *testing.T) { t.Fatalf("AUTH failed: %s", err) } + if err := c.Rcpt("golang-nuts@googlegroups.com>\r\nDATA\r\nInjected message body\r\n.\r\nQUIT\r\n"); err == nil { + t.Fatalf("RCPT should have failed due to a message injection attempt") + } + if err := c.Mail("user@gmail.com>\r\nDATA\r\nAnother injected message body\r\n.\r\nQUIT\r\n"); err == nil { + t.Fatalf("MAIL should have failed due to a message injection attempt") + } if err := c.Mail("user@gmail.com"); err != nil { t.Fatalf("MAIL failed: %s", err) } @@ -352,6 +373,53 @@ HELO localhost QUIT ` +func TestNewClientWithTLS(t *testing.T) { + cert, err := tls.X509KeyPair(localhostCert, localhostKey) + if err != nil { + t.Fatalf("loadcert: %v", err) + } + + config := tls.Config{Certificates: []tls.Certificate{cert}} + + ln, err := tls.Listen("tcp", "127.0.0.1:0", &config) + if err != nil { + ln, err = tls.Listen("tcp", "[::1]:0", &config) + if err != nil { + t.Fatalf("server: listen: %v", err) + } + } + + go func() { + conn, err := ln.Accept() + if err != nil { + t.Errorf("server: accept: %v", err) + return + } + defer conn.Close() + + _, err = conn.Write([]byte("220 SIGNS\r\n")) + if err != nil { + t.Errorf("server: write: %v", err) + return + } + }() + + config.InsecureSkipVerify = true + conn, err := tls.Dial("tcp", ln.Addr().String(), &config) + if err != nil { + t.Fatalf("client: dial: %v", err) + } + defer conn.Close() + + client, err := NewClient(conn, ln.Addr().String()) + if err != nil { + t.Fatalf("smtp: newclient: %v", err) + } + if !client.tls { + t.Errorf("client.tls Got: %t Expected: %t", client.tls, true) + } +} + func TestHello(t *testing.T) { if len(helloServer) != len(helloClient) { @@ -375,6 +443,10 @@ func TestHello(t *testing.T) { switch i { case 0: + err = c.Hello("hostinjection>\n\rDATA\r\nInjected message body\r\n.\r\nQUIT\r\n") + if err == nil { + t.Errorf("Expected Hello to be rejected due to a message injection attempt") + } err = c.Hello("customhost") case 1: err = c.StartTLS(nil) @@ -406,6 +478,8 @@ func TestHello(t *testing.T) { t.Errorf("Want error, got none") } } + case 9: + err = c.Noop() default: t.Fatalf("Unhandled command") } @@ -438,6 +512,7 @@ var helloServer = []string{ "250 Reset ok\n", "221 Goodbye\n", "250 Sender ok\n", + "250 ok\n", } var baseHelloClient = `EHLO customhost @@ -454,6 +529,7 @@ var helloClient = []string{ "RSET\n", "QUIT\n", "VRFY test@example.com\n", + "NOOP\n", } func TestSendMail(t *testing.T) { @@ -506,6 +582,16 @@ func TestSendMail(t *testing.T) { } }(strings.Split(server, "\r\n")) + err = SendMail(l.Addr().String(), nil, "test@example.com", []string{"other@example.com>\n\rDATA\r\nInjected message body\r\n.\r\nQUIT\r\n"}, []byte(strings.Replace(`From: test@example.com +To: other@example.com +Subject: SendMail test + +SendMail is working for me. +`, "\n", "\r\n", -1))) + if err == nil { + t.Errorf("Expected SendMail to be rejected due to a message injection attempt") + } + err = SendMail(l.Addr().String(), nil, "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com To: other@example.com Subject: SendMail test diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go index 4e0e9e01f2c..dfb09205502 100644 --- a/libgo/go/net/sock_bsd.go +++ b/libgo/go/net/sock_bsd.go @@ -17,8 +17,10 @@ func maxListenerBacklog() int { err error ) switch runtime.GOOS { - case "darwin", "freebsd": + case "darwin": n, err = syscall.SysctlUint32("kern.ipc.somaxconn") + case "freebsd": + n, err = syscall.SysctlUint32("kern.ipc.acceptqueue") case "netbsd": // NOTE: NetBSD has no somaxconn-like kernel state so far case "openbsd": diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go index 89a3ca42585..fa11c7af2e7 100644 --- a/libgo/go/net/sock_windows.go +++ b/libgo/go/net/sock_windows.go @@ -5,6 +5,7 @@ package net import ( + "internal/syscall/windows" "os" "syscall" ) @@ -16,9 +17,19 @@ func maxListenerBacklog() int { } func sysSocket(family, sotype, proto int) (syscall.Handle, error) { + s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), + nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) + if err == nil { + return s, nil + } + // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some + // old versions of Windows, see + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx + // for details. Just use syscall.Socket, if windows.WSASocket failed. + // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err := socketFunc(family, sotype, proto) + s, err = socketFunc(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } diff --git a/libgo/go/net/sockoptip_bsd.go b/libgo/go/net/sockoptip_bsdvar.go similarity index 93% rename from libgo/go/net/sockoptip_bsd.go rename to libgo/go/net/sockoptip_bsdvar.go index b11f3a4edbe..95601013987 100644 --- a/libgo/go/net/sockoptip_bsd.go +++ b/libgo/go/net/sockoptip_bsdvar.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 netbsd openbsd solaris package net diff --git a/libgo/go/net/sockoptip_posix.go b/libgo/go/net/sockoptip_posix.go index 92af7646ef9..b14963ff32e 100644 --- a/libgo/go/net/sockoptip_posix.go +++ b/libgo/go/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 aix darwin dragonfly freebsd linux netbsd openbsd windows +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/libgo/go/net/sockoptip_stub.go b/libgo/go/net/sockoptip_stub.go index f698687514d..fc20a9fc331 100644 --- a/libgo/go/net/sockoptip_stub.go +++ b/libgo/go/net/sockoptip_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build nacl solaris +// +build nacl package net diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go index e957aa3005a..9528140b940 100644 --- a/libgo/go/net/tcpsock.go +++ b/libgo/go/net/tcpsock.go @@ -225,6 +225,18 @@ type TCPListener struct { fd *netFD } +// SyscallConn returns a raw network connection. +// This implements the syscall.Conn interface. +// +// The returned RawConn only supports calling Control. Read and +// Write return an error. +func (l *TCPListener) SyscallConn() (syscall.RawConn, error) { + if !l.ok() { + return nil, syscall.EINVAL + } + return newRawListener(l.fd) +} + // AcceptTCP accepts the next incoming call and returns the new // connection. func (l *TCPListener) AcceptTCP() (*TCPConn, error) { diff --git a/libgo/go/net/tcpsock_test.go b/libgo/go/net/tcpsock_test.go index 660f4249d40..04b38b60741 100644 --- a/libgo/go/net/tcpsock_test.go +++ b/libgo/go/net/tcpsock_test.go @@ -8,6 +8,7 @@ import ( "fmt" "internal/testenv" "io" + "os" "reflect" "runtime" "sync" @@ -727,3 +728,74 @@ func TestTCPBig(t *testing.T) { }) } } + +func TestCopyPipeIntoTCP(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + errc := make(chan error, 1) + defer func() { + if err := <-errc; err != nil { + t.Error(err) + } + }() + go func() { + c, err := ln.Accept() + if err != nil { + errc <- err + return + } + defer c.Close() + + buf := make([]byte, 100) + n, err := io.ReadFull(c, buf) + if err != io.ErrUnexpectedEOF || n != 2 { + errc <- fmt.Errorf("got err=%q n=%v; want err=%q n=2", err, n, io.ErrUnexpectedEOF) + return + } + + errc <- nil + }() + + c, err := Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + + errc2 := make(chan error, 1) + defer func() { + if err := <-errc2; err != nil { + t.Error(err) + } + }() + + defer w.Close() + + go func() { + _, err := io.Copy(c, r) + errc2 <- err + }() + + // Split write into 2 packets. That makes Windows TransmitFile + // drop second packet. + packet := make([]byte, 1) + _, err = w.Write(packet) + if err != nil { + t.Fatal(err) + } + time.Sleep(100 * time.Millisecond) + _, err = w.Write(packet) + if err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go index e07d1d62e09..8c3a05264a4 100644 --- a/libgo/go/net/textproto/reader.go +++ b/libgo/go/net/textproto/reader.go @@ -476,15 +476,25 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { } m := make(MIMEHeader, hint) + + // The first line cannot start with a leading space. + if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { + line, err := r.readLineSlice() + if err != nil { + return m, err + } + return m, ProtocolError("malformed MIME header initial line: " + string(line)) + } + for { kv, err := r.readContinuedLineSlice() if len(kv) == 0 { return m, err } - // Key ends at first colon; should not have spaces but - // they appear in the wild, violating specs, so we - // remove them if present. + // Key ends at first colon; should not have trailing spaces + // but they appear in the wild, violating specs, so we remove + // them if present. i := bytes.IndexByte(kv, ':') if i < 0 { return m, ProtocolError("malformed MIME header line: " + string(kv)) diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go index 0c53d48b74a..c6a6ced6493 100644 --- a/libgo/go/net/textproto/reader_test.go +++ b/libgo/go/net/textproto/reader_test.go @@ -211,6 +211,24 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) { } } +func TestReadMIMEHeaderMalformed(t *testing.T) { + inputs := []string{ + "No colon first line\r\nFoo: foo\r\n\r\n", + " No colon first line with leading space\r\nFoo: foo\r\n\r\n", + "\tNo colon first line with leading tab\r\nFoo: foo\r\n\r\n", + " First: line with leading space\r\nFoo: foo\r\n\r\n", + "\tFirst: line with leading tab\r\nFoo: foo\r\n\r\n", + "Foo: foo\r\nNo colon second line\r\n\r\n", + } + + for _, input := range inputs { + r := reader(input) + if m, err := r.ReadMIMEHeader(); err == nil { + t.Errorf("ReadMIMEHeader(%q) = %v, %v; want nil, err", input, m, err) + } + } +} + // Test that continued lines are properly trimmed. Issue 11204. func TestReadMIMEHeaderTrimContinued(t *testing.T) { // In this header, \n and \r\n terminated lines are mixed on purpose. diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go index 2c0f74fdabd..158265f06f8 100644 --- a/libgo/go/net/udpsock.go +++ b/libgo/go/net/udpsock.go @@ -9,7 +9,7 @@ import ( "syscall" ) -// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgUDP and +// BUG(mikio): On NaCl and Plan 9, the ReadMsgUDP and // WriteMsgUDP methods of UDPConn are not implemented. // BUG(mikio): On Windows, the File method of UDPConn is not diff --git a/libgo/go/net/udpsock_test.go b/libgo/go/net/udpsock_test.go index 6d4974e3e49..4ae014c01d9 100644 --- a/libgo/go/net/udpsock_test.go +++ b/libgo/go/net/udpsock_test.go @@ -161,7 +161,7 @@ func testWriteToConn(t *testing.T, raddr string) { } _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil) switch runtime.GOOS { - case "nacl", "windows": // see golang.org/issue/9252 + case "nacl": // see golang.org/issue/9252 t.Skipf("not implemented yet on %s", runtime.GOOS) default: if err != nil { @@ -204,7 +204,7 @@ func testWriteToPacketConn(t *testing.T, raddr string) { } _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra) switch runtime.GOOS { - case "nacl", "windows": // see golang.org/issue/9252 + case "nacl": // see golang.org/issue/9252 t.Skipf("not implemented yet on %s", runtime.GOOS) default: if err != nil { diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go index 057940acf65..20326dabeaa 100644 --- a/libgo/go/net/unixsock.go +++ b/libgo/go/net/unixsock.go @@ -219,6 +219,18 @@ type UnixListener struct { func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil } +// SyscallConn returns a raw network connection. +// This implements the syscall.Conn interface. +// +// The returned RawConn only supports calling Control. Read and +// Write return an error. +func (l *UnixListener) SyscallConn() (syscall.RawConn, error) { + if !l.ok() { + return nil, syscall.EINVAL + } + return newRawListener(l.fd) +} + // AcceptUnix accepts the next incoming call and returns the new // connection. func (l *UnixListener) AcceptUnix() (*UnixConn, error) { diff --git a/libgo/go/net/unixsock_linux_test.go b/libgo/go/net/unixsock_linux_test.go new file mode 100644 index 00000000000..d04007cef38 --- /dev/null +++ b/libgo/go/net/unixsock_linux_test.go @@ -0,0 +1,104 @@ +// Copyright 2017 The Go Authors. 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 ( + "bytes" + "reflect" + "syscall" + "testing" + "time" +) + +func TestUnixgramAutobind(t *testing.T) { + laddr := &UnixAddr{Name: "", Net: "unixgram"} + c1, err := ListenUnixgram("unixgram", laddr) + if err != nil { + t.Fatal(err) + } + defer c1.Close() + + // retrieve the autobind address + autoAddr := c1.LocalAddr().(*UnixAddr) + if len(autoAddr.Name) <= 1 { + t.Fatalf("invalid autobind address: %v", autoAddr) + } + if autoAddr.Name[0] != '@' { + t.Fatalf("invalid autobind address: %v", autoAddr) + } + + c2, err := DialUnix("unixgram", nil, autoAddr) + if err != nil { + t.Fatal(err) + } + defer c2.Close() + + if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) { + t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr()) + } +} + +func TestUnixAutobindClose(t *testing.T) { + laddr := &UnixAddr{Name: "", Net: "unix"} + ln, err := ListenUnix("unix", laddr) + if err != nil { + t.Fatal(err) + } + ln.Close() +} + +func TestUnixgramLinuxAbstractLongName(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("abstract unix socket long name test") + } + + // Create an abstract socket name whose length is exactly + // the maximum RawSockkaddrUnix Path len + rsu := syscall.RawSockaddrUnix{} + addrBytes := make([]byte, len(rsu.Path)) + copy(addrBytes, "@abstract_test") + addr := string(addrBytes) + + la, err := ResolveUnixAddr("unixgram", addr) + if err != nil { + t.Fatal(err) + } + c, err := ListenUnixgram("unixgram", la) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + off := make(chan bool) + data := [5]byte{1, 2, 3, 4, 5} + go func() { + defer func() { off <- true }() + s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) + if err != nil { + t.Error(err) + return + } + defer syscall.Close(s) + rsa := &syscall.SockaddrUnix{Name: addr} + if err := syscall.Sendto(s, data[:], 0, rsa); err != nil { + t.Error(err) + return + } + }() + + <-off + b := make([]byte, 64) + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + n, from, err := c.ReadFrom(b) + if err != nil { + t.Fatal(err) + } + if from != nil { + t.Fatalf("unexpected peer address: %v", from) + } + if !bytes.Equal(b[:n], data[:]) { + t.Fatalf("got %v; want %v", b[:n], data[:]) + } +} diff --git a/libgo/go/net/unixsock_test.go b/libgo/go/net/unixsock_test.go index 489a29bc7d7..3e5c8bc3769 100644 --- a/libgo/go/net/unixsock_test.go +++ b/libgo/go/net/unixsock_test.go @@ -170,51 +170,6 @@ func TestUnixgramZeroByteBuffer(t *testing.T) { } } -func TestUnixgramAutobind(t *testing.T) { - if runtime.GOOS != "linux" { - t.Skip("autobind is linux only") - } - - laddr := &UnixAddr{Name: "", Net: "unixgram"} - c1, err := ListenUnixgram("unixgram", laddr) - if err != nil { - t.Fatal(err) - } - defer c1.Close() - - // retrieve the autobind address - autoAddr := c1.LocalAddr().(*UnixAddr) - if len(autoAddr.Name) <= 1 { - t.Fatalf("invalid autobind address: %v", autoAddr) - } - if autoAddr.Name[0] != '@' { - t.Fatalf("invalid autobind address: %v", autoAddr) - } - - c2, err := DialUnix("unixgram", nil, autoAddr) - if err != nil { - t.Fatal(err) - } - defer c2.Close() - - if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) { - t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr()) - } -} - -func TestUnixAutobindClose(t *testing.T) { - if runtime.GOOS != "linux" { - t.Skip("autobind is linux only") - } - - laddr := &UnixAddr{Name: "", Net: "unix"} - ln, err := ListenUnix("unix", laddr) - if err != nil { - t.Fatal(err) - } - ln.Close() -} - func TestUnixgramWrite(t *testing.T) { if !testableNetwork("unixgram") { t.Skip("unixgram test") diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go index 2ac24725692..7c3d24493e0 100644 --- a/libgo/go/net/url/url.go +++ b/libgo/go/net/url/url.go @@ -163,18 +163,23 @@ func shouldEscape(c byte, mode encoding) bool { return true } -// QueryUnescape does the inverse transformation of QueryEscape, converting -// %AB into the byte 0xAB and '+' into ' ' (space). It returns an error if -// any % is not followed by two hexadecimal digits. +// QueryUnescape does the inverse transformation of QueryEscape, +// converting each 3-byte encoded substring of the form "%AB" into the +// hex-decoded byte 0xAB. It also converts '+' into ' ' (space). +// It returns an error if any % is not followed by two hexadecimal +// digits. func QueryUnescape(s string) (string, error) { return unescape(s, encodeQueryComponent) } -// PathUnescape does the inverse transformation of PathEscape, converting -// %AB into the byte 0xAB. It returns an error if any % is not followed by -// two hexadecimal digits. +// PathUnescape does the inverse transformation of PathEscape, +// converting each 3-byte encoded substring of the form "%AB" into the +// hex-decoded byte 0xAB. It also converts '+' into ' ' (space). +// It returns an error if any % is not followed by two hexadecimal +// digits. // -// PathUnescape is identical to QueryUnescape except that it does not unescape '+' to ' ' (space). +// PathUnescape is identical to QueryUnescape except that it does not +// unescape '+' to ' ' (space). func PathUnescape(s string) (string, error) { return unescape(s, encodePathSegment) } @@ -367,17 +372,26 @@ type Userinfo struct { // Username returns the username. func (u *Userinfo) Username() string { + if u == nil { + return "" + } return u.username } // Password returns the password in case it is set, and whether it is set. func (u *Userinfo) Password() (string, bool) { + if u == nil { + return "", false + } return u.password, u.passwordSet } // String returns the encoded userinfo information in the standard form // of "username[:password]". func (u *Userinfo) String() string { + if u == nil { + return "" + } s := escape(u.username, encodeUserPassword) if u.passwordSet { s += ":" + escape(u.password, encodeUserPassword) @@ -427,7 +441,11 @@ func split(s string, c string, cutc bool) (string, string) { } // Parse parses rawurl into a URL structure. -// The rawurl may be relative or absolute. +// +// The rawurl may be relative (a path, without a host) or absolute +// (starting with a scheme). Trying to parse a hostname and path +// without a scheme is invalid but may not necessarily return an +// error, due to parsing ambiguities. func Parse(rawurl string) (*URL, error) { // Cut off #frag u, frag := split(rawurl, "#", true) @@ -726,7 +744,9 @@ func (u *URL) String() string { buf.WriteString(u.Opaque) } else { if u.Scheme != "" || u.Host != "" || u.User != nil { - buf.WriteString("//") + if u.Host != "" || u.Path != "" || u.User != nil { + buf.WriteString("//") + } if ui := u.User; ui != nil { buf.WriteString(ui.String()) buf.WriteByte('@') @@ -909,7 +929,7 @@ func resolvePath(base, ref string) string { // Add final slash to the joined path. dst = append(dst, "") } - return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/") + return "/" + strings.TrimPrefix(strings.Join(dst, "/"), "/") } // IsAbs reports whether the URL is absolute. @@ -953,12 +973,10 @@ func (u *URL) ResolveReference(ref *URL) *URL { url.Path = "" return &url } - if ref.Path == "" { - if ref.RawQuery == "" { - url.RawQuery = u.RawQuery - if ref.Fragment == "" { - url.Fragment = u.Fragment - } + if ref.Path == "" && ref.RawQuery == "" { + url.RawQuery = u.RawQuery + if ref.Fragment == "" { + url.Fragment = u.Fragment } } // The "abs_path" or "rel_path" cases. diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go index 6c3bb21d20c..d6aed3acafa 100644 --- a/libgo/go/net/url/url_test.go +++ b/libgo/go/net/url/url_test.go @@ -568,6 +568,28 @@ var urltests = []URLTest{ }, "", }, + // test we can roundtrip magnet url + // fix issue https://golang.org/issue/20054 + { + "magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&dn", + &URL{ + Scheme: "magnet", + Host: "", + Path: "", + RawQuery: "xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&dn", + }, + "magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&dn", + }, + { + "mailto:?subject=hi", + &URL{ + Scheme: "mailto", + Host: "", + Path: "", + RawQuery: "subject=hi", + }, + "mailto:?subject=hi", + }, } // more useful string for debugging than fmt's struct printer @@ -1010,6 +1032,10 @@ var resolveReferenceTests = []struct { {"http://foo.com/bar?a=b", "/baz?", "http://foo.com/baz?"}, {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"}, + // Multiple slashes + {"http://foo.com/bar", "http://foo.com//baz", "http://foo.com//baz"}, + {"http://foo.com/bar", "http://foo.com///baz/quux", "http://foo.com///baz/quux"}, + // Scheme-relative {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"}, @@ -1683,3 +1709,29 @@ func TestGob(t *testing.T) { t.Errorf("json decoded to: %s\nwant: %s\n", u1, u) } } + +func TestNilUser(t *testing.T) { + defer func() { + if v := recover(); v != nil { + t.Fatalf("unexpected panic: %v", v) + } + }() + + u, err := Parse("http://foo.com/") + + if err != nil { + t.Fatalf("parse err: %v", err) + } + + if v := u.User.Username(); v != "" { + t.Fatalf("expected empty username, got %s", v) + } + + if v, ok := u.User.Password(); v != "" || ok { + t.Fatalf("expected empty password, got %s (%v)", v, ok) + } + + if v := u.User.String(); v != "" { + t.Fatalf("expected empty string, got %s", v) + } +} diff --git a/libgo/go/net/write_unix_test.go b/libgo/go/net/write_unix_test.go new file mode 100644 index 00000000000..6d8cb6a6f81 --- /dev/null +++ b/libgo/go/net/write_unix_test.go @@ -0,0 +1,66 @@ +// Copyright 2017 The Go 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 ( + "bytes" + "syscall" + "testing" + "time" +) + +// Test that a client can't trigger an endless loop of write system +// calls on the server by shutting down the write side on the client. +// Possibility raised in the discussion of https://golang.org/cl/71973. +func TestEndlessWrite(t *testing.T) { + t.Parallel() + c := make(chan bool) + server := func(cs *TCPConn) error { + cs.CloseWrite() + <-c + return nil + } + client := func(ss *TCPConn) error { + // Tell the server to return when we return. + defer close(c) + + // Loop writing to the server. The server is not reading + // anything, so this will eventually block, and then time out. + b := bytes.Repeat([]byte{'a'}, 8192) + cagain := 0 + for { + n, err := ss.conn.fd.pfd.WriteOnce(b) + if n > 0 { + cagain = 0 + } + switch err { + case nil: + case syscall.EAGAIN: + if cagain == 0 { + // We've written enough data to + // start blocking. Set a deadline + // so that we will stop. + ss.SetWriteDeadline(time.Now().Add(5 * time.Millisecond)) + } + cagain++ + if cagain > 20 { + t.Error("looping on EAGAIN") + return nil + } + if err = ss.conn.fd.pfd.WaitWrite(); err != nil { + t.Logf("client WaitWrite: %v", err) + return nil + } + default: + // We expect to eventually get an error. + t.Logf("client WriteOnce: %v", err) + return nil + } + } + } + withTCPConnPair(t, client, server) +} diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go index e5749f0e899..16f19456381 100644 --- a/libgo/go/os/env_test.go +++ b/libgo/go/os/env_test.go @@ -134,7 +134,7 @@ func TestLookupEnv(t *testing.T) { if err != nil { t.Fatalf("failed to release smallpox virus") } - value, ok = LookupEnv(smallpox) + _, ok = LookupEnv(smallpox) if !ok { t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken") } diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go index 7235bfb6d61..b4242a4829c 100644 --- a/libgo/go/os/error.go +++ b/libgo/go/os/error.go @@ -6,6 +6,7 @@ package os import ( "errors" + "internal/poll" ) // Portable analogs of some common system call errors. @@ -15,8 +16,13 @@ var ( ErrExist = errors.New("file already exists") ErrNotExist = errors.New("file does not exist") ErrClosed = errors.New("file already closed") + ErrNoDeadline = poll.ErrNoDeadline ) +type timeout interface { + Timeout() bool +} + // PathError records an error and the operation and file path that caused it. type PathError struct { Op string @@ -26,6 +32,12 @@ type PathError struct { func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } +// Timeout reports whether this error represents a timeout. +func (e *PathError) Timeout() bool { + t, ok := e.Err.(timeout) + return ok && t.Timeout() +} + // SyscallError records an error from a specific system call. type SyscallError struct { Syscall string @@ -34,6 +46,12 @@ type SyscallError struct { func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } +// Timeout reports whether this error represents a timeout. +func (e *SyscallError) Timeout() bool { + t, ok := e.Err.(timeout) + return ok && t.Timeout() +} + // NewSyscallError returns, as an error, a new SyscallError // with the given system call name and error details. // As a convenience, if err is nil, NewSyscallError returns nil. @@ -65,6 +83,13 @@ func IsPermission(err error) bool { return isPermission(err) } +// IsTimeout returns a boolean indicating whether the error is known +// to report that a timeout occurred. +func IsTimeout(err error) bool { + terr, ok := underlyingError(err).(timeout) + return ok && terr.Timeout() +} + // underlyingError returns the underlying error for known os error types. func underlyingError(err error) error { switch err := err.(type) { diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go index 893d8ee99a8..8a49fe3b58e 100644 --- a/libgo/go/os/exec/exec.go +++ b/libgo/go/os/exec/exec.go @@ -77,9 +77,12 @@ type Cmd struct { Dir string // Stdin specifies the process's standard input. + // // If Stdin is nil, the process reads from the null device (os.DevNull). + // // If Stdin is an *os.File, the process's standard input is connected // directly to that file. + // // Otherwise, during the execution of the command a separate // goroutine reads from Stdin and delivers that data to the command // over a pipe. In this case, Wait does not complete until the goroutine @@ -92,8 +95,16 @@ type Cmd struct { // If either is nil, Run connects the corresponding file descriptor // to the null device (os.DevNull). // - // If Stdout and Stderr are the same writer, and have a type that can be compared with ==, - // at most one goroutine at a time will call Write. + // If either is an *os.File, the corresponding output from the process + // is connected directly to that file. + // + // Otherwise, during the execution of the command a separate goroutine + // reads from the process over a pipe and delivers that data to the + // corresponding Writer. In this case, Wait does not complete until the + // goroutine reaches EOF or encounters an error. + // + // If Stdout and Stderr are the same writer, and have a type that can + // be compared with ==, at most one goroutine at a time will call Write. Stdout io.Writer Stderr io.Writer @@ -190,7 +201,7 @@ func (c *Cmd) argv() []string { } // skipStdinCopyError optionally specifies a function which reports -// whether the provided the stdin copy error should be ignored. +// whether the provided stdin copy error should be ignored. // It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go. var skipStdinCopyError func(error) bool @@ -429,9 +440,8 @@ func (e *ExitError) Error() string { // error is of type *ExitError. Other error types may be // returned for I/O problems. // -// If c.Stdin is not an *os.File, Wait also waits for the I/O loop -// copying from c.Stdin into the process's standard input -// to complete. +// If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits +// for the respective I/O loop copying to or from the process to complete. // // Wait releases any resources associated with the Cmd. func (c *Cmd) Wait() error { @@ -527,16 +537,15 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) { c.Stdin = pr c.closeAfterStart = append(c.closeAfterStart, pr) wc := &closeOnce{File: pw} - c.closeAfterWait = append(c.closeAfterWait, closerFunc(wc.safeClose)) + c.closeAfterWait = append(c.closeAfterWait, wc) return wc, nil } type closeOnce struct { *os.File - writers sync.RWMutex // coordinate safeClose and Write - once sync.Once - err error + once sync.Once + err error } func (c *closeOnce) Close() error { @@ -548,55 +557,6 @@ func (c *closeOnce) close() { c.err = c.File.Close() } -type closerFunc func() error - -func (f closerFunc) Close() error { return f() } - -// safeClose closes c being careful not to race with any calls to c.Write. -// See golang.org/issue/9307 and TestEchoFileRace in exec_test.go. -// In theory other calls could also be excluded (by writing appropriate -// wrappers like c.Write's implementation below), but since c is most -// commonly used as a WriteCloser, Write is the main one to worry about. -// See also #7970, for which this is a partial fix for this specific instance. -// The idea is that we return a WriteCloser, and so the caller can be -// relied upon not to call Write and Close simultaneously, but it's less -// obvious that cmd.Wait calls Close and that the caller must not call -// Write and cmd.Wait simultaneously. In fact that seems too onerous. -// So we change the use of Close in cmd.Wait to use safeClose, which will -// synchronize with any Write. -// -// It's important that we know this won't block forever waiting for the -// operations being excluded. At the point where this is called, -// the invoked command has exited and the parent copy of the read side -// of the pipe has also been closed, so there should really be no read side -// of the pipe left. Any active writes should return very shortly with an EPIPE, -// making it reasonable to wait for them. -// Technically it is possible that the child forked a sub-process or otherwise -// handed off the read side of the pipe before exiting and the current holder -// is not reading from the pipe, and the pipe is full, in which case the close here -// might block waiting for the write to complete. That's probably OK. -// It's a small enough problem to be outweighed by eliminating the race here. -func (c *closeOnce) safeClose() error { - c.writers.Lock() - err := c.Close() - c.writers.Unlock() - return err -} - -func (c *closeOnce) Write(b []byte) (int, error) { - c.writers.RLock() - n, err := c.File.Write(b) - c.writers.RUnlock() - return n, err -} - -func (c *closeOnce) WriteString(s string) (int, error) { - c.writers.RLock() - n, err := c.File.WriteString(s) - c.writers.RUnlock() - return n, err -} - // StdoutPipe returns a pipe that will be connected to the command's // standard output when the command starts. // diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 676be36ac77..6b4d28c93da 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -11,9 +11,10 @@ import ( "time" ) -// The only signal values guaranteed to be present on all systems -// are Interrupt (send the process an interrupt) and Kill (force -// the process to exit). +// The only signal values guaranteed to be present in the os package +// on all systems are Interrupt (send the process an interrupt) and +// Kill (force the process to exit). Interrupt is not implemented on +// Windows; using it with os.Process.Signal will return an error. var ( Interrupt Signal = syscall.Note("interrupt") Kill Signal = syscall.Note("kill") diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index 9e792b4b34f..056f1397a30 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -10,9 +10,10 @@ import ( "syscall" ) -// The only signal values guaranteed to be present on all systems -// are Interrupt (send the process an interrupt) and Kill (force -// the process to exit). +// The only signal values guaranteed to be present in the os package +// on all systems are Interrupt (send the process an interrupt) and +// Kill (force the process to exit). Interrupt is not implemented on +// Windows; using it with os.Process.Signal will return an error. var ( Interrupt Signal = syscall.SIGINT Kill Signal = syscall.SIGKILL diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index 4b4d8fb0367..542b07447ff 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -41,6 +41,7 @@ import ( "internal/poll" "io" "syscall" + "time" ) // Name returns the name of the file as presented to Open. @@ -61,12 +62,14 @@ var ( // Flags to OpenFile wrapping those of the underlying system. Not all // flags may be implemented on a given system. const ( + // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. O_RDONLY int = syscall.O_RDONLY // open the file read-only. O_WRONLY int = syscall.O_WRONLY // open the file write-only. O_RDWR int = syscall.O_RDWR // open the file read-write. + // The remaining values may be or'ed in to control behavior. O_APPEND int = syscall.O_APPEND // append data to the file when writing. O_CREATE int = syscall.O_CREAT // create a new file if none exists. - O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist + O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist. O_SYNC int = syscall.O_SYNC // open for synchronous I/O. O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened. ) @@ -316,3 +319,47 @@ func Chmod(name string, mode FileMode) error { return chmod(name, mode) } // Chmod changes the mode of the file to mode. // If there is an error, it will be of type *PathError. func (f *File) Chmod(mode FileMode) error { return f.chmod(mode) } + +// SetDeadline sets the read and write deadlines for a File. +// It is equivalent to calling both SetReadDeadline and SetWriteDeadline. +// +// Only some kinds of files support setting a deadline. Calls to SetDeadline +// for files that do not support deadlines will return ErrNoDeadline. +// On most systems ordinary files do not support deadlines, but pipes do. +// +// A deadline is an absolute time after which I/O operations fail with an +// error instead of blocking. The deadline applies to all future and pending +// I/O, not just the immediately following call to Read or Write. +// After a deadline has been exceeded, the connection can be refreshed +// by setting a deadline in the future. +// +// An error returned after a timeout fails will implement the +// Timeout method, and calling the Timeout method will return true. +// The PathError and SyscallError types implement the Timeout method. +// In general, call IsTimeout to test whether an error indicates a timeout. +// +// An idle timeout can be implemented by repeatedly extending +// the deadline after successful Read or Write calls. +// +// A zero value for t means I/O operations will not time out. +func (f *File) SetDeadline(t time.Time) error { + return f.setDeadline(t) +} + +// SetReadDeadline sets the deadline for future Read calls and any +// currently-blocked Read call. +// A zero value for t means Read will not time out. +// Not all files support setting deadlines; see SetDeadline. +func (f *File) SetReadDeadline(t time.Time) error { + return f.setReadDeadline(t) +} + +// SetWriteDeadline sets the deadline for any future Write calls and any +// currently-blocked Write call. +// Even if Write times out, it may return n > 0, indicating that +// some of the data was successfully written. +// A zero value for t means Write will not time out. +// Not all files support setting deadlines; see SetDeadline. +func (f *File) SetWriteDeadline(t time.Time) error { + return f.setWriteDeadline(t) +} diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go index 0f4a736c269..e4f8fd987bc 100644 --- a/libgo/go/os/file_plan9.go +++ b/libgo/go/os/file_plan9.go @@ -5,6 +5,7 @@ package os import ( + "internal/poll" "io" "runtime" "syscall" @@ -28,6 +29,7 @@ type file struct { // Fd returns the integer Plan 9 file descriptor referencing the open file. // The file descriptor is valid only until f.Close is called or f is garbage collected. +// On Unix systems this will cause the SetDeadline methods to stop working. func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0)) @@ -491,6 +493,30 @@ func (f *File) Chdir() error { return nil } +// setDeadline sets the read and write deadline. +func (f *File) setDeadline(time.Time) error { + if err := f.checkValid("SetDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + +// setReadDeadline sets the read deadline. +func (f *File) setReadDeadline(time.Time) error { + if err := f.checkValid("SetReadDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + +// setWriteDeadline sets the write deadline. +func (f *File) setWriteDeadline(time.Time) error { + if err := f.checkValid("SetWriteDeadline"); err != nil { + return err + } + return poll.ErrNoDeadline +} + // checkValid checks whether f is valid for use. // If not, it returns an appropriate error, perhaps incorporating the operation name op. func (f *File) checkValid(op string) error { diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index 51cae9de6de..67da3849bff 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -163,6 +163,30 @@ func (f *File) Chdir() error { return nil } +// setDeadline sets the read and write deadline. +func (f *File) setDeadline(t time.Time) error { + if err := f.checkValid("SetDeadline"); err != nil { + return err + } + return f.pfd.SetDeadline(t) +} + +// setReadDeadline sets the read deadline. +func (f *File) setReadDeadline(t time.Time) error { + if err := f.checkValid("SetReadDeadline"); err != nil { + return err + } + return f.pfd.SetReadDeadline(t) +} + +// setWriteDeadline sets the write deadline. +func (f *File) setWriteDeadline(t time.Time) error { + if err := f.checkValid("SetWriteDeadline"); err != nil { + return err + } + return f.pfd.SetWriteDeadline(t) +} + // checkValid checks whether f is valid for use. // If not, it returns an appropriate error, perhaps incorporating the operation name op. func (f *File) checkValid(op string) error { diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index 819999409a9..af9c37f9c09 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -45,14 +45,16 @@ func rename(oldname, newname string) error { // can overwrite this data, which could cause the finalizer // to close the wrong file descriptor. type file struct { - pfd poll.FD - name string - dirinfo *dirInfo // nil unless directory being read - nonblock bool // whether we set nonblocking mode + pfd poll.FD + name string + dirinfo *dirInfo // nil unless directory being read + nonblock bool // whether we set nonblocking mode + stdoutOrErr bool // whether this is stdout or stderr } // Fd returns the integer Unix file descriptor referencing the open file. // The file descriptor is valid only until f.Close is called or f is garbage collected. +// On Unix systems this will cause the SetDeadline methods to stop working. func (f *File) Fd() uintptr { if f == nil { return ^(uintptr(0)) @@ -74,12 +76,22 @@ func (f *File) Fd() uintptr { // name. The returned value will be nil if fd is not a valid file // descriptor. func NewFile(fd uintptr, name string) *File { - return newFile(fd, name, false) + return newFile(fd, name, kindNewFile) } -// newFile is like NewFile, but if pollable is true it tries to add the -// file to the runtime poller. -func newFile(fd uintptr, name string, pollable bool) *File { +// newFileKind describes the kind of file to newFile. +type newFileKind int + +const ( + kindNewFile newFileKind = iota + kindOpenFile + kindPipe +) + +// newFile is like NewFile, but if called from OpenFile or Pipe +// (as passed in the kind parameter) it tries to add the file to +// the runtime poller. +func newFile(fd uintptr, name string, kind newFileKind) *File { fdi := int(fd) if fdi < 0 { return nil @@ -90,16 +102,18 @@ func newFile(fd uintptr, name string, pollable bool) *File { IsStream: true, ZeroReadIsEOF: true, }, - name: name, + name: name, + stdoutOrErr: fdi == 1 || fdi == 2, }} // Don't try to use kqueue with regular files on FreeBSD. // It crashes the system unpredictably while running all.bash. // Issue 19093. - if runtime.GOOS == "freebsd" { - pollable = false + if runtime.GOOS == "freebsd" && kind == kindOpenFile { + kind = kindNewFile } + pollable := kind == kindOpenFile || kind == kindPipe if err := f.pfd.Init("file", pollable); err != nil { // An error here indicates a failure to register // with the netpoll system. That can happen for @@ -129,7 +143,7 @@ type dirInfo struct { // output or standard error. See the SIGPIPE docs in os/signal, and // issue 11845. func epipecheck(file *File, e error) { - if e == syscall.EPIPE && (file.pfd.Sysfd == 1 || file.pfd.Sysfd == 2) { + if e == syscall.EPIPE && file.stdoutOrErr { sigpipe() } } @@ -180,7 +194,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) { syscall.CloseOnExec(r) } - return newFile(uintptr(r), name, true), nil + return newFile(uintptr(r), name, kindOpenFile), nil } // Close closes the File, rendering it unusable for I/O. diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 9033c4fcdb5..e1c5b451d89 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -719,6 +719,27 @@ func TestHardLink(t *testing.T) { if !SameFile(tostat, fromstat) { t.Errorf("link %q, %q did not create hard link", to, from) } + // We should not be able to perform the same Link() a second time + err = Link(to, from) + switch err := err.(type) { + case *LinkError: + if err.Op != "link" { + t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link") + } + if err.Old != to { + t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to) + } + if err.New != from { + t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from) + } + if !IsExist(err.Err) { + t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error") + } + case nil: + t.Errorf("link %q, %q: expected error, got nil", from, to) + default: + t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) + } } // chtmpdir changes the working directory to a new temporary directory and @@ -1012,9 +1033,14 @@ func TestStartProcess(t *testing.T) { dir = Getenv("SystemRoot") args = []string{"/c", "cd"} default: - cmd = "/bin/pwd" + var err error + cmd, err = osexec.LookPath("pwd") + if err != nil { + t.Fatalf("Can't find pwd: %v", err) + } dir = "/" args = []string{} + t.Logf("Testing with %v", cmd) } cmddir, cmdbase := filepath.Split(cmd) args = append([]string{cmdbase}, args...) @@ -1162,9 +1188,14 @@ func testChtimes(t *testing.T, name string) { // the contents are accessed; also, it is set // whenever mtime is set. case "netbsd": - t.Logf("AccessTime didn't go backwards; was=%d, after=%d (Ignoring. See NetBSD issue golang.org/issue/19293)", at, pat) + mounts, _ := ioutil.ReadFile("/proc/mounts") + if strings.Contains(string(mounts), "noatime") { + t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.") + } else { + t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat) + } default: - t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat) + t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat) } } @@ -1211,9 +1242,9 @@ func TestChdirAndGetwd(t *testing.T) { if mode == 0 { err = Chdir(d) } else { - fd1, err := Open(d) - if err != nil { - t.Errorf("Open %s: %s", d, err) + fd1, err1 := Open(d) + if err1 != nil { + t.Errorf("Open %s: %s", d, err1) continue } err = fd1.Chdir() @@ -2204,22 +2235,24 @@ func TestPipeThreads(t *testing.T) { defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2)) - var wg sync.WaitGroup - wg.Add(threads) - c := make(chan bool, threads) + creading := make(chan bool, threads) + cdone := make(chan bool, threads) for i := 0; i < threads; i++ { go func(i int) { - defer wg.Done() var b [1]byte - c <- true + creading <- true if _, err := r[i].Read(b[:]); err != nil { t.Error(err) } + if err := r[i].Close(); err != nil { + t.Error(err) + } + cdone <- true }(i) } for i := 0; i < threads; i++ { - <-c + <-creading } // If we are still alive, it means that the 100 goroutines did @@ -2232,14 +2265,7 @@ func TestPipeThreads(t *testing.T) { if err := w[i].Close(); err != nil { t.Error(err) } - } - - wg.Wait() - - for i := 0; i < threads; i++ { - if err := r[i].Close(); err != nil { - t.Error(err) - } + <-cdone } } diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go index e239835c6ac..56c885c6662 100644 --- a/libgo/go/os/os_unix_test.go +++ b/libgo/go/os/os_unix_test.go @@ -36,11 +36,6 @@ func checkUidGid(t *testing.T, path string, uid, gid int) { } func TestChown(t *testing.T) { - // Chown is not supported under windows or Plan 9. - // Plan9 provides a native ChownPlan9 version instead. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - t.Skipf("%s does not support syscall.Chown", runtime.GOOS) - } // Use TempDir() to make sure we're on a local file system, // so that the group ids returned by Getgroups will be allowed // on the file. On NFS, the Getgroups groups are @@ -84,10 +79,6 @@ func TestChown(t *testing.T) { } func TestFileChown(t *testing.T) { - // Fchown is not supported under windows or Plan 9. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - t.Skipf("%s does not support syscall.Fchown", runtime.GOOS) - } // Use TempDir() to make sure we're on a local file system, // so that the group ids returned by Getgroups will be allowed // on the file. On NFS, the Getgroups groups are @@ -131,10 +122,6 @@ func TestFileChown(t *testing.T) { } func TestLchown(t *testing.T) { - // Lchown is not supported under windows or Plan 9. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - t.Skipf("%s does not support syscall.Lchown", runtime.GOOS) - } // Use TempDir() to make sure we're on a local file system, // so that the group ids returned by Getgroups will be allowed // on the file. On NFS, the Getgroups groups are diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go index 146d7b69548..17c49c8687d 100644 --- a/libgo/go/os/path.go +++ b/libgo/go/os/path.go @@ -6,6 +6,7 @@ package os import ( "io" + "runtime" "syscall" ) @@ -97,6 +98,11 @@ func RemoveAll(path string) error { // Remove contents & return first error. err = nil for { + if err == nil && (runtime.GOOS == "plan9" || runtime.GOOS == "nacl") { + // Reset read offset after removing directory entries. + // See golang.org/issue/22572. + fd.Seek(0, 0) + } names, err1 := fd.Readdirnames(100) for _, name := range names { err1 := RemoveAll(path + string(PathSeparator) + name) diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go index 6f5bfa54f8f..f58c7e746d9 100644 --- a/libgo/go/os/path_test.go +++ b/libgo/go/os/path_test.go @@ -5,6 +5,7 @@ package os_test import ( + "fmt" "internal/testenv" "io/ioutil" . "os" @@ -169,6 +170,36 @@ func TestRemoveAll(t *testing.T) { } } +// Test RemoveAll on a large directory. +func TestRemoveAllLarge(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + tmpDir := TempDir() + // Work directory. + path := tmpDir + "/_TestRemoveAllLarge_" + + // Make directory with 1000 files and remove. + if err := MkdirAll(path, 0777); err != nil { + t.Fatalf("MkdirAll %q: %s", path, err) + } + for i := 0; i < 1000; i++ { + fpath := fmt.Sprintf("%s/file%d", path, i) + fd, err := Create(fpath) + if err != nil { + t.Fatalf("create %q: %s", fpath, err) + } + fd.Close() + } + if err := RemoveAll(path); err != nil { + t.Fatalf("RemoveAll %q: %s", path, err) + } + if _, err := Lstat(path); err == nil { + t.Fatalf("Lstat %q succeeded after RemoveAll", path) + } +} + func TestMkdirAllWithSymlink(t *testing.T) { testenv.MustHaveSymlink(t) diff --git a/libgo/go/os/pipe_bsd.go b/libgo/go/os/pipe_bsd.go index ae153fa00d6..8398a242760 100644 --- a/libgo/go/os/pipe_bsd.go +++ b/libgo/go/os/pipe_bsd.go @@ -24,5 +24,5 @@ func Pipe() (r *File, w *File, err error) { syscall.CloseOnExec(p[1]) syscall.ForkLock.RUnlock() - return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil + return newFile(uintptr(p[0]), "|0", kindPipe), newFile(uintptr(p[1]), "|1", kindPipe), nil } diff --git a/libgo/go/os/pipe_freebsd.go b/libgo/go/os/pipe_freebsd.go index ea6622cd260..93bd869afd4 100644 --- a/libgo/go/os/pipe_freebsd.go +++ b/libgo/go/os/pipe_freebsd.go @@ -13,22 +13,8 @@ func Pipe() (r *File, w *File, err error) { e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC) if e != nil { - // Fallback support for FreeBSD 9, which lacks Pipe2. - // - // TODO: remove this for Go 1.10 when FreeBSD 9 - // is removed (Issue 19072). - - // See ../syscall/exec.go for description of lock. - syscall.ForkLock.RLock() - e := syscall.Pipe(p[0:]) - if e != nil { - syscall.ForkLock.RUnlock() - return nil, nil, NewSyscallError("pipe", e) - } - syscall.CloseOnExec(p[0]) - syscall.CloseOnExec(p[1]) - syscall.ForkLock.RUnlock() + return nil, nil, NewSyscallError("pipe", e) } - return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil + return newFile(uintptr(p[0]), "|0", kindPipe), newFile(uintptr(p[1]), "|1", kindPipe), nil } diff --git a/libgo/go/os/pipe_linux.go b/libgo/go/os/pipe_linux.go index 96f2ce900cb..acd7b88e1d4 100644 --- a/libgo/go/os/pipe_linux.go +++ b/libgo/go/os/pipe_linux.go @@ -29,5 +29,5 @@ func Pipe() (r *File, w *File, err error) { return nil, nil, NewSyscallError("pipe2", e) } - return newFile(uintptr(p[0]), "|0", true), newFile(uintptr(p[1]), "|1", true), nil + return newFile(uintptr(p[0]), "|0", kindPipe), newFile(uintptr(p[1]), "|1", kindPipe), nil } diff --git a/libgo/go/os/signal/internal/pty/pty.go b/libgo/go/os/signal/internal/pty/pty.go new file mode 100644 index 00000000000..4728de71d43 --- /dev/null +++ b/libgo/go/os/signal/internal/pty/pty.go @@ -0,0 +1,62 @@ +// Copyright 2017 The Go 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,!android netbsd openbsd + +// Package pty is a simple pseudo-terminal package for Unix systems, +// implemented by calling C functions via cgo. +// This is only used for testing the os/signal package. +package pty + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +//extern posix_openpt +func posix_openpt(int32) int32 + +//extern grantpt +func grantpt(int32) int32 + +//extern unlockpt +func unlockpt(int32) int32 + +//extern ptsname +func ptsname(int32) *byte + +//extern close +func close(int32) int32 + +const _O_RDWR = 2 + +// Open returns a master pty and the name of the linked slave tty. +func Open() (master *os.File, slave string, err error) { + m := posix_openpt(_O_RDWR) + if m < 0 { + return nil, "", fmt.Errorf("posix_openpt: %v", syscall.GetErrno()) + } + if grantpt(m) < 0 { + errno := syscall.GetErrno() + close(m) + return nil, "", fmt.Errorf("grantpt: %v", errno) + } + if unlockpt(m) < 0 { + errno := syscall.GetErrno() + close(m) + return nil, "", fmt.Errorf("unlockpt: %v", errno) + } + p := ptsname(m) + s := (*[32000]byte)(unsafe.Pointer(p))[:] + for i, v := range s { + if v == 0 { + s = s[:i:i] + break + } + } + slave = string(s) + return os.NewFile(uintptr(m), "pty-master"), slave, nil +} diff --git a/libgo/go/os/signal/signal_cgo_test.go b/libgo/go/os/signal/signal_cgo_test.go new file mode 100644 index 00000000000..27707fadcee --- /dev/null +++ b/libgo/go/os/signal/signal_cgo_test.go @@ -0,0 +1,228 @@ +// Copyright 2017 The Go 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,!android netbsd openbsd +// +build cgo + +// Note that this test does not work on Solaris: issue #22849. +// Don't run the test on Android because at least some versions of the +// C library do not define the posix_openpt function. + +package signal_test + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "os" + "os/exec" + "os/signal/internal/pty" + "strconv" + "strings" + "syscall" + "testing" + "time" +) + +func TestTerminalSignal(t *testing.T) { + const enteringRead = "test program entering read" + if os.Getenv("GO_TEST_TERMINAL_SIGNALS") != "" { + var b [1]byte + fmt.Println(enteringRead) + n, err := os.Stdin.Read(b[:]) + if n == 1 { + if b[0] == '\n' { + // This is what we expect + fmt.Println("read newline") + } else { + fmt.Printf("read 1 byte: %q\n", b) + } + } else { + fmt.Printf("read %d bytes\n", n) + } + if err != nil { + fmt.Println(err) + os.Exit(1) + } + os.Exit(0) + } + + t.Parallel() + + // The test requires a shell that uses job control. + bash, err := exec.LookPath("bash") + if err != nil { + t.Skipf("could not find bash: %v", err) + } + + scale := 1 + if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { + if sc, err := strconv.Atoi(s); err == nil { + scale = sc + } + } + pause := time.Duration(scale) * 10 * time.Millisecond + wait := time.Duration(scale) * 5 * time.Second + + // The test only fails when using a "slow device," in this + // case a pseudo-terminal. + + master, sname, err := pty.Open() + if err != nil { + t.Fatal(err) + } + defer master.Close() + slave, err := os.OpenFile(sname, os.O_RDWR, 0) + if err != nil { + t.Fatal(err) + } + defer slave.Close() + + // Start an interactive shell. + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i") + cmd.Stdin = slave + cmd.Stdout = slave + cmd.Stderr = slave + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, + Setctty: true, + Ctty: int(slave.Fd()), + } + + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + + if err := slave.Close(); err != nil { + t.Errorf("closing slave: %v", err) + } + + progReady := make(chan bool) + sawPrompt := make(chan bool, 10) + const prompt = "prompt> " + + // Read data from master in the background. + go func() { + input := bufio.NewReader(master) + var line, handled []byte + for { + b, err := input.ReadByte() + if err != nil { + if len(line) > 0 || len(handled) > 0 { + t.Logf("%q", append(handled, line...)) + } + if perr, ok := err.(*os.PathError); ok { + err = perr.Err + } + // EOF means master is closed. + // EIO means child process is done. + // "file already closed" means deferred close of master has happened. + if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") { + t.Logf("error reading from master: %v", err) + } + return + } + + line = append(line, b) + + if b == '\n' { + t.Logf("%q", append(handled, line...)) + line = nil + handled = nil + continue + } + + if bytes.Contains(line, []byte(enteringRead)) { + close(progReady) + handled = append(handled, line...) + line = nil + } else if bytes.Contains(line, []byte(prompt)) && !bytes.Contains(line, []byte("PS1=")) { + sawPrompt <- true + handled = append(handled, line...) + line = nil + } + } + }() + + // Set the bash prompt so that we can see it. + if _, err := master.Write([]byte("PS1='" + prompt + "'\n")); err != nil { + t.Fatalf("setting prompt: %v", err) + } + select { + case <-sawPrompt: + case <-time.After(wait): + t.Fatal("timed out waiting for shell prompt") + } + + // Start a small program that reads from stdin + // (namely the code at the top of this function). + if _, err := master.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil { + t.Fatal(err) + } + + // Wait for the program to print that it is starting. + select { + case <-progReady: + case <-time.After(wait): + t.Fatal("timed out waiting for program to start") + } + + // Give the program time to enter the read call. + // It doesn't matter much if we occasionally don't wait long enough; + // we won't be testing what we want to test, but the overall test + // will pass. + time.Sleep(pause) + + // Send a ^Z to stop the program. + if _, err := master.Write([]byte{26}); err != nil { + t.Fatalf("writing ^Z to pty: %v", err) + } + + // Wait for the program to stop and return to the shell. + select { + case <-sawPrompt: + case <-time.After(wait): + t.Fatal("timed out waiting for shell prompt") + } + + // Restart the stopped program. + if _, err := master.Write([]byte("fg\n")); err != nil { + t.Fatalf("writing %q to pty: %v", "fg", err) + } + + // Give the process time to restart. + // This is potentially racy: if the process does not restart + // quickly enough then the byte we send will go to bash rather + // than the program. Unfortunately there isn't anything we can + // look for to know that the program is running again. + // bash will print the program name, but that happens before it + // restarts the program. + time.Sleep(10 * pause) + + // Write some data for the program to read, + // which should cause it to exit. + if _, err := master.Write([]byte{'\n'}); err != nil { + t.Fatalf("writing %q to pty: %v", "\n", err) + } + + // Wait for the program to exit. + select { + case <-sawPrompt: + case <-time.After(wait): + t.Fatal("timed out waiting for shell prompt") + } + + // Exit the shell with the program's exit status. + if _, err := master.Write([]byte("exit $?\n")); err != nil { + t.Fatalf("writing %q to pty: %v", "exit", err) + } + + if err = cmd.Wait(); err != nil { + t.Errorf("subprogram failed: %v", err) + } +} diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go index 10a4146f5e9..d27ff0bfbea 100644 --- a/libgo/go/os/signal/signal_test.go +++ b/libgo/go/os/signal/signal_test.go @@ -321,7 +321,9 @@ func TestAtomicStop(t *testing.T) { cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1") out, err := cmd.CombinedOutput() if err == nil { - t.Logf("iteration %d: output %s", i, out) + if len(out) > 0 { + t.Logf("iteration %d: output %s", i, out) + } } else { t.Logf("iteration %d: exit status %q: output: %s", i, err, out) } @@ -378,7 +380,7 @@ func atomicStopTestProgram() { case <-cs: case <-time.After(1 * time.Second): if !printed { - fmt.Print("lost signal on iterations:") + fmt.Print("lost signal on tries:") printed = true } fmt.Printf(" %d", i) diff --git a/libgo/go/os/sys_freebsd.go b/libgo/go/os/sys_freebsd.go index 273c2df1c12..3ec49faedf1 100644 --- a/libgo/go/os/sys_freebsd.go +++ b/libgo/go/os/sys_freebsd.go @@ -4,20 +4,7 @@ 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 - } -} +// The O_CLOEXEC flag was introduced in FreeBSD 8.3. +const supportsCloseOnExec bool = true diff --git a/libgo/go/os/timeout_test.go b/libgo/go/os/timeout_test.go new file mode 100644 index 00000000000..6f47ed04a97 --- /dev/null +++ b/libgo/go/os/timeout_test.go @@ -0,0 +1,589 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !nacl +// +build !plan9 +// +build !windows + +package os_test + +import ( + "fmt" + "internal/poll" + "io" + "io/ioutil" + "math/rand" + "os" + "runtime" + "sync" + "testing" + "time" +) + +func TestNonpollableDeadline(t *testing.T) { + // On BSD systems regular files seem to be pollable, + // so just run this test on Linux. + if runtime.GOOS != "linux" { + t.Skipf("skipping on %s", runtime.GOOS) + } + + f, err := ioutil.TempFile("", "ostest") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + defer f.Close() + deadline := time.Now().Add(10 * time.Second) + if err := f.SetDeadline(deadline); err != os.ErrNoDeadline { + t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) + } + if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline { + t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) + } + if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline { + t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) + } +} + +// noDeadline is a zero time.Time value, which cancels a deadline. +var noDeadline time.Time + +var readTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that read deadlines work, even if there's data ready + // to be read. + {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}}, + + {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}}, +} + +func TestReadTimeout(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + if _, err := w.Write([]byte("READ TIMEOUT TEST")); err != nil { + t.Fatal(err) + } + + for i, tt := range readTimeoutTests { + if err := r.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("#%d: %v", i, err) + } + var b [1]byte + for j, xerr := range tt.xerrs { + for { + n, err := r.Read(b[:]) + if xerr != nil { + if !os.IsTimeout(err) { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("#%d/%d: read %d; want 0", i, j, n) + } + break + } + } + } +} + +func TestReadTimeoutMustNotReturn(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + max := time.NewTimer(100 * time.Millisecond) + defer max.Stop() + ch := make(chan error) + go func() { + if err := r.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := r.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := r.SetReadDeadline(noDeadline); err != nil { + t.Error(err) + } + var b [1]byte + _, err := r.Read(b[:]) + ch <- err + }() + + select { + case err := <-ch: + t.Fatalf("expected Read to not return, but it returned with %v", err) + case <-max.C: + w.Close() + err := <-ch // wait for tester goroutine to stop + if os.IsTimeout(err) { + t.Fatal(err) + } + } +} + +var writeTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that write deadlines work, even if there's buffer + // space available to write. + {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}}, + + {10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}}, +} + +func TestWriteTimeout(t *testing.T) { + t.Parallel() + + for i, tt := range writeTimeoutTests { + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("%v", err) + } + for j, xerr := range tt.xerrs { + for { + n, err := w.Write([]byte("WRITE TIMEOUT TEST")) + if xerr != nil { + if !os.IsTimeout(err) { + t.Fatalf("%d: %v", j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("%d: wrote %d; want 0", j, n) + } + break + } + } + }) + } +} + +func TestWriteTimeoutMustNotReturn(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + max := time.NewTimer(100 * time.Millisecond) + defer max.Stop() + ch := make(chan error) + go func() { + if err := w.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := w.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := w.SetWriteDeadline(noDeadline); err != nil { + t.Error(err) + } + var b [1]byte + for { + if _, err := w.Write(b[:]); err != nil { + ch <- err + break + } + } + }() + + select { + case err := <-ch: + t.Fatalf("expected Write to not return, but it returned with %v", err) + case <-max.C: + r.Close() + err := <-ch // wait for tester goroutine to stop + if os.IsTimeout(err) { + t.Fatal(err) + } + } +} + +func timeoutReader(r *os.File, d, min, max time.Duration, ch chan<- error) { + var err error + defer func() { ch <- err }() + + t0 := time.Now() + if err = r.SetReadDeadline(time.Now().Add(d)); err != nil { + return + } + b := make([]byte, 256) + var n int + n, err = r.Read(b) + t1 := time.Now() + if n != 0 || err == nil || !os.IsTimeout(err) { + err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err) + return + } + if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { + err = fmt.Errorf("Read took %s; expected %s", dt, d) + return + } +} + +func TestReadTimeoutFluctuation(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + max := time.NewTimer(time.Second) + defer max.Stop() + ch := make(chan error) + go timeoutReader(r, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) + + select { + case <-max.C: + t.Fatal("Read took over 1s; expected 0.1s") + case err := <-ch: + if !os.IsTimeout(err) { + t.Fatal(err) + } + } +} + +func timeoutWriter(w *os.File, d, min, max time.Duration, ch chan<- error) { + var err error + defer func() { ch <- err }() + + t0 := time.Now() + if err = w.SetWriteDeadline(time.Now().Add(d)); err != nil { + return + } + var n int + for { + n, err = w.Write([]byte("TIMEOUT WRITER")) + if err != nil { + break + } + } + t1 := time.Now() + if err == nil || !os.IsTimeout(err) { + err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err) + return + } + if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { + err = fmt.Errorf("Write took %s; expected %s", dt, d) + return + } +} + +func TestWriteTimeoutFluctuation(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + d := time.Second + max := time.NewTimer(d) + defer max.Stop() + ch := make(chan error) + go timeoutWriter(w, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) + + select { + case <-max.C: + t.Fatalf("Write took over %v; expected 0.1s", d) + case err := <-ch: + if !os.IsTimeout(err) { + t.Fatal(err) + } + } +} + +func TestVariousDeadlines(t *testing.T) { + t.Parallel() + testVariousDeadlines(t) +} + +func TestVariousDeadlines1Proc(t *testing.T) { + // Cannot use t.Parallel - modifies global GOMAXPROCS. + if testing.Short() { + t.Skip("skipping in short mode") + } + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) + testVariousDeadlines(t) +} + +func TestVariousDeadlines4Proc(t *testing.T) { + // Cannot use t.Parallel - modifies global GOMAXPROCS. + if testing.Short() { + t.Skip("skipping in short mode") + } + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) + testVariousDeadlines(t) +} + +type neverEnding byte + +func (b neverEnding) Read(p []byte) (int, error) { + for i := range p { + p[i] = byte(b) + } + return len(p), nil +} + +func testVariousDeadlines(t *testing.T) { + type result struct { + n int64 + err error + d time.Duration + } + + handler := func(w *os.File, pasvch chan result) { + // The writer, with no timeouts of its own, + // sending bytes to clients as fast as it can. + t0 := time.Now() + n, err := io.Copy(w, neverEnding('a')) + dt := time.Since(t0) + pasvch <- result{n, err, dt} + } + + for _, timeout := range []time.Duration{ + 1 * time.Nanosecond, + 2 * time.Nanosecond, + 5 * time.Nanosecond, + 50 * time.Nanosecond, + 100 * time.Nanosecond, + 200 * time.Nanosecond, + 500 * time.Nanosecond, + 750 * time.Nanosecond, + 1 * time.Microsecond, + 5 * time.Microsecond, + 25 * time.Microsecond, + 250 * time.Microsecond, + 500 * time.Microsecond, + 1 * time.Millisecond, + 5 * time.Millisecond, + 100 * time.Millisecond, + 250 * time.Millisecond, + 500 * time.Millisecond, + 1 * time.Second, + } { + numRuns := 3 + if testing.Short() { + numRuns = 1 + if timeout > 500*time.Microsecond { + continue + } + } + for run := 0; run < numRuns; run++ { + t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + pasvch := make(chan result) + go handler(w, pasvch) + + tooLong := 5 * time.Second + max := time.NewTimer(tooLong) + defer max.Stop() + actvch := make(chan result) + go func() { + t0 := time.Now() + if err := r.SetDeadline(t0.Add(timeout)); err != nil { + t.Error(err) + } + n, err := io.Copy(ioutil.Discard, r) + dt := time.Since(t0) + r.Close() + actvch <- result{n, err, dt} + }() + + select { + case res := <-actvch: + if os.IsTimeout(res.err) { + t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n) + } else { + t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err) + } + case <-max.C: + t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout) + } + + select { + case res := <-pasvch: + t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err) + case <-max.C: + t.Fatalf("timeout waiting for writer to finish writing") + } + }) + } + } +} + +func TestReadWriteDeadlineRace(t *testing.T) { + t.Parallel() + + N := 1000 + if testing.Short() { + N = 50 + } + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + var wg sync.WaitGroup + wg.Add(3) + go func() { + defer wg.Done() + tic := time.NewTicker(2 * time.Microsecond) + defer tic.Stop() + for i := 0; i < N; i++ { + if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { + break + } + if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { + break + } + <-tic.C + } + }() + go func() { + defer wg.Done() + var b [1]byte + for i := 0; i < N; i++ { + _, err := r.Read(b[:]) + if err != nil && !os.IsTimeout(err) { + t.Error("Read returned non-timeout error", err) + } + } + }() + go func() { + defer wg.Done() + var b [1]byte + for i := 0; i < N; i++ { + _, err := w.Write(b[:]) + if err != nil && !os.IsTimeout(err) { + t.Error("Write returned non-timeout error", err) + } + } + }() + wg.Wait() // wait for tester goroutine to stop +} + +// TestRacyRead tests that it is safe to mutate the input Read buffer +// immediately after cancelation has occurred. +func TestRacyRead(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + var wg sync.WaitGroup + defer wg.Wait() + + go io.Copy(w, rand.New(rand.NewSource(0))) + + r.SetReadDeadline(time.Now().Add(time.Millisecond)) + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + b1 := make([]byte, 1024) + b2 := make([]byte, 1024) + for j := 0; j < 100; j++ { + _, err := r.Read(b1) + copy(b1, b2) // Mutate b1 to trigger potential race + if err != nil { + if !os.IsTimeout(err) { + t.Error(err) + } + r.SetReadDeadline(time.Now().Add(time.Millisecond)) + } + } + }() + } +} + +// TestRacyWrite tests that it is safe to mutate the input Write buffer +// immediately after cancelation has occurred. +func TestRacyWrite(t *testing.T) { + t.Parallel() + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer r.Close() + defer w.Close() + + var wg sync.WaitGroup + defer wg.Wait() + + go io.Copy(ioutil.Discard, r) + + w.SetWriteDeadline(time.Now().Add(time.Millisecond)) + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + b1 := make([]byte, 1024) + b2 := make([]byte, 1024) + for j := 0; j < 100; j++ { + _, err := w.Write(b1) + copy(b1, b2) // Mutate b1 to trigger potential race + if err != nil { + if !os.IsTimeout(err) { + t.Error(err) + } + w.SetWriteDeadline(time.Now().Add(time.Millisecond)) + } + } + }() + } +} diff --git a/libgo/go/os/user/cgo_lookup_unix.go b/libgo/go/os/user/cgo_lookup_unix.go index 9670ada4942..6c815b4d011 100644 --- a/libgo/go/os/user/cgo_lookup_unix.go +++ b/libgo/go/os/user/cgo_lookup_unix.go @@ -18,6 +18,9 @@ import ( // bytePtrToString takes a NUL-terminated array of bytes and convert // it to a Go string. func bytePtrToString(p *byte) string { + if p == nil { + return "" + } a := (*[10000]byte)(unsafe.Pointer(p)) i := 0 for a[i] != 0 { @@ -99,8 +102,8 @@ func lookupUnixUid(uid int) (*User, error) { func buildUser(pwd *syscall.Passwd) *User { u := &User{ - Uid: strconv.Itoa(int(pwd.Pw_uid)), - Gid: strconv.Itoa(int(pwd.Pw_gid)), + Uid: strconv.FormatUint(uint64(pwd.Pw_uid), 10), + Gid: strconv.FormatUint(uint64(pwd.Pw_gid), 10), Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))), Name: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))), HomeDir: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))), @@ -264,3 +267,11 @@ const maxBufferSize = 1 << 20 func isSizeReasonable(sz int64) bool { return sz > 0 && sz <= maxBufferSize } + +// Because we can't use cgo in tests: +func structPasswdForNegativeTest() syscall.Passwd { + sp := syscall.Passwd{} + sp.Pw_uid = 1<<32 - 2 + sp.Pw_gid = 1<<32 - 3 + return sp +} diff --git a/libgo/go/os/user/cgo_unix_test.go b/libgo/go/os/user/cgo_unix_test.go new file mode 100644 index 00000000000..674111800fb --- /dev/null +++ b/libgo/go/os/user/cgo_unix_test.go @@ -0,0 +1,24 @@ +// Copyright 2017 The Go 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 !android,linux netbsd openbsd solaris +// +build cgo + +package user + +import ( + "testing" +) + +// Issue 22739 +func TestNegativeUid(t *testing.T) { + sp := structPasswdForNegativeTest() + u := buildUser(&sp) + if g, w := u.Uid, "4294967294"; g != w { + t.Errorf("Uid = %q; want %q", g, w) + } + if g, w := u.Gid, "4294967293"; g != w { + t.Errorf("Gid = %q; want %q", g, w) + } +} diff --git a/libgo/go/os/user/listgroups_unix.go b/libgo/go/os/user/listgroups_unix.go index 8b2b13d563f..b142e2bfb72 100644 --- a/libgo/go/os/user/listgroups_unix.go +++ b/libgo/go/os/user/listgroups_unix.go @@ -15,9 +15,10 @@ import ( /* #include #include -#include */ +const maxGroups = 2048 + func listGroups(u *User) ([]string, error) { ug, err := strconv.Atoi(u.Gid) if err != nil { diff --git a/libgo/go/os/wait_wait6.go b/libgo/go/os/wait_wait6.go index b30981199e1..891f242dacd 100644 --- a/libgo/go/os/wait_wait6.go +++ b/libgo/go/os/wait_wait6.go @@ -30,11 +30,6 @@ func (p *Process) blockUntilWaitable() (bool, error) { } runtime.KeepAlive(p) if errno != 0 { - // The wait6 system call is supported only on FreeBSD - // 9.3 and above, so it may return an ENOSYS error. - if errno == syscall.ENOSYS { - return false, nil - } return false, NewSyscallError("wait6", errno) } return true, nil diff --git a/libgo/go/path/example_test.go b/libgo/go/path/example_test.go index 21ed1fb2fcd..5cac36c98f5 100644 --- a/libgo/go/path/example_test.go +++ b/libgo/go/path/example_test.go @@ -49,11 +49,15 @@ func ExampleClean() { func ExampleDir() { fmt.Println(path.Dir("/a/b/c")) fmt.Println(path.Dir("a/b/c")) + fmt.Println(path.Dir("/a/")) + fmt.Println(path.Dir("a/")) fmt.Println(path.Dir("/")) fmt.Println(path.Dir("")) // Output: // /a/b // a/b + // /a + // a // / // . } diff --git a/libgo/go/path/filepath/example_test.go b/libgo/go/path/filepath/example_test.go new file mode 100644 index 00000000000..d019c260c58 --- /dev/null +++ b/libgo/go/path/filepath/example_test.go @@ -0,0 +1,22 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package filepath_test + +import ( + "fmt" + "path/filepath" +) + +func ExampleExt() { + fmt.Printf("No dots: %q\n", filepath.Ext("index")) + fmt.Printf("One dot: %q\n", filepath.Ext("index.js")) + fmt.Printf("Two dots: %q\n", filepath.Ext("main.test.js")) + // Output: + // No dots: "" + // One dot: ".js" + // Two dots: ".js" +} diff --git a/libgo/go/path/filepath/example_unix_test.go b/libgo/go/path/filepath/example_unix_test.go index cd8233ceb6a..40bc547fe46 100644 --- a/libgo/go/path/filepath/example_unix_test.go +++ b/libgo/go/path/filepath/example_unix_test.go @@ -8,6 +8,7 @@ package filepath_test import ( "fmt" + "os" "path/filepath" ) @@ -79,3 +80,24 @@ func ExampleJoin() { // a/b/c // a/b/c } +func ExampleWalk() { + dir := "dir/to/walk" + subDirToSkip := "skip" // dir/to/walk/skip + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", dir, err) + return err + } + if info.IsDir() && info.Name() == subDirToSkip { + fmt.Printf("skipping a dir without errors: %+v \n", info.Name()) + return filepath.SkipDir + } + fmt.Printf("visited file: %q\n", path) + return nil + }) + + if err != nil { + fmt.Printf("error walking the path %q: %v\n", dir, err) + } +} diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index c242143c7a3..87f8faf21a0 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -351,23 +351,23 @@ type WalkFunc func(path string, info os.FileInfo, err error) error var lstat = os.Lstat // for testing -// walk recursively descends path, calling w. +// walk recursively descends path, calling walkFn. func walk(path string, info os.FileInfo, walkFn WalkFunc) error { - err := walkFn(path, info, nil) - if err != nil { - if info.IsDir() && err == SkipDir { - return nil - } - return err - } - if !info.IsDir() { - return nil + return walkFn(path, info, nil) } names, err := readDirNames(path) - if err != nil { - return walkFn(path, info, err) + err1 := walkFn(path, info, err) + // If err != nil, walk can't walk into this directory. + // err1 != nil means walkFn want walk to skip this directory or stop walking. + // Therefore, if one of err and err1 isn't nil, walk will return. + if err != nil || err1 != nil { + // The caller's behavior is controlled by the return value, which is decided + // by walkFn. walkFn may ignore err and return nil. + // If walkFn returns SkipDir, it will be handled by the caller. + // So walk should return whatever walkFn returns. + return err1 } for _, name := range names { diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index f2e92528a96..ccffdba78fc 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -392,6 +392,12 @@ func checkMarks(t *testing.T, report bool) { // If clear is true, any incoming error is cleared before return. The errors // are always accumulated, though. func mark(info os.FileInfo, err error, errors *[]error, clear bool) error { + name := info.Name() + walkTree(tree, tree.name, func(path string, n *Node) { + if n.name == name { + n.mark++ + } + }) if err != nil { *errors = append(*errors, err) if clear { @@ -399,12 +405,6 @@ func mark(info os.FileInfo, err error, errors *[]error, clear bool) error { } return err } - name := info.Name() - walkTree(tree, tree.name, func(path string, n *Node) { - if n.name == name { - n.mark++ - } - }) return nil } @@ -774,24 +774,50 @@ var EvalSymlinksTests = []EvalSymlinksTest{ {"test/linkabs", "/"}, } -// findEvalSymlinksTestDirsDest searches testDirs -// for matching path and returns correspondent dest. -func findEvalSymlinksTestDirsDest(t *testing.T, testDirs []EvalSymlinksTest, path string) string { - for _, d := range testDirs { - if d.path == path { - return d.dest - } - } - t.Fatalf("did not find %q in testDirs slice", path) - return "" -} - // simpleJoin builds a file name from the directory and path. // It does not use Join because we don't want ".." to be evaluated. func simpleJoin(dir, path string) string { return dir + string(filepath.Separator) + path } +func testEvalSymlinks(t *testing.T, path, want string) { + have, err := filepath.EvalSymlinks(path) + if err != nil { + t.Errorf("EvalSymlinks(%q) error: %v", path, err) + return + } + if filepath.Clean(have) != filepath.Clean(want) { + t.Errorf("EvalSymlinks(%q) returns %q, want %q", path, have, want) + } +} + +func testEvalSymlinksAfterChdir(t *testing.T, wd, path, want string) { + cwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.Chdir(cwd) + if err != nil { + t.Fatal(err) + } + }() + + err = os.Chdir(wd) + if err != nil { + t.Fatal(err) + } + + have, err := filepath.EvalSymlinks(path) + if err != nil { + t.Errorf("EvalSymlinks(%q) in %q directory error: %v", path, wd, err) + return + } + if filepath.Clean(have) != filepath.Clean(want) { + t.Errorf("EvalSymlinks(%q) in %q directory returns %q, want %q", path, wd, have, want) + } +} + func TestEvalSymlinks(t *testing.T) { testenv.MustHaveSymlink(t) @@ -808,22 +834,8 @@ func TestEvalSymlinks(t *testing.T) { t.Fatal("eval symlink for tmp dir:", err) } - tests := EvalSymlinksTests - testdirs := EvalSymlinksTestDirs - if runtime.GOOS == "windows" { - if len(tmpDir) < 3 { - t.Fatalf("tmpDir path %q is too short", tmpDir) - } - if tmpDir[1] != ':' { - t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir) - } - newtest := EvalSymlinksTest{"test/linkabswin", tmpDir[:3]} - tests = append(tests, newtest) - testdirs = append(testdirs, newtest) - } - // Create the symlink farm using relative paths. - for _, d := range testdirs { + for _, d := range EvalSymlinksTestDirs { var err error path := simpleJoin(tmpDir, d.path) if d.dest == "" { @@ -836,135 +848,37 @@ func TestEvalSymlinks(t *testing.T) { } } - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - // Evaluate the symlink farm. - for _, d := range tests { - path := simpleJoin(tmpDir, d.path) - dest := simpleJoin(tmpDir, d.dest) - if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { - dest = d.dest - } - if p, err := filepath.EvalSymlinks(path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) + for _, test := range EvalSymlinksTests { + path := simpleJoin(tmpDir, test.path) + + dest := simpleJoin(tmpDir, test.dest) + if filepath.IsAbs(test.dest) || os.IsPathSeparator(test.dest[0]) { + dest = test.dest } + testEvalSymlinks(t, path, dest) // test EvalSymlinks(".") - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(path) - if err != nil { - t.Error(err) - return - } - p, err := filepath.EvalSymlinks(".") - if err != nil { - t.Errorf(`EvalSymlinks(".") in %q directory error: %v`, d.path, err) - return - } - if p == "." { - return - } - want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path)) - if p == want { - return - } - t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want) - }() + testEvalSymlinksAfterChdir(t, path, ".", ".") // test EvalSymlinks("C:.") on Windows if runtime.GOOS == "windows" { - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(path) - if err != nil { - t.Error(err) - return - } - - volDot := filepath.VolumeName(tmpDir) + "." - - p, err := filepath.EvalSymlinks(volDot) - if err != nil { - t.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot, d.path, err) - return - } - if p == volDot { - return - } - want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path)) - if p == want { - return - } - t.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot, d.path, p, volDot, want) - }() + volDot := filepath.VolumeName(tmpDir) + "." + testEvalSymlinksAfterChdir(t, path, volDot, volDot) } // test EvalSymlinks(".."+path) - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(simpleJoin(tmpDir, "test")) - if err != nil { - t.Error(err) - return - } - - path := simpleJoin("..", d.path) - dest := simpleJoin("..", d.dest) - if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { - dest = d.dest - } + dotdotPath := simpleJoin("..", test.dest) + if filepath.IsAbs(test.dest) || os.IsPathSeparator(test.dest[0]) { + dotdotPath = test.dest + } + testEvalSymlinksAfterChdir(t, + simpleJoin(tmpDir, "test"), + simpleJoin("..", test.path), + dotdotPath) - if p, err := filepath.EvalSymlinks(path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) - } - }() - - // test EvalSymlinks where parameter is relative path - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(tmpDir) - if err != nil { - t.Error(err) - return - } - if p, err := filepath.EvalSymlinks(d.path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(d.dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest) - } - }() + // test EvalSymlinks(p) where p is relative path + testEvalSymlinksAfterChdir(t, tmpDir, test.path, test.dest) } } diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go index 0d8b62015c5..03542559f8b 100644 --- a/libgo/go/path/filepath/path_windows.go +++ b/libgo/go/path/filepath/path_windows.go @@ -100,9 +100,7 @@ func splitList(path string) []string { // Remove quotes. for i, s := range list { - if strings.Contains(s, `"`) { - list[i] = strings.Replace(s, `"`, ``, -1) - } + list[i] = strings.Replace(s, `"`, ``, -1) } return list diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go index f771fe3a8a3..78cde4aa090 100644 --- a/libgo/go/path/filepath/symlink_windows.go +++ b/libgo/go/path/filepath/symlink_windows.go @@ -5,6 +5,9 @@ package filepath import ( + "errors" + "internal/syscall/windows" + "os" "strings" "syscall" ) @@ -106,10 +109,100 @@ func toNorm(path string, normBase func(string) (string, error)) (string, error) return volume + normPath, nil } +// evalSymlinksUsingGetFinalPathNameByHandle uses Windows +// GetFinalPathNameByHandle API to retrieve the final +// path for the specified file. +func evalSymlinksUsingGetFinalPathNameByHandle(path string) (string, error) { + err := windows.LoadGetFinalPathNameByHandle() + if err != nil { + // we must be using old version of Windows + return "", err + } + + if path == "" { + return path, nil + } + + // Use Windows I/O manager to dereference the symbolic link, as per + // https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/ + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return "", err + } + h, err := syscall.CreateFile(p, 0, 0, nil, + syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) + if err != nil { + return "", err + } + defer syscall.CloseHandle(h) + + buf := make([]uint16, 100) + for { + n, err := windows.GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), windows.VOLUME_NAME_DOS) + if err != nil { + return "", err + } + if n < uint32(len(buf)) { + break + } + buf = make([]uint16, n) + } + s := syscall.UTF16ToString(buf) + if len(s) > 4 && s[:4] == `\\?\` { + s = s[4:] + if len(s) > 3 && s[:3] == `UNC` { + // return path like \\server\share\... + return `\` + s[3:], nil + } + return s, nil + } + return "", errors.New("GetFinalPathNameByHandle returned unexpected path=" + s) +} + +func samefile(path1, path2 string) bool { + fi1, err := os.Lstat(path1) + if err != nil { + return false + } + fi2, err := os.Lstat(path2) + if err != nil { + return false + } + return os.SameFile(fi1, fi2) +} + func evalSymlinks(path string) (string, error) { - path, err := walkSymlinks(path) + newpath, err := walkSymlinks(path) + if err != nil { + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 == nil { + return toNorm(newpath2, normBase) + } + return "", err + } + newpath, err = toNorm(newpath, normBase) if err != nil { + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 == nil { + return toNorm(newpath2, normBase) + } return "", err } - return toNorm(path, normBase) + if strings.ToUpper(newpath) == strings.ToUpper(path) { + // walkSymlinks did not actually walk any symlinks, + // so we don't need to try GetFinalPathNameByHandle. + return newpath, nil + } + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 != nil { + return newpath, nil + } + newpath2, err2 = toNorm(newpath2, normBase) + if err2 != nil { + return newpath, nil + } + if samefile(newpath, newpath2) { + return newpath, nil + } + return newpath2, nil } diff --git a/libgo/go/plugin/plugin.go b/libgo/go/plugin/plugin.go index c7744658122..c37b65fd824 100644 --- a/libgo/go/plugin/plugin.go +++ b/libgo/go/plugin/plugin.go @@ -20,6 +20,7 @@ package plugin // Plugin is a loaded Go plugin. type Plugin struct { pluginpath string + err string // set if plugin failed to load loaded chan struct{} // closed when loaded syms map[string]interface{} } diff --git a/libgo/go/plugin/plugin_dlopen.go b/libgo/go/plugin/plugin_dlopen.go index 3237598f06b..47f2b29a80b 100644 --- a/libgo/go/plugin/plugin_dlopen.go +++ b/libgo/go/plugin/plugin_dlopen.go @@ -49,75 +49,50 @@ func lastIndexByte(s string, c byte) int { return -1 } -// pathToPrefix converts raw string to the prefix that will be used in the symbol -// table. If modifying, modify the version in internal/obj/sym.go as well. -func pathToPrefix(s string) string { - slash := lastIndexByte(s, '/') - // check for chars that need escaping - n := 0 - for r := 0; r < len(s); r++ { - if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { - n++ - } - } - - // quick exit - if n == 0 { - return s - } - - // escape - const hex = "0123456789abcdef" - p := make([]byte, 0, len(s)+2*n) - for r := 0; r < len(s); r++ { - if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { - p = append(p, '%', hex[c>>4], hex[c&0xF]) - } else { - p = append(p, c) - } - } - - return string(p) -} - func open(name string) (*Plugin, error) { - cPath := (*C.char)(C.malloc(C.PATH_MAX + 1)) - defer C.free(unsafe.Pointer(cPath)) - - cRelName := C.CString(name) - defer C.free(unsafe.Pointer(cRelName)) - if C.realpath(cRelName, cPath) == nil { - return nil, errors.New("plugin.Open(" + name + "): realpath failed") + cPath := make([]byte, C.PATH_MAX+1) + cRelName := make([]byte, len(name)+1) + copy(cRelName, name) + if C.realpath( + (*C.char)(unsafe.Pointer(&cRelName[0])), + (*C.char)(unsafe.Pointer(&cPath[0]))) == nil { + return nil, errors.New(`plugin.Open("` + name + `"): realpath failed`) } - filepath := C.GoString(cPath) + filepath := C.GoString((*C.char)(unsafe.Pointer(&cPath[0]))) pluginsMu.Lock() if p := plugins[filepath]; p != nil { pluginsMu.Unlock() + if p.err != "" { + return nil, errors.New(`plugin.Open("` + name + `"): ` + p.err + ` (previous failure)`) + } <-p.loaded return p, nil } var cErr *C.char - h := C.pluginOpen(cPath, &cErr) + h := C.pluginOpen((*C.char)(unsafe.Pointer(&cPath[0])), &cErr) if h == 0 { pluginsMu.Unlock() - return nil, errors.New("plugin.Open: " + C.GoString(cErr)) + return nil, errors.New(`plugin.Open("` + name + `"): ` + C.GoString(cErr)) } // TODO(crawshaw): look for plugin note, confirm it is a Go plugin // and it was built with the correct toolchain. if len(name) > 3 && name[len(name)-3:] == ".so" { name = name[:len(name)-3] } - - pluginpath, syms, mismatchpkg := lastmoduleinit() - if mismatchpkg != "" { - pluginsMu.Unlock() - return nil, errors.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg) - } if plugins == nil { plugins = make(map[string]*Plugin) } + pluginpath, syms, errstr := lastmoduleinit() + if errstr != "" { + plugins[filepath] = &Plugin{ + pluginpath: pluginpath, + err: errstr, + } + pluginsMu.Unlock() + return nil, errors.New(`plugin.Open("` + name + `"): ` + errstr) + } // This function can be called from the init function of a plugin. // Drop a placeholder in the map so subsequent opens can wait on it. p := &Plugin{ @@ -127,9 +102,11 @@ func open(name string) (*Plugin, error) { plugins[filepath] = p pluginsMu.Unlock() - initStr := C.CString(pluginpath + ".init") - initFuncPC := C.pluginLookup(h, initStr, &cErr) - C.free(unsafe.Pointer(initStr)) + initStr := make([]byte, len(pluginpath)+6) + copy(initStr, pluginpath) + copy(initStr[len(pluginpath):], ".init") + + initFuncPC := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&initStr[0])), &cErr) if initFuncPC != nil { initFuncP := &initFuncPC initFunc := *(*func())(unsafe.Pointer(&initFuncP)) @@ -144,11 +121,14 @@ func open(name string) (*Plugin, error) { delete(syms, symName) symName = symName[1:] } - cname := C.CString(pathToPrefix(pluginpath) + "." + symName) - p := C.pluginLookup(h, cname, &cErr) - C.free(unsafe.Pointer(cname)) + + fullName := pluginpath + "." + symName + cname := make([]byte, len(fullName)+1) + copy(cname, fullName) + + p := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&cname[0])), &cErr) if p == nil { - return nil, errors.New("plugin.Open: could not find symbol " + symName + ": " + C.GoString(cErr)) + return nil, errors.New(`plugin.Open("` + name + `"): could not find symbol ` + symName + `: ` + C.GoString(cErr)) } valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym)) if isFunc { @@ -179,4 +159,4 @@ var ( ) // lastmoduleinit is defined in package runtime -func lastmoduleinit() (pluginpath string, syms map[string]interface{}, mismatchpkg string) +func lastmoduleinit() (pluginpath string, syms map[string]interface{}, errstr string) diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 736467319ee..6e748599de5 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -19,6 +19,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "testing" "time" "unicode" @@ -321,6 +322,89 @@ func TestSetValue(t *testing.T) { } } +func TestCanSetField(t *testing.T) { + type embed struct{ x, X int } + type Embed struct{ x, X int } + type S1 struct { + embed + x, X int + } + type S2 struct { + *embed + x, X int + } + type S3 struct { + Embed + x, X int + } + type S4 struct { + *Embed + x, X int + } + + type testCase struct { + index []int + canSet bool + } + tests := []struct { + val Value + cases []testCase + }{{ + val: ValueOf(&S1{}), + cases: []testCase{ + {[]int{0}, false}, + {[]int{0, 0}, false}, + {[]int{0, 1}, true}, + {[]int{1}, false}, + {[]int{2}, true}, + }, + }, { + val: ValueOf(&S2{embed: &embed{}}), + cases: []testCase{ + {[]int{0}, false}, + {[]int{0, 0}, false}, + {[]int{0, 1}, true}, + {[]int{1}, false}, + {[]int{2}, true}, + }, + }, { + val: ValueOf(&S3{}), + cases: []testCase{ + {[]int{0}, true}, + {[]int{0, 0}, false}, + {[]int{0, 1}, true}, + {[]int{1}, false}, + {[]int{2}, true}, + }, + }, { + val: ValueOf(&S4{Embed: &Embed{}}), + cases: []testCase{ + {[]int{0}, true}, + {[]int{0, 0}, false}, + {[]int{0, 1}, true}, + {[]int{1}, false}, + {[]int{2}, true}, + }, + }} + + for _, tt := range tests { + t.Run(tt.val.Type().Name(), func(t *testing.T) { + for _, tc := range tt.cases { + f := tt.val + for _, i := range tc.index { + if f.Kind() == Ptr { + f = f.Elem() + } + f = f.Field(i) + } + if got := f.CanSet(); got != tc.canSet { + t.Errorf("CanSet() = %v, want %v", got, tc.canSet) + } + } + }) + } +} + var _i = 7 var valueToStringTests = []pair{ @@ -584,6 +668,47 @@ func TestCopy(t *testing.T) { } } +func TestCopyString(t *testing.T) { + t.Run("Slice", func(t *testing.T) { + s := bytes.Repeat([]byte{'_'}, 8) + val := ValueOf(s) + + n := Copy(val, ValueOf("")) + if expecting := []byte("________"); n != 0 || !bytes.Equal(s, expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 0, s = %s", n, s, expecting) + } + + n = Copy(val, ValueOf("hello")) + if expecting := []byte("hello___"); n != 5 || !bytes.Equal(s, expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 5, s = %s", n, s, expecting) + } + + n = Copy(val, ValueOf("helloworld")) + if expecting := []byte("hellowor"); n != 8 || !bytes.Equal(s, expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 8, s = %s", n, s, expecting) + } + }) + t.Run("Array", func(t *testing.T) { + s := [...]byte{'_', '_', '_', '_', '_', '_', '_', '_'} + val := ValueOf(&s).Elem() + + n := Copy(val, ValueOf("")) + if expecting := []byte("________"); n != 0 || !bytes.Equal(s[:], expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 0, s = %s", n, s[:], expecting) + } + + n = Copy(val, ValueOf("hello")) + if expecting := []byte("hello___"); n != 5 || !bytes.Equal(s[:], expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 5, s = %s", n, s[:], expecting) + } + + n = Copy(val, ValueOf("helloworld")) + if expecting := []byte("hellowor"); n != 8 || !bytes.Equal(s[:], expecting) { + t.Errorf("got n = %d, s = %s, expecting n = 8, s = %s", n, s[:], expecting) + } + }) +} + func TestCopyArray(t *testing.T) { a := [8]int{1, 2, 3, 4, 10, 9, 8, 7} b := [11]int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44} @@ -1506,6 +1631,15 @@ func TestFunc(t *testing.T) { } } +func TestCallConvert(t *testing.T) { + v := ValueOf(new(io.ReadWriter)).Elem() + f := ValueOf(func(r io.Reader) io.Reader { return r }) + out := f.Call([]Value{v}) + if len(out) != 1 || out[0].Type() != TypeOf(new(io.Reader)).Elem() || !out[0].IsNil() { + t.Errorf("expected [nil], got %v", out) + } +} + type emptyStruct struct{} type nonEmptyStruct struct { @@ -1546,6 +1680,33 @@ func TestCallWithStruct(t *testing.T) { } } +func TestCallReturnsEmpty(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("skipping on gccgo: imprecise stack can keep i live") + } + // Issue 21717: past-the-end pointer write in Call with + // nonzero-sized frame and zero-sized return value. + runtime.GC() + var finalized uint32 + f := func() (emptyStruct, *int) { + i := new(int) + runtime.SetFinalizer(i, func(*int) { atomic.StoreUint32(&finalized, 1) }) + return emptyStruct{}, i + } + v := ValueOf(f).Call(nil)[0] // out[0] should not alias out[1]'s memory, so the finalizer should run. + timeout := time.After(5 * time.Second) + for atomic.LoadUint32(&finalized) == 0 { + select { + case <-timeout: + t.Fatal("finalizer did not run") + default: + } + runtime.Gosched() + runtime.GC() + } + runtime.KeepAlive(v) +} + func BenchmarkCall(b *testing.B) { fv := ValueOf(func(a, b string) {}) b.ReportAllocs() @@ -2357,10 +2518,13 @@ func TestImportPath(t *testing.T) { } func TestFieldPkgPath(t *testing.T) { + type x int typ := TypeOf(struct { Exported string unexported string OtherPkgFields + int // issue 21702 + *x // issue 21122 }{}) type pkgpathTest struct { @@ -2387,6 +2551,8 @@ func TestFieldPkgPath(t *testing.T) { {[]int{2}, "", true}, // OtherPkgFields {[]int{2, 0}, "", false}, // OtherExported {[]int{2, 1}, "reflect", false}, // otherUnexported + {[]int{3}, "reflect_test", true}, // int + {[]int{4}, "reflect_test", true}, // *x }) type localOtherPkgFields OtherPkgFields @@ -3118,7 +3284,7 @@ func TestCallPanic(t *testing.T) { i := timp(0) v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}}) ok(func() { call(v.Field(0).Method(0)) }) // .t0.W - ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W + bad(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W bad(func() { call(v.Field(0).Method(1)) }) // .t0.w bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y @@ -3136,10 +3302,10 @@ func TestCallPanic(t *testing.T) { bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y - ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y - ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W - ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W - ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W + ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y + ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W + ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W + bad(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W @@ -5538,6 +5704,25 @@ func TestKeepFuncLive(t *testing.T) { MakeFunc(typ, f).Call([]Value{ValueOf(10)}) } +type UnExportedFirst int + +func (i UnExportedFirst) ΦExported() {} +func (i UnExportedFirst) unexported() {} + +// Issue 21177 +func TestMethodByNameUnExportedFirst(t *testing.T) { + defer func() { + if recover() != nil { + t.Errorf("should not panic") + } + }() + typ := TypeOf(UnExportedFirst(0)) + m, _ := typ.MethodByName("ΦExported") + if m.Name != "ΦExported" { + t.Errorf("got %s, expected ΦExported", m.Name) + } +} + // Issue 18635 (method version). type KeepMethodLive struct{} @@ -6292,3 +6477,37 @@ func TestAliasNames(t *testing.T) { t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want) } } + +func TestIssue22031(t *testing.T) { + type s []struct{ C int } + + type t1 struct{ s } + type t2 struct{ f s } + + tests := []Value{ + ValueOf(t1{s{{}}}).Field(0).Index(0).Field(0), + ValueOf(t2{s{{}}}).Field(0).Index(0).Field(0), + } + + for i, test := range tests { + if test.CanSet() { + t.Errorf("%d: CanSet: got true, want false", i) + } + } +} + +type NonExportedFirst int + +func (i NonExportedFirst) ΦExported() {} +func (i NonExportedFirst) nonexported() int { panic("wrong") } + +func TestIssue22073(t *testing.T) { + m := ValueOf(NonExportedFirst(0)).Method(0) + + if got := m.Type().NumOut(); got != 0 { + t.Errorf("NumOut: got %v, want 0", got) + } + + // Shouldn't panic. + m.Call(nil) +} diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index 92b13025380..203a3075117 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -62,7 +62,7 @@ func FirstMethodNameBytes(t Type) *byte { } m := ut.methods()[0] mname := t.(*rtype).nameOff(m.name) - if *mname.data(0)&(1<<2) == 0 { + if *mname.data(0, "name flag field")&(1<<2) == 0 { panic("method name does not have pkgPath *string") } return mname.bytes @@ -80,7 +80,7 @@ func IsExported(t Type) bool { /* func ResolveReflectName(s string) { - resolveReflectName(newName(s, "", "", false)) + resolveReflectName(newName(s, "", false)) } */ diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go index 5441cb03150..bf77b682c4d 100644 --- a/libgo/go/reflect/swapper.go +++ b/libgo/go/reflect/swapper.go @@ -65,8 +65,8 @@ func Swapper(slice interface{}) func(i, j int) { if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { panic("reflect: slice index out of range") } - val1 := arrayAt(s.Data, i, size) - val2 := arrayAt(s.Data, j, size) + val1 := arrayAt(s.Data, i, size, "i < s.Len") + val2 := arrayAt(s.Data, j, size, "j < s.Len") typedmemmove(typ, tmp, val1) typedmemmove(typ, val1, val2) typedmemmove(typ, val2, tmp) diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 664d9717a06..5402a93288b 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -214,7 +214,7 @@ type Type interface { // t.FieldByName("x") is not well defined if the struct type t contains // multiple fields named x (embedded from different packages). // FieldByName may return one of the fields named x or may report that there are none. -// See golang.org/issue/4876 for more details. +// See https://golang.org/issue/4876 for more details. /* * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). @@ -600,10 +600,15 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) { if ut == nil { return Method{}, false } - for i := range ut.methods { - p := &ut.methods[i] - if p.pkgPath == nil && p.name != nil && *p.name == name { - return t.Method(i), true + utmethods := ut.methods + var eidx int + for i := 0; i < len(utmethods); i++ { + p := utmethods[i] + if p.pkgPath == nil { + if p.name != nil && *p.name == name { + return t.Method(eidx), true + } + eidx++ } } return Method{}, false @@ -742,6 +747,17 @@ func (t *rtype) Out(i int) Type { return toType(tt.out[i]) } +// add returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + func (d ChanDir) String() string { switch d { case SendDir: @@ -2127,7 +2143,7 @@ func StructOf(fields []StructField) Type { typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr { o := seed for _, ft := range typ.fields { - pi := unsafe.Pointer(uintptr(p) + ft.offset()) + pi := add(p, ft.offset(), "&x.field safe") o = ft.typ.hashfn(pi, o) } return o @@ -2139,8 +2155,8 @@ func StructOf(fields []StructField) Type { if comparable { typ.equalfn = func(p, q unsafe.Pointer) bool { for _, ft := range typ.fields { - pi := unsafe.Pointer(uintptr(p) + ft.offset()) - qi := unsafe.Pointer(uintptr(q) + ft.offset()) + pi := add(p, ft.offset(), "&x.field safe") + qi := add(q, ft.offset(), "&x.field safe") if !ft.typ.equalfn(pi, qi) { return false } @@ -2360,8 +2376,8 @@ func ArrayOf(count int, elem Type) Type { eequal := typ.equalfn array.equalfn = func(p, q unsafe.Pointer) bool { for i := 0; i < count; i++ { - pi := arrayAt(p, i, esize) - qi := arrayAt(q, i, esize) + pi := arrayAt(p, i, esize, "i < count") + qi := arrayAt(q, i, esize, "i < count") if !eequal(pi, qi) { return false } @@ -2377,7 +2393,7 @@ func ArrayOf(count int, elem Type) Type { array.hashfn = func(ptr unsafe.Pointer, seed uintptr) uintptr { o := seed for i := 0; i < count; i++ { - o = ehash(arrayAt(ptr, i, esize), o) + o = ehash(arrayAt(ptr, i, esize, "i < count"), o) } return o } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 792699a6f65..3682b39f8a5 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -81,6 +81,13 @@ func (f flag) kind() Kind { return Kind(f & flagKindMask) } +func (f flag) ro() flag { + if f&flagRO != 0 { + return flagStickyRO + } + return 0 +} + // pointer returns the underlying pointer represented by v. // v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer func (v Value) pointer() unsafe.Pointer { @@ -177,7 +184,7 @@ type emptyInterface struct { word unsafe.Pointer } -// nonEmptyInterface is the header for a interface value with methods. +// nonEmptyInterface is the header for an interface value with methods. type nonEmptyInterface struct { // see ../runtime/iface.go:/Itab itab *struct { @@ -235,7 +242,7 @@ func (v Value) Addr() Value { if v.flag&flagAddr == 0 { panic("reflect.Value.Addr of unaddressable value") } - return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)} + return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)} } // Bool returns v's underlying value. @@ -485,11 +492,11 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn t = m.typ } else { rcvrtype = v.typ - ut := v.typ.uncommon() - if ut == nil || uint(i) >= uint(len(ut.methods)) { + ms := v.typ.exportedMethods() + if uint(i) >= uint(len(ms)) { panic("reflect: internal error: invalid method index") } - m := &ut.methods[i] + m := ms[i] if m.pkgPath != nil { panic("reflect: " + op + " of unexported method") } @@ -587,7 +594,7 @@ func (v Value) Elem() Value { } x := unpackEface(eface) if x.flag != 0 { - x.flag |= v.flag & flagRO + x.flag |= v.flag.ro() } return x case Ptr: @@ -635,8 +642,8 @@ func (v Value) Field(i int) Value { // or flagIndir is not set and v.ptr is the actual struct data. // In the former case, we want v.ptr + offset. // In the latter case, we must have field.offset = 0, - // so v.ptr + field.offset is still okay. - ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset()) + // so v.ptr + field.offset is still the correct address. + ptr := add(v.ptr, field.offset(), "same as non-reflect &v.field") return Value{typ, ptr, fl} } @@ -714,9 +721,9 @@ func (v Value) Index(i int) Value { // or flagIndir is not set and v.ptr is the actual array data. // In the former case, we want v.ptr + offset. // In the latter case, we must be doing Index(0), so offset = 0, - // so v.ptr + offset is still okay. - val := unsafe.Pointer(uintptr(v.ptr) + offset) - fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array + // so v.ptr + offset is still the correct address. + val := add(v.ptr, offset, "same as &v[i], i < tt.len") + fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array return Value{typ, val, fl} case Slice: @@ -728,8 +735,8 @@ func (v Value) Index(i int) Value { } tt := (*sliceType)(unsafe.Pointer(v.typ)) typ := tt.elem - val := arrayAt(s.Data, i, typ.size) - fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind()) + val := arrayAt(s.Data, i, typ.size, "i < s.Len") + fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind()) return Value{typ, val, fl} case String: @@ -737,8 +744,8 @@ func (v Value) Index(i int) Value { if uint(i) >= uint(s.Len) { panic("reflect: string index out of range") } - p := arrayAt(s.Data, i, 1) - fl := v.flag&flagRO | flag(Uint8) | flagIndir + p := arrayAt(s.Data, i, 1, "i < s.Len") + fl := v.flag.ro() | flag(Uint8) | flagIndir return Value{uint8Type, p, fl} } panic(&ValueError{"reflect.Value.Index", v.kind()}) @@ -926,17 +933,16 @@ func (v Value) MapIndex(key Value) Value { return Value{} } typ := tt.elem - fl := (v.flag | key.flag) & flagRO + fl := (v.flag | key.flag).ro() fl |= flag(typ.Kind()) - if ifaceIndir(typ) { - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(typ) - typedmemmove(typ, c, e) - return Value{typ, c, fl | flagIndir} - } else { + if !ifaceIndir(typ) { return Value{typ, *(*unsafe.Pointer)(e), fl} } + // Copy result so future changes to the map + // won't change the underlying value. + c := unsafe_New(typ) + typedmemmove(typ, c, e) + return Value{typ, c, fl | flagIndir} } // MapKeys returns a slice containing all the keys present in the map, @@ -948,7 +954,7 @@ func (v Value) MapKeys() []Value { tt := (*mapType)(unsafe.Pointer(v.typ)) keyType := tt.key - fl := v.flag&flagRO | flag(keyType.Kind()) + fl := v.flag.ro() | flag(keyType.Kind()) m := v.pointer() mlen := int(0) @@ -1420,7 +1426,10 @@ func (v Value) Slice(i, j int) Value { if i < 0 || j < i || j > s.Len { panic("reflect.Value.Slice: string slice index out of bounds") } - t := stringHeader{arrayAt(s.Data, i, 1), j - i} + var t stringHeader + if i < s.Len { + t = stringHeader{arrayAt(s.Data, i, 1, "i < s.Len"), j - i} + } return Value{v.typ, unsafe.Pointer(&t), v.flag} } @@ -1436,13 +1445,13 @@ func (v Value) Slice(i, j int) Value { s.Len = j - i s.Cap = cap - i if cap-i > 0 { - s.Data = arrayAt(base, i, typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size(), "i < cap") } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base } - fl := v.flag&flagRO | flagIndir | flag(Slice) + fl := v.flag.ro() | flagIndir | flag(Slice) return Value{typ.common(), unsafe.Pointer(&x), fl} } @@ -1488,13 +1497,13 @@ func (v Value) Slice3(i, j, k int) Value { s.Len = j - i s.Cap = k - i if k-i > 0 { - s.Data = arrayAt(base, i, typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size(), "i < k <= cap") } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base } - fl := v.flag&flagRO | flagIndir | flag(Slice) + fl := v.flag.ro() | flagIndir | flag(Slice) return Value{typ.common(), unsafe.Pointer(&x), fl} } @@ -1561,11 +1570,11 @@ func (v Value) Type() Type { return toType(m.typ) } // Method on concrete type. - ut := v.typ.uncommon() - if ut == nil || uint(i) >= uint(len(ut.methods)) { + ms := v.typ.exportedMethods() + if uint(i) >= uint(len(ms)) { panic("reflect: internal error: invalid method index") } - m := &ut.methods[i] + m := ms[i] return toType(m.mtyp) } @@ -1647,10 +1656,15 @@ func typesMustMatch(what string, t1, t2 Type) { } } -// arrayAt returns the i-th element of p, a C-array whose elements are -// eltSize wide (in bytes). -func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize) +// arrayAt returns the i-th element of p, +// an array whose elements are eltSize bytes wide. +// The array pointed at by p must have at least i+1 elements: +// it is invalid (but impossible to check here) to pass i >= len, +// because then the result will point outside the array. +// whySafe must explain why i < len. (Passing "i < len" is fine; +// the benefit is to surface this assumption at the call site.) +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { + return add(p, uintptr(i)*eltSize, "i < len") } // grow grows the slice s so that it can hold extra more values, allocating @@ -1708,6 +1722,8 @@ func AppendSlice(s, t Value) Value { // It returns the number of elements copied. // Dst and src each must have kind Slice or Array, and // dst and src must have the same element type. +// +// As a special case, src can have kind String if the element type of dst is kind Uint8. func Copy(dst, src Value) int { dk := dst.kind() if dk != Array && dk != Slice { @@ -1719,14 +1735,20 @@ func Copy(dst, src Value) int { dst.mustBeExported() sk := src.kind() + var stringCopy bool if sk != Array && sk != Slice { - panic(&ValueError{"reflect.Copy", sk}) + stringCopy = sk == String && dst.typ.Elem().Kind() == Uint8 + if !stringCopy { + panic(&ValueError{"reflect.Copy", sk}) + } } src.mustBeExported() de := dst.typ.Elem() - se := src.typ.Elem() - typesMustMatch("reflect.Copy", de, se) + if !stringCopy { + se := src.typ.Elem() + typesMustMatch("reflect.Copy", de, se) + } var ds, ss sliceHeader if dk == Array { @@ -1740,8 +1762,13 @@ func Copy(dst, src Value) int { ss.Data = src.ptr ss.Len = src.Len() ss.Cap = ss.Len - } else { + } else if sk == Slice { ss = *(*sliceHeader)(src.ptr) + } else { + sh := *(*stringHeader)(src.ptr) + ss.Data = sh.Data + ss.Len = sh.Len + ss.Cap = sh.Len } return typedslicecopy(de.common(), ds, ss) @@ -1929,7 +1956,7 @@ func MakeChan(typ Type, buffer int) Value { if typ.ChanDir() != BothDir { panic("reflect.MakeChan: unidirectional channel type") } - ch := makechan(typ.(*rtype), uint64(buffer)) + ch := makechan(typ.(*rtype), buffer) return Value{typ.common(), unsafe.Pointer(&ch), flag(Chan) | flagIndir} } @@ -2021,7 +2048,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value case directlyAssignable(dst, v.typ): // Overwrite type so that they match. // Same memory layout, so no harm done. - fl := v.flag & (flagRO | flagAddr | flagIndir) + fl := v.flag&(flagAddr|flagIndir) | v.flag.ro() fl |= flag(dst.Kind()) return Value{dst, v.ptr, fl} @@ -2029,6 +2056,12 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value if target == nil { target = unsafe_New(dst) } + if v.Kind() == Interface && v.IsNil() { + // A nil ReadWriter passed to nil Reader is OK, + // but using ifaceE2I below will panic. + // Avoid the panic by returning a nil dst (e.g., Reader) explicitly. + return Value{dst, nil, flag(Interface)} + } x := valueInterface(v, false) if dst.NumMethod() == 0 { *(*interface{})(target) = x @@ -2213,72 +2246,72 @@ func makeRunes(f flag, v []rune, t Type) Value { // convertOp: intXX -> [u]intXX func cvtInt(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(v.Int()), t) + return makeInt(v.flag.ro(), uint64(v.Int()), t) } // convertOp: uintXX -> [u]intXX func cvtUint(v Value, t Type) Value { - return makeInt(v.flag&flagRO, v.Uint(), t) + return makeInt(v.flag.ro(), v.Uint(), t) } // convertOp: floatXX -> intXX func cvtFloatInt(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t) + return makeInt(v.flag.ro(), uint64(int64(v.Float())), t) } // convertOp: floatXX -> uintXX func cvtFloatUint(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(v.Float()), t) + return makeInt(v.flag.ro(), uint64(v.Float()), t) } // convertOp: intXX -> floatXX func cvtIntFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, float64(v.Int()), t) + return makeFloat(v.flag.ro(), float64(v.Int()), t) } // convertOp: uintXX -> floatXX func cvtUintFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, float64(v.Uint()), t) + return makeFloat(v.flag.ro(), float64(v.Uint()), t) } // convertOp: floatXX -> floatXX func cvtFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, v.Float(), t) + return makeFloat(v.flag.ro(), v.Float(), t) } // convertOp: complexXX -> complexXX func cvtComplex(v Value, t Type) Value { - return makeComplex(v.flag&flagRO, v.Complex(), t) + return makeComplex(v.flag.ro(), v.Complex(), t) } // convertOp: intXX -> string func cvtIntString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Int()), t) + return makeString(v.flag.ro(), string(v.Int()), t) } // convertOp: uintXX -> string func cvtUintString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Uint()), t) + return makeString(v.flag.ro(), string(v.Uint()), t) } // convertOp: []byte -> string func cvtBytesString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Bytes()), t) + return makeString(v.flag.ro(), string(v.Bytes()), t) } // convertOp: string -> []byte func cvtStringBytes(v Value, t Type) Value { - return makeBytes(v.flag&flagRO, []byte(v.String()), t) + return makeBytes(v.flag.ro(), []byte(v.String()), t) } // convertOp: []rune -> string func cvtRunesString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.runes()), t) + return makeString(v.flag.ro(), string(v.runes()), t) } // convertOp: string -> []rune func cvtStringRunes(v Value, t Type) Value { - return makeRunes(v.flag&flagRO, []rune(v.String()), t) + return makeRunes(v.flag.ro(), []rune(v.String()), t) } // convertOp: direct copy @@ -2293,7 +2326,7 @@ func cvtDirect(v Value, typ Type) Value { ptr = c f &^= flagAddr } - return Value{t, ptr, v.flag&flagRO | f} // v.flag&flagRO|f == f? + return Value{t, ptr, v.flag.ro() | f} // v.flag.ro()|f == f? } // convertOp: concrete -> interface @@ -2305,14 +2338,14 @@ func cvtT2I(v Value, typ Type) Value { } else { ifaceE2I(typ.(*rtype), x, target) } - return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)} + return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)} } // convertOp: interface -> interface func cvtI2I(v Value, typ Type) Value { if v.IsNil() { ret := Zero(typ) - ret.flag |= v.flag & flagRO + ret.flag |= v.flag.ro() return ret } return cvtT2I(v.Elem(), typ) @@ -2337,7 +2370,7 @@ func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, receive //go:noescape func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool -func makechan(typ *rtype, size uint64) (ch unsafe.Pointer) +func makechan(typ *rtype, size int) (ch unsafe.Pointer) func makemap(t *rtype, cap int) (m unsafe.Pointer) //go:noescape diff --git a/libgo/go/regexp/backtrack.go b/libgo/go/regexp/backtrack.go index 29f624b54c7..440bf7ffc59 100644 --- a/libgo/go/regexp/backtrack.go +++ b/libgo/go/regexp/backtrack.go @@ -20,7 +20,7 @@ import "regexp/syntax" // the instruction pc and the position in the input. type job struct { pc uint32 - arg int + arg bool pos int } @@ -114,18 +114,12 @@ func (b *bitState) shouldVisit(pc uint32, pos int) bool { // push pushes (pc, pos, arg) onto the job stack if it should be // visited. -func (b *bitState) push(pc uint32, pos int, arg int) { - if b.prog.Inst[pc].Op == syntax.InstFail { - return +func (b *bitState) push(pc uint32, pos int, arg bool) { + // Only check shouldVisit when arg is false. + // When arg is true, we are continuing a previous visit. + if b.prog.Inst[pc].Op != syntax.InstFail && (arg || b.shouldVisit(pc, pos)) { + b.jobs = append(b.jobs, job{pc: pc, arg: arg, pos: pos}) } - - // Only check shouldVisit when arg == 0. - // When arg > 0, we are continuing a previous visit. - if arg == 0 && !b.shouldVisit(pc, pos) { - return - } - - b.jobs = append(b.jobs, job{pc: pc, arg: arg, pos: pos}) } // tryBacktrack runs a backtracking search starting at pos. @@ -133,7 +127,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { longest := m.re.longest m.matched = false - b.push(pc, pos, 0) + b.push(pc, pos, false) for len(b.jobs) > 0 { l := len(b.jobs) - 1 // Pop job off the stack. @@ -165,38 +159,36 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { panic("unexpected InstFail") case syntax.InstAlt: // Cannot just - // b.push(inst.Out, pos, 0) - // b.push(inst.Arg, pos, 0) + // b.push(inst.Out, pos, false) + // b.push(inst.Arg, pos, false) // If during the processing of inst.Out, we encounter // inst.Arg via another path, we want to process it then. // Pushing it here will inhibit that. Instead, re-push - // inst with arg==1 as a reminder to push inst.Arg out + // inst with arg==true as a reminder to push inst.Arg out // later. - switch arg { - case 0: - b.push(pc, pos, 1) - pc = inst.Out - goto CheckAndLoop - case 1: + if arg { // Finished inst.Out; try inst.Arg. - arg = 0 + arg = false pc = inst.Arg goto CheckAndLoop + } else { + b.push(pc, pos, true) + pc = inst.Out + goto CheckAndLoop } - panic("bad arg in InstAlt") case syntax.InstAltMatch: // One opcode consumes runes; the other leads to match. switch b.prog.Inst[inst.Out].Op { case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL: // inst.Arg is the match. - b.push(inst.Arg, pos, 0) + b.push(inst.Arg, pos, false) pc = inst.Arg pos = b.end goto CheckAndLoop } // inst.Out is the match - non-greedy - b.push(inst.Out, b.end, 0) + b.push(inst.Out, b.end, false) pc = inst.Out goto CheckAndLoop @@ -237,22 +229,19 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { goto CheckAndLoop case syntax.InstCapture: - switch arg { - case 0: + if arg { + // Finished inst.Out; restore the old value. + b.cap[inst.Arg] = pos + continue + } else { if 0 <= inst.Arg && inst.Arg < uint32(len(b.cap)) { // Capture pos to register, but save old value. - b.push(pc, b.cap[inst.Arg], 1) // come back when we're done. + b.push(pc, b.cap[inst.Arg], true) // come back when we're done. b.cap[inst.Arg] = pos } pc = inst.Out goto CheckAndLoop - case 1: - // Finished inst.Out; restore the old value. - b.cap[inst.Arg] = pos - continue - } - panic("bad arg in InstCapture") case syntax.InstEmptyWidth: if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 { diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go index f8fe7b5deff..84cb3e6fa51 100644 --- a/libgo/go/regexp/exec.go +++ b/libgo/go/regexp/exec.go @@ -16,7 +16,7 @@ type queue struct { dense []entry } -// A entry is an entry on a queue. +// An entry is an entry on a queue. // It holds both the instruction pc and the actual thread. // Some queue entries are just place holders so that the machine // knows it has considered that pc. Such entries have t == nil. @@ -338,15 +338,14 @@ func (m *machine) onepass(i input, pos, ncap int) bool { 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 { + if !i.hasPrefix(m.re) { return m.matched } + 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) } for { inst = m.op.Inst[pc] diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go index c32ae8d9fac..6c56371b4c9 100644 --- a/libgo/go/regexp/syntax/prog.go +++ b/libgo/go/regexp/syntax/prog.go @@ -247,15 +247,6 @@ func (i *Inst) MatchRunePos(r rune) int { return noMatch } -// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char. -// Since we act on runes, it would be easy to support Unicode here. -func wordRune(r rune) bool { - return r == '_' || - ('A' <= r && r <= 'Z') || - ('a' <= r && r <= 'z') || - ('0' <= r && r <= '9') -} - // MatchEmptyWidth reports whether the instruction matches // an empty string between the runes before and after. // It should only be called when i.Op == InstEmptyWidth. @@ -270,9 +261,9 @@ func (i *Inst) MatchEmptyWidth(before rune, after rune) bool { case EmptyEndText: return after == -1 case EmptyWordBoundary: - return wordRune(before) != wordRune(after) + return IsWordChar(before) != IsWordChar(after) case EmptyNoWordBoundary: - return wordRune(before) == wordRune(after) + return IsWordChar(before) == IsWordChar(after) } panic("unknown empty width arg") } diff --git a/libgo/go/runtime/alg.go b/libgo/go/runtime/alg.go index 174320fe85a..7c98f1bc940 100644 --- a/libgo/go/runtime/alg.go +++ b/libgo/go/runtime/alg.go @@ -57,18 +57,15 @@ const ( func memhash0(p unsafe.Pointer, h uintptr) uintptr { return h } + func memhash8(p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, 1) } + func memhash16(p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, 2) } -func memhash32(p unsafe.Pointer, h uintptr) uintptr { - return memhash(p, h, 4) -} -func memhash64(p unsafe.Pointer, h uintptr) uintptr { - return memhash(p, h, 8) -} + func memhash128(p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, 16) } diff --git a/libgo/go/runtime/append_test.go b/libgo/go/runtime/append_test.go index 6bd8f3bd951..ef1e812c0dc 100644 --- a/libgo/go/runtime/append_test.go +++ b/libgo/go/runtime/append_test.go @@ -18,42 +18,52 @@ func BenchmarkMakeSlice(b *testing.B) { } } -func BenchmarkGrowSliceBytes(b *testing.B) { - b.StopTimer() - var x = make([]byte, 9) - b.StartTimer() - for i := 0; i < b.N; i++ { - _ = append([]byte(nil), x...) - } -} - -func BenchmarkGrowSliceInts(b *testing.B) { - b.StopTimer() - var x = make([]int, 9) - b.StartTimer() - for i := 0; i < b.N; i++ { - _ = append([]int(nil), x...) - } -} - -func BenchmarkGrowSlicePtr(b *testing.B) { - b.StopTimer() - var x = make([]*byte, 9) - b.StartTimer() - for i := 0; i < b.N; i++ { - _ = append([]*byte(nil), x...) - } -} +type ( + struct24 struct{ a, b, c int64 } + struct32 struct{ a, b, c, d int64 } + struct40 struct{ a, b, c, d, e int64 } +) -type struct24 struct{ a, b, c int64 } +func BenchmarkGrowSlice(b *testing.B) { + b.Run("Byte", func(b *testing.B) { + x := make([]byte, 9) + for i := 0; i < b.N; i++ { + _ = append([]byte(nil), x...) + } + }) + b.Run("Int", func(b *testing.B) { + x := make([]int, 9) + for i := 0; i < b.N; i++ { + _ = append([]int(nil), x...) + } + }) + b.Run("Ptr", func(b *testing.B) { + x := make([]*byte, 9) + for i := 0; i < b.N; i++ { + _ = append([]*byte(nil), x...) + } + }) + b.Run("Struct", func(b *testing.B) { + b.Run("24", func(b *testing.B) { + x := make([]struct24, 9) + for i := 0; i < b.N; i++ { + _ = append([]struct24(nil), x...) + } + }) + b.Run("32", func(b *testing.B) { + x := make([]struct32, 9) + for i := 0; i < b.N; i++ { + _ = append([]struct32(nil), x...) + } + }) + b.Run("40", func(b *testing.B) { + x := make([]struct40, 9) + for i := 0; i < b.N; i++ { + _ = append([]struct40(nil), x...) + } + }) -func BenchmarkGrowSliceStruct24Bytes(b *testing.B) { - b.StopTimer() - var x = make([]struct24, 9) - b.StartTimer() - for i := 0; i < b.N; i++ { - _ = append([]struct24(nil), x...) - } + }) } func BenchmarkAppend(b *testing.B) { diff --git a/libgo/go/runtime/cgo_gccgo.go b/libgo/go/runtime/cgo_gccgo.go index c3bf9552ea8..05be4964500 100644 --- a/libgo/go/runtime/cgo_gccgo.go +++ b/libgo/go/runtime/cgo_gccgo.go @@ -27,6 +27,13 @@ var iscgo bool // The extra M must be created before any C/C++ code calls cgocallback. var cgoHasExtraM bool +// cgoAlwaysFalse is a boolean value that is always false. +// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }. +// The compiler cannot see that cgoAlwaysFalse is always false, +// so it emits the test and keeps the call, giving the desired +// escape analysis result. The test is cheaper than the call. +var cgoAlwaysFalse bool + // Cgocall prepares to call from code written in Go to code written in // C/C++. This takes the current goroutine out of the Go scheduler, as // though it were making a system call. Otherwise the program can @@ -37,12 +44,11 @@ var cgoHasExtraM bool // defer syscall.Cgocalldone() // cfunction() func Cgocall() { - lockOSThread() mp := getg().m mp.ncgocall++ mp.ncgo++ - mp.incgo = true entersyscall(0) + mp.incgo = true } // CgocallDone prepares to return to Go code from C/C++ code. @@ -59,8 +65,6 @@ func CgocallDone() { if readgstatus(gp)&^_Gscan == _Gsyscall { exitsyscall(0) } - - unlockOSThread() } // CgocallBack is used when calling from C/C++ code into Go code. @@ -78,6 +82,8 @@ func CgocallBack() { mp.dropextram = true } + lockOSThread() + exitsyscall(0) gp.m.incgo = false @@ -100,6 +106,8 @@ func CgocallBack() { // CgocallBackDone prepares to return to C/C++ code that has called // into Go code. func CgocallBackDone() { + unlockOSThread() + // If we are the top level Go function called from C/C++, then // we need to release the m. But don't release it if we are // panicing; since this is the top level, we are going to diff --git a/libgo/go/runtime/cgocall.go b/libgo/go/runtime/cgocall.go index 4a416fbf6ad..9d161202dfa 100644 --- a/libgo/go/runtime/cgocall.go +++ b/libgo/go/runtime/cgocall.go @@ -234,10 +234,8 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) { // No more possible pointers. break } - if hbits.isPointer() { - if cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) { - panic(errorString(msg)) - } + if hbits.isPointer() && cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) { + panic(errorString(msg)) } hbits = hbits.next() } diff --git a/libgo/go/runtime/cgocheck.go b/libgo/go/runtime/cgocheck.go index 30f054b3633..b85b519460e 100644 --- a/libgo/go/runtime/cgocheck.go +++ b/libgo/go/runtime/cgocheck.go @@ -16,6 +16,10 @@ const cgoWriteBarrierFail = "Go pointer stored into non-Go memory" // cgoCheckWriteBarrier is called whenever a pointer is stored into memory. // It throws if the program is storing a Go pointer into non-Go memory. +// +// This is called from the write barrier, so its entire call tree must +// be nosplit. +// //go:nosplit //go:nowritebarrier func cgoCheckWriteBarrier(dst *uintptr, src uintptr) { diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go index 7bb919c41db..8db728d5430 100644 --- a/libgo/go/runtime/chan.go +++ b/libgo/go/runtime/chan.go @@ -64,11 +64,19 @@ type waitq struct { } //go:linkname reflect_makechan reflect.makechan -func reflect_makechan(t *chantype, size int64) *hchan { +func reflect_makechan(t *chantype, size int) *hchan { return makechan(t, size) } -func makechan(t *chantype, size int64) *hchan { +func makechan64(t *chantype, size int64) *hchan { + if int64(int(size)) != size { + panic(plainError("makechan: size out of range")) + } + + return makechan(t, int(size)) +} + +func makechan(t *chantype, size int) *hchan { elem := t.elem // compiler checks this but be safe. @@ -78,29 +86,33 @@ func makechan(t *chantype, size int64) *hchan { if hchanSize%maxAlign != 0 || elem.align > maxAlign { throw("makechan: bad alignment") } - if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) { + + if size < 0 || uintptr(size) > maxSliceCap(elem.size) || uintptr(size)*elem.size > _MaxMem-hchanSize { panic(plainError("makechan: size out of range")) } + // Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers. + // buf points into the same allocation, elemtype is persistent. + // SudoG's are referenced from their owning thread so they can't be collected. + // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. var c *hchan - if elem.kind&kindNoPointers != 0 || size == 0 { - // Allocate memory in one call. - // Hchan does not contain pointers interesting for GC in this case: - // buf points into the same allocation, elemtype is persistent. - // SudoG's are referenced from their owning thread so they can't be collected. - // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. + switch { + case size == 0 || elem.size == 0: + // Queue or element size is zero. + c = (*hchan)(mallocgc(hchanSize, nil, true)) + // Race detector uses this location for synchronization. + c.buf = unsafe.Pointer(c) + case elem.kind&kindNoPointers != 0: + // Elements do not contain pointers. + // Allocate hchan and buf in one call. c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true)) - if size > 0 && elem.size != 0 { - c.buf = add(unsafe.Pointer(c), hchanSize) - } else { - // race detector uses this location for synchronization - // Also prevents us from pointing beyond the allocation (see issue 9401). - c.buf = unsafe.Pointer(c) - } - } else { + c.buf = add(unsafe.Pointer(c), hchanSize) + default: + // Elements contain pointers. c = new(hchan) - c.buf = newarray(elem, int(size)) + c.buf = mallocgc(uintptr(size)*elem.size, elem, true) } + c.elemsize = uint16(elem.size) c.elemtype = elem c.dataqsiz = uint(size) @@ -119,7 +131,7 @@ func chanbuf(c *hchan, i uint) unsafe.Pointer { // entry point for c <- x from compiled code //go:nosplit func chansend1(c *hchan, elem unsafe.Pointer) { - chansend(c, elem, true, getcallerpc(unsafe.Pointer(&c))) + chansend(c, elem, true, getcallerpc()) } /* @@ -223,7 +235,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { mysg.elem = ep mysg.waitlink = nil mysg.g = gp - mysg.selectdone = nil + mysg.isSelect = false mysg.c = c gp.waiting = mysg gp.param = nil @@ -331,7 +343,7 @@ func closechan(c *hchan) { } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&c)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan)) racerelease(unsafe.Pointer(c)) } @@ -508,7 +520,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) mysg.waitlink = nil gp.waiting = mysg mysg.g = gp - mysg.selectdone = nil + mysg.isSelect = false mysg.c = c gp.param = nil c.recvq.enqueue(mysg) @@ -603,7 +615,7 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { // } // func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) { - return chansend(c, elem, false, getcallerpc(unsafe.Pointer(&c))) + return chansend(c, elem, false, getcallerpc()) } // compiler implements @@ -653,7 +665,7 @@ func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool //go:linkname reflect_chansend reflect.chansend func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { - return chansend(c, elem, !nb, getcallerpc(unsafe.Pointer(&c))) + return chansend(c, elem, !nb, getcallerpc()) } //go:linkname reflect_chanrecv reflect.chanrecv @@ -712,10 +724,16 @@ func (q *waitq) dequeue() *sudog { sgp.next = nil // mark as removed (see dequeueSudog) } - // 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 || !atomic.Cas(sgp.selectdone, 0, 1) { + // if a goroutine was put on this queue because of a + // select, there is a small window between the goroutine + // being woken up by a different case and it grabbing the + // channel locks. Once it has the lock + // it removes itself from the queue, so we won't see it after that. + // We use a flag in the G struct to tell us when someone + // else has won the race to signal this goroutine but the goroutine + // hasn't removed itself from the queue yet. + if sgp.isSelect { + if !atomic.Cas(&sgp.g.selectDone, 0, 1) { continue } } diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go index b96af8af5d7..29fb321c926 100644 --- a/libgo/go/runtime/chan_test.go +++ b/libgo/go/runtime/chan_test.go @@ -5,6 +5,8 @@ package runtime_test import ( + "internal/testenv" + "math" "runtime" "sync" "sync/atomic" @@ -435,6 +437,65 @@ func TestSelectStress(t *testing.T) { wg.Wait() } +func TestSelectFairness(t *testing.T) { + const trials = 10000 + if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" { + testenv.SkipFlaky(t, 22047) + } + c1 := make(chan byte, trials+1) + c2 := make(chan byte, trials+1) + for i := 0; i < trials+1; i++ { + c1 <- 1 + c2 <- 2 + } + c3 := make(chan byte) + c4 := make(chan byte) + out := make(chan byte) + done := make(chan byte) + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + for { + var b byte + select { + case b = <-c3: + case b = <-c4: + case b = <-c1: + case b = <-c2: + } + select { + case out <- b: + case <-done: + return + } + } + }() + cnt1, cnt2 := 0, 0 + for i := 0; i < trials; i++ { + switch b := <-out; b { + case 1: + cnt1++ + case 2: + cnt2++ + default: + t.Fatalf("unexpected value %d on channel", b) + } + } + // If the select in the goroutine is fair, + // cnt1 and cnt2 should be about the same value. + // With 10,000 trials, the expected margin of error at + // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). + r := float64(cnt1) / trials + e := math.Abs(r - 0.5) + t.Log(cnt1, cnt2, r, e) + if e > 4.4172/(2*math.Sqrt(trials)) { + t.Errorf("unfair select: in %d trials, results were %d, %d", trials, cnt1, cnt2) + } + close(done) + wg.Wait() +} + func TestChanSendInterface(t *testing.T) { type mt struct{} m := &mt{} @@ -674,6 +735,55 @@ done: <-ready2 } +type struct0 struct{} + +func BenchmarkMakeChan(b *testing.B) { + b.Run("Byte", func(b *testing.B) { + var x chan byte + for i := 0; i < b.N; i++ { + x = make(chan byte, 8) + } + close(x) + }) + b.Run("Int", func(b *testing.B) { + var x chan int + for i := 0; i < b.N; i++ { + x = make(chan int, 8) + } + close(x) + }) + b.Run("Ptr", func(b *testing.B) { + var x chan *byte + for i := 0; i < b.N; i++ { + x = make(chan *byte, 8) + } + close(x) + }) + b.Run("Struct", func(b *testing.B) { + b.Run("0", func(b *testing.B) { + var x chan struct0 + for i := 0; i < b.N; i++ { + x = make(chan struct0, 8) + } + close(x) + }) + b.Run("32", func(b *testing.B) { + var x chan struct32 + for i := 0; i < b.N; i++ { + x = make(chan struct32, 8) + } + close(x) + }) + b.Run("40", func(b *testing.B) { + var x chan struct40 + for i := 0; i < b.N; i++ { + x = make(chan struct40, 8) + } + close(x) + }) + }) +} + func BenchmarkChanNonblocking(b *testing.B) { myc := make(chan int) b.RunParallel(func(pb *testing.PB) { diff --git a/libgo/go/runtime/cpuprof.go b/libgo/go/runtime/cpuprof.go index b031b1a5e75..91cdf2b5594 100644 --- a/libgo/go/runtime/cpuprof.go +++ b/libgo/go/runtime/cpuprof.go @@ -160,6 +160,7 @@ func (p *cpuProfile) addExtra() { funcPC(_ExternalCode) + sys.PCQuantum, } cpuprof.log.write(nil, 0, hdr[:], lostStk[:]) + p.lostExtra = 0 } } diff --git a/libgo/go/runtime/cputicks.go b/libgo/go/runtime/cputicks.go index ee15aca24ef..7e62dc1e108 100644 --- a/libgo/go/runtime/cputicks.go +++ b/libgo/go/runtime/cputicks.go @@ -4,6 +4,6 @@ package runtime -// careful: cputicks is not guaranteed to be monotonic! In particular, we have +// careful: cputicks is not guaranteed to be monotonic! In particular, we have // noticed drift between cpus on certain os/arch combinations. See issue 8976. func cputicks() int64 diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go index b79873185cc..7e14e573bc5 100644 --- a/libgo/go/runtime/crash_cgo_test.go +++ b/libgo/go/runtime/crash_cgo_test.go @@ -13,6 +13,7 @@ import ( "os" "os/exec" "runtime" + "strconv" "strings" "testing" "time" @@ -113,7 +114,7 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() if err != nil { t.Fatalf("exit status: %v\n%s", err, got) } @@ -136,7 +137,7 @@ func TestCgoExternalThreadSignal(t *testing.T) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() if err != nil { t.Fatalf("exit status: %v\n%s", err, got) } @@ -203,14 +204,14 @@ func TestCgoCheckBytes(t *testing.T) { const tries = 10 var tot1, tot2 time.Duration for i := 0; i < tries; i++ { - cmd := testEnv(exec.Command(exe, "CgoCheckBytes")) + cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) start := time.Now() cmd.Run() d1 := time.Since(start) - cmd = testEnv(exec.Command(exe, "CgoCheckBytes")) + cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) start = time.Now() @@ -251,7 +252,7 @@ func TestCgoCCodeSIGPROF(t *testing.T) { func TestCgoCrashTraceback(t *testing.T) { t.Parallel() - if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { + if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) } if runtime.Compiler == "gccgo" { @@ -279,7 +280,7 @@ func TestCgoTracebackContext(t *testing.T) { func testCgoPprof(t *testing.T, buildArg, runArg string) { t.Parallel() - if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { + if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) } if runtime.Compiler == "gccgo" { @@ -292,7 +293,7 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, runArg)).CombinedOutput() if err != nil { if testenv.Builder() == "linux-amd64-alpine" { // See Issue 18243 and Issue 19938. @@ -304,7 +305,7 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) { defer os.Remove(fn) for try := 0; try < 2; try++ { - cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1")) + cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1")) // Check that pprof works both with and without explicit executable on command line. if try == 0 { cmd.Args = append(cmd.Args, exe, fn) @@ -339,7 +340,7 @@ func TestCgoPprof(t *testing.T) { } func TestCgoPprofPIE(t *testing.T) { - testCgoPprof(t, "-ldflags=-extldflags=-pie", "CgoPprof") + testCgoPprof(t, "-buildmode=pie", "CgoPprof") } func TestCgoPprofThread(t *testing.T) { @@ -371,7 +372,7 @@ func TestRaceProf(t *testing.T) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput() if err != nil { t.Fatal(err) } @@ -400,7 +401,7 @@ func TestRaceSignal(t *testing.T) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput() if err != nil { t.Logf("%s\n", got) t.Fatal(err) @@ -423,3 +424,72 @@ func TestCgoNumGoroutine(t *testing.T) { t.Errorf("expected %q got %v", want, got) } } + +func TestCatchPanic(t *testing.T) { + t.Parallel() + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("no signals on %s", runtime.GOOS) + case "darwin": + if runtime.GOARCH == "amd64" { + t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT") + } + } + + testenv.MustHaveGoRun(t) + + exe, err := buildTestProg(t, "testprogcgo") + if err != nil { + t.Fatal(err) + } + + for _, early := range []bool{true, false} { + cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic")) + // Make sure a panic results in a crash. + cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") + if early { + // Tell testprogcgo to install an early signal handler for SIGABRT + cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1") + } + if out, err := cmd.CombinedOutput(); err != nil { + t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out) + } + } +} + +func TestCgoLockOSThreadExit(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("no pthreads on %s", runtime.GOOS) + } + t.Parallel() + testLockOSThreadExit(t, "testprogcgo") +} + +func TestWindowsStackMemoryCgo(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("skipping windows specific test") + } + testenv.SkipFlaky(t, 22575) + o := runTestProg(t, "testprogcgo", "StackMemory") + stackUsage, err := strconv.Atoi(o) + if err != nil { + t.Fatalf("Failed to read stack usage: %v", err) + } + if expected, got := 100<<10, stackUsage; got > expected { + t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got) + } +} + +func TestSigStackSwapping(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skip("no sigaltstack on %s", runtime.GOOS) + } + t.Parallel() + got := runTestProg(t, "testprogcgo", "SigStack") + want := "OK\n" + if got != want { + t.Errorf("expected %q got %v", want, got) + } +} diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index 1cde6bf7997..8ec034835ec 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -32,25 +32,6 @@ func TestMain(m *testing.M) { os.Exit(status) } -func testEnv(cmd *exec.Cmd) *exec.Cmd { - if cmd.Env != nil { - panic("environment already set") - } - for _, env := range os.Environ() { - // Exclude GODEBUG from the environment to prevent its output - // from breaking tests that are trying to parse other command output. - if strings.HasPrefix(env, "GODEBUG=") { - continue - } - // Exclude GOTRACEBACK for the same reason. - if strings.HasPrefix(env, "GOTRACEBACK=") { - continue - } - cmd.Env = append(cmd.Env, env) - } - return cmd -} - var testprog struct { sync.Mutex dir string @@ -62,7 +43,11 @@ type buildexe struct { err error } -func runTestProg(t *testing.T, binary, name string) string { +func runTestProg(t *testing.T, binary, name string, env ...string) string { + if *flagQuick { + t.Skip("-quick") + } + testenv.MustHaveGoBuild(t) exe, err := buildTestProg(t, binary) @@ -70,7 +55,11 @@ func runTestProg(t *testing.T, binary, name string) string { t.Fatal(err) } - cmd := testEnv(exec.Command(exe, name)) + cmd := testenv.CleanCmdEnv(exec.Command(exe, name)) + cmd.Env = append(cmd.Env, env...) + if testing.Short() { + cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1") + } var b bytes.Buffer cmd.Stdout = &b cmd.Stderr = &b @@ -111,6 +100,10 @@ func runTestProg(t *testing.T, binary, name string) string { } func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) { + if *flagQuick { + t.Skip("-quick") + } + checkStaleRuntime(t) testprog.Lock() @@ -139,7 +132,7 @@ func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) exe := filepath.Join(testprog.dir, name+".exe") cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...) cmd.Dir = "testdata/" + binary - out, err := testEnv(cmd).CombinedOutput() + out, err := testenv.CleanCmdEnv(cmd).CombinedOutput() if err != nil { target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out) testprog.target[name] = target @@ -158,14 +151,14 @@ var ( func checkStaleRuntime(t *testing.T) { staleRuntimeOnce.Do(func() { // 'go run' uses the installed copy of runtime.a, which may be out of date. - out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput() + out, err := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "list", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "-f", "{{.Stale}}", "runtime")).CombinedOutput() if err != nil { staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out)) return } if string(out) != "false\n" { t.Logf("go list -f {{.Stale}} runtime:\n%s", out) - out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.StaleReason}}", "runtime")).CombinedOutput() + out, err := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "list", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "-f", "{{.StaleReason}}", "runtime")).CombinedOutput() if err != nil { t.Logf("go list -f {{.StaleReason}} failed: %v", err) } @@ -483,7 +476,7 @@ func TestMemPprof(t *testing.T) { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "MemProf")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput() if err != nil { t.Fatal(err) } @@ -491,7 +484,7 @@ func TestMemPprof(t *testing.T) { defer os.Remove(fn) for try := 0; try < 2; try++ { - cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top")) + cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top")) // Check that pprof works both with and without explicit executable on command line. if try == 0 { cmd.Args = append(cmd.Args, exe, fn) @@ -606,7 +599,7 @@ func TestPanicRace(t *testing.T) { const tries = 10 retry: for i := 0; i < tries; i++ { - got, err := testEnv(exec.Command(exe, "PanicRace")).CombinedOutput() + got, err := testenv.CleanCmdEnv(exec.Command(exe, "PanicRace")).CombinedOutput() if err == nil { t.Logf("try %d: program exited successfully, should have failed", i+1) continue diff --git a/libgo/go/runtime/crash_unix_test.go b/libgo/go/runtime/crash_unix_test.go index 09c25471d10..584a6c74232 100644 --- a/libgo/go/runtime/crash_unix_test.go +++ b/libgo/go/runtime/crash_unix_test.go @@ -65,13 +65,13 @@ func TestCrashDumpsAllThreads(t *testing.T) { cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe") cmd.Dir = dir - out, err := testEnv(cmd).CombinedOutput() + out, err := testenv.CleanCmdEnv(cmd).CombinedOutput() if err != nil { t.Fatalf("building source: %v\n%s", err, out) } cmd = exec.Command(filepath.Join(dir, "a.exe")) - cmd = testEnv(cmd) + cmd = testenv.CleanCmdEnv(cmd) cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") // Set GOGC=off. Because of golang.org/issue/10958, the tight @@ -132,6 +132,7 @@ import ( "fmt" "os" "runtime" + "time" ) func main() { @@ -149,6 +150,8 @@ func main() { <-c } + time.Sleep(time.Millisecond) + // Tell our parent that all the goroutines are executing. if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) @@ -184,7 +187,7 @@ func TestPanicSystemstack(t *testing.T) { t.Parallel() cmd := exec.Command(os.Args[0], "testPanicSystemstackInternal") - cmd = testEnv(cmd) + cmd = testenv.CleanCmdEnv(cmd) cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") pr, pw, err := os.Pipe() if err != nil { @@ -249,7 +252,7 @@ func TestSignalExitStatus(t *testing.T) { if err != nil { t.Fatal(err) } - err = testEnv(exec.Command(exe, "SignalExitStatus")).Run() + err = testenv.CleanCmdEnv(exec.Command(exe, "SignalExitStatus")).Run() if err == nil { t.Error("test program succeeded unexpectedly") } else if ee, ok := err.(*exec.ExitError); !ok { diff --git a/libgo/go/runtime/debug.go b/libgo/go/runtime/debug.go index fdd73463aba..7cddd29ed0f 100644 --- a/libgo/go/runtime/debug.go +++ b/libgo/go/runtime/debug.go @@ -15,9 +15,6 @@ import ( // The number of logical CPUs on the local machine can be queried with NumCPU. // This call will go away when the scheduler improves. func GOMAXPROCS(n int) int { - if n > _MaxGomaxprocs { - n = _MaxGomaxprocs - } lock(&sched.lock) ret := int(gomaxprocs) unlock(&sched.lock) diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index 6325dcb3948..e385f14c5bc 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -149,12 +149,19 @@ func RunSchedLocalQueueEmptyTest(iters int) { } } -var StringHash = stringHash -var BytesHash = bytesHash -var Int32Hash = int32Hash -var Int64Hash = int64Hash -var EfaceHash = efaceHash -var IfaceHash = ifaceHash +var ( + StringHash = stringHash + BytesHash = bytesHash + Int32Hash = int32Hash + Int64Hash = int64Hash + MemHash = memhash + MemHash32 = memhash32 + MemHash64 = memhash64 + EfaceHash = efaceHash + IfaceHash = ifaceHash +) + +var UseAeshash = &useAeshash func MemclrBytes(b []byte) { s := (*slice)(unsafe.Pointer(&b)) @@ -364,3 +371,27 @@ func (rw *RWMutex) Lock() { func (rw *RWMutex) Unlock() { rw.rw.unlock() } + +func MapBucketsCount(m map[int]int) int { + h := *(**hmap)(unsafe.Pointer(&m)) + return 1 << h.B +} + +func MapBucketsPointerIsNil(m map[int]int) bool { + h := *(**hmap)(unsafe.Pointer(&m)) + return h.buckets == nil +} + +func LockOSCounts() (external, internal uint32) { + g := getg() + if g.m.lockedExt+g.m.lockedInt == 0 { + if g.lockedm != 0 { + panic("lockedm on non-locked goroutine") + } + } else { + if g.lockedm == 0 { + panic("nil lockedm on locked goroutine") + } + } + return g.m.lockedExt, g.m.lockedInt +} diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 6ca978980f2..36787e38b02 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -184,8 +184,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) // program counter adjustment. func Callers(skip int, pc []uintptr) int -// GOROOT returns the root of the Go tree. -// It uses the GOROOT environment variable, if set, +// GOROOT returns the root of the Go tree. It uses the +// GOROOT environment variable, if set at process start, // or else the root used during the Go build. func GOROOT() string { s := gogetenv("GOROOT") diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go index f14e0d5050e..a8c52d206f3 100644 --- a/libgo/go/runtime/gc_test.go +++ b/libgo/go/runtime/gc_test.go @@ -10,12 +10,14 @@ import ( "reflect" "runtime" "runtime/debug" + "sync/atomic" "testing" "time" "unsafe" ) func TestGcSys(t *testing.T) { + t.Skip("does not test anything; https://golang.org/issue/23343") if os.Getenv("GOGC") == "off" { t.Skip("skipping test; GOGC=off in environment") } @@ -171,7 +173,7 @@ func TestPeriodicGC(t *testing.T) { // slack if things are slow. var numGCs uint32 const want = 2 - for i := 0; i < 20 && numGCs < want; i++ { + for i := 0; i < 200 && numGCs < want; i++ { time.Sleep(5 * time.Millisecond) // Test that periodic GC actually happened. @@ -501,3 +503,142 @@ func BenchmarkReadMemStats(b *testing.B) { hugeSink = nil } + +func TestUserForcedGC(t *testing.T) { + // Test that runtime.GC() triggers a GC even if GOGC=off. + defer debug.SetGCPercent(debug.SetGCPercent(-1)) + + var ms1, ms2 runtime.MemStats + runtime.ReadMemStats(&ms1) + runtime.GC() + runtime.ReadMemStats(&ms2) + if ms1.NumGC == ms2.NumGC { + t.Fatalf("runtime.GC() did not trigger GC") + } + if ms1.NumForcedGC == ms2.NumForcedGC { + t.Fatalf("runtime.GC() was not accounted in NumForcedGC") + } +} + +func writeBarrierBenchmark(b *testing.B, f func()) { + runtime.GC() + var ms runtime.MemStats + runtime.ReadMemStats(&ms) + //b.Logf("heap size: %d MB", ms.HeapAlloc>>20) + + // Keep GC running continuously during the benchmark, which in + // turn keeps the write barrier on continuously. + var stop uint32 + done := make(chan bool) + go func() { + for atomic.LoadUint32(&stop) == 0 { + runtime.GC() + } + close(done) + }() + defer func() { + atomic.StoreUint32(&stop, 1) + <-done + }() + + b.ResetTimer() + f() + b.StopTimer() +} + +func BenchmarkWriteBarrier(b *testing.B) { + if runtime.GOMAXPROCS(-1) < 2 { + // We don't want GC to take our time. + b.Skip("need GOMAXPROCS >= 2") + } + + // Construct a large tree both so the GC runs for a while and + // so we have a data structure to manipulate the pointers of. + type node struct { + l, r *node + } + var wbRoots []*node + var mkTree func(level int) *node + mkTree = func(level int) *node { + if level == 0 { + return nil + } + n := &node{mkTree(level - 1), mkTree(level - 1)} + if level == 10 { + // Seed GC with enough early pointers so it + // doesn't accidentally switch to mark 2 when + // it only has the top of the tree. + wbRoots = append(wbRoots, n) + } + return n + } + const depth = 22 // 64 MB + root := mkTree(22) + + writeBarrierBenchmark(b, func() { + var stack [depth]*node + tos := -1 + + // There are two write barriers per iteration, so i+=2. + for i := 0; i < b.N; i += 2 { + if tos == -1 { + stack[0] = root + tos = 0 + } + + // Perform one step of reversing the tree. + n := stack[tos] + if n.l == nil { + tos-- + } else { + n.l, n.r = n.r, n.l + stack[tos] = n.l + stack[tos+1] = n.r + tos++ + } + + if i%(1<<12) == 0 { + // Avoid non-preemptible loops (see issue #10958). + runtime.Gosched() + } + } + }) + + runtime.KeepAlive(wbRoots) +} + +func BenchmarkBulkWriteBarrier(b *testing.B) { + if runtime.GOMAXPROCS(-1) < 2 { + // We don't want GC to take our time. + b.Skip("need GOMAXPROCS >= 2") + } + + // Construct a large set of objects we can copy around. + const heapSize = 64 << 20 + type obj [16]*byte + ptrs := make([]*obj, heapSize/unsafe.Sizeof(obj{})) + for i := range ptrs { + ptrs[i] = new(obj) + } + + writeBarrierBenchmark(b, func() { + const blockSize = 1024 + var pos int + for i := 0; i < b.N; i += blockSize { + // Rotate block. + block := ptrs[pos : pos+blockSize] + first := block[0] + copy(block, block[1:]) + block[blockSize-1] = first + + pos += blockSize + if pos+blockSize > len(ptrs) { + pos = 0 + } + + runtime.Gosched() + } + }) + + runtime.KeepAlive(ptrs) +} diff --git a/libgo/go/runtime/hash32.go b/libgo/go/runtime/hash32.go index dd2e657fe3f..401fe2857d9 100644 --- a/libgo/go/runtime/hash32.go +++ b/libgo/go/runtime/hash32.go @@ -86,6 +86,32 @@ tail: return uintptr(h) } +func memhash32(p unsafe.Pointer, seed uintptr) uintptr { + h := uint32(seed + 4*hashkey[0]) + h ^= readUnaligned32(p) + h = rotl_15(h*m1) * m2 + h ^= h >> 17 + h *= m3 + h ^= h >> 13 + h *= m4 + h ^= h >> 16 + return uintptr(h) +} + +func memhash64(p unsafe.Pointer, seed uintptr) uintptr { + h := uint32(seed + 8*hashkey[0]) + h ^= readUnaligned32(p) + h = rotl_15(h*m1) * m2 + h ^= readUnaligned32(add(p, 4)) + h = rotl_15(h*m1) * m2 + h ^= h >> 17 + h *= m3 + h ^= h >> 13 + h *= m4 + h ^= h >> 16 + return uintptr(h) +} + // Note: in order to get the compiler to issue rotl instructions, we // need to constant fold the shift amount by hand. // TODO: convince the compiler to issue rotl instructions after inlining. diff --git a/libgo/go/runtime/hash64.go b/libgo/go/runtime/hash64.go index f7d4a6f2f2a..5912943a4e9 100644 --- a/libgo/go/runtime/hash64.go +++ b/libgo/go/runtime/hash64.go @@ -86,6 +86,28 @@ tail: return uintptr(h) } +func memhash32(p unsafe.Pointer, seed uintptr) uintptr { + h := uint64(seed + 4*hashkey[0]) + v := uint64(readUnaligned32(p)) + h ^= v + h ^= v << 32 + h = rotl_31(h*m1) * m2 + h ^= h >> 29 + h *= m3 + h ^= h >> 32 + return uintptr(h) +} + +func memhash64(p unsafe.Pointer, seed uintptr) uintptr { + h := uint64(seed + 8*hashkey[0]) + h ^= uint64(readUnaligned32(p)) | uint64(readUnaligned32(add(p, 4)))<<32 + h = rotl_31(h*m1) * m2 + h ^= h >> 29 + h *= m3 + h ^= h >> 32 + return uintptr(h) +} + // Note: in order to get the compiler to issue rotl instructions, we // need to constant fold the shift amount by hand. // TODO: convince the compiler to issue rotl instructions after inlining. diff --git a/libgo/go/runtime/hash_test.go b/libgo/go/runtime/hash_test.go index 167c49eb5f5..54c91609f60 100644 --- a/libgo/go/runtime/hash_test.go +++ b/libgo/go/runtime/hash_test.go @@ -14,6 +14,40 @@ import ( "unsafe" ) +func TestMemHash32Equality(t *testing.T) { + if *UseAeshash { + t.Skip("skipping since AES hash implementation is used") + } + var b [4]byte + r := rand.New(rand.NewSource(1234)) + seed := uintptr(r.Uint64()) + for i := 0; i < 100; i++ { + randBytes(r, b[:]) + got := MemHash32(unsafe.Pointer(&b), seed) + want := MemHash(unsafe.Pointer(&b), seed, 4) + if got != want { + t.Errorf("MemHash32(%x, %v) = %v; want %v", b, seed, got, want) + } + } +} + +func TestMemHash64Equality(t *testing.T) { + if *UseAeshash { + t.Skip("skipping since AES hash implementation is used") + } + var b [8]byte + r := rand.New(rand.NewSource(1234)) + seed := uintptr(r.Uint64()) + for i := 0; i < 100; i++ { + randBytes(r, b[:]) + got := MemHash64(unsafe.Pointer(&b), seed) + want := MemHash(unsafe.Pointer(&b), seed, 8) + if got != want { + t.Errorf("MemHash64(%x, %v) = %v; want %v", b, seed, got, want) + } + } +} + // Smhasher is a torture test for hash functions. // https://code.google.com/p/smhasher/ // This code is a port of some of the Smhasher tests to Go. diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go index a3e50cd9221..a1fe49e9305 100644 --- a/libgo/go/runtime/hashmap.go +++ b/libgo/go/runtime/hashmap.go @@ -63,6 +63,8 @@ import ( // themselves, so that the compiler will export them. // //go:linkname makemap runtime.makemap +//go:linkname makemap64 runtime.makemap64 +//go:linkname makemap_small runtime.makemap_small //go:linkname mapaccess1 runtime.mapaccess1 //go:linkname mapaccess2 runtime.mapaccess2 //go:linkname mapaccess1_fat runtime.mapaccess1_fat @@ -77,8 +79,10 @@ const ( bucketCntBits = 3 bucketCnt = 1 << bucketCntBits - // Maximum average load of a bucket that triggers growth. - loadFactor = 6.5 + // Maximum average load of a bucket that triggers growth is 6.5. + // Represent as loadFactorNum/loadFactDen, to allow integer math. + loadFactorNum = 13 + loadFactorDen = 2 // Maximum key or value size to keep inline (instead of mallocing per element). // Must fit in a uint8. @@ -137,12 +141,13 @@ type mapextra struct { // If both key and value do not contain pointers and are inline, then we mark bucket // type as containing no pointers. This avoids scanning such maps. // However, bmap.overflow is a pointer. In order to keep overflow buckets - // alive, we store pointers to all overflow buckets in hmap.overflow. - // Overflow is used only if key and value do not contain pointers. - // overflow[0] contains overflow buckets for hmap.buckets. - // overflow[1] contains overflow buckets for hmap.oldbuckets. + // alive, we store pointers to all overflow buckets in hmap.overflow and h.map.oldoverflow. + // overflow and oldoverflow are only used if key and value do not contain pointers. + // overflow contains overflow buckets for hmap.buckets. + // oldoverflow contains overflow buckets for hmap.oldbuckets. // The indirection allows to store a pointer to the slice in hiter. - overflow [2]*[]*bmap + overflow *[]*bmap + oldoverflow *[]*bmap // nextOverflow holds a pointer to a free overflow bucket. nextOverflow *bmap @@ -171,7 +176,8 @@ type hiter struct { h *hmap buckets unsafe.Pointer // bucket ptr at hash_iter initialization time bptr *bmap // current bucket - overflow [2]*[]*bmap // keeps overflow buckets alive + overflow *[]*bmap // keeps overflow buckets of hmap.buckets alive + oldoverflow *[]*bmap // keeps overflow buckets of hmap.oldbuckets alive startBucket uintptr // bucket iteration started at offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) wrapped bool // already wrapped around from end of bucket array to beginning @@ -181,6 +187,28 @@ type hiter struct { checkBucket uintptr } +// bucketShift returns 1<> (sys.PtrSize*8 - 8)) + if top < minTopHash { + top += minTopHash + } + return top +} + func evacuated(b *bmap) bool { h := b.tophash[0] return h > empty && h < minTopHash @@ -194,6 +222,10 @@ func (b *bmap) setoverflow(t *maptype, ovf *bmap) { *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf } +func (b *bmap) keys() unsafe.Pointer { + return add(unsafe.Pointer(b), dataOffset) +} + // incrnoverflow increments h.noverflow. // noverflow counts the number of overflow buckets. // This is used to trigger same-size map growth. @@ -242,7 +274,7 @@ func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap { h.incrnoverflow() if t.bucket.kind&kindNoPointers != 0 { h.createOverflow() - *h.extra.overflow[0] = append(*h.extra.overflow[0], ovf) + *h.extra.overflow = append(*h.extra.overflow, ovf) } b.setoverflow(t, ovf) return ovf @@ -252,97 +284,69 @@ func (h *hmap) createOverflow() { if h.extra == nil { h.extra = new(mapextra) } - if h.extra.overflow[0] == nil { - h.extra.overflow[0] = new([]*bmap) + if h.extra.overflow == nil { + h.extra.overflow = new([]*bmap) } } -// makemap implements a Go map creation make(map[k]v, hint) +func makemap64(t *maptype, hint int64, h *hmap) *hmap { + if int64(int(hint)) != hint { + hint = 0 + } + return makemap(t, int(hint), h) +} + +// makehmap_small implements Go map creation for make(map[k]v) and +// make(map[k]v, hint) when hint is known to be at most bucketCnt +// at compile time and the map needs to be allocated on the heap. +func makemap_small() *hmap { + h := new(hmap) + h.hash0 = fastrand() + return h +} + +// makemap implements Go map creation for make(map[k]v, hint). // If the compiler has determined that the map or the first bucket // can be created on the stack, h and/or bucket may be non-nil. // If h != nil, the map can be created directly in h. -// If bucket != nil, bucket can be used as the first bucket. -func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { - if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != t.hmap.size { +// If h.buckets != nil, bucket pointed to can be used as the first bucket. +func makemap(t *maptype, hint int, h *hmap) *hmap { + // The size of hmap should be 48 bytes on 64 bit + // and 28 bytes on 32 bit platforms. + if sz := unsafe.Sizeof(hmap{}); sz != 8+5*sys.PtrSize { println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) throw("bad hmap size") } - if hint < 0 || hint > int64(maxSliceCap(t.bucket.size)) { + if hint < 0 || hint > int(maxSliceCap(t.bucket.size)) { hint = 0 } - if !ismapkey(t.key) { - throw("runtime.makemap: unsupported map key type") - } - - // check compiler's and reflect's math - if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(sys.PtrSize)) || - t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) { - throw("key size wrong") - } - if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(sys.PtrSize)) || - t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) { - throw("value size wrong") - } - - // invariants we depend on. We should probably check these at compile time - // somewhere, but for now we'll do it here. - if t.key.align > bucketCnt { - throw("key align too big") - } - if t.elem.align > bucketCnt { - throw("value align too big") - } - if t.key.size%uintptr(t.key.align) != 0 { - throw("key size not a multiple of key align") - } - if t.elem.size%uintptr(t.elem.align) != 0 { - throw("value size not a multiple of value align") - } - if bucketCnt < 8 { - throw("bucketsize too small for proper alignment") - } - if dataOffset%uintptr(t.key.align) != 0 { - throw("need padding in bucket (key)") - } - if dataOffset%uintptr(t.elem.align) != 0 { - throw("need padding in bucket (value)") + // initialize Hmap + if h == nil { + h = (*hmap)(newobject(t.hmap)) } + h.hash0 = fastrand() // find size parameter which will hold the requested # of elements B := uint8(0) - for ; overLoadFactor(hint, B); B++ { + for overLoadFactor(hint, B) { + B++ } + h.B = B // allocate initial hash table // if B == 0, the buckets field is allocated lazily later (in mapassign) // If hint is large zeroing this memory could take a while. - buckets := bucket - var extra *mapextra - if B != 0 { + if h.B != 0 { var nextOverflow *bmap - buckets, nextOverflow = makeBucketArray(t, B) + h.buckets, nextOverflow = makeBucketArray(t, h.B) if nextOverflow != nil { - extra = new(mapextra) - extra.nextOverflow = nextOverflow + h.extra = new(mapextra) + h.extra.nextOverflow = nextOverflow } } - // initialize Hmap - if h == nil { - h = (*hmap)(newobject(t.hmap)) - } - h.count = 0 - h.B = B - h.extra = extra - h.flags = 0 - h.hash0 = fastrand() - h.buckets = buckets - h.oldbuckets = nil - h.nevacuate = 0 - h.noverflow = 0 - return h } @@ -353,7 +357,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { // hold onto it for very long. func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() pc := funcPC(mapaccess1) racereadpc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) @@ -370,7 +374,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { hashfn := t.key.hashfn equalfn := t.key.equalfn hash := hashfn(key, uintptr(h.hash0)) - m := uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { + top := tophash(hash) + for ; b != nil; b = b.overflow(t) { for i := uintptr(0); i < bucketCnt; i++ { if b.tophash[i] != top { continue @@ -403,16 +404,13 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { return v } } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(&zeroVal[0]) - } } + return unsafe.Pointer(&zeroVal[0]) } func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() pc := funcPC(mapaccess2) racereadpc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) @@ -429,7 +427,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) hashfn := t.key.hashfn equalfn := t.key.equalfn hash := hashfn(key, uintptr(h.hash0)) - m := uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { + top := tophash(hash) + for ; b != nil; b = b.overflow(t) { for i := uintptr(0); i < bucketCnt; i++ { if b.tophash[i] != top { continue @@ -462,11 +457,8 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) return v, true } } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(&zeroVal[0]), false - } } + return unsafe.Pointer(&zeroVal[0]), false } // returns both key and value. Used by map iterator @@ -477,7 +469,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe hashfn := t.key.hashfn equalfn := t.key.equalfn hash := hashfn(key, uintptr(h.hash0)) - m := uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { + top := tophash(hash) + for ; b != nil; b = b.overflow(t) { for i := uintptr(0); i < bucketCnt; i++ { if b.tophash[i] != top { continue @@ -510,11 +499,8 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe return k, v } } - b = b.overflow(t) - if b == nil { - return nil, nil - } } + return nil, nil } func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer { @@ -539,7 +525,7 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { panic(plainError("assignment to entry in nil map")) } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() pc := funcPC(mapassign) racewritepc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) @@ -559,19 +545,16 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { h.flags |= hashWriting if h.buckets == nil { - h.buckets = newarray(t.bucket, 1) + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) } again: - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } + top := tophash(hash) var inserti *uint8 var insertk unsafe.Pointer @@ -611,7 +594,7 @@ again: // If we hit the max load factor or we have too many overflow buckets, // and we're not already in the middle of growing, start growing. - if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { hashGrow(t, h) goto again // Growing the table invalidates everything, so try again } @@ -651,7 +634,7 @@ done: func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() pc := funcPC(mapdelete) racewritepc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) @@ -674,16 +657,14 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { // in which case we have not actually done a write (delete). h.flags |= hashWriting - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { + b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize))) + top := tophash(hash) +search: + for ; b != nil; b = b.overflow(t) { for i := uintptr(0); i < bucketCnt; i++ { if b.tophash[i] != top { continue @@ -696,53 +677,58 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { if !equalfn(key, k2) { continue } + // Only clear key if there are pointers in it. if t.indirectkey { *(*unsafe.Pointer)(k) = nil - } else { - typedmemclr(t.key, k) + } else if t.key.kind&kindNoPointers == 0 { + memclrHasPointers(k, t.key.size) } - v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize)) - if t.indirectvalue { - *(*unsafe.Pointer)(v) = nil - } else { - typedmemclr(t.elem, v) + // Only clear value if there are pointers in it. + if t.indirectvalue || t.elem.kind&kindNoPointers == 0 { + v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) + if t.indirectvalue { + *(*unsafe.Pointer)(v) = nil + } else { + memclrHasPointers(v, t.elem.size) + } } b.tophash[i] = empty h.count-- - goto done - } - b = b.overflow(t) - if b == nil { - goto done + break search } } -done: if h.flags&hashWriting == 0 { throw("concurrent map writes") } h.flags &^= hashWriting } +// mapiterinit initializes the hiter struct used for ranging over maps. +// The hiter struct pointed to by 'it' is allocated on the stack +// by the compilers order pass or on the heap by reflect_mapiterinit. +// Both need to have zeroed hiter since the struct contains pointers. +// Gccgo-specific: *it need not be zeroed by the compiler, +// and it's cheaper to zero it here. 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 - it.overflow[0] = nil - it.overflow[1] = nil + it.overflow = nil + it.oldoverflow = nil + it.wrapped = false + it.i = 0 + it.checkBucket = 0 if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit)) } if h == nil || h.count == 0 { - it.key = nil - it.value = nil return } @@ -762,6 +748,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { // while we are iterating. h.createOverflow() it.overflow = h.extra.overflow + it.oldoverflow = h.extra.oldoverflow } // decide where to start @@ -769,16 +756,14 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { if h.B > 31-bucketCntBits { r += uintptr(fastrand()) << 31 } - it.startBucket = r & (uintptr(1)<> h.B & (bucketCnt - 1)) // iterator state it.bucket = it.startBucket - it.wrapped = false - it.bptr = nil // Remember we have an iterator. - // Can run concurrently with another hash_iter_init(). + // Can run concurrently with another mapiterinit(). if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator { atomic.Or8(&h.flags, iterator|oldIterator) } @@ -789,7 +774,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { func mapiternext(it *hiter) { h := it.h if raceenabled { - callerpc := getcallerpc(unsafe.Pointer( /* &it */ nil)) + callerpc := getcallerpc() racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext)) } if h.flags&hashWriting != 0 { @@ -829,7 +814,7 @@ next: checkBucket = noCheck } bucket++ - if bucket == uintptr(1)<>(it.B-1) != uintptr(b.tophash[offi]&1) { - continue - } - } - } - if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY { - // this is the golden data, we can return it. - if t.indirectkey { - k = *((*unsafe.Pointer)(k)) - } - it.key = k - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) + if checkBucket != noCheck && !h.sameSizeGrow() { + // Special case: iterator was started during a grow to a larger size + // and the grow is not done yet. We're working on a bucket whose + // oldbucket has not been evacuated yet. Or at least, it wasn't + // evacuated when we started the bucket. So we're iterating + // through the oldbucket, skipping any keys that will go + // to the other new bucket (each oldbucket expands to two + // buckets during a grow). + if t.reflexivekey || equalfn(k, k) { + // If the item in the oldbucket is not destined for + // the current new bucket in the iteration, skip it. + hash := hashfn(k, uintptr(h.hash0)) + if hash&bucketMask(it.B) != checkBucket { + continue } - it.value = v } else { - // The hash table has grown since the iterator was started. - // The golden data for this key is now somewhere else. - k2 := k - if t.indirectkey { - k2 = *((*unsafe.Pointer)(k2)) - } - if t.reflexivekey || equalfn(k2, k2) { - // Check the current hash table for the data. - // This code handles the case where the key - // has been deleted, updated, or deleted and reinserted. - // NOTE: we need to regrab the key as it has potentially been - // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). - rk, rv := mapaccessK(t, h, k2) - if rk == nil { - continue // key has been deleted - } - it.key = rk - it.value = rv - } else { - // if key!=key then the entry can't be deleted or - // updated, so we can just return it. That's lucky for - // us because when key!=key we can't look it up - // successfully in the current table. - it.key = k2 - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - it.value = v + // Hash isn't repeatable if k != k (NaNs). We need a + // repeatable and randomish choice of which direction + // to send NaNs during evacuation. We'll use the low + // bit of tophash to decide which way NaNs go. + // NOTE: this case is why we need two evacuate tophash + // values, evacuatedX and evacuatedY, that differ in + // their low bit. + if checkBucket>>(it.B-1) != uintptr(b.tophash[offi]&1) { + continue } } - it.bucket = bucket - if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 - it.bptr = b + } + if (b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY) || + !(t.reflexivekey || equalfn(k, k)) { + // This is the golden data, we can return it. + // OR + // key!=key, so the entry can't be deleted or updated, so we can just return it. + // That's lucky for us because when key!=key we can't look it up successfully. + it.key = k + if t.indirectvalue { + v = *((*unsafe.Pointer)(v)) } - it.i = i + 1 - it.checkBucket = checkBucket - return + it.value = v + } else { + // The hash table has grown since the iterator was started. + // The golden data for this key is now somewhere else. + // Check the current hash table for the data. + // This code handles the case where the key + // has been deleted, updated, or deleted and reinserted. + // NOTE: we need to regrab the key as it has potentially been + // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). + rk, rv := mapaccessK(t, h, k) + if rk == nil { + continue // key has been deleted + } + it.key = rk + it.value = rv } + it.bucket = bucket + if it.bptr != b { // avoid unnecessary write barrier; see issue 14921 + it.bptr = b + } + it.i = i + 1 + it.checkBucket = checkBucket + return } b = b.overflow(t) i = 0 @@ -928,7 +898,7 @@ next: } func makeBucketArray(t *maptype, b uint8) (buckets unsafe.Pointer, nextOverflow *bmap) { - base := uintptr(1 << b) + base := bucketShift(b) nbuckets := base // For small b, overflow buckets are unlikely. // Avoid the overhead of the calculation. @@ -936,7 +906,7 @@ func makeBucketArray(t *maptype, b uint8) (buckets unsafe.Pointer, nextOverflow // Add on the estimated number of overflow buckets // required to insert the median number of elements // used with this value of b. - nbuckets += 1 << (b - 4) + nbuckets += bucketShift(b - 4) sz := t.bucket.size * nbuckets up := roundupsize(sz) if up != sz { @@ -962,7 +932,7 @@ func hashGrow(t *maptype, h *hmap) { // Otherwise, there are too many overflow buckets, // so keep the same number of buckets and "grow" laterally. bigger := uint8(1) - if !overLoadFactor(int64(h.count), h.B) { + if !overLoadFactor(h.count+1, h.B) { bigger = 0 h.flags |= sameSizeGrow } @@ -981,13 +951,13 @@ func hashGrow(t *maptype, h *hmap) { h.nevacuate = 0 h.noverflow = 0 - if h.extra != nil && h.extra.overflow[0] != nil { + if h.extra != nil && h.extra.overflow != nil { // Promote current overflow buckets to the old generation. - if h.extra.overflow[1] != nil { - throw("overflow is not nil") + if h.extra.oldoverflow != nil { + throw("oldoverflow is not nil") } - h.extra.overflow[1] = h.extra.overflow[0] - h.extra.overflow[0] = nil + h.extra.oldoverflow = h.extra.overflow + h.extra.overflow = nil } if nextOverflow != nil { if h.extra == nil { @@ -1001,9 +971,8 @@ func hashGrow(t *maptype, h *hmap) { } // overLoadFactor reports whether count items placed in 1<= bucketCnt && float32(count) >= loadFactor*float32((uint64(1)< bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) } // tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<= uint16(1)< 15 { + B = 15 } - return noverflow >= 1<<15 + // The compiler doesn't see here that B < 16; mask B to generate shorter shift code. + return noverflow >= uint16(1)<<(B&15) } // growing reports whether h is growing. The growth may be to the same size or bigger. @@ -1036,7 +1006,7 @@ func (h *hmap) noldbuckets() uintptr { if !h.sameSizeGrow() { oldB-- } - return uintptr(1) << oldB + return bucketShift(oldB) } // oldbucketmask provides a mask that can be applied to calculate n % noldbuckets(). @@ -1060,33 +1030,38 @@ func bucketEvacuated(t *maptype, h *hmap, bucket uintptr) bool { return evacuated(b) } +// evacDst is an evacuation destination. +type evacDst struct { + b *bmap // current destination bucket + i int // key/val index into b + k unsafe.Pointer // pointer to current key storage + v unsafe.Pointer // pointer to current value storage +} + func evacuate(t *maptype, h *hmap, oldbucket uintptr) { b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) newbit := h.noldbuckets() hashfn := t.key.hashfn - equalfn := t.key.equalfn if !evacuated(b) { // TODO: reuse overflow buckets instead of using new ones, if there // is no iterator using the old buckets. (If !oldIterator.) - var ( - x, y *bmap // current low/high buckets in new map - xi, yi int // key/val indices into x and y - xk, yk unsafe.Pointer // pointers to current x and y key storage - xv, yv unsafe.Pointer // pointers to current x and y value storage - ) - x = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) - xi = 0 - xk = add(unsafe.Pointer(x), dataOffset) - xv = add(xk, bucketCnt*uintptr(t.keysize)) + // xy contains the x and y (low and high) evacuation destinations. + var xy [2]evacDst + x := &xy[0] + x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) + x.k = add(unsafe.Pointer(x.b), dataOffset) + x.v = add(x.k, bucketCnt*uintptr(t.keysize)) + if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. // Otherwise GC can see bad pointers. - y = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) - yi = 0 - yk = add(unsafe.Pointer(y), dataOffset) - yv = add(yk, bucketCnt*uintptr(t.keysize)) + y := &xy[1] + y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) + y.k = add(unsafe.Pointer(y.b), dataOffset) + y.v = add(y.k, bucketCnt*uintptr(t.keysize)) } + for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) v := add(k, bucketCnt*uintptr(t.keysize)) @@ -1103,122 +1078,102 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { if t.indirectkey { k2 = *((*unsafe.Pointer)(k2)) } - useX := true + var useY uint8 if !h.sameSizeGrow() { // Compute hash to make our evacuation decision (whether we need // to send this key/value to bucket x or bucket y). hash := hashfn(k2, uintptr(h.hash0)) - if h.flags&iterator != 0 { - if !t.reflexivekey && !equalfn(k2, k2) { - // If key != key (NaNs), then the hash could be (and probably - // will be) entirely different from the old hash. Moreover, - // it isn't reproducible. Reproducibility is required in the - // presence of iterators, as our evacuation decision must - // match whatever decision the iterator made. - // Fortunately, we have the freedom to send these keys either - // way. Also, tophash is meaningless for these kinds of keys. - // We let the low bit of tophash drive the evacuation decision. - // We recompute a new random tophash for the next level so - // these keys will get evenly distributed across all buckets - // after multiple grows. - if top&1 != 0 { - hash |= newbit - } else { - hash &^= newbit - } - top = uint8(hash >> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } + if h.flags&iterator != 0 && !t.reflexivekey && !t.key.equalfn(k2, k2) { + // If key != key (NaNs), then the hash could be (and probably + // will be) entirely different from the old hash. Moreover, + // it isn't reproducible. Reproducibility is required in the + // presence of iterators, as our evacuation decision must + // match whatever decision the iterator made. + // Fortunately, we have the freedom to send these keys either + // way. Also, tophash is meaningless for these kinds of keys. + // We let the low bit of tophash drive the evacuation decision. + // We recompute a new random tophash for the next level so + // these keys will get evenly distributed across all buckets + // after multiple grows. + useY = top & 1 + top = tophash(hash) + } else { + if hash&newbit != 0 { + useY = 1 } } - useX = hash&newbit == 0 } - if useX { - b.tophash[i] = evacuatedX - if xi == bucketCnt { - newx := h.newoverflow(t, x) - x = newx - xi = 0 - xk = add(unsafe.Pointer(x), dataOffset) - xv = add(xk, bucketCnt*uintptr(t.keysize)) - } - x.tophash[xi] = top - if t.indirectkey { - *(*unsafe.Pointer)(xk) = k2 // copy pointer - } else { - typedmemmove(t.key, xk, k) // copy value - } - if t.indirectvalue { - *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v) - } else { - typedmemmove(t.elem, xv, v) - } - xi++ - xk = add(xk, uintptr(t.keysize)) - xv = add(xv, uintptr(t.valuesize)) + + if evacuatedX+1 != evacuatedY { + throw("bad evacuatedN") + } + + b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY + dst := &xy[useY] // evacuation destination + + if dst.i == bucketCnt { + dst.b = h.newoverflow(t, dst.b) + dst.i = 0 + dst.k = add(unsafe.Pointer(dst.b), dataOffset) + dst.v = add(dst.k, bucketCnt*uintptr(t.keysize)) + } + dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + if t.indirectkey { + *(*unsafe.Pointer)(dst.k) = k2 // copy pointer } else { - b.tophash[i] = evacuatedY - if yi == bucketCnt { - newy := h.newoverflow(t, y) - y = newy - yi = 0 - yk = add(unsafe.Pointer(y), dataOffset) - yv = add(yk, bucketCnt*uintptr(t.keysize)) - } - y.tophash[yi] = top - if t.indirectkey { - *(*unsafe.Pointer)(yk) = k2 - } else { - typedmemmove(t.key, yk, k) - } - if t.indirectvalue { - *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v) - } else { - typedmemmove(t.elem, yv, v) - } - yi++ - yk = add(yk, uintptr(t.keysize)) - yv = add(yv, uintptr(t.valuesize)) + typedmemmove(t.key, dst.k, k) // copy value } + if t.indirectvalue { + *(*unsafe.Pointer)(dst.v) = *(*unsafe.Pointer)(v) + } else { + typedmemmove(t.elem, dst.v, v) + } + dst.i++ + // These updates might push these pointers past the end of the + // key or value arrays. That's ok, as we have the overflow pointer + // at the end of the bucket to protect against pointing past the + // end of the bucket. + dst.k = add(dst.k, uintptr(t.keysize)) + dst.v = add(dst.v, uintptr(t.valuesize)) } } // Unlink the overflow buckets & clear key/value to help GC. - if h.flags&oldIterator == 0 { - b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) + if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 { + b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)) // Preserve b.tophash because the evacuation // state is maintained there. - if t.bucket.kind&kindNoPointers == 0 { - memclrHasPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset) - } else { - memclrNoHeapPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset) - } + ptr := add(b, dataOffset) + n := uintptr(t.bucketsize) - dataOffset + memclrHasPointers(ptr, n) } } - // Advance evacuation mark if oldbucket == h.nevacuate { - h.nevacuate = oldbucket + 1 - // Experiments suggest that 1024 is overkill by at least an order of magnitude. - // Put it in there as a safeguard anyway, to ensure O(1) behavior. - stop := h.nevacuate + 1024 - if stop > newbit { - stop = newbit - } - for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { - h.nevacuate++ - } - if h.nevacuate == newbit { // newbit == # of oldbuckets - // Growing is all done. Free old main bucket array. - h.oldbuckets = nil - // Can discard old overflow buckets as well. - // If they are still referenced by an iterator, - // then the iterator holds a pointers to the slice. - if h.extra != nil { - h.extra.overflow[1] = nil - } - h.flags &^= sameSizeGrow + advanceEvacuationMark(h, t, newbit) + } +} + +func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) { + h.nevacuate++ + // Experiments suggest that 1024 is overkill by at least an order of magnitude. + // Put it in there as a safeguard anyway, to ensure O(1) behavior. + stop := h.nevacuate + 1024 + if stop > newbit { + stop = newbit + } + for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) { + h.nevacuate++ + } + if h.nevacuate == newbit { // newbit == # of oldbuckets + // Growing is all done. Free old main bucket array. + h.oldbuckets = nil + // Can discard old overflow buckets as well. + // If they are still referenced by an iterator, + // then the iterator holds a pointers to the slice. + if h.extra != nil { + h.extra.oldoverflow = nil } + h.flags &^= sameSizeGrow } } @@ -1230,7 +1185,45 @@ func ismapkey(t *_type) bool { //go:linkname reflect_makemap reflect.makemap func reflect_makemap(t *maptype, cap int) *hmap { - return makemap(t, int64(cap), nil, nil) + // Check invariants and reflects math. + if sz := unsafe.Sizeof(hmap{}); sz != t.hmap.size { + println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) + throw("bad hmap size") + } + if !ismapkey(t.key) { + throw("runtime.reflect_makemap: unsupported map key type") + } + if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(sys.PtrSize)) || + t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) { + throw("key size wrong") + } + if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(sys.PtrSize)) || + t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) { + throw("value size wrong") + } + if t.key.align > bucketCnt { + throw("key align too big") + } + if t.elem.align > bucketCnt { + throw("value align too big") + } + if t.key.size%uintptr(t.key.align) != 0 { + throw("key size not a multiple of key align") + } + if t.elem.size%uintptr(t.elem.align) != 0 { + throw("value size not a multiple of value align") + } + if bucketCnt < 8 { + throw("bucketsize too small for proper alignment") + } + if dataOffset%uintptr(t.key.align) != 0 { + throw("need padding in bucket (key)") + } + if dataOffset%uintptr(t.elem.align) != 0 { + throw("need padding in bucket (value)") + } + + return makemap(t, cap, nil) } //go:linkname reflect_mapaccess reflect.mapaccess @@ -1277,7 +1270,7 @@ func reflect_maplen(h *hmap) int { return 0 } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer( /* &h */ nil)) + callerpc := getcallerpc() racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen)) } return h.count diff --git a/libgo/go/runtime/hashmap_fast.go b/libgo/go/runtime/hashmap_fast.go index bec8fdac14e..e0fc9815131 100644 --- a/libgo/go/runtime/hashmap_fast.go +++ b/libgo/go/runtime/hashmap_fast.go @@ -11,7 +11,7 @@ import ( func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32)) } if h == nil || h.count == 0 { @@ -26,7 +26,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { b = (*bmap)(h.buckets) } else { hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0)) - m := uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check - if x != top { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) - if k.len != key.len { + top := tophash(hash) + for ; b != nil; b = b.overflow(t) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + k := (*stringStruct)(kptr) + if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) } } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(&zeroVal[0]) - } } + return unsafe.Pointer(&zeroVal[0]) } func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer( /* &t */ nil)) + callerpc := getcallerpc() racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr)) } if h == nil || h.count == 0 { @@ -329,13 +275,9 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) - if k.len != key.len { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + k := (*stringStruct)(kptr) + if k.len != key.len || b.tophash[i] == empty { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { @@ -346,13 +288,9 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { } // long key, try not to do more comparisons than necessary keymaybe := uintptr(bucketCnt) - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) - if k.len != key.len { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + k := (*stringStruct)(kptr) + if k.len != key.len || b.tophash[i] == empty { continue } if k.str == key.str { @@ -382,7 +320,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { } dohash: hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0)) - m := uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash + top := tophash(hash) + for ; b != nil; b = b.overflow(t) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + k := (*stringStruct)(kptr) + if k.len != key.len || b.tophash[i] != top { + continue + } + if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { + return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true + } + } + } + return unsafe.Pointer(&zeroVal[0]), false +} + +func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { + if h == nil { + panic(plainError("assignment to entry in nil map")) + } + if raceenabled { + callerpc := getcallerpc() + racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32)) + } + if h.flags&hashWriting != 0 { + throw("concurrent map writes") + } + hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0)) + + // Set hashWriting after calling alg.hash for consistency with mapassign. + h.flags |= hashWriting + + if h.buckets == nil { + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) + } + +again: + bucket := hash & bucketMask(h.B) + if h.growing() { + growWork_fast32(t, h, bucket) } + b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize))) + + var insertb *bmap + var inserti uintptr + var insertk unsafe.Pointer + for { for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.tophash[i] without the bounds check - if x != top { + if b.tophash[i] == empty { + if insertb == nil { + inserti = i + insertb = b + } continue } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) - if k.len != key.len { + k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4))) + if k != key { continue } - if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true - } + inserti = i + insertb = b + goto done } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(&zeroVal[0]), false + ovf := b.overflow(t) + if ovf == nil { + break } + b = ovf + } + + // Did not find mapping for key. Allocate new cell & add entry. + + // If we hit the max load factor or we have too many overflow buckets, + // and we're not already in the middle of growing, start growing. + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + hashGrow(t, h) + goto again // Growing the table invalidates everything, so try again + } + + if insertb == nil { + // all current buckets are full, allocate a new one. + insertb = h.newoverflow(t, b) + inserti = 0 // not necessary, but avoids needlessly spilling inserti } + insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) + // store new key at insert position + *(*uint32)(insertk) = key + + h.count++ + +done: + val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.valuesize)) + if h.flags&hashWriting == 0 { + throw("concurrent map writes") + } + h.flags &^= hashWriting + return val } -func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { +func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&t)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast32)) } if h.flags&hashWriting != 0 { @@ -436,38 +450,35 @@ func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { h.flags |= hashWriting if h.buckets == nil { - h.buckets = newarray(t.bucket, 1) + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) } again: - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - var inserti *uint8 + var insertb *bmap + var inserti uintptr var insertk unsafe.Pointer - var val unsafe.Pointer + for { for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == empty && inserti == nil { - inserti = &b.tophash[i] - insertk = add(unsafe.Pointer(b), dataOffset+i*4) - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)) + if b.tophash[i] == empty { + if insertb == nil { + inserti = i + insertb = b } continue } - k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4))) + k := *((*unsafe.Pointer)(add(unsafe.Pointer(b), dataOffset+i*4))) if k != key { continue } - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)) + inserti = i + insertb = b goto done } ovf := b.overflow(t) @@ -481,25 +492,26 @@ again: // If we hit the max load factor or we have too many overflow buckets, // and we're not already in the middle of growing, start growing. - if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { hashGrow(t, h) goto again // Growing the table invalidates everything, so try again } - if inserti == nil { + if insertb == nil { // all current buckets are full, allocate a new one. - newb := h.newoverflow(t, b) - inserti = &newb.tophash[0] - insertk = add(unsafe.Pointer(newb), dataOffset) - val = add(insertk, bucketCnt*4) + insertb = h.newoverflow(t, b) + inserti = 0 // not necessary, but avoids needlessly spilling inserti } + insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) + // store new key at insert position + *(*unsafe.Pointer)(insertk) = key - // store new key/value at insert position - typedmemmove(t.key, insertk, unsafe.Pointer(&key)) - *inserti = top h.count++ done: + val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.valuesize)) if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -512,7 +524,7 @@ func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { panic(plainError("assignment to entry in nil map")) } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&t)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64)) } if h.flags&hashWriting != 0 { @@ -524,30 +536,26 @@ func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { h.flags |= hashWriting if h.buckets == nil { - h.buckets = newarray(t.bucket, 1) + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) } again: - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - var inserti *uint8 + var insertb *bmap + var inserti uintptr var insertk unsafe.Pointer - var val unsafe.Pointer + for { for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == empty && inserti == nil { - inserti = &b.tophash[i] - insertk = add(unsafe.Pointer(b), dataOffset+i*8) - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)) + if b.tophash[i] == empty { + if insertb == nil { + insertb = b + inserti = i } continue } @@ -555,7 +563,8 @@ again: if k != key { continue } - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)) + insertb = b + inserti = i goto done } ovf := b.overflow(t) @@ -569,25 +578,26 @@ again: // If we hit the max load factor or we have too many overflow buckets, // and we're not already in the middle of growing, start growing. - if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { hashGrow(t, h) goto again // Growing the table invalidates everything, so try again } - if inserti == nil { + if insertb == nil { // all current buckets are full, allocate a new one. - newb := h.newoverflow(t, b) - inserti = &newb.tophash[0] - insertk = add(unsafe.Pointer(newb), dataOffset) - val = add(insertk, bucketCnt*8) + insertb = h.newoverflow(t, b) + inserti = 0 // not necessary, but avoids needlessly spilling inserti } + insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) + // store new key at insert position + *(*uint64)(insertk) = key - // store new key/value at insert position - typedmemmove(t.key, insertk, unsafe.Pointer(&key)) - *inserti = top h.count++ done: + val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.valuesize)) if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -595,48 +605,131 @@ done: return val } -func mapassign_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { +func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_faststr)) + callerpc := getcallerpc() + racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_fast64)) } if h.flags&hashWriting != 0 { throw("concurrent map writes") } - key := stringStructOf(&ky) - hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0)) + hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0)) // Set hashWriting after calling alg.hash for consistency with mapassign. h.flags |= hashWriting if h.buckets == nil { - h.buckets = newarray(t.bucket, 1) + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) } again: - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash + + var insertb *bmap + var inserti uintptr + var insertk unsafe.Pointer + + for { + for i := uintptr(0); i < bucketCnt; i++ { + if b.tophash[i] == empty { + if insertb == nil { + insertb = b + inserti = i + } + continue + } + k := *((*unsafe.Pointer)(add(unsafe.Pointer(b), dataOffset+i*8))) + if k != key { + continue + } + insertb = b + inserti = i + goto done + } + ovf := b.overflow(t) + if ovf == nil { + break + } + b = ovf + } + + // Did not find mapping for key. Allocate new cell & add entry. + + // If we hit the max load factor or we have too many overflow buckets, + // and we're not already in the middle of growing, start growing. + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + hashGrow(t, h) + goto again // Growing the table invalidates everything, so try again } - var inserti *uint8 + if insertb == nil { + // all current buckets are full, allocate a new one. + insertb = h.newoverflow(t, b) + inserti = 0 // not necessary, but avoids needlessly spilling inserti + } + insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) + // store new key at insert position + *(*unsafe.Pointer)(insertk) = key + + h.count++ + +done: + val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.valuesize)) + if h.flags&hashWriting == 0 { + throw("concurrent map writes") + } + h.flags &^= hashWriting + return val +} + +func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer { + if h == nil { + panic(plainError("assignment to entry in nil map")) + } + if raceenabled { + callerpc := getcallerpc() + racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapassign_faststr)) + } + if h.flags&hashWriting != 0 { + throw("concurrent map writes") + } + key := stringStructOf(&s) + hash := t.key.hashfn(noescape(unsafe.Pointer(&s)), uintptr(h.hash0)) + + // Set hashWriting after calling alg.hash for consistency with mapassign. + h.flags |= hashWriting + + if h.buckets == nil { + h.buckets = newobject(t.bucket) // newarray(t.bucket, 1) + } + +again: + bucket := hash & bucketMask(h.B) + if h.growing() { + growWork_faststr(t, h, bucket) + } + b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize))) + top := tophash(hash) + + var insertb *bmap + var inserti uintptr var insertk unsafe.Pointer - var val unsafe.Pointer + for { for i := uintptr(0); i < bucketCnt; i++ { if b.tophash[i] != top { - if b.tophash[i] == empty && inserti == nil { - inserti = &b.tophash[i] - insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) + if b.tophash[i] == empty && insertb == nil { + insertb = b + inserti = i } continue } @@ -648,7 +741,8 @@ again: continue } // already have a mapping for key. Update it. - val = add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) + inserti = i + insertb = b goto done } ovf := b.overflow(t) @@ -662,25 +756,25 @@ again: // If we hit the max load factor or we have too many overflow buckets, // and we're not already in the middle of growing, start growing. - if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { + if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { hashGrow(t, h) goto again // Growing the table invalidates everything, so try again } - if inserti == nil { + if insertb == nil { // all current buckets are full, allocate a new one. - newb := h.newoverflow(t, b) - inserti = &newb.tophash[0] - insertk = add(unsafe.Pointer(newb), dataOffset) - val = add(insertk, bucketCnt*2*sys.PtrSize) + insertb = h.newoverflow(t, b) + inserti = 0 // not necessary, but avoids needlessly spilling inserti } + insertb.tophash[inserti&(bucketCnt-1)] = top // mask inserti to avoid bounds checks - // store new key/value at insert position + insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*sys.PtrSize) + // store new key at insert position *((*stringStruct)(insertk)) = *key - *inserti = top h.count++ done: + val := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*sys.PtrSize+inserti*uintptr(t.valuesize)) if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -690,7 +784,7 @@ done: func mapdelete_fast32(t *maptype, h *hmap, key uint32) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast32)) } if h == nil || h.count == 0 { @@ -705,38 +799,32 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) { // Set hashWriting after calling alg.hash for consistency with mapdelete h.flags |= hashWriting - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash + growWork_fast32(t, h, bucket) } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { + b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize))) +search: + for ; b != nil; b = b.overflow(t) { + for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + if key != *(*uint32)(k) || b.tophash[i] == empty { continue } - k := (*uint32)(add(unsafe.Pointer(b), dataOffset+i*4)) - if key != *k { - continue + // Only clear key if there are pointers in it. + if t.key.kind&kindNoPointers == 0 { + memclrHasPointers(k, t.key.size) + } + // Only clear value if there are pointers in it. + if t.elem.kind&kindNoPointers == 0 { + v := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)) + memclrHasPointers(v, t.elem.size) } - typedmemclr(t.key, unsafe.Pointer(k)) - v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*4 + i*uintptr(t.valuesize)) - typedmemclr(t.elem, v) b.tophash[i] = empty h.count-- - goto done - } - b = b.overflow(t) - if b == nil { - goto done + break search } } -done: if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -745,7 +833,7 @@ done: func mapdelete_fast64(t *maptype, h *hmap, key uint64) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_fast64)) } if h == nil || h.count == 0 { @@ -760,38 +848,32 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) { // Set hashWriting after calling alg.hash for consistency with mapdelete h.flags |= hashWriting - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { + b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize))) +search: + for ; b != nil; b = b.overflow(t) { + for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + if key != *(*uint64)(k) || b.tophash[i] == empty { continue } - k := (*uint64)(add(unsafe.Pointer(b), dataOffset+i*8)) - if key != *k { - continue + // Only clear key if there are pointers in it. + if t.key.kind&kindNoPointers == 0 { + memclrHasPointers(k, t.key.size) + } + // Only clear value if there are pointers in it. + if t.elem.kind&kindNoPointers == 0 { + v := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)) + memclrHasPointers(v, t.elem.size) } - typedmemclr(t.key, unsafe.Pointer(k)) - v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*8 + i*uintptr(t.valuesize)) - typedmemclr(t.elem, v) b.tophash[i] = empty h.count-- - goto done - } - b = b.overflow(t) - if b == nil { - goto done + break search } } -done: if h.flags&hashWriting == 0 { throw("concurrent map writes") } @@ -800,7 +882,7 @@ done: func mapdelete_faststr(t *maptype, h *hmap, ky string) { if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) + callerpc := getcallerpc() racewritepc(unsafe.Pointer(h), callerpc, funcPC(mapdelete_faststr)) } if h == nil || h.count == 0 { @@ -816,43 +898,340 @@ func mapdelete_faststr(t *maptype, h *hmap, ky string) { // Set hashWriting after calling alg.hash for consistency with mapdelete h.flags |= hashWriting - bucket := hash & (uintptr(1)<> (sys.PtrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*sys.PtrSize)) - if k.len != key.len { + growWork_faststr(t, h, bucket) + } + b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize))) + top := tophash(hash) +search: + for ; b != nil; b = b.overflow(t) { + for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) { + k := (*stringStruct)(kptr) + if k.len != key.len || b.tophash[i] != top { continue } if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) { continue } - typedmemclr(t.key, unsafe.Pointer(k)) - v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*2*sys.PtrSize + i*uintptr(t.valuesize)) - typedmemclr(t.elem, v) + // Clear key's pointer. + k.str = nil + // Only clear value if there are pointers in it. + if t.elem.kind&kindNoPointers == 0 { + v := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) + memclrHasPointers(v, t.elem.size) + } b.tophash[i] = empty h.count-- - goto done - } - b = b.overflow(t) - if b == nil { - goto done + break search } } -done: if h.flags&hashWriting == 0 { throw("concurrent map writes") } h.flags &^= hashWriting } + +func growWork_fast32(t *maptype, h *hmap, bucket uintptr) { + // make sure we evacuate the oldbucket corresponding + // to the bucket we're about to use + evacuate_fast32(t, h, bucket&h.oldbucketmask()) + + // evacuate one more oldbucket to make progress on growing + if h.growing() { + evacuate_fast32(t, h, h.nevacuate) + } +} + +func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { + b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) + newbit := h.noldbuckets() + if !evacuated(b) { + // TODO: reuse overflow buckets instead of using new ones, if there + // is no iterator using the old buckets. (If !oldIterator.) + + // xy contains the x and y (low and high) evacuation destinations. + var xy [2]evacDst + x := &xy[0] + x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) + x.k = add(unsafe.Pointer(x.b), dataOffset) + x.v = add(x.k, bucketCnt*4) + + if !h.sameSizeGrow() { + // Only calculate y pointers if we're growing bigger. + // Otherwise GC can see bad pointers. + y := &xy[1] + y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) + y.k = add(unsafe.Pointer(y.b), dataOffset) + y.v = add(y.k, bucketCnt*4) + } + + for ; b != nil; b = b.overflow(t) { + k := add(unsafe.Pointer(b), dataOffset) + v := add(k, bucketCnt*4) + for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 4), add(v, uintptr(t.valuesize)) { + top := b.tophash[i] + if top == empty { + b.tophash[i] = evacuatedEmpty + continue + } + if top < minTopHash { + throw("bad map state") + } + var useY uint8 + if !h.sameSizeGrow() { + // Compute hash to make our evacuation decision (whether we need + // to send this key/value to bucket x or bucket y). + hash := t.key.hashfn(k, uintptr(h.hash0)) + if hash&newbit != 0 { + useY = 1 + } + } + + b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap + dst := &xy[useY] // evacuation destination + + if dst.i == bucketCnt { + dst.b = h.newoverflow(t, dst.b) + dst.i = 0 + dst.k = add(unsafe.Pointer(dst.b), dataOffset) + dst.v = add(dst.k, bucketCnt*4) + } + dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + + // Copy key. + if sys.PtrSize == 4 && t.key.kind&kindNoPointers == 0 && writeBarrier.enabled { + writebarrierptr((*uintptr)(dst.k), *(*uintptr)(k)) + } else { + *(*uint32)(dst.k) = *(*uint32)(k) + } + + typedmemmove(t.elem, dst.v, v) + dst.i++ + // These updates might push these pointers past the end of the + // key or value arrays. That's ok, as we have the overflow pointer + // at the end of the bucket to protect against pointing past the + // end of the bucket. + dst.k = add(dst.k, 4) + dst.v = add(dst.v, uintptr(t.valuesize)) + } + } + // Unlink the overflow buckets & clear key/value to help GC. + if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 { + b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)) + // Preserve b.tophash because the evacuation + // state is maintained there. + ptr := add(b, dataOffset) + n := uintptr(t.bucketsize) - dataOffset + memclrHasPointers(ptr, n) + } + } + + if oldbucket == h.nevacuate { + advanceEvacuationMark(h, t, newbit) + } +} + +func growWork_fast64(t *maptype, h *hmap, bucket uintptr) { + // make sure we evacuate the oldbucket corresponding + // to the bucket we're about to use + evacuate_fast64(t, h, bucket&h.oldbucketmask()) + + // evacuate one more oldbucket to make progress on growing + if h.growing() { + evacuate_fast64(t, h, h.nevacuate) + } +} + +func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { + b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) + newbit := h.noldbuckets() + if !evacuated(b) { + // TODO: reuse overflow buckets instead of using new ones, if there + // is no iterator using the old buckets. (If !oldIterator.) + + // xy contains the x and y (low and high) evacuation destinations. + var xy [2]evacDst + x := &xy[0] + x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) + x.k = add(unsafe.Pointer(x.b), dataOffset) + x.v = add(x.k, bucketCnt*8) + + if !h.sameSizeGrow() { + // Only calculate y pointers if we're growing bigger. + // Otherwise GC can see bad pointers. + y := &xy[1] + y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) + y.k = add(unsafe.Pointer(y.b), dataOffset) + y.v = add(y.k, bucketCnt*8) + } + + for ; b != nil; b = b.overflow(t) { + k := add(unsafe.Pointer(b), dataOffset) + v := add(k, bucketCnt*8) + for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 8), add(v, uintptr(t.valuesize)) { + top := b.tophash[i] + if top == empty { + b.tophash[i] = evacuatedEmpty + continue + } + if top < minTopHash { + throw("bad map state") + } + var useY uint8 + if !h.sameSizeGrow() { + // Compute hash to make our evacuation decision (whether we need + // to send this key/value to bucket x or bucket y). + hash := t.key.hashfn(k, uintptr(h.hash0)) + if hash&newbit != 0 { + useY = 1 + } + } + + b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap + dst := &xy[useY] // evacuation destination + + if dst.i == bucketCnt { + dst.b = h.newoverflow(t, dst.b) + dst.i = 0 + dst.k = add(unsafe.Pointer(dst.b), dataOffset) + dst.v = add(dst.k, bucketCnt*8) + } + dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + + // Copy key. + if t.key.kind&kindNoPointers == 0 && writeBarrier.enabled { + if sys.PtrSize == 8 { + writebarrierptr((*uintptr)(dst.k), *(*uintptr)(k)) + } else { + // There are three ways to squeeze at least one 32 bit pointer into 64 bits. + // Give up and call typedmemmove. + typedmemmove(t.key, dst.k, k) + } + } else { + *(*uint64)(dst.k) = *(*uint64)(k) + } + + typedmemmove(t.elem, dst.v, v) + dst.i++ + // These updates might push these pointers past the end of the + // key or value arrays. That's ok, as we have the overflow pointer + // at the end of the bucket to protect against pointing past the + // end of the bucket. + dst.k = add(dst.k, 8) + dst.v = add(dst.v, uintptr(t.valuesize)) + } + } + // Unlink the overflow buckets & clear key/value to help GC. + if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 { + b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)) + // Preserve b.tophash because the evacuation + // state is maintained there. + ptr := add(b, dataOffset) + n := uintptr(t.bucketsize) - dataOffset + memclrHasPointers(ptr, n) + } + } + + if oldbucket == h.nevacuate { + advanceEvacuationMark(h, t, newbit) + } +} + +func growWork_faststr(t *maptype, h *hmap, bucket uintptr) { + // make sure we evacuate the oldbucket corresponding + // to the bucket we're about to use + evacuate_faststr(t, h, bucket&h.oldbucketmask()) + + // evacuate one more oldbucket to make progress on growing + if h.growing() { + evacuate_faststr(t, h, h.nevacuate) + } +} + +func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { + b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) + newbit := h.noldbuckets() + if !evacuated(b) { + // TODO: reuse overflow buckets instead of using new ones, if there + // is no iterator using the old buckets. (If !oldIterator.) + + // xy contains the x and y (low and high) evacuation destinations. + var xy [2]evacDst + x := &xy[0] + x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) + x.k = add(unsafe.Pointer(x.b), dataOffset) + x.v = add(x.k, bucketCnt*2*sys.PtrSize) + + if !h.sameSizeGrow() { + // Only calculate y pointers if we're growing bigger. + // Otherwise GC can see bad pointers. + y := &xy[1] + y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) + y.k = add(unsafe.Pointer(y.b), dataOffset) + y.v = add(y.k, bucketCnt*2*sys.PtrSize) + } + + for ; b != nil; b = b.overflow(t) { + k := add(unsafe.Pointer(b), dataOffset) + v := add(k, bucketCnt*2*sys.PtrSize) + for i := 0; i < bucketCnt; i, k, v = i+1, add(k, 2*sys.PtrSize), add(v, uintptr(t.valuesize)) { + top := b.tophash[i] + if top == empty { + b.tophash[i] = evacuatedEmpty + continue + } + if top < minTopHash { + throw("bad map state") + } + var useY uint8 + if !h.sameSizeGrow() { + // Compute hash to make our evacuation decision (whether we need + // to send this key/value to bucket x or bucket y). + hash := t.key.hashfn(k, uintptr(h.hash0)) + if hash&newbit != 0 { + useY = 1 + } + } + + b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap + dst := &xy[useY] // evacuation destination + + if dst.i == bucketCnt { + dst.b = h.newoverflow(t, dst.b) + dst.i = 0 + dst.k = add(unsafe.Pointer(dst.b), dataOffset) + dst.v = add(dst.k, bucketCnt*2*sys.PtrSize) + } + dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + + // Copy key. + *(*string)(dst.k) = *(*string)(k) + + typedmemmove(t.elem, dst.v, v) + dst.i++ + // These updates might push these pointers past the end of the + // key or value arrays. That's ok, as we have the overflow pointer + // at the end of the bucket to protect against pointing past the + // end of the bucket. + dst.k = add(dst.k, 2*sys.PtrSize) + dst.v = add(dst.v, uintptr(t.valuesize)) + } + } + // Unlink the overflow buckets & clear key/value to help GC. + // Unlink the overflow buckets & clear key/value to help GC. + if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 { + b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)) + // Preserve b.tophash because the evacuation + // state is maintained there. + ptr := add(b, dataOffset) + n := uintptr(t.bucketsize) - dataOffset + memclrHasPointers(ptr, n) + } + } + + if oldbucket == h.nevacuate { + advanceEvacuationMark(h, t, newbit) + } +} diff --git a/libgo/go/runtime/heapdump.go b/libgo/go/runtime/heapdump.go index 166199b5ca3..a4b168d7313 100644 --- a/libgo/go/runtime/heapdump.go +++ b/libgo/go/runtime/heapdump.go @@ -200,7 +200,6 @@ func dumptype(t *_type) { // dump an object func dumpobj(obj unsafe.Pointer, size uintptr, bv bitvector) { - dumpbvtypes(&bv, obj) dumpint(tagObject) dumpint(uint64(uintptr(obj))) dumpmemrange(obj, size) @@ -539,16 +538,6 @@ func dumpfields(bv bitvector) { dumpint(fieldKindEol) } -// 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 routine accomplishes that. -// TODO(rsc, khr): Delete - no longer possible. - -// Dump all the types that appear in the type field of -// any Eface described by this bit vector. -func dumpbvtypes(bv *bitvector, base unsafe.Pointer) { -} - func makeheapobjbv(p uintptr, size uintptr) bitvector { // Extend the temp buffer if necessary. nptr := size / sys.PtrSize diff --git a/libgo/go/runtime/internal/atomic/atomic_test.go b/libgo/go/runtime/internal/atomic/atomic_test.go index 879a82f9c82..b697aa8bd39 100644 --- a/libgo/go/runtime/internal/atomic/atomic_test.go +++ b/libgo/go/runtime/internal/atomic/atomic_test.go @@ -52,7 +52,7 @@ func TestXadduintptr(t *testing.T) { // Tests that xadduintptr correctly updates 64-bit values. The place where // we actually do so is mstats.go, functions mSysStat{Inc,Dec}. func TestXadduintptrOnUint64(t *testing.T) { - if sys.BigEndian != 0 { + if sys.BigEndian { // On big endian architectures, we never use xadduintptr to update // 64-bit values and hence we skip the test. (Note that functions // mSysStat{Inc,Dec} in mstats.go have explicit checks for diff --git a/libgo/go/runtime/internal/sys/sys.go b/libgo/go/runtime/internal/sys/sys.go index 586a763717d..9d9ac4507f6 100644 --- a/libgo/go/runtime/internal/sys/sys.go +++ b/libgo/go/runtime/internal/sys/sys.go @@ -6,9 +6,9 @@ // constants used by the runtime. package sys -// The next line makes 'go generate' write the zgen_*.go files with +// The next line makes 'go generate' write the zgo*.go files with // per-OS and per-arch information, including constants -// named goos_$GOOS and goarch_$GOARCH for every +// named Goos$GOOS and Goarch$GOARCH for every // known GOOS and GOARCH. The constant is 1 on the // current system, 0 otherwise; multiplying by them is // useful for defining GOOS- or GOARCH-specific constants. diff --git a/libgo/go/runtime/lock_sema.go b/libgo/go/runtime/lock_sema.go index 52a2376dc5e..d000b112f44 100644 --- a/libgo/go/runtime/lock_sema.go +++ b/libgo/go/runtime/lock_sema.go @@ -83,7 +83,7 @@ Loop: // for this lock, chained through m->nextwaitm. // Queue this M. for { - gp.m.nextwaitm = v &^ mutex_locked + gp.m.nextwaitm = muintptr(v &^ mutex_locked) if atomic.Casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|mutex_locked) { break } @@ -115,8 +115,8 @@ func unlock(l *mutex) { } else { // Other M's are waiting for the lock. // Dequeue an M. - mp = (*m)(unsafe.Pointer(v &^ mutex_locked)) - if atomic.Casuintptr(&l.key, v, mp.nextwaitm) { + mp = muintptr(v &^ mutex_locked).ptr() + if atomic.Casuintptr(&l.key, v, uintptr(mp.nextwaitm)) { // Dequeued an M. Wake it. semawakeup(mp) break @@ -152,7 +152,7 @@ func notewakeup(n *note) { case v == 0: // Nothing was waiting. Done. case v == mutex_locked: - // Two notewakeups! Not allowed. + // Two notewakeups! Not allowed. throw("notewakeup - double wakeup") default: // Must be the waiting m. Wake it up. diff --git a/libgo/go/runtime/malloc.go b/libgo/go/runtime/malloc.go index 796cd8a7c64..88e4ba3657b 100644 --- a/libgo/go/runtime/malloc.go +++ b/libgo/go/runtime/malloc.go @@ -546,9 +546,8 @@ func nextFreeFast(s *mspan) gclinkptr { } s.allocCache >>= uint(theBit + 1) s.freeindex = freeidx - v := gclinkptr(result*s.elemsize + s.base()) s.allocCount++ - return v + return gclinkptr(result*s.elemsize + s.base()) } } return 0 @@ -877,6 +876,9 @@ func reflect_unsafe_New(typ *_type) unsafe.Pointer { // newarray allocates an array of n elements of type typ. func newarray(typ *_type, n int) unsafe.Pointer { + if n == 1 { + return mallocgc(typ.size, typ, true) + } if n < 0 || uintptr(n) > maxSliceCap(typ.size) { panic(plainError("runtime: allocation size out of range")) } @@ -893,11 +895,13 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { mProf_Malloc(x, size) } -// nextSample returns the next sampling point for heap profiling. -// It produces a random variable with a geometric distribution and -// mean MemProfileRate. This is done by generating a uniformly -// distributed random number and applying the cumulative distribution -// function for an exponential. +// nextSample returns the next sampling point for heap profiling. The goal is +// to sample allocations on average every MemProfileRate bytes, but with a +// completely random distribution over the allocation timeline; this +// corresponds to a Poisson process with parameter MemProfileRate. In Poisson +// processes, the distance between two samples follows the exponential +// distribution (exp(MemProfileRate)), so the best return value is a random +// number taken from an exponential distribution whose mean is MemProfileRate. func nextSample() int32 { if GOOS == "plan9" { // Plan 9 doesn't support floating point in note handler. @@ -906,25 +910,29 @@ func nextSample() int32 { } } - period := MemProfileRate + return fastexprand(MemProfileRate) +} - // make nextSample not overflow. Maximum possible step is - // -ln(1/(1< 0x7000000: - period = 0x7000000 - case period == 0: + case mean > 0x7000000: + mean = 0x7000000 + case mean == 0: return 0 } - // Let m be the sample rate, - // the probability distribution function is m*exp(-mx), so the CDF is - // p = 1 - exp(-mx), so - // q = 1 - p == exp(-mx) - // log_e(q) = -mx - // -log_e(q)/m = x - // x = -log_e(q) * period - // x = log_2(q) * (-log_e(2)) * period ; Using log_2 for efficiency + // Take a random sample of the exponential distribution exp(-mean*x). + // The probability distribution function is mean*exp(-mean*x), so the CDF is + // p = 1 - exp(-mean*x), so + // q = 1 - p == exp(-mean*x) + // log_e(q) = -mean*x + // -log_e(q)/mean = x + // x = -log_e(q) * mean + // x = log_2(q) * (-log_e(2)) * mean ; Using log_2 for efficiency const randomBitCount = 26 q := fastrand()%(1<= maxBlock { - return sysAlloc(size, sysStat) + return (*notInHeap)(sysAlloc(size, sysStat)) } mp := acquirem() @@ -1011,7 +1019,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { } persistent.off = round(persistent.off, align) if persistent.off+size > chunk || persistent.base == nil { - persistent.base = sysAlloc(chunk, &memstats.other_sys) + persistent.base = (*notInHeap)(sysAlloc(chunk, &memstats.other_sys)) if persistent.base == nil { if persistent == &globalAlloc.persistentAlloc { unlock(&globalAlloc.mutex) @@ -1020,7 +1028,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { } persistent.off = 0 } - p := add(persistent.base, persistent.off) + p := persistent.base.add(persistent.off) persistent.off += size releasem(mp) if persistent == &globalAlloc.persistentAlloc { @@ -1033,3 +1041,19 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { } return p } + +// notInHeap is off-heap memory allocated by a lower-level allocator +// like sysAlloc or persistentAlloc. +// +// In general, it's better to use real types marked as go:notinheap, +// but this serves as a generic type for situations where that isn't +// possible (like in the allocators). +// +// TODO: Use this as the return type of sysAlloc, persistentAlloc, etc? +// +//go:notinheap +type notInHeap struct{} + +func (p *notInHeap) add(bytes uintptr) *notInHeap { + return (*notInHeap)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + bytes)) +} diff --git a/libgo/go/runtime/malloc_test.go b/libgo/go/runtime/malloc_test.go index 0d43cf65976..ab580f81800 100644 --- a/libgo/go/runtime/malloc_test.go +++ b/libgo/go/runtime/malloc_test.go @@ -48,9 +48,6 @@ func TestMemStats(t *testing.T) { } // Of the uint fields, HeapReleased, HeapIdle can be 0. // PauseTotalNs can be 0 if timer resolution is poor. - // - // TODO: Test that GCCPUFraction is <= 0.99. This currently - // fails on windows/386. (Issue #19319) fields := map[string][]func(interface{}) error{ "Alloc": {nz, le(1e10)}, "TotalAlloc": {nz, le(1e11)}, "Sys": {nz, le(1e10)}, "Lookups": {nz, le(1e10)}, "Mallocs": {nz, le(1e10)}, "Frees": {nz, le(1e10)}, @@ -63,7 +60,7 @@ func TestMemStats(t *testing.T) { "NextGC": {nz, le(1e10)}, "LastGC": {nz}, "PauseTotalNs": {le(1e11)}, "PauseNs": nil, "PauseEnd": nil, "NumGC": {nz, le(1e9)}, "NumForcedGC": {nz, le(1e9)}, - "GCCPUFraction": nil, "EnableGC": {eq(true)}, "DebugGC": {eq(false)}, + "GCCPUFraction": {le(0.99)}, "EnableGC": {eq(true)}, "DebugGC": {eq(false)}, "BySize": nil, } diff --git a/libgo/go/runtime/map_test.go b/libgo/go/runtime/map_test.go index 37c959f8327..6d7097e07ef 100644 --- a/libgo/go/runtime/map_test.go +++ b/libgo/go/runtime/map_test.go @@ -249,7 +249,7 @@ func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) { numGrowStep := 250 numReader := 16 if testing.Short() { - numLoop, numGrowStep = 2, 500 + numLoop, numGrowStep = 2, 100 } for i := 0; i < numLoop; i++ { m := make(map[int]int, 0) @@ -603,6 +603,142 @@ func TestIgnoreBogusMapHint(t *testing.T) { } } +var mapSink map[int]int + +var mapBucketTests = [...]struct { + n int // n is the number of map elements + noescape int // number of expected buckets for non-escaping map + escape int // number of expected buckets for escaping map +}{ + {-(1 << 30), 1, 1}, + {-1, 1, 1}, + {0, 1, 1}, + {1, 1, 1}, + {8, 1, 1}, + {9, 2, 2}, + {13, 2, 2}, + {14, 4, 4}, + {26, 4, 4}, +} + +func TestMapBuckets(t *testing.T) { + // Test that maps of different sizes have the right number of buckets. + // Non-escaping maps with small buckets (like map[int]int) never + // have a nil bucket pointer due to starting with preallocated buckets + // on the stack. Escaping maps start with a non-nil bucket pointer if + // hint size is above bucketCnt and thereby have more than one bucket. + // These tests depend on bucketCnt and loadFactor* in hashmap.go. + t.Run("mapliteral", func(t *testing.T) { + for _, tt := range mapBucketTests { + localMap := map[int]int{} + // Skip test on gccgo until escape analysis is + // turned on. + if runtime.MapBucketsPointerIsNil(localMap) && runtime.Compiler != "gccgo" { + t.Errorf("no escape: buckets pointer is nil for non-escaping map") + } + for i := 0; i < tt.n; i++ { + localMap[i] = i + } + if got := runtime.MapBucketsCount(localMap); got != tt.noescape { + t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got) + } + escapingMap := map[int]int{} + if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) { + t.Errorf("escape: buckets pointer is nil for n=%d buckets", count) + } + for i := 0; i < tt.n; i++ { + escapingMap[i] = i + } + if got := runtime.MapBucketsCount(escapingMap); got != tt.escape { + t.Errorf("escape n=%d want %d buckets, got %d", tt.n, tt.escape, got) + } + mapSink = escapingMap + } + }) + t.Run("nohint", func(t *testing.T) { + for _, tt := range mapBucketTests { + localMap := make(map[int]int) + // Skip test on gccgo until escape analysis is + // turned on. + if runtime.MapBucketsPointerIsNil(localMap) && runtime.Compiler != "gccgo" { + t.Errorf("no escape: buckets pointer is nil for non-escaping map") + } + for i := 0; i < tt.n; i++ { + localMap[i] = i + } + if got := runtime.MapBucketsCount(localMap); got != tt.noescape { + t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got) + } + escapingMap := make(map[int]int) + if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) { + t.Errorf("escape: buckets pointer is nil for n=%d buckets", count) + } + for i := 0; i < tt.n; i++ { + escapingMap[i] = i + } + if got := runtime.MapBucketsCount(escapingMap); got != tt.escape { + t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got) + } + mapSink = escapingMap + } + }) + t.Run("makemap", func(t *testing.T) { + for _, tt := range mapBucketTests { + localMap := make(map[int]int, tt.n) + // Skip test on gccgo until escape analysis is + // turned on. + if runtime.MapBucketsPointerIsNil(localMap) && runtime.Compiler != "gccgo" { + t.Errorf("no escape: buckets pointer is nil for non-escaping map") + } + for i := 0; i < tt.n; i++ { + localMap[i] = i + } + if got := runtime.MapBucketsCount(localMap); got != tt.noescape { + t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got) + } + escapingMap := make(map[int]int, tt.n) + if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) { + t.Errorf("escape: buckets pointer is nil for n=%d buckets", count) + } + for i := 0; i < tt.n; i++ { + escapingMap[i] = i + } + if got := runtime.MapBucketsCount(escapingMap); got != tt.escape { + t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got) + } + mapSink = escapingMap + } + }) + t.Run("makemap64", func(t *testing.T) { + for _, tt := range mapBucketTests { + localMap := make(map[int]int, int64(tt.n)) + // Skip test on gccgo until escape analysis is + // turned on. + if runtime.MapBucketsPointerIsNil(localMap) && runtime.Compiler != "gccgo" { + t.Errorf("no escape: buckets pointer is nil for non-escaping map") + } + for i := 0; i < tt.n; i++ { + localMap[i] = i + } + if got := runtime.MapBucketsCount(localMap); got != tt.noescape { + t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got) + } + escapingMap := make(map[int]int, tt.n) + if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) { + t.Errorf("escape: buckets pointer is nil for n=%d buckets", count) + } + for i := 0; i < tt.n; i++ { + escapingMap[i] = i + } + if got := runtime.MapBucketsCount(escapingMap); got != tt.escape { + t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got) + } + mapSink = escapingMap + } + }) + +} + func benchmarkMapPop(b *testing.B, n int) { m := map[int]int{} for i := 0; i < b.N; i++ { @@ -624,15 +760,39 @@ func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) } func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) } func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) } +var testNonEscapingMapVariable int = 8 + func TestNonEscapingMap(t *testing.T) { t.Skip("does not work on gccgo without better escape analysis") n := testing.AllocsPerRun(1000, func() { + m := map[int]int{} + m[0] = 0 + }) + if n != 0 { + t.Fatalf("mapliteral: want 0 allocs, got %v", n) + } + n = testing.AllocsPerRun(1000, func() { m := make(map[int]int) m[0] = 0 }) if n != 0 { - t.Fatalf("want 0 allocs, got %v", n) + t.Fatalf("no hint: want 0 allocs, got %v", n) + } + n = testing.AllocsPerRun(1000, func() { + m := make(map[int]int, 8) + m[0] = 0 + }) + if n != 0 { + t.Fatalf("with small hint: want 0 allocs, got %v", n) + } + n = testing.AllocsPerRun(1000, func() { + m := make(map[int]int, testNonEscapingMapVariable) + m[0] = 0 + }) + if n != 0 { + t.Fatalf("with variable hint: want 0 allocs, got %v", n) } + } func benchmarkMapAssignInt32(b *testing.B, n int) { @@ -643,12 +803,16 @@ func benchmarkMapAssignInt32(b *testing.B, n int) { } func benchmarkMapDeleteInt32(b *testing.B, n int) { - a := make(map[int32]int) - for i := 0; i < n*b.N; i++ { - a[int32(i)] = i - } + a := make(map[int32]int, n) b.ResetTimer() - for i := 0; i < n*b.N; i = i + n { + for i := 0; i < b.N; i++ { + if len(a) == 0 { + b.StopTimer() + for j := i; j < i+n; j++ { + a[int32(j)] = j + } + b.StartTimer() + } delete(a, int32(i)) } } @@ -661,12 +825,16 @@ func benchmarkMapAssignInt64(b *testing.B, n int) { } func benchmarkMapDeleteInt64(b *testing.B, n int) { - a := make(map[int64]int) - for i := 0; i < n*b.N; i++ { - a[int64(i)] = i - } + a := make(map[int64]int, n) b.ResetTimer() - for i := 0; i < n*b.N; i = i + n { + for i := 0; i < b.N; i++ { + if len(a) == 0 { + b.StopTimer() + for j := i; j < i+n; j++ { + a[int64(j)] = j + } + b.StartTimer() + } delete(a, int64(i)) } } @@ -684,17 +852,23 @@ func benchmarkMapAssignStr(b *testing.B, n int) { } func benchmarkMapDeleteStr(b *testing.B, n int) { - k := make([]string, n*b.N) - for i := 0; i < n*b.N; i++ { - k[i] = strconv.Itoa(i) - } - a := make(map[string]int) - for i := 0; i < n*b.N; i++ { - a[k[i]] = i + i2s := make([]string, n) + for i := 0; i < n; i++ { + i2s[i] = strconv.Itoa(i) } + a := make(map[string]int, n) b.ResetTimer() - for i := 0; i < n*b.N; i = i + n { - delete(a, k[i]) + k := 0 + for i := 0; i < b.N; i++ { + if len(a) == 0 { + b.StopTimer() + for j := 0; j < n; j++ { + a[i2s[j]] = j + } + k = i + b.StartTimer() + } + delete(a, i2s[i-k]) } } @@ -713,7 +887,7 @@ func BenchmarkMapAssign(b *testing.B) { } func BenchmarkMapDelete(b *testing.B) { - b.Run("Int32", runWith(benchmarkMapDeleteInt32, 1, 2, 4)) - b.Run("Int64", runWith(benchmarkMapDeleteInt64, 1, 2, 4)) - b.Run("Str", runWith(benchmarkMapDeleteStr, 1, 2, 4)) + b.Run("Int32", runWith(benchmarkMapDeleteInt32, 100, 1000, 10000)) + b.Run("Int64", runWith(benchmarkMapDeleteInt64, 100, 1000, 10000)) + b.Run("Str", runWith(benchmarkMapDeleteStr, 100, 1000, 10000)) } diff --git a/libgo/go/runtime/mbarrier.go b/libgo/go/runtime/mbarrier.go index d54016f0ba9..3b8f71434b8 100644 --- a/libgo/go/runtime/mbarrier.go +++ b/libgo/go/runtime/mbarrier.go @@ -189,6 +189,8 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) { func writebarrierptr_prewrite1(dst *uintptr, src uintptr) { mp := acquirem() if mp.inwb || mp.dying > 0 { + // We explicitly allow write barriers in startpanic_m, + // since we're going down anyway. Ignore them here. releasem(mp) return } @@ -244,6 +246,10 @@ func writebarrierptr_prewrite(dst *uintptr, src uintptr) { // typedmemmove copies a value of type t to dst from src. // Must be nosplit, see #16026. +// +// TODO: Perfect for go:nosplitrec since we can't have a safe point +// anywhere in the bulk barrier or memmove. +// //go:nosplit func typedmemmove(typ *_type, dst, src unsafe.Pointer) { if typ.kind&kindNoPointers == 0 { @@ -265,8 +271,8 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) { //go:linkname reflect_typedmemmove reflect.typedmemmove func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { if raceenabled { - raceWriteObjectPC(typ, dst, getcallerpc(unsafe.Pointer(&typ)), funcPC(reflect_typedmemmove)) - raceReadObjectPC(typ, src, getcallerpc(unsafe.Pointer(&typ)), funcPC(reflect_typedmemmove)) + raceWriteObjectPC(typ, dst, getcallerpc(), funcPC(reflect_typedmemmove)) + raceReadObjectPC(typ, src, getcallerpc(), funcPC(reflect_typedmemmove)) } if msanenabled { msanwrite(dst, typ.size) @@ -310,8 +316,12 @@ func typedslicecopy(typ *_type, dst, src slice) int { dstp := dst.array srcp := src.array + // The compiler emits calls to typedslicecopy before + // instrumentation runs, so unlike the other copying and + // assignment operations, it's not instrumented in the calling + // code and needs its own instrumentation. if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&typ)) + callerpc := getcallerpc() pc := funcPC(slicecopy) racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc) racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc) @@ -329,41 +339,13 @@ func typedslicecopy(typ *_type, dst, src slice) int { // compiler only emits calls to typedslicecopy for types with pointers, // and growslice and reflect_typedslicecopy check for pointers // before calling typedslicecopy. - if !writeBarrier.needed { - memmove(dstp, srcp, uintptr(n)*typ.size) - return n + size := uintptr(n) * typ.size + if writeBarrier.needed { + bulkBarrierPreWrite(uintptr(dstp), uintptr(srcp), size) } - - systemstack(func() { - if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) { - // Overlap with src before dst. - // Copy backward, being careful not to move dstp/srcp - // out of the array they point into. - dstp = add(dstp, uintptr(n-1)*typ.size) - srcp = add(srcp, uintptr(n-1)*typ.size) - i := 0 - for { - typedmemmove(typ, dstp, srcp) - if i++; i >= n { - break - } - dstp = add(dstp, -typ.size) - srcp = add(srcp, -typ.size) - } - } else { - // Copy forward, being careful not to move dstp/srcp - // out of the array they point into. - i := 0 - for { - typedmemmove(typ, dstp, srcp) - if i++; i >= n { - break - } - dstp = add(dstp, typ.size) - srcp = add(srcp, typ.size) - } - } - }) + // See typedmemmove for a discussion of the race between the + // barrier and memmove. + memmove(dstp, srcp, size) return n } @@ -380,7 +362,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int { size := uintptr(n) * elemType.size if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&elemType)) + callerpc := getcallerpc() pc := funcPC(reflect_typedslicecopy) racewriterangepc(dst.array, size, callerpc, pc) racereadrangepc(src.array, size, callerpc, pc) diff --git a/libgo/go/runtime/mbitmap.go b/libgo/go/runtime/mbitmap.go index d1a58202352..a775b57b033 100644 --- a/libgo/go/runtime/mbitmap.go +++ b/libgo/go/runtime/mbitmap.go @@ -463,11 +463,6 @@ func heapBitsForObject(p, refBase, refOff uintptr, forStack bool) (base uintptr, return } -// prefetch the bits. -func (h heapBits) prefetch() { - prefetchnta(uintptr(unsafe.Pointer((h.bitp)))) -} - // next returns the heapBits describing the next pointer-sized word in memory. // That is, if h describes address p, h.next() describes p+ptrSize. // Note that next does not modify h. The caller must record the result. @@ -542,12 +537,13 @@ func (h heapBits) setCheckmarked(size uintptr) { atomic.Or8(h.bitp, bitScan<<(heapBitsShift+h.shift)) } -// bulkBarrierPreWrite executes writebarrierptr_prewrite1 +// bulkBarrierPreWrite executes a write barrier // for every pointer slot in the memory range [src, src+size), // using pointer/scalar information from [dst, dst+size). // This executes the write barriers necessary before a memmove. // src, dst, and size must be pointer-aligned. // The range [dst, dst+size) must lie within a single object. +// It does not perform the actual writes. // // As a special case, src == 0 indicates that this is being used for a // memclr. bulkBarrierPreWrite will pass 0 for the src of each write @@ -593,12 +589,15 @@ func bulkBarrierPreWrite(dst, src, size uintptr) { return } + buf := &getg().m.p.ptr().wbBuf h := heapBitsForAddr(dst) if src == 0 { for i := uintptr(0); i < size; i += sys.PtrSize { if h.isPointer() { dstx := (*uintptr)(unsafe.Pointer(dst + i)) - writebarrierptr_prewrite1(dstx, 0) + if !buf.putFast(*dstx, 0) { + wbBufFlush(nil, 0) + } } h = h.next() } @@ -607,7 +606,9 @@ func bulkBarrierPreWrite(dst, src, size uintptr) { if h.isPointer() { dstx := (*uintptr)(unsafe.Pointer(dst + i)) srcx := (*uintptr)(unsafe.Pointer(src + i)) - writebarrierptr_prewrite1(dstx, *srcx) + if !buf.putFast(*dstx, *srcx) { + wbBufFlush(nil, 0) + } } h = h.next() } @@ -627,6 +628,7 @@ func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { bits = addb(bits, word/8) mask := uint8(1) << (word % 8) + buf := &getg().m.p.ptr().wbBuf for i := uintptr(0); i < size; i += sys.PtrSize { if mask == 0 { bits = addb(bits, 1) @@ -640,10 +642,14 @@ func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { if *bits&mask != 0 { dstx := (*uintptr)(unsafe.Pointer(dst + i)) if src == 0 { - writebarrierptr_prewrite1(dstx, 0) + if !buf.putFast(*dstx, 0) { + wbBufFlush(nil, 0) + } } else { srcx := (*uintptr)(unsafe.Pointer(src + i)) - writebarrierptr_prewrite1(dstx, *srcx) + if !buf.putFast(*dstx, *srcx) { + wbBufFlush(nil, 0) + } } } mask <<= 1 diff --git a/libgo/go/runtime/mcache.go b/libgo/go/runtime/mcache.go index 71a2f22114f..766cfd17523 100644 --- a/libgo/go/runtime/mcache.go +++ b/libgo/go/runtime/mcache.go @@ -96,7 +96,7 @@ func freemcache(c *mcache) { // 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. -func (c *mcache) refill(spc spanClass) *mspan { +func (c *mcache) refill(spc spanClass) { _g_ := getg() _g_.m.locks++ @@ -123,7 +123,6 @@ func (c *mcache) refill(spc spanClass) *mspan { c.alloc[spc] = s _g_.m.locks-- - return s } func (c *mcache) releaseAll() { diff --git a/libgo/go/runtime/mem_gccgo.go b/libgo/go/runtime/mem_gccgo.go index ea3e5ebab4e..a087945251f 100644 --- a/libgo/go/runtime/mem_gccgo.go +++ b/libgo/go/runtime/mem_gccgo.go @@ -13,9 +13,10 @@ import ( // Functions called by C code. //go:linkname sysAlloc runtime.sysAlloc +//go:linkname sysFree runtime.sysFree //extern mmap -func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) unsafe.Pointer +func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) unsafe.Pointer //extern munmap func munmap(addr unsafe.Pointer, length uintptr) int32 @@ -40,6 +41,14 @@ func init() { } } +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) (unsafe.Pointer, int) { + p := sysMmap(addr, n, prot, flags, fd, off) + if uintptr(p) == _MAP_FAILED { + return nil, errno() + } + return p, 0 +} + // 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. @@ -75,31 +84,30 @@ func addrspace_free(v unsafe.Pointer, n uintptr) bool { return true } -func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uintptr) unsafe.Pointer { - p := mmap(v, n, prot, flags, fd, offset) +func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uintptr) (unsafe.Pointer, int) { + p, err := mmap(v, n, prot, flags, fd, offset) // On some systems, mmap ignores v without // MAP_FIXED, so retry if the address space is free. if p != v && addrspace_free(v, n) { - if uintptr(p) != _MAP_FAILED { + if err == 0 { munmap(p, n) } - p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset) + p, err = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset) } - return p + return p, err } // Don't split the stack as this method may be invoked without a valid G, which // prevents us from allocating more stack. //go:nosplit func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer { - p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED { - errval := errno() - if errval == _EACCES { + p, err := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if err != 0 { + if err == _EACCES { print("runtime: mmap: access denied\n") exit(2) } - if errval == _EAGAIN { + if err == _EAGAIN { print("runtime: mmap: too much locked memory (check 'ulimit -l').\n") exit(2) } @@ -225,9 +233,9 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { // if we can reserve at least 64K and check the assumption in SysMap. // Only user-mode Linux (UML) rejects these requests. if sys.PtrSize == 8 && uint64(n) > 1<<32 { - p := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if p != v { - if uintptr(p) != _MAP_FAILED { + p, err := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if p != v || err != 0 { + if err == 0 { munmap(p, 64<<10) } return nil @@ -237,8 +245,8 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { return v } - p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED { + p, err := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if err != 0 { return nil } *reserved = true @@ -259,12 +267,12 @@ func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) { // to do this - we do not on other platforms. flags |= _MAP_FIXED } - p := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, flags, mmapFD, 0) - if uintptr(p) == _MAP_FAILED && errno() == _ENOMEM { + p, err := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, flags, mmapFD, 0) + if err == _ENOMEM { throw("runtime: out of memory") } - if p != v { - print("runtime: address space conflict: map(", v, ") = ", p, "\n") + if p != v || err != 0 { + print("runtime: address space conflict: map(", v, ") = ", p, " (err ", err, ")\n") throw("runtime: address space conflict") } return @@ -275,11 +283,11 @@ func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) { // So always unmap first even if it is already unmapped. munmap(v, n) } - p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED && errno() == _ENOMEM { + p, err := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, mmapFD, 0) + if err == _ENOMEM { throw("runtime: out of memory") } - if p != v { + if p != v || err != 0 { throw("runtime: cannot map pages in arena address space") } } diff --git a/libgo/go/runtime/memmove_test.go b/libgo/go/runtime/memmove_test.go index 74b8753b5f7..62de604e69c 100644 --- a/libgo/go/runtime/memmove_test.go +++ b/libgo/go/runtime/memmove_test.go @@ -9,6 +9,7 @@ import ( "encoding/binary" "fmt" "internal/race" + "internal/testenv" . "runtime" "testing" ) @@ -88,6 +89,10 @@ func TestMemmoveAlias(t *testing.T) { } func TestMemmoveLarge0x180000(t *testing.T) { + if testing.Short() && testenv.Builder() == "" { + t.Skip("-short") + } + t.Parallel() if race.Enabled { t.Skip("skipping large memmove test under race detector") @@ -96,6 +101,10 @@ func TestMemmoveLarge0x180000(t *testing.T) { } func TestMemmoveOverlapLarge0x120000(t *testing.T) { + if testing.Short() && testenv.Builder() == "" { + t.Skip("-short") + } + t.Parallel() if race.Enabled { t.Skip("skipping large memmove test under race detector") diff --git a/libgo/go/runtime/mfinal.go b/libgo/go/runtime/mfinal.go index 4353ee57569..19573d8b8d3 100644 --- a/libgo/go/runtime/mfinal.go +++ b/libgo/go/runtime/mfinal.go @@ -419,11 +419,7 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) { return } -// Mark KeepAlive as noinline so that the current compiler will ensure -// that the argument is alive at the point of the function call. -// If it were inlined, it would disappear, and there would be nothing -// keeping the argument alive. Perhaps a future compiler will recognize -// runtime.KeepAlive specially and do something more efficient. +// Mark KeepAlive as noinline so that it is easily detectable as an intrinsic. //go:noinline // KeepAlive marks its argument as currently reachable. @@ -445,4 +441,11 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) { // Without the KeepAlive call, the finalizer could run at the start of // syscall.Read, closing the file descriptor before syscall.Read makes // the actual system call. -func KeepAlive(interface{}) {} +func KeepAlive(x interface{}) { + // Introduce a use of x that the compiler can't eliminate. + // This makes sure x is alive on entry. We need x to be alive + // on entry for "defer runtime.KeepAlive(x)"; see issue 21402. + if cgoAlwaysFalse { + println(x) + } +} diff --git a/libgo/go/runtime/mfinal_test.go b/libgo/go/runtime/mfinal_test.go index 38c2623bb7b..2086e42ba33 100644 --- a/libgo/go/runtime/mfinal_test.go +++ b/libgo/go/runtime/mfinal_test.go @@ -254,3 +254,24 @@ var ( Foo2 = &Object2{} Foo1 = &Object1{} ) + +func TestDeferKeepAlive(t *testing.T) { + if *flagQuick { + t.Skip("-quick") + } + + // See issue 21402. + t.Parallel() + type T *int // needs to be a pointer base type to avoid tinyalloc and its never-finalized behavior. + x := new(T) + finRun := false + runtime.SetFinalizer(x, func(x *T) { + finRun = true + }) + defer runtime.KeepAlive(x) + runtime.GC() + time.Sleep(time.Second) + if finRun { + t.Errorf("finalizer ran prematurely") + } +} diff --git a/libgo/go/runtime/mgc.go b/libgo/go/runtime/mgc.go index 31c4be86fe4..626f088d450 100644 --- a/libgo/go/runtime/mgc.go +++ b/libgo/go/runtime/mgc.go @@ -231,6 +231,24 @@ func setGCPercent(in int32) (out int32) { // Update pacing in response to gcpercent change. gcSetTriggerRatio(memstats.triggerRatio) unlock(&mheap_.lock) + + // If we just disabled GC, wait for any concurrent GC to + // finish so we always return with no GC running. + if in < 0 { + // Disable phase transitions. + lock(&work.sweepWaiters.lock) + if gcphase == _GCmark { + // GC is active. Wait until we reach sweeping. + gp := getg() + gp.schedlink = work.sweepWaiters.head + work.sweepWaiters.head.set(gp) + goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1) + } else { + // GC isn't active. + unlock(&work.sweepWaiters.lock) + } + } + return out } @@ -300,10 +318,10 @@ const ( // gcMarkWorkerFractionalMode indicates that a P is currently // running the "fractional" mark worker. The fractional worker - // is necessary when GOMAXPROCS*gcGoalUtilization is not an - // integer. The fractional worker should run until it is + // is necessary when GOMAXPROCS*gcBackgroundUtilization is not + // an integer. The fractional worker should run until it is // preempted and will be scheduled to pick up the fractional - // part of GOMAXPROCS*gcGoalUtilization. + // part of GOMAXPROCS*gcBackgroundUtilization. gcMarkWorkerFractionalMode // gcMarkWorkerIdleMode indicates that a P is running the mark @@ -397,23 +415,18 @@ type gcControllerState struct { assistBytesPerWork float64 // fractionalUtilizationGoal is the fraction of wall clock - // time that should be spent in the fractional mark worker. - // For example, if the overall mark utilization goal is 25% - // and GOMAXPROCS is 6, one P will be a dedicated mark worker - // and this will be set to 0.5 so that 50% of the time some P - // is in a fractional mark worker. This is computed at the - // beginning of each cycle. + // time that should be spent in the fractional mark worker on + // each P that isn't running a dedicated worker. + // + // For example, if the utilization goal is 25% and there are + // no dedicated workers, this will be 0.25. If there goal is + // 25%, there is one dedicated worker, and GOMAXPROCS is 5, + // this will be 0.05 to make up the missing 5%. + // + // If this is zero, no fractional workers are needed. fractionalUtilizationGoal float64 _ [sys.CacheLineSize]byte - - // fractionalMarkWorkersNeeded is the number of fractional - // mark workers that need to be started. This is either 0 or - // 1. This is potentially updated atomically at every - // scheduling point (hence it gets its own cache line). - fractionalMarkWorkersNeeded int64 - - _ [sys.CacheLineSize]byte } // startCycle resets the GC controller's state and computes estimates @@ -454,23 +467,33 @@ func (c *gcControllerState) startCycle() { memstats.next_gc = memstats.heap_live + 1024*1024 } - // Compute the total mark utilization goal and divide it among - // dedicated and fractional workers. - totalUtilizationGoal := float64(gomaxprocs) * gcGoalUtilization - c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal) - c.fractionalUtilizationGoal = totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded) - if c.fractionalUtilizationGoal > 0 { - c.fractionalMarkWorkersNeeded = 1 + // Compute the background mark utilization goal. In general, + // this may not come out exactly. We round the number of + // dedicated workers so that the utilization is closest to + // 25%. For small GOMAXPROCS, this would introduce too much + // error, so we add fractional workers in that case. + totalUtilizationGoal := float64(gomaxprocs) * gcBackgroundUtilization + c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal + 0.5) + utilError := float64(c.dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1 + const maxUtilError = 0.3 + if utilError < -maxUtilError || utilError > maxUtilError { + // Rounding put us more than 30% off our goal. With + // gcBackgroundUtilization of 25%, this happens for + // GOMAXPROCS<=3 or GOMAXPROCS=6. Enable fractional + // workers to compensate. + if float64(c.dedicatedMarkWorkersNeeded) > totalUtilizationGoal { + // Too many dedicated workers. + c.dedicatedMarkWorkersNeeded-- + } + c.fractionalUtilizationGoal = (totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)) / float64(gomaxprocs) } else { - c.fractionalMarkWorkersNeeded = 0 + c.fractionalUtilizationGoal = 0 } // Clear per-P state - for _, p := range &allp { - if p == nil { - break - } + for _, p := range allp { p.gcAssistTime = 0 + p.gcFractionalMarkTime = 0 } // Compute initial values for controls that are updated @@ -483,7 +506,7 @@ func (c *gcControllerState) startCycle() { work.initialHeapLive>>20, "->", memstats.next_gc>>20, " MB)", " workers=", c.dedicatedMarkWorkersNeeded, - "+", c.fractionalMarkWorkersNeeded, "\n") + "+", c.fractionalUtilizationGoal, "\n") } } @@ -496,47 +519,73 @@ func (c *gcControllerState) startCycle() { // is when assists are enabled and the necessary statistics are // available). func (c *gcControllerState) revise() { - // Compute the expected scan work remaining. + gcpercent := gcpercent + if gcpercent < 0 { + // If GC is disabled but we're running a forced GC, + // act like GOGC is huge for the below calculations. + gcpercent = 100000 + } + live := atomic.Load64(&memstats.heap_live) + + var heapGoal, scanWorkExpected int64 + if live <= memstats.next_gc { + // We're under the soft goal. Pace GC to complete at + // next_gc assuming the heap is in steady-state. + heapGoal = int64(memstats.next_gc) + + // Compute the expected scan work remaining. + // + // This is estimated based on the expected + // steady-state scannable heap. For example, with + // GOGC=100, only half of the scannable heap is + // expected to be live, so that's what we target. + // + // (This is a float calculation to avoid overflowing on + // 100*heap_scan.) + scanWorkExpected = int64(float64(memstats.heap_scan) * 100 / float64(100+gcpercent)) + } else { + // We're past the soft goal. Pace GC so that in the + // worst case it will complete by the hard goal. + const maxOvershoot = 1.1 + heapGoal = int64(float64(memstats.next_gc) * maxOvershoot) + + // Compute the upper bound on the scan work remaining. + scanWorkExpected = int64(memstats.heap_scan) + } + + // Compute the remaining scan work estimate. // // Note that we currently count allocations during GC as both // scannable heap (heap_scan) and scan work completed - // (scanWork), so this difference won't be changed by - // allocations during GC. - // - // This particular estimate is a strict upper bound on the - // possible remaining scan work for the current heap. - // You might consider dividing this by 2 (or by - // (100+GOGC)/100) to counter this over-estimation, but - // benchmarks show that this has almost no effect on mean - // mutator utilization, heap size, or assist time and it - // introduces the danger of under-estimating and letting the - // mutator outpace the garbage collector. - scanWorkExpected := int64(memstats.heap_scan) - c.scanWork - if scanWorkExpected < 1000 { + // (scanWork), so allocation will change this difference will + // slowly in the soft regime and not at all in the hard + // regime. + scanWorkRemaining := scanWorkExpected - c.scanWork + if scanWorkRemaining < 1000 { // We set a somewhat arbitrary lower bound on // remaining scan work since if we aim a little high, // we can miss by a little. // // We *do* need to enforce that this is at least 1, // since marking is racy and double-scanning objects - // may legitimately make the expected scan work - // negative. - scanWorkExpected = 1000 + // may legitimately make the remaining scan work + // negative, even in the hard goal regime. + scanWorkRemaining = 1000 } // Compute the heap distance remaining. - heapDistance := int64(memstats.next_gc) - int64(atomic.Load64(&memstats.heap_live)) - if heapDistance <= 0 { + heapRemaining := heapGoal - int64(live) + if heapRemaining <= 0 { // This shouldn't happen, but if it does, avoid // dividing by zero or setting the assist negative. - heapDistance = 1 + heapRemaining = 1 } // Compute the mutator assist ratio so by the time the mutator // allocates the remaining heap bytes up to next_gc, it will // have done (or stolen) the remaining amount of scan work. - c.assistWorkPerByte = float64(scanWorkExpected) / float64(heapDistance) - c.assistBytesPerWork = float64(heapDistance) / float64(scanWorkExpected) + c.assistWorkPerByte = float64(scanWorkRemaining) / float64(heapRemaining) + c.assistBytesPerWork = float64(heapRemaining) / float64(scanWorkRemaining) } // endCycle computes the trigger ratio for the next cycle. @@ -570,7 +619,7 @@ func (c *gcControllerState) endCycle() float64 { assistDuration := nanotime() - c.markStartTime // Assume background mark hit its utilization goal. - utilization := gcGoalUtilization + utilization := gcBackgroundUtilization // Add assist utilization; avoid divide by zero. if assistDuration > 0 { utilization += float64(c.assistTime) / float64(assistDuration*int64(gomaxprocs)) @@ -689,51 +738,20 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g { // This P is now dedicated to marking until the end of // the concurrent mark phase. _p_.gcMarkWorkerMode = gcMarkWorkerDedicatedMode + } else if c.fractionalUtilizationGoal == 0 { + // No need for fractional workers. + return nil } else { - if !decIfPositive(&c.fractionalMarkWorkersNeeded) { - // No more workers are need right now. - return nil - } - - // This P has picked the token for the fractional worker. - // Is the GC currently under or at the utilization goal? - // If so, do more work. - // - // We used to check whether doing one time slice of work - // would remain under the utilization goal, but that has the - // effect of delaying work until the mutator has run for - // enough time slices to pay for the work. During those time - // slices, write barriers are enabled, so the mutator is running slower. - // Now instead we do the work whenever we're under or at the - // utilization work and pay for it by letting the mutator run later. - // This doesn't change the overall utilization averages, but it - // front loads the GC work so that the GC finishes earlier and - // write barriers can be turned off sooner, effectively giving - // the mutator a faster machine. - // - // The old, slower behavior can be restored by setting - // gcForcePreemptNS = forcePreemptNS. - const gcForcePreemptNS = 0 - - // TODO(austin): We could fast path this and basically - // eliminate contention on c.fractionalMarkWorkersNeeded by - // precomputing the minimum time at which it's worth - // next scheduling the fractional worker. Then Ps - // don't have to fight in the window where we've - // passed that deadline and no one has started the - // worker yet. + // Is this P behind on the fractional utilization + // goal? // - // TODO(austin): Shorter preemption interval for mark - // worker to improve fairness and give this - // finer-grained control over schedule? - now := nanotime() - gcController.markStartTime - then := now + gcForcePreemptNS - timeUsed := c.fractionalMarkTime + gcForcePreemptNS - if then > 0 && float64(timeUsed)/float64(then) > c.fractionalUtilizationGoal { - // Nope, we'd overshoot the utilization goal - atomic.Xaddint64(&c.fractionalMarkWorkersNeeded, +1) + // This should be kept in sync with pollFractionalWorkerExit. + delta := nanotime() - gcController.markStartTime + if delta > 0 && float64(_p_.gcFractionalMarkTime)/float64(delta) > c.fractionalUtilizationGoal { + // Nope. No need to run a fractional worker. return nil } + // Run a fractional worker. _p_.gcMarkWorkerMode = gcMarkWorkerFractionalMode } @@ -746,6 +764,24 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g { return gp } +// pollFractionalWorkerExit returns true if a fractional mark worker +// should self-preempt. It assumes it is called from the fractional +// worker. +func pollFractionalWorkerExit() bool { + // This should be kept in sync with the fractional worker + // scheduler logic in findRunnableGCWorker. + now := nanotime() + delta := now - gcController.markStartTime + if delta <= 0 { + return true + } + p := getg().m.p.ptr() + selfTime := p.gcFractionalMarkTime + (now - p.gcMarkWorkerStartTime) + // Add some slack to the utilization goal so that the + // fractional worker isn't behind again the instant it exits. + return float64(selfTime)/float64(delta) > 1.2*gcController.fractionalUtilizationGoal +} + // gcSetTriggerRatio sets the trigger ratio and updates everything // derived from it: the absolute trigger, the heap goal, mark pacing, // and sweep pacing. @@ -860,9 +896,22 @@ func gcSetTriggerRatio(triggerRatio float64) { } } -// gcGoalUtilization is the goal CPU utilization for background +// gcGoalUtilization is the goal CPU utilization for // marking as a fraction of GOMAXPROCS. -const gcGoalUtilization = 0.25 +const gcGoalUtilization = 0.30 + +// gcBackgroundUtilization is the fixed CPU utilization for background +// marking. It must be <= gcGoalUtilization. The difference between +// gcGoalUtilization and gcBackgroundUtilization will be made up by +// mark assists. The scheduler will aim to use within 50% of this +// goal. +// +// Setting this to < gcGoalUtilization avoids saturating the trigger +// feedback controller when there are no assists, which allows it to +// better control CPU and heap growth. However, the larger the gap, +// the more mutator assists are expected to happen, which impact +// mutator latency. +const gcBackgroundUtilization = 0.25 // gcCreditSlack is the amount of scan work credit that can can // accumulate locally before updating gcController.scanWork and, @@ -1159,7 +1208,7 @@ func (t gcTrigger) test() bool { if t.kind == gcTriggerAlways { return true } - if gcphase != _GCoff || gcpercent < 0 { + if gcphase != _GCoff { return false } switch t.kind { @@ -1170,6 +1219,9 @@ func (t gcTrigger) test() bool { // own write. return memstats.heap_live >= memstats.gc_trigger case gcTriggerTime: + if gcpercent < 0 { + return false + } lastgc := int64(atomic.Load64(&memstats.last_gc_nanotime)) return lastgc != 0 && t.now-lastgc > forcegcperiod case gcTriggerCycle: @@ -1236,7 +1288,7 @@ func gcStart(mode gcMode, trigger gcTrigger) { } } - // Ok, we're doing it! Stop everybody else + // Ok, we're doing it! Stop everybody else semacquire(&worldsema) if trace.enabled { @@ -1249,7 +1301,12 @@ func gcStart(mode gcMode, trigger gcTrigger) { gcResetMarkState() - work.stwprocs, work.maxprocs = gcprocs(), gomaxprocs + work.stwprocs, work.maxprocs = gomaxprocs, gomaxprocs + if work.stwprocs > ncpu { + // This is used to compute CPU time of the STW phases, + // so it can't be more than ncpu, even if GOMAXPROCS is. + work.stwprocs = ncpu + } work.heap0 = atomic.Load64(&memstats.heap_live) work.pauseNS = 0 work.mode = mode @@ -1257,6 +1314,9 @@ func gcStart(mode gcMode, trigger gcTrigger) { now := nanotime() work.tSweepTerm = now work.pauseStart = now + if trace.enabled { + traceGCSTWStart(1) + } systemstack(stopTheWorldWithSema) // Finish sweep before we start concurrent scan. systemstack(func() { @@ -1309,11 +1369,17 @@ func gcStart(mode gcMode, trigger gcTrigger) { gcController.markStartTime = now // Concurrent mark. - systemstack(startTheWorldWithSema) - now = nanotime() + systemstack(func() { + now = startTheWorldWithSema(trace.enabled) + }) work.pauseNS += now - work.pauseStart work.tMark = now } else { + if trace.enabled { + // Switch to mark termination STW. + traceGCSTWDone() + traceGCSTWStart(0) + } t := nanotime() work.tMark, work.tMarkTerm = t, t work.heapGoal = work.heap0 @@ -1356,7 +1422,8 @@ top: // TODO(austin): Should dedicated workers keep an eye on this // and exit gcDrain promptly? atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, -0xffffffff) - atomic.Xaddint64(&gcController.fractionalMarkWorkersNeeded, -0xffffffff) + prevFractionalGoal := gcController.fractionalUtilizationGoal + gcController.fractionalUtilizationGoal = 0 if !gcBlackenPromptly { // Transition from mark 1 to mark 2. @@ -1383,6 +1450,7 @@ top: // workers have exited their loop so we can // start new mark 2 workers. forEachP(func(_p_ *p) { + wbBufFlush1(_p_) _p_.gcw.dispose() }) }) @@ -1399,7 +1467,7 @@ top: // Now we can start up mark 2 workers. atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 0xffffffff) - atomic.Xaddint64(&gcController.fractionalMarkWorkersNeeded, 0xffffffff) + gcController.fractionalUtilizationGoal = prevFractionalGoal incnwait := atomic.Xadd(&work.nwait, +1) if incnwait == work.nproc && !gcMarkWorkAvailable(nil) { @@ -1414,6 +1482,9 @@ top: work.tMarkTerm = now work.pauseStart = now getg().m.preemptoff = "gcing" + if trace.enabled { + traceGCSTWStart(0) + } systemstack(stopTheWorldWithSema) // The gcphase is _GCmark, it will transition to _GCmarktermination // below. The important thing is that the wb remains active until @@ -1574,7 +1645,7 @@ func gcMarkTermination(nextTriggerRatio float64) { // so events don't leak into the wrong cycle. mProf_NextCycle() - systemstack(startTheWorldWithSema) + systemstack(func() { startTheWorldWithSema(true) }) // Flush the heap profile so we can start a new cycle next GC. // This is relatively expensive, so we don't do it with the @@ -1645,10 +1716,7 @@ func gcMarkTermination(nextTriggerRatio float64) { func gcBgMarkStartWorkers() { // Background marking is performed by per-P G's. Ensure that // each P has a background GC G. - for _, p := range &allp { - if p == nil || p.status == _Pdead { - break - } + for _, p := range allp { if p.gcBgMarkWorker == 0 { expectSystemGoroutine() go gcBgMarkWorker(p) @@ -1751,6 +1819,7 @@ func gcBgMarkWorker(_p_ *p) { } startTime := nanotime() + _p_.gcMarkWorkerStartTime = startTime decnwait := atomic.Xadd(&work.nwait, -1) if decnwait == work.nproc { @@ -1792,7 +1861,7 @@ func gcBgMarkWorker(_p_ *p) { // without preemption. gcDrain(&_p_.gcw, gcDrainNoBlock|gcDrainFlushBgCredit) case gcMarkWorkerFractionalMode: - gcDrain(&_p_.gcw, gcDrainUntilPreempt|gcDrainFlushBgCredit) + gcDrain(&_p_.gcw, gcDrainFractional|gcDrainUntilPreempt|gcDrainFlushBgCredit) case gcMarkWorkerIdleMode: gcDrain(&_p_.gcw, gcDrainIdle|gcDrainUntilPreempt|gcDrainFlushBgCredit) } @@ -1817,7 +1886,7 @@ func gcBgMarkWorker(_p_ *p) { atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 1) case gcMarkWorkerFractionalMode: atomic.Xaddint64(&gcController.fractionalMarkTime, duration) - atomic.Xaddint64(&gcController.fractionalMarkWorkersNeeded, 1) + atomic.Xaddint64(&_p_.gcFractionalMarkTime, duration) case gcMarkWorkerIdleMode: atomic.Xaddint64(&gcController.idleMarkTime, duration) } @@ -1915,10 +1984,6 @@ func gcMark(start_time int64) { work.helperDrainBlock = true } - if trace.enabled { - traceGCScanStart() - } - if work.nproc > 1 { noteclear(&work.alldone) helpgc(int32(work.nproc)) @@ -1952,8 +2017,8 @@ func gcMark(start_time int64) { // Double-check that all gcWork caches are empty. This should // be ensured by mark 2 before we enter mark termination. - for i := 0; i < int(gomaxprocs); i++ { - gcw := &allp[i].gcw + for _, p := range allp { + gcw := &p.gcw if !gcw.empty() { throw("P has cached GC work at end of mark termination") } @@ -1962,10 +2027,6 @@ func gcMark(start_time int64) { } } - if trace.enabled { - traceGCScanDone() - } - cachestats() // Update the marked heap stat. @@ -2093,18 +2154,19 @@ func clearpools() { unlock(&sched.deferlock) } -// Timing - -//go:nowritebarrier +// gchelper runs mark termination tasks on Ps other than the P +// coordinating mark termination. +// +// The caller is responsible for ensuring that this has a P to run on, +// even though it's running during STW. Because of this, it's allowed +// to have write barriers. +// +//go:yeswritebarrierrec func gchelper() { _g_ := getg() _g_.m.traceback = 2 gchelperstart() - if trace.enabled { - traceGCScanStart() - } - // Parallel mark over GC roots and heap if gcphase == _GCmarktermination { gcw := &_g_.m.p.ptr().gcw @@ -2116,10 +2178,6 @@ func gchelper() { gcw.dispose() } - if trace.enabled { - traceGCScanDone() - } - nproc := atomic.Load(&work.nproc) // work.nproc can change right after we increment work.ndone if atomic.Xadd(&work.ndone, +1) == nproc-1 { notewakeup(&work.alldone) @@ -2138,6 +2196,8 @@ func gchelperstart() { } } +// Timing + // itoaDiv formats val/(10**dec) into buf. func itoaDiv(buf []byte, val uint64, dec int) []byte { i := len(buf) - 1 diff --git a/libgo/go/runtime/mgc_gccgo.go b/libgo/go/runtime/mgc_gccgo.go index c1fa1547adc..107a70a7898 100644 --- a/libgo/go/runtime/mgc_gccgo.go +++ b/libgo/go/runtime/mgc_gccgo.go @@ -6,7 +6,10 @@ package runtime -import "unsafe" +import ( + "runtime/internal/sys" + "unsafe" +) // gcRoot is a single GC root: a variable plus a ptrmask. type gcRoot struct { @@ -85,3 +88,21 @@ func checkPreempt() { gp.scanningself = false mcall(gopreempt_m) } + +// gcWriteBarrier implements a write barrier. This is implemented in +// assembly in the gc library, but there is no special advantage to +// doing so with gccgo. +//go:nosplit +//go:nowritebarrier +func gcWriteBarrier(dst *uintptr, src uintptr) { + buf := &getg().m.p.ptr().wbBuf + next := buf.next + np := next + 2*sys.PtrSize + buf.next = np + *(*uintptr)(unsafe.Pointer(next)) = src + *(*uintptr)(unsafe.Pointer(next + sys.PtrSize)) = *dst + if np >= buf.end { + wbBufFlush(dst, src) + } + *dst = src +} diff --git a/libgo/go/runtime/mgclarge.go b/libgo/go/runtime/mgclarge.go index 757e88d1d9d..fe437bf5e84 100644 --- a/libgo/go/runtime/mgclarge.go +++ b/libgo/go/runtime/mgclarge.go @@ -164,11 +164,10 @@ func (root *mTreap) insert(span *mspan) { } } -func (root *mTreap) removeNode(t *treapNode) *mspan { +func (root *mTreap) removeNode(t *treapNode) { if t.spanKey.npages != t.npagesKey { throw("span and treap node npages do not match") } - result := t.spanKey // Rotate t down to be leaf of tree for removal, respecting priorities. for t.right != nil || t.left != nil { @@ -192,7 +191,6 @@ func (root *mTreap) removeNode(t *treapNode) *mspan { t.spanKey = nil t.npagesKey = 0 mheap_.treapalloc.free(unsafe.Pointer(t)) - return result } // remove searches for, finds, removes from the treap, and returns the smallest diff --git a/libgo/go/runtime/mgcmark.go b/libgo/go/runtime/mgcmark.go index 998a830caa8..7297fcb6d1a 100644 --- a/libgo/go/runtime/mgcmark.go +++ b/libgo/go/runtime/mgcmark.go @@ -34,13 +34,13 @@ const ( // span base. maxObletBytes = 128 << 10 - // idleCheckThreshold specifies how many units of work to do - // between run queue checks in an idle worker. Assuming a scan + // drainCheckThreshold specifies how many units of work to do + // between self-preemption checks in gcDrain. Assuming a scan // rate of 1 MB/ms, this is ~100 µs. Lower values have higher // overhead in the scan loop (the scheduler check may perform // a syscall, so its overhead is nontrivial). Higher values // make the system less responsive to incoming work. - idleCheckThreshold = 100000 + drainCheckThreshold = 100000 ) // gcMarkRootPrepare queues root scanning jobs (stacks, globals, and @@ -717,6 +717,7 @@ const ( gcDrainNoBlock gcDrainFlushBgCredit gcDrainIdle + gcDrainFractional // gcDrainBlock means neither gcDrainUntilPreempt or // gcDrainNoBlock. It is the default, but callers should use @@ -733,6 +734,10 @@ const ( // If flags&gcDrainIdle != 0, gcDrain returns when there is other work // to do. This implies gcDrainNoBlock. // +// If flags&gcDrainFractional != 0, gcDrain self-preempts when +// pollFractionalWorkerExit() returns true. This implies +// gcDrainNoBlock. +// // If flags&gcDrainNoBlock != 0, gcDrain returns as soon as it is // unable to get more work. Otherwise, it will block until all // blocking calls are blocked in gcDrain. @@ -749,14 +754,24 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) { gp := getg().m.curg preemptible := flags&gcDrainUntilPreempt != 0 - blocking := flags&(gcDrainUntilPreempt|gcDrainIdle|gcDrainNoBlock) == 0 + blocking := flags&(gcDrainUntilPreempt|gcDrainIdle|gcDrainFractional|gcDrainNoBlock) == 0 flushBgCredit := flags&gcDrainFlushBgCredit != 0 idle := flags&gcDrainIdle != 0 initScanWork := gcw.scanWork - // idleCheck is the scan work at which to perform the next - // idle check with the scheduler. - idleCheck := initScanWork + idleCheckThreshold + + // checkWork is the scan work before performing the next + // self-preempt check. + checkWork := int64(1<<63 - 1) + var check func() bool + if flags&(gcDrainIdle|gcDrainFractional) != 0 { + checkWork = initScanWork + drainCheckThreshold + if idle { + check = pollWork + } else if flags&gcDrainFractional != 0 { + check = pollFractionalWorkerExit + } + } // Drain root marking jobs. if work.markrootNext < work.markrootJobs { @@ -766,7 +781,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) { break } markroot(gcw, job) - if idle && pollWork() { + if check != nil && check() { goto done } } @@ -807,12 +822,12 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) { gcFlushBgCredit(gcw.scanWork - initScanWork) initScanWork = 0 } - idleCheck -= gcw.scanWork + checkWork -= gcw.scanWork gcw.scanWork = 0 - if idle && idleCheck <= 0 { - idleCheck += idleCheckThreshold - if pollWork() { + if checkWork <= 0 { + checkWork += drainCheckThreshold + if check != nil && check() { break } } @@ -1091,6 +1106,9 @@ func shade(b uintptr) { // obj is the start of an object with mark mbits. // If it isn't already marked, mark it and enqueue into gcw. // base and off are for debugging only and could be removed. +// +// See also wbBufFlush1, which partially duplicates this logic. +// //go:nowritebarrierrec func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork, objIndex uintptr, forStack bool) { // obj should be start of allocation, and so must be at least pointer-aligned. @@ -1249,10 +1267,7 @@ func gcmarknewobject(obj, size, scanSize uintptr) { // // The world must be stopped. func gcMarkTinyAllocs() { - for _, p := range &allp { - if p == nil || p.status == _Pdead { - break - } + for _, p := range allp { c := p.mcache if c == nil || c.tiny == 0 { continue diff --git a/libgo/go/runtime/mgcwork.go b/libgo/go/runtime/mgcwork.go index 461679b9343..c6634fc78ca 100644 --- a/libgo/go/runtime/mgcwork.go +++ b/libgo/go/runtime/mgcwork.go @@ -85,6 +85,13 @@ type gcWork struct { scanWork int64 } +// Most of the methods of gcWork are go:nowritebarrierrec because the +// write barrier itself can invoke gcWork methods but the methods are +// not generally re-entrant. Hence, if a gcWork method invoked the +// write barrier while the gcWork was in an inconsistent state, and +// the write barrier in turn invoked a gcWork method, it could +// permanently corrupt the gcWork. + func (w *gcWork) init() { w.wbuf1 = getempty() wbuf2 := trygetfull() @@ -96,7 +103,7 @@ func (w *gcWork) init() { // put enqueues a pointer for the garbage collector to trace. // obj must point to the beginning of a heap object or an oblet. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) put(obj uintptr) { flushed := false wbuf := w.wbuf1 @@ -129,7 +136,7 @@ func (w *gcWork) put(obj uintptr) { // putFast does a put and returns true if it can be done quickly // otherwise it returns false and the caller needs to call put. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) putFast(obj uintptr) bool { wbuf := w.wbuf1 if wbuf == nil { @@ -143,12 +150,45 @@ func (w *gcWork) putFast(obj uintptr) bool { return true } +// putBatch performs a put on every pointer in obj. See put for +// constraints on these pointers. +// +//go:nowritebarrierrec +func (w *gcWork) putBatch(obj []uintptr) { + if len(obj) == 0 { + return + } + + flushed := false + wbuf := w.wbuf1 + if wbuf == nil { + w.init() + wbuf = w.wbuf1 + } + + for len(obj) > 0 { + for wbuf.nobj == len(wbuf.obj) { + putfull(wbuf) + w.wbuf1, w.wbuf2 = w.wbuf2, getempty() + wbuf = w.wbuf1 + flushed = true + } + n := copy(wbuf.obj[wbuf.nobj:], obj) + wbuf.nobj += n + obj = obj[n:] + } + + if flushed && gcphase == _GCmark { + gcController.enlistWorker() + } +} + // tryGet dequeues a pointer for the garbage collector to trace. // // If there are no pointers remaining in this gcWork or in the global // queue, tryGet returns 0. Note that there may still be pointers in // other gcWork instances or other caches. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) tryGet() uintptr { wbuf := w.wbuf1 if wbuf == nil { @@ -177,7 +217,7 @@ func (w *gcWork) tryGet() uintptr { // tryGetFast dequeues a pointer for the garbage collector to trace // if one is readily available. Otherwise it returns 0 and // the caller is expected to call tryGet(). -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) tryGetFast() uintptr { wbuf := w.wbuf1 if wbuf == nil { @@ -194,7 +234,7 @@ func (w *gcWork) tryGetFast() uintptr { // get dequeues a pointer for the garbage collector to trace, blocking // if necessary to ensure all pointers from all queues and caches have // been retrieved. get returns 0 if there are no pointers remaining. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) get() uintptr { wbuf := w.wbuf1 if wbuf == nil { @@ -228,7 +268,7 @@ func (w *gcWork) get() uintptr { // GC can inspect them. This helps reduce the mutator's // ability to hide pointers during the concurrent mark phase. // -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) dispose() { if wbuf := w.wbuf1; wbuf != nil { if wbuf.nobj == 0 { @@ -262,7 +302,7 @@ func (w *gcWork) dispose() { // balance moves some work that's cached in this gcWork back on the // global queue. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) balance() { if w.wbuf1 == nil { return @@ -282,7 +322,7 @@ func (w *gcWork) balance() { } // empty returns true if w has no mark work available. -//go:nowritebarrier +//go:nowritebarrierrec func (w *gcWork) empty() bool { return w.wbuf1 == nil || (w.wbuf1.nobj == 0 && w.wbuf2.nobj == 0) } diff --git a/libgo/go/runtime/mheap.go b/libgo/go/runtime/mheap.go index 8749f971065..d971bfee4df 100644 --- a/libgo/go/runtime/mheap.go +++ b/libgo/go/runtime/mheap.go @@ -56,6 +56,12 @@ type mheap struct { // Internal pages map to an arbitrary span. // For pages that have never been allocated, spans entries are nil. // + // Modifications are protected by mheap.lock. Reads can be + // performed without locking, but ONLY from indexes that are + // known to contain in-use or stack spans. This means there + // must not be a safe-point between establishing that an + // address is live and looking it up in the spans array. + // // This is backed by a reserved region of the address space so // it can grow without moving. The memory up to len(spans) is // mapped. cap(spans) indicates the total reserved memory. @@ -154,6 +160,8 @@ type mheap struct { specialfinalizeralloc fixalloc // allocator for specialfinalizer* specialprofilealloc fixalloc // allocator for specialprofile* speciallock mutex // lock for special record allocators. + + unused *specialfinalizer // never set, just here to force the specialfinalizer type into DWARF } var mheap_ mheap @@ -311,6 +319,17 @@ func (s *mspan) layout() (size, n, total uintptr) { return } +// recordspan adds a newly allocated span to h.allspans. +// +// This only happens the first time a span is allocated from +// mheap.spanalloc (it is not called when a span is reused). +// +// Write barriers are disallowed here because it can be called from +// gcWork when allocating new workbufs. However, because it's an +// indirect call from the fixalloc initializer, the compiler can't see +// this. +// +//go:nowritebarrierrec func recordspan(vh unsafe.Pointer, p unsafe.Pointer) { h := (*mheap)(vh) s := (*mspan)(p) @@ -320,8 +339,8 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) { n = cap(h.allspans) * 3 / 2 } var new []*mspan - sp := (*slice)(unsafe.Pointer(&new)) - sp.array = sysAlloc(uintptr(n)*sys.PtrSize, &memstats.other_sys) + sp := (*notInHeapSlice)(unsafe.Pointer(&new)) + sp.array = (*notInHeap)(sysAlloc(uintptr(n)*sys.PtrSize, &memstats.other_sys)) if sp.array == nil { throw("runtime: cannot allocate memory") } @@ -331,12 +350,13 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) { copy(new, h.allspans) } oldAllspans := h.allspans - h.allspans = new + *(*notInHeapSlice)(unsafe.Pointer(&h.allspans)) = *(*notInHeapSlice)(unsafe.Pointer(&new)) if len(oldAllspans) != 0 { sysFree(unsafe.Pointer(&oldAllspans[0]), uintptr(cap(oldAllspans))*unsafe.Sizeof(oldAllspans[0]), &memstats.other_sys) } } - h.allspans = append(h.allspans, s) + h.allspans = h.allspans[:len(h.allspans)+1] + h.allspans[len(h.allspans)-1] = s } // A spanClass represents the size class and noscan-ness of a span. @@ -854,7 +874,7 @@ HaveSpan: // Large spans have a minimum size of 1MByte. The maximum number of large spans to support // 1TBytes is 1 million, experimentation using random sizes indicates that the depth of // the tree is less that 2x that of a perfectly balanced tree. For 1TByte can be referenced -// by a perfectly balanced tree with a a depth of 20. Twice that is an acceptable 40. +// by a perfectly balanced tree with a depth of 20. Twice that is an acceptable 40. func (h *mheap) isLargeSpan(npages uintptr) bool { return npages >= uintptr(len(h.free)) } @@ -1120,34 +1140,35 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr { var sumreleased uintptr for s := list.first; s != nil; s = s.next { - if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages { - start := s.base() - end := start + s.npages<<_PageShift - if physPageSize > _PageSize { - // We can only release pages in - // physPageSize blocks, so round start - // and end in. (Otherwise, madvise - // will round them *out* and release - // more memory than we want.) - start = (start + physPageSize - 1) &^ (physPageSize - 1) - end &^= physPageSize - 1 - if end <= start { - // start and end don't span a - // whole physical page. - continue - } - } - len := end - start - - released := len - (s.npreleased << _PageShift) - if physPageSize > _PageSize && released == 0 { + if (now-uint64(s.unusedsince)) <= limit || s.npreleased == s.npages { + continue + } + start := s.base() + end := start + s.npages<<_PageShift + if physPageSize > _PageSize { + // We can only release pages in + // physPageSize blocks, so round start + // and end in. (Otherwise, madvise + // will round them *out* and release + // more memory than we want.) + start = (start + physPageSize - 1) &^ (physPageSize - 1) + end &^= physPageSize - 1 + if end <= start { + // start and end don't span a + // whole physical page. continue } - memstats.heap_released += uint64(released) - sumreleased += released - s.npreleased = len >> _PageShift - sysUnused(unsafe.Pointer(start), len) } + len := end - start + + released := len - (s.npreleased << _PageShift) + if physPageSize > _PageSize && released == 0 { + continue + } + memstats.heap_released += uint64(released) + sumreleased += released + s.npreleased = len >> _PageShift + sysUnused(unsafe.Pointer(start), len) } return sumreleased } diff --git a/libgo/go/runtime/mksizeclasses.go b/libgo/go/runtime/mksizeclasses.go index 0cb2b33a8cd..b146dbcd6c9 100644 --- a/libgo/go/runtime/mksizeclasses.go +++ b/libgo/go/runtime/mksizeclasses.go @@ -24,8 +24,8 @@ // In practice, only one of the wastes comes into play for a // given size (sizes < 512 waste mainly on the round-up, // sizes > 512 waste mainly on the page chopping). -// -// TODO(rsc): Compute max waste for any given size. +// For really small sizes, alignment constraints force the +// overhead higher. package main @@ -242,15 +242,18 @@ nextk: } func printComment(w io.Writer, classes []class) { - fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-11s\n", "class", "bytes/obj", "bytes/span", "objects", "waste bytes") + fmt.Fprintf(w, "// %-5s %-9s %-10s %-7s %-10s %-9s\n", "class", "bytes/obj", "bytes/span", "objects", "tail waste", "max waste") + prevSize := 0 for i, c := range classes { if i == 0 { continue } spanSize := c.npages * pageSize objects := spanSize / c.size - waste := spanSize - c.size*(spanSize/c.size) - fmt.Fprintf(w, "// %5d %9d %10d %7d %11d\n", i, c.size, spanSize, objects, waste) + tailWaste := spanSize - c.size*(spanSize/c.size) + maxWaste := float64((c.size-prevSize-1)*objects+tailWaste) / float64(spanSize) + prevSize = c.size + fmt.Fprintf(w, "// %5d %9d %10d %7d %10d %8.2f%%\n", i, c.size, spanSize, objects, tailWaste, 100*maxWaste) } fmt.Fprintf(w, "\n") } diff --git a/libgo/go/runtime/mstats.go b/libgo/go/runtime/mstats.go index 71dc2239854..22f5195cd58 100644 --- a/libgo/go/runtime/mstats.go +++ b/libgo/go/runtime/mstats.go @@ -589,12 +589,13 @@ func updatememstats() { memstats.heap_objects = memstats.nmalloc - memstats.nfree } +// cachestats flushes all mcache stats. +// +// The world must be stopped. +// //go:nowritebarrier func cachestats() { - for _, p := range &allp { - if p == nil { - break - } + for _, p := range allp { c := p.mcache if c == nil { continue @@ -610,9 +611,6 @@ func cachestats() { //go:nowritebarrier func flushmcache(i int) { p := allp[i] - if p == nil { - return - } c := p.mcache if c == nil { return @@ -665,7 +663,7 @@ func purgecachedstats(c *mcache) { // overflow errors. //go:nosplit func mSysStatInc(sysStat *uint64, n uintptr) { - if sys.BigEndian != 0 { + if sys.BigEndian { atomic.Xadd64(sysStat, int64(n)) return } @@ -679,7 +677,7 @@ func mSysStatInc(sysStat *uint64, n uintptr) { // mSysStatInc apply. //go:nosplit func mSysStatDec(sysStat *uint64, n uintptr) { - if sys.BigEndian != 0 { + if sys.BigEndian { atomic.Xadd64(sysStat, -int64(n)) return } diff --git a/libgo/go/runtime/mwbbuf.go b/libgo/go/runtime/mwbbuf.go new file mode 100644 index 00000000000..a060df8bc06 --- /dev/null +++ b/libgo/go/runtime/mwbbuf.go @@ -0,0 +1,248 @@ +// Copyright 2017 The Go 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 implements the write barrier buffer. The write barrier itself +// is gcWriteBarrier and is implemented in assembly. +// +// The write barrier has a fast path and a slow path. The fast path +// simply enqueues to a per-P write barrier buffer. It's written in +// assembly and doesn't clobber any general purpose registers, so it +// doesn't have the usual overheads of a Go call. +// +// When the buffer fills up, the write barrier invokes the slow path +// (wbBufFlush) to flush the buffer to the GC work queues. In this +// path, since the compiler didn't spill registers, we spill *all* +// registers and disallow any GC safe points that could observe the +// stack frame (since we don't know the types of the spilled +// registers). + +package runtime + +import ( + "runtime/internal/sys" + "unsafe" +) + +// testSmallBuf forces a small write barrier buffer to stress write +// barrier flushing. +const testSmallBuf = false + +// wbBuf is a per-P buffer of pointers queued by the write barrier. +// This buffer is flushed to the GC workbufs when it fills up and on +// various GC transitions. +// +// This is closely related to a "sequential store buffer" (SSB), +// except that SSBs are usually used for maintaining remembered sets, +// while this is used for marking. +type wbBuf struct { + // next points to the next slot in buf. It must not be a + // pointer type because it can point past the end of buf and + // must be updated without write barriers. + // + // This is a pointer rather than an index to optimize the + // write barrier assembly. + next uintptr + + // end points to just past the end of buf. It must not be a + // pointer type because it points past the end of buf and must + // be updated without write barriers. + end uintptr + + // buf stores a series of pointers to execute write barriers + // on. This must be a multiple of wbBufEntryPointers because + // the write barrier only checks for overflow once per entry. + buf [wbBufEntryPointers * wbBufEntries]uintptr +} + +const ( + // wbBufEntries is the number of write barriers between + // flushes of the write barrier buffer. + // + // This trades latency for throughput amortization. Higher + // values amortize flushing overhead more, but increase the + // latency of flushing. Higher values also increase the cache + // footprint of the buffer. + // + // TODO: What is the latency cost of this? Tune this value. + wbBufEntries = 256 + + // wbBufEntryPointers is the number of pointers added to the + // buffer by each write barrier. + wbBufEntryPointers = 2 +) + +// reset empties b by resetting its next and end pointers. +func (b *wbBuf) reset() { + start := uintptr(unsafe.Pointer(&b.buf[0])) + b.next = start + if gcBlackenPromptly || writeBarrier.cgo { + // Effectively disable the buffer by forcing a flush + // on every barrier. + b.end = uintptr(unsafe.Pointer(&b.buf[wbBufEntryPointers])) + } else if testSmallBuf { + // For testing, allow two barriers in the buffer. If + // we only did one, then barriers of non-heap pointers + // would be no-ops. This lets us combine a buffered + // barrier with a flush at a later time. + b.end = uintptr(unsafe.Pointer(&b.buf[2*wbBufEntryPointers])) + } else { + b.end = start + uintptr(len(b.buf))*unsafe.Sizeof(b.buf[0]) + } + + if (b.end-b.next)%(wbBufEntryPointers*unsafe.Sizeof(b.buf[0])) != 0 { + throw("bad write barrier buffer bounds") + } +} + +// putFast adds old and new to the write barrier buffer and returns +// false if a flush is necessary. Callers should use this as: +// +// buf := &getg().m.p.ptr().wbBuf +// if !buf.putFast(old, new) { +// wbBufFlush(...) +// } +// +// The arguments to wbBufFlush depend on whether the caller is doing +// its own cgo pointer checks. If it is, then this can be +// wbBufFlush(nil, 0). Otherwise, it must pass the slot address and +// new. +// +// Since buf is a per-P resource, the caller must ensure there are no +// preemption points while buf is in use. +// +// It must be nowritebarrierrec to because write barriers here would +// corrupt the write barrier buffer. It (and everything it calls, if +// it called anything) has to be nosplit to avoid scheduling on to a +// different P and a different buffer. +// +//go:nowritebarrierrec +//go:nosplit +func (b *wbBuf) putFast(old, new uintptr) bool { + p := (*[2]uintptr)(unsafe.Pointer(b.next)) + p[0] = old + p[1] = new + b.next += 2 * sys.PtrSize + return b.next != b.end +} + +// wbBufFlush flushes the current P's write barrier buffer to the GC +// workbufs. It is passed the slot and value of the write barrier that +// caused the flush so that it can implement cgocheck. +// +// This must not have write barriers because it is part of the write +// barrier implementation. +// +// This and everything it calls must be nosplit because 1) the stack +// contains untyped slots from gcWriteBarrier and 2) there must not be +// a GC safe point between the write barrier test in the caller and +// flushing the buffer. +// +// TODO: A "go:nosplitrec" annotation would be perfect for this. +// +//go:nowritebarrierrec +//go:nosplit +func wbBufFlush(dst *uintptr, src uintptr) { + if getg().m.dying > 0 { + // We're going down. Not much point in write barriers + // and this way we can allow write barriers in the + // panic path. + return + } + + if writeBarrier.cgo && dst != nil { + // This must be called from the stack that did the + // write. It's nosplit all the way down. + cgoCheckWriteBarrier(dst, src) + if !writeBarrier.needed { + // We were only called for cgocheck. + b := &getg().m.p.ptr().wbBuf + b.next = uintptr(unsafe.Pointer(&b.buf[0])) + return + } + } + + // Switch to the system stack so we don't have to worry about + // the untyped stack slots or safe points. + systemstack(func() { + wbBufFlush1(getg().m.p.ptr()) + }) +} + +// wbBufFlush1 flushes p's write barrier buffer to the GC work queue. +// +// This must not have write barriers because it is part of the write +// barrier implementation, so this may lead to infinite loops or +// buffer corruption. +// +// This must be non-preemptible because it uses the P's workbuf. +// +//go:nowritebarrierrec +//go:systemstack +func wbBufFlush1(_p_ *p) { + // Get the buffered pointers. + start := uintptr(unsafe.Pointer(&_p_.wbBuf.buf[0])) + n := (_p_.wbBuf.next - start) / unsafe.Sizeof(_p_.wbBuf.buf[0]) + ptrs := _p_.wbBuf.buf[:n] + + // Reset the buffer. + _p_.wbBuf.reset() + + if useCheckmark { + // Slow path for checkmark mode. + for _, ptr := range ptrs { + shade(ptr) + } + return + } + + // Mark all of the pointers in the buffer and record only the + // pointers we greyed. We use the buffer itself to temporarily + // record greyed pointers. + // + // TODO: Should scanobject/scanblock just stuff pointers into + // the wbBuf? Then this would become the sole greying path. + gcw := &_p_.gcw + pos := 0 + arenaStart := mheap_.arena_start + for _, ptr := range ptrs { + if ptr < arenaStart { + // nil pointers are very common, especially + // for the "old" values. Filter out these and + // other "obvious" non-heap pointers ASAP. + // + // TODO: Should we filter out nils in the fast + // path to reduce the rate of flushes? + continue + } + // TODO: This doesn't use hbits, so calling + // heapBitsForObject seems a little silly. We could + // easily separate this out since heapBitsForObject + // just calls heapBitsForAddr(obj) to get hbits. + obj, _, span, objIndex := heapBitsForObject(ptr, 0, 0, false) + if obj == 0 { + continue + } + // TODO: Consider making two passes where the first + // just prefetches the mark bits. + mbits := span.markBitsForIndex(objIndex) + if mbits.isMarked() { + continue + } + mbits.setMarked() + if span.spanclass.noscan() { + gcw.bytesMarked += uint64(span.elemsize) + continue + } + ptrs[pos] = obj + pos++ + } + + // Enqueue the greyed objects. + gcw.putBatch(ptrs[:pos]) + if gcphase == _GCmarktermination || gcBlackenPromptly { + // Ps aren't allowed to cache work during mark + // termination. + gcw.dispose() + } +} diff --git a/libgo/go/runtime/netpoll_kqueue.go b/libgo/go/runtime/netpoll_kqueue.go index 47927fe7c37..1f68effbf9d 100644 --- a/libgo/go/runtime/netpoll_kqueue.go +++ b/libgo/go/runtime/netpoll_kqueue.go @@ -97,10 +97,23 @@ retry: for i := 0; i < int(n); i++ { ev := &events[i] var mode int32 - if ev.filter == _EVFILT_READ { + switch ev.filter { + case _EVFILT_READ: mode += 'r' - } - if ev.filter == _EVFILT_WRITE { + + // On some systems when the read end of a pipe + // is closed the write end will not get a + // _EVFILT_WRITE event, but will get a + // _EVFILT_READ event with EV_EOF set. + // Note that setting 'w' here just means that we + // will wake up a goroutine waiting to write; + // that goroutine will try the write again, + // and the appropriate thing will happen based + // on what that write returns (success, EPIPE, EAGAIN). + if ev.flags&_EV_EOF != 0 { + mode += 'w' + } + case _EVFILT_WRITE: mode += 'w' } if mode != 0 { diff --git a/libgo/go/runtime/netpoll_windows.go b/libgo/go/runtime/netpoll_windows.go index 79dafb02796..134071f5e3c 100644 --- a/libgo/go/runtime/netpoll_windows.go +++ b/libgo/go/runtime/netpoll_windows.go @@ -47,7 +47,7 @@ func netpolldescriptor() uintptr { func netpollopen(fd uintptr, pd *pollDesc) int32 { if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 { - return -int32(getlasterror()) + return int32(getlasterror()) } return 0 } diff --git a/libgo/go/runtime/os_freebsd.go b/libgo/go/runtime/os_freebsd.go index a4d2886d6af..8c3535b893b 100644 --- a/libgo/go/runtime/os_freebsd.go +++ b/libgo/go/runtime/os_freebsd.go @@ -16,6 +16,17 @@ type mOS struct { //extern _umtx_op func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uinptr, ts *umtx_time) int32 +func getPageSize() uintptr { + mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} + out := uint32(0) + nout := unsafe.Sizeof(out) + ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) + if ret >= 0 { + return uintptr(out) + } + return 0 +} + // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and // thus the code is largely similar. See Linux implementation // and lock_futex.go for comments. diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go index e1a6a308cf2..816327e70b8 100644 --- a/libgo/go/runtime/os_linux.go +++ b/libgo/go/runtime/os_linux.go @@ -106,45 +106,46 @@ func sysargs(argc int32, argv **byte) { // now argv+n is auxv auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) - if sysauxv(auxv[:]) == 0 { - // In some situations we don't get a loader-provided - // auxv, such as when loaded as a library on Android. - // Fall back to /proc/self/auxv. - fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0) - if fd < 0 { - // On Android, /proc/self/auxv might be unreadable (issue 9229), so we fallback to - // try using mincore to detect the physical page size. - // mincore should return EINVAL when address is not a multiple of system page size. - const size = 256 << 10 // size of memory region to allocate - p := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0) - if uintptr(p) < 4096 { - return - } - var n uintptr - for n = 4 << 10; n < size; n <<= 1 { - err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0]) - if err == 0 { - physPageSize = n - break - } - } - if physPageSize == 0 { - physPageSize = size - } - munmap(p, size) + if sysauxv(auxv[:]) != 0 { + return + } + // In some situations we don't get a loader-provided + // auxv, such as when loaded as a library on Android. + // Fall back to /proc/self/auxv. + fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0) + if fd < 0 { + // On Android, /proc/self/auxv might be unreadable (issue 9229), so we fallback to + // try using mincore to detect the physical page size. + // mincore should return EINVAL when address is not a multiple of system page size. + const size = 256 << 10 // size of memory region to allocate + p, err := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0) + if err != 0 { return } - var buf [128]uintptr - n := read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf))) - closefd(fd) - if n < 0 { - return + var n uintptr + for n = 4 << 10; n < size; n <<= 1 { + err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0]) + if err == 0 { + physPageSize = n + break + } + } + if physPageSize == 0 { + physPageSize = size } - // Make sure buf is terminated, even if we didn't read - // the whole file. - buf[len(buf)-2] = _AT_NULL - sysauxv(buf[:]) + munmap(p, size) + return + } + var buf [128]uintptr + n = read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf))) + closefd(fd) + if n < 0 { + return } + // Make sure buf is terminated, even if we didn't read + // the whole file. + buf[len(buf)-2] = _AT_NULL + sysauxv(buf[:]) } func sysauxv(auxv []uintptr) int { diff --git a/libgo/go/runtime/os_linux_ppc64x.go b/libgo/go/runtime/os_linux_ppc64x.go index b324344493e..d27902d794d 100644 --- a/libgo/go/runtime/os_linux_ppc64x.go +++ b/libgo/go/runtime/os_linux_ppc64x.go @@ -7,55 +7,22 @@ package runtime -import ( - "runtime/internal/sys" -) +// For go:linkname +import _ "unsafe" -const ( - // ISA level - // Go currently requires POWER5 as a minimum for ppc64, so we need - // to check for ISA 2.03 and beyond. - _PPC_FEATURE_POWER5_PLUS = 0x00020000 // ISA 2.03 (POWER5+) - _PPC_FEATURE_ARCH_2_05 = 0x00001000 // ISA 2.05 (POWER6) - _PPC_FEATURE_POWER6_EXT = 0x00000200 // mffgpr/mftgpr extension (POWER6x) - _PPC_FEATURE_ARCH_2_06 = 0x00000100 // ISA 2.06 (POWER7) - _PPC_FEATURE2_ARCH_2_07 = 0x80000000 // ISA 2.07 (POWER8) +// ppc64x doesn't have a 'cpuid' instruction equivalent and relies on +// HWCAP/HWCAP2 bits for hardware capabilities. - // Standalone capabilities - _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 // SIMD/Vector unit - _PPC_FEATURE_HAS_VSX = 0x00000080 // Vector scalar unit -) - -type facilities struct { - _ [sys.CacheLineSize]byte - isPOWER5x bool // ISA 2.03 - isPOWER6 bool // ISA 2.05 - isPOWER6x bool // ISA 2.05 + mffgpr/mftgpr extension - isPOWER7 bool // ISA 2.06 - isPOWER8 bool // ISA 2.07 - hasVMX bool // Vector unit - hasVSX bool // Vector scalar unit - _ [sys.CacheLineSize]byte -} - -// cpu can be tested at runtime in go assembler code to check for -// a certain ISA level or hardware capability, for example: -// ·cpu+facilities_hasVSX(SB) for checking the availability of VSX -// or -// ·cpu+facilities_isPOWER7(SB) for checking if the processor implements -// ISA 2.06 instructions. -var cpu facilities +//go:linkname cpu_hwcap internal/cpu.ppc64x_hwcap +//go:linkname cpu_hwcap2 internal/cpu.ppc64x_hwcap2 +var cpu_hwcap uint +var cpu_hwcap2 uint func archauxv(tag, val uintptr) { switch tag { case _AT_HWCAP: - cpu.isPOWER5x = val&_PPC_FEATURE_POWER5_PLUS != 0 - cpu.isPOWER6 = val&_PPC_FEATURE_ARCH_2_05 != 0 - cpu.isPOWER6x = val&_PPC_FEATURE_POWER6_EXT != 0 - cpu.isPOWER7 = val&_PPC_FEATURE_ARCH_2_06 != 0 - cpu.hasVMX = val&_PPC_FEATURE_HAS_ALTIVEC != 0 - cpu.hasVSX = val&_PPC_FEATURE_HAS_VSX != 0 + cpu_hwcap = uint(val) case _AT_HWCAP2: - cpu.isPOWER8 = val&_PPC_FEATURE2_ARCH_2_07 != 0 + cpu_hwcap2 = uint(val) } } diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index 464ce88d9c4..81ebe7636a1 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -15,7 +15,7 @@ type mOS struct { //go:noescape //extern lwp_park -func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 +func lwp_park(ts int32, rel int32, abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 //go:noescape //extern lwp_unpark @@ -31,10 +31,9 @@ func semasleep(ns int64) int32 { // Compute sleep deadline. var tsp *timespec + var ts timespec if ns >= 0 { - var ts timespec var nsec int32 - ns += nanotime() ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) ts.set_nsec(nsec) tsp = &ts @@ -50,9 +49,18 @@ func semasleep(ns int64) int32 { } // Sleep until unparked by semawakeup or timeout. - ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.mos.waitsemacount), nil) + ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) if ret == _ETIMEDOUT { return -1 + } else if ret == _EINTR && ns >= 0 { + // Avoid sleeping forever if we keep getting + // interrupted (for example by the profiling + // timer). It would be if tsp upon return had the + // remaining time to sleep, but this is good enough. + var nsec int32 + ns /= 2 + ts.set_sec(timediv(ns, 1000000000, &nsec)) + ts.set_nsec(nsec) } } } diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go index c39a58d0c4b..5cc325f3954 100644 --- a/libgo/go/runtime/panic.go +++ b/libgo/go/runtime/panic.go @@ -170,7 +170,18 @@ func freedefer(d *_defer) { unlock(&sched.deferlock) }) } - *d = _defer{} + + // These lines used to be simply `*d = _defer{}` but that + // started causing a nosplit stack overflow via typedmemmove. + d.link = nil + d.frame = nil + d.panicStack = nil + d._panic = nil + d.pfn = 0 + d.arg = nil + d.retaddr = 0 + d.makefunccanrecover = false + pp.deferpool = append(pp.deferpool, d) } @@ -327,7 +338,7 @@ func unwindStack() { // Goexit terminates the goroutine that calls it. No other goroutine is affected. // Goexit runs all deferred calls before terminating the goroutine. Because Goexit -// is not panic, however, any recover calls in those deferred functions will return nil. +// is not a panic, any recover calls in those deferred functions will return nil. // // Calling Goexit from the main goroutine terminates that goroutine // without func main returning. Since func main has not returned, @@ -599,7 +610,7 @@ func canrecover(retaddr uintptr) bool { // caller starts with "runtime.", then we are permitted to // call recover. var locs [16]location - if callers(2, locs[:2]) < 2 { + if callers(1, locs[:2]) < 2 { return false } @@ -619,7 +630,7 @@ func canrecover(retaddr uintptr) bool { // reflect.makeFuncStub or reflect.ffi_callback called by FFI // functions. Then we check the caller of that function. - n := callers(3, locs[:]) + n := callers(2, locs[:]) foundFFICallback := false i := 0 for ; i < n; i++ { @@ -822,6 +833,12 @@ var panicking uint32 // so that two concurrent panics don't overlap their output. var paniclk mutex +// startpanic_m implements unrecoverable panic. +// +// It can have write barriers because the write barrier explicitly +// ignores writes once dying > 0. +// +//go:yeswritebarrierrec func startpanic() { _g_ := getg() // Uncomment when mheap_ is in Go. @@ -860,7 +877,7 @@ func startpanic() { exit(4) fallthrough default: - // Can't even print! Just exit. + // Can't even print! Just exit. exit(5) } } diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go index a57b69dca35..8a562e2ce8b 100644 --- a/libgo/go/runtime/pprof/pprof.go +++ b/libgo/go/runtime/pprof/pprof.go @@ -18,7 +18,7 @@ // To add equivalent profiling support to a standalone program, add // code like the following to your main function: // -// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`") +// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") // var memprofile = flag.String("memprofile", "", "write memory profile to `file`") // // func main() { @@ -319,7 +319,15 @@ func (p *Profile) WriteTo(w io.Writer, debug int) error { p.mu.Unlock() // Map order is non-deterministic; make output deterministic. - sort.Sort(stackProfile(all)) + sort.Slice(all, func(i, j int) bool { + t, u := all[i], all[j] + for k := 0; k < len(t) && k < len(u); k++ { + if t[k] != u[k] { + return t[k] < u[k] + } + } + return len(t) < len(u) + }) return printCountProfile(w, debug, p.name, stackProfile(all)) } @@ -328,16 +336,6 @@ type stackProfile [][]uintptr func (x stackProfile) Len() int { return len(x) } func (x stackProfile) Stack(i int) []uintptr { return x[i] } -func (x stackProfile) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x stackProfile) Less(i, j int) bool { - t, u := x[i], x[j] - for k := 0; k < len(t) && k < len(u); k++ { - if t[k] != u[k] { - return t[k] < u[k] - } - } - return len(t) < len(u) -} // A countProfile is a set of stack traces to be printed as counts // grouped by stack trace. There are multiple implementations: @@ -348,6 +346,41 @@ type countProfile interface { Stack(i int) []uintptr } +// printCountCycleProfile outputs block profile records (for block or mutex profiles) +// as the pprof-proto format output. Translations from cycle count to time duration +// are done because The proto expects count and time (nanoseconds) instead of count +// and the number of cycles for block, contention profiles. +func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error { + // Output profile in protobuf form. + b := newProfileBuilder(w) + b.pbValueType(tagProfile_PeriodType, countName, "count") + b.pb.int64Opt(tagProfile_Period, 1) + b.pbValueType(tagProfile_SampleType, countName, "count") + b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") + + cpuGHz := float64(runtime_cyclesPerSecond()) / 1e9 + + values := []int64{0, 0} + var locs []uint64 + for _, r := range records { + values[0] = int64(r.Count) + values[1] = int64(float64(r.Cycles) / cpuGHz) // to nanoseconds + locs = locs[:0] + for _, addr := range r.Stack() { + // For count profiles, all stack addresses are + // return PCs, which is what locForPC expects. + l := b.locForPC(addr) + if l == 0 { // runtime.goexit + continue + } + locs = append(locs, l) + } + b.pbSample(values, locs, nil) + } + b.build() + return nil +} + // printCountProfile prints a countProfile at the specified debug level. // The profile will be in compressed proto format unless debug is nonzero. func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { @@ -441,7 +474,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { // Hide runtime.goexit and any runtime functions at the beginning. // This is useful mainly for allocation traces. - skip := name == "runtime.goexit" + skip := name == "runtime.goexit" || name == "runtime.kickoff" if !show { switch { case strings.HasPrefix(name, "runtime."): @@ -490,6 +523,14 @@ func countHeap() int { // writeHeap writes the current runtime heap profile to w. func writeHeap(w io.Writer, debug int) error { + var memStats *runtime.MemStats + if debug != 0 { + // Read mem stats first, so that our other allocations + // do not appear in the statistics. + memStats = new(runtime.MemStats) + runtime.ReadMemStats(memStats) + } + // Find out how many records there are (MemProfile(nil, true)), // allocate that many records, and get the data. // There's a race—more records might be added between @@ -552,8 +593,7 @@ func writeHeap(w io.Writer, debug int) error { // Print memstats information too. // Pprof will ignore, but useful for people - s := new(runtime.MemStats) - runtime.ReadMemStats(s) + s := memStats fmt.Fprintf(w, "\n# runtime.MemStats\n") fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) @@ -779,14 +819,14 @@ func writeBlock(w io.Writer, debug int) error { sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) - b := bufio.NewWriter(w) - var tw *tabwriter.Writer - w = b - if debug > 0 { - tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) - w = tw + if debug <= 0 { + return printCountCycleProfile(w, "contentions", "delay", p) } + b := bufio.NewWriter(w) + tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) + w = tw + fmt.Fprintf(w, "--- contention:\n") fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) for i := range p { @@ -823,14 +863,14 @@ func writeMutex(w io.Writer, debug int) error { sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) - b := bufio.NewWriter(w) - var tw *tabwriter.Writer - w = b - if debug > 0 { - tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) - w = tw + if debug <= 0 { + return printCountCycleProfile(w, "contentions", "delay", p) } + b := bufio.NewWriter(w) + tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) + w = tw + fmt.Fprintf(w, "--- mutex:\n") fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1)) diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go index 9e5e403b741..08a4f969ca2 100644 --- a/libgo/go/runtime/pprof/pprof_test.go +++ b/libgo/go/runtime/pprof/pprof_test.go @@ -26,16 +26,18 @@ import ( "time" ) -func cpuHogger(f func() int, dur time.Duration) { +func cpuHogger(f func(x int) int, y *int, dur time.Duration) { // We only need to get one 100 Hz clock tick, so we've got // a large safety buffer. // But do at least 500 iterations (which should take about 100ms), // otherwise TestCPUProfileMultithreaded can fail if only one // thread is scheduled during the testing period. t0 := time.Now() + accum := *y for i := 0; i < 500 || time.Since(t0) < dur; i++ { - f() + accum = f(accum) } + *y = accum } var ( @@ -46,8 +48,8 @@ var ( // The actual CPU hogging function. // Must not call other functions nor access heap/globals in the loop, // otherwise under race detector the samples will be in the race runtime. -func cpuHog1() int { - foo := salt1 +func cpuHog1(x int) int { + foo := x for i := 0; i < 1e5; i++ { if foo > 0 { foo *= foo @@ -58,8 +60,8 @@ func cpuHog1() int { return foo } -func cpuHog2() int { - foo := salt2 +func cpuHog2(x int) int { + foo := x for i := 0; i < 1e5; i++ { if foo > 0 { foo *= foo @@ -72,7 +74,7 @@ func cpuHog2() int { func TestCPUProfile(t *testing.T) { testCPUProfile(t, []string{"pprof.cpuHog1"}, func(dur time.Duration) { - cpuHogger(cpuHog1, dur) + cpuHogger(cpuHog1, &salt1, dur) }) } @@ -81,29 +83,29 @@ func TestCPUProfileMultithreaded(t *testing.T) { testCPUProfile(t, []string{"pprof.cpuHog1", "pprof.cpuHog2"}, func(dur time.Duration) { c := make(chan int) go func() { - cpuHogger(cpuHog1, dur) + cpuHogger(cpuHog1, &salt1, dur) c <- 1 }() - cpuHogger(cpuHog2, dur) + cpuHogger(cpuHog2, &salt2, dur) <-c }) } func TestCPUProfileInlining(t *testing.T) { testCPUProfile(t, []string{"pprof.inlinedCallee", "pprof.inlinedCaller"}, func(dur time.Duration) { - cpuHogger(inlinedCaller, dur) + cpuHogger(inlinedCaller, &salt1, dur) }) } -func inlinedCaller() int { - inlinedCallee() - return 0 +func inlinedCaller(x int) int { + x = inlinedCallee(x) + return x } -func inlinedCallee() { +func inlinedCallee(x int) int { // We could just use cpuHog1, but for loops prevent inlining // right now. :( - foo := salt1 + foo := x i := 0 loop: if foo > 0 { @@ -114,7 +116,7 @@ loop: if i++; i < 1e5 { goto loop } - salt1 = foo + return foo } func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Location, map[string][]string)) { @@ -177,9 +179,9 @@ func testCPUProfile(t *testing.T, need []string, f func(dur time.Duration)) { } } - if badOS[runtime.GOOS] { + switch runtime.GOOS { + case "darwin", "dragonfly", "netbsd", "solaris": t.Skipf("ignoring failure on %s; see golang.org/issue/13841", runtime.GOOS) - return } // Ignore the failure if the tests are running in a QEMU-based emulator, // QEMU is not perfect at emulating everything. @@ -187,7 +189,6 @@ func testCPUProfile(t *testing.T, need []string, f func(dur time.Duration)) { // IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605. if os.Getenv("IN_QEMU") == "1" { t.Skip("ignore the failure in QEMU; see golang.org/issue/9605") - return } t.FailNow() } @@ -394,60 +395,108 @@ func TestMathBigDivide(t *testing.T) { }) } -// Operating systems that are expected to fail the tests. See issue 13841. -var badOS = map[string]bool{ - "darwin": true, - "netbsd": true, - "plan9": true, - "dragonfly": true, - "solaris": true, -} - func TestBlockProfile(t *testing.T) { t.Skip("lots of details are different for gccgo; FIXME") type TestCase struct { name string f func() + stk []string re string } tests := [...]TestCase{ - {"chan recv", blockChanRecv, ` + { + name: "chan recv", + f: blockChanRecv, + stk: []string{ + "runtime.chanrecv1", + "runtime/pprof.blockChanRecv", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ runtime\.chanrecv1\+0x[0-9a-f]+ .*/src/runtime/chan.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockChanRecv\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"chan send", blockChanSend, ` + { + name: "chan send", + f: blockChanSend, + stk: []string{ + "runtime.chansend1", + "runtime/pprof.blockChanSend", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ runtime\.chansend1\+0x[0-9a-f]+ .*/src/runtime/chan.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockChanSend\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"chan close", blockChanClose, ` + { + name: "chan close", + f: blockChanClose, + stk: []string{ + "runtime.chanrecv1", + "runtime/pprof.blockChanClose", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ runtime\.chanrecv1\+0x[0-9a-f]+ .*/src/runtime/chan.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockChanClose\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"select recv async", blockSelectRecvAsync, ` + { + name: "select recv async", + f: blockSelectRecvAsync, + stk: []string{ + "runtime.selectgo", + "runtime/pprof.blockSelectRecvAsync", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ runtime\.selectgo\+0x[0-9a-f]+ .*/src/runtime/select.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockSelectRecvAsync\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"select send sync", blockSelectSendSync, ` + { + name: "select send sync", + f: blockSelectSendSync, + stk: []string{ + "runtime.selectgo", + "runtime/pprof.blockSelectSendSync", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ runtime\.selectgo\+0x[0-9a-f]+ .*/src/runtime/select.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockSelectSendSync\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"mutex", blockMutex, ` + { + name: "mutex", + f: blockMutex, + stk: []string{ + "sync.(*Mutex).Lock", + "runtime/pprof.blockMutex", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ sync\.\(\*Mutex\)\.Lock\+0x[0-9a-f]+ .*/src/sync/mutex\.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockMutex\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.TestBlockProfile\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ `}, - {"cond", blockCond, ` + { + name: "cond", + f: blockCond, + stk: []string{ + "sync.(*Cond).Wait", + "runtime/pprof.blockCond", + "runtime/pprof.TestBlockProfile", + }, + re: ` [0-9]+ [0-9]+ @( 0x[[:xdigit:]]+)+ # 0x[0-9a-f]+ sync\.\(\*Cond\)\.Wait\+0x[0-9a-f]+ .*/src/sync/cond\.go:[0-9]+ # 0x[0-9a-f]+ runtime/pprof\.blockCond\+0x[0-9a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+ @@ -455,28 +504,84 @@ func TestBlockProfile(t *testing.T) { `}, } + // Generate block profile runtime.SetBlockProfileRate(1) defer runtime.SetBlockProfileRate(0) for _, test := range tests { test.f() } - var w bytes.Buffer - Lookup("block").WriteTo(&w, 1) - prof := w.String() - if !strings.HasPrefix(prof, "--- contention:\ncycles/second=") { - t.Fatalf("Bad profile header:\n%v", prof) - } + t.Run("debug=1", func(t *testing.T) { + var w bytes.Buffer + Lookup("block").WriteTo(&w, 1) + prof := w.String() - if strings.HasSuffix(prof, "#\t0x0\n\n") { - t.Errorf("Useless 0 suffix:\n%v", prof) + if !strings.HasPrefix(prof, "--- contention:\ncycles/second=") { + t.Fatalf("Bad profile header:\n%v", prof) + } + + if strings.HasSuffix(prof, "#\t0x0\n\n") { + t.Errorf("Useless 0 suffix:\n%v", prof) + } + + for _, test := range tests { + if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) { + t.Errorf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof) + } + } + }) + + t.Run("proto", func(t *testing.T) { + // proto format + var w bytes.Buffer + Lookup("block").WriteTo(&w, 0) + p, err := profile.Parse(&w) + if err != nil { + t.Fatalf("failed to parse profile: %v", err) + } + t.Logf("parsed proto: %s", p) + if err := p.CheckValid(); err != nil { + t.Fatalf("invalid profile: %v", err) + } + + stks := stacks(p) + for _, test := range tests { + if !containsStack(stks, test.stk) { + t.Errorf("No matching stack entry for %v, want %+v", test.name, test.stk) + } + } + }) + +} + +func stacks(p *profile.Profile) (res [][]string) { + for _, s := range p.Sample { + var stk []string + for _, l := range s.Location { + for _, line := range l.Line { + stk = append(stk, line.Function.Name) + } + } + res = append(res, stk) } + return res +} - for _, test := range tests { - if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) { - t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof) +func containsStack(got [][]string, want []string) bool { + for _, stk := range got { + if len(stk) < len(want) { + continue + } + for i, f := range want { + if f != stk[i] { + break + } + if i == len(want)-1 { + return true + } } } + return false } const blockDelay = 10 * time.Millisecond @@ -568,6 +673,8 @@ func blockCond() { } func TestMutexProfile(t *testing.T) { + // Generate mutex profile + old := runtime.SetMutexProfileFraction(1) defer runtime.SetMutexProfileFraction(old) if old != 0 { @@ -576,39 +683,60 @@ func TestMutexProfile(t *testing.T) { blockMutex() - var w bytes.Buffer - Lookup("mutex").WriteTo(&w, 1) - prof := w.String() + t.Run("debug=1", func(t *testing.T) { + var w bytes.Buffer + Lookup("mutex").WriteTo(&w, 1) + prof := w.String() + t.Logf("received profile: %v", prof) - if !strings.HasPrefix(prof, "--- mutex:\ncycles/second=") { - t.Errorf("Bad profile header:\n%v", prof) - } - prof = strings.Trim(prof, "\n") - lines := strings.Split(prof, "\n") - // gccgo adds an extra line in the stack trace, not sure why. - if len(lines) < 6 { - t.Errorf("expected 6 lines, got %d %q\n%s", len(lines), prof, prof) - } - if len(lines) < 6 { - return - } - // checking that the line is like "35258904 1 @ 0x48288d 0x47cd28 0x458931" - r2 := `^\d+ 1 @(?: 0x[[:xdigit:]]+)+` - //r2 := "^[0-9]+ 1 @ 0x[0-9a-f x]+$" - if ok, err := regexp.MatchString(r2, lines[3]); err != nil || !ok { - t.Errorf("%q didn't match %q", lines[3], r2) - } - r3 := "^#.*pprof.\\$nested.*$" - match := false - for _, i := range []int{5, 6} { - if ok, _ := regexp.MatchString(r3, lines[i]); ok { - match = true - break + if !strings.HasPrefix(prof, "--- mutex:\ncycles/second=") { + t.Errorf("Bad profile header:\n%v", prof) } - } - if !match { - t.Errorf("neither %q nor %q matched %q", lines[5], lines[6], r3) - } + prof = strings.Trim(prof, "\n") + lines := strings.Split(prof, "\n") + if len(lines) != 6 { + t.Errorf("expected 6 lines, got %d %q\n%s", len(lines), prof, prof) + } + if len(lines) < 6 { + return + } + // checking that the line is like "35258904 1 @ 0x48288d 0x47cd28 0x458931" + r2 := `^\d+ 1 @(?: 0x[[:xdigit:]]+)+` + //r2 := "^[0-9]+ 1 @ 0x[0-9a-f x]+$" + if ok, err := regexp.MatchString(r2, lines[3]); err != nil || !ok { + t.Errorf("%q didn't match %q", lines[3], r2) + } + if runtime.Compiler != "gccgo" { + r3 := "^#.*pprof.blockMutex.*$" + if ok, err := regexp.MatchString(r3, lines[5]); err != nil || !ok { + t.Errorf("%q didn't match %q", lines[5], r3) + } + } + t.Logf(prof) + }) + t.Run("proto", func(t *testing.T) { + // proto format + var w bytes.Buffer + Lookup("mutex").WriteTo(&w, 0) + p, err := profile.Parse(&w) + if err != nil { + t.Fatalf("failed to parse profile: %v", err) + } + t.Logf("parsed proto: %s", p) + if err := p.CheckValid(); err != nil { + t.Fatalf("invalid profile: %v", err) + } + + stks := stacks(p) + for _, want := range [][]string{ + // {"sync.(*Mutex).Unlock", "pprof.blockMutex.func1"}, + {"sync.Unlock.pN10_sync.Mutex", "pprof.$nested17"}, + } { + if !containsStack(stks, want) { + t.Errorf("No matching stack entry for %+v", want) + } + } + }) } func func1(c chan int) { <-c } @@ -725,7 +853,7 @@ func TestEmptyCallStack(t *testing.T) { func TestCPUProfileLabel(t *testing.T) { testCPUProfile(t, []string{"pprof.cpuHogger;key=value"}, func(dur time.Duration) { Do(context.Background(), Labels("key", "value"), func(context.Context) { - cpuHogger(cpuHog1, dur) + cpuHogger(cpuHog1, &salt1, dur) }) }) } @@ -738,14 +866,15 @@ func TestLabelRace(t *testing.T) { start := time.Now() var wg sync.WaitGroup for time.Since(start) < dur { + var salts [10]int for i := 0; i < 10; i++ { wg.Add(1) - go func() { + go func(j int) { Do(context.Background(), Labels("key", "value"), func(context.Context) { - cpuHogger(cpuHog1, time.Millisecond) + cpuHogger(cpuHog1, &salts[j], time.Millisecond) }) wg.Done() - }() + }(i) } wg.Wait() } diff --git a/libgo/go/runtime/pprof/proto.go b/libgo/go/runtime/pprof/proto.go index 5e1d71c7e72..793be44a417 100644 --- a/libgo/go/runtime/pprof/proto.go +++ b/libgo/go/runtime/pprof/proto.go @@ -202,7 +202,7 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 { // the stack and we have return PCs anyway. frames := runtime.CallersFrames([]uintptr{addr}) frame, more := frames.Next() - if frame.Function == "runtime.goexit" { + if frame.Function == "runtime.goexit" || frame.Function == "runtime.kickoff" { // Short-circuit if we see runtime.goexit so the loop // below doesn't allocate a useless empty location. return 0 @@ -228,7 +228,7 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 { start := b.pb.startMessage() b.pb.uint64Opt(tagLocation_ID, id) b.pb.uint64Opt(tagLocation_Address, uint64(frame.PC)) - for frame.Function != "runtime.goexit" { + for frame.Function != "runtime.goexit" && frame.Function != "runtime.kickoff" { // Write out each line in frame expansion. funcID := uint64(b.funcs[frame.Function]) if funcID == 0 { diff --git a/libgo/go/runtime/print.go b/libgo/go/runtime/print.go index 4db726a7552..3da05ad5f9e 100644 --- a/libgo/go/runtime/print.go +++ b/libgo/go/runtime/print.go @@ -78,7 +78,7 @@ var debuglock mutex // The compiler emits calls to printlock and printunlock around // the multiple calls that implement a single Go print or println -// statement. Some of the print helpers (printsp, for example) +// statement. Some of the print helpers (printslice, for example) // call print recursively. There is also the problem of a crash // happening during the print routines and needing to acquire // the print lock to print information about the crash. @@ -120,31 +120,31 @@ func gwrite(b []byte) { } func printsp() { - print(" ") + printstring(" ") } func printnl() { - print("\n") + printstring("\n") } func printbool(v bool) { if v { - print("true") + printstring("true") } else { - print("false") + printstring("false") } } func printfloat(v float64) { switch { case v != v: - print("NaN") + printstring("NaN") return case v+v == v && v > 0: - print("+Inf") + printstring("+Inf") return case v+v == v && v < 0: - print("-Inf") + printstring("-Inf") return } @@ -226,7 +226,7 @@ func printuint(v uint64) { func printint(v int64) { if v < 0 { - print("-") + printstring("-") v = -v } printuint(uint64(v)) diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 345f57b6875..1ea41528600 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -34,6 +34,7 @@ import ( //go:linkname helpgc runtime.helpgc //go:linkname kickoff runtime.kickoff //go:linkname mstart1 runtime.mstart1 +//go:linkname mexit runtime.mexit //go:linkname globrunqput runtime.globrunqput //go:linkname pidleget runtime.pidleget @@ -54,6 +55,7 @@ func getTraceback(me, gp *g) func gtraceback(*g) func _cgo_notify_runtime_init_done() func alreadyInCallers() bool +func stackfree(*g) // Functions created by the compiler. //extern __go_init_main @@ -138,6 +140,9 @@ var ( // it is closed, meaning cgocallbackg can reliably receive from it. var main_init_done chan bool +// mainStarted indicates that the main M has started. +var mainStarted bool + // runtimeInitTime is the nanotime() at which the runtime started. var runtimeInitTime int64 @@ -157,8 +162,8 @@ func main() { maxstacksize = 250000000 } - // Record when the world started. - runtimeInitTime = nanotime() + // Allow newproc to start new Ms. + mainStarted = true systemstack(func() { newm(sysmon, nil) @@ -184,8 +189,15 @@ func main() { } }() + // Record when the world started. Must be after runtime_init + // because nanotime on some platforms depends on startNano. + runtimeInitTime = nanotime() + main_init_done = make(chan bool) if iscgo { + // Start the template thread in case we enter Go from + // a C-created thread and need to create a new thread. + startTemplateThread() _cgo_notify_runtime_init_done() } @@ -269,9 +281,10 @@ func forcegchelper() { } } +//go:nosplit + // Gosched yields the processor, allowing other goroutines to run. It does not // suspend the current goroutine, so execution resumes automatically. -//go:nosplit func Gosched() { mcall(gosched_m) } @@ -359,8 +372,8 @@ func releaseSudog(s *sudog) { if s.elem != nil { throw("runtime: sudog with non-nil elem") } - if s.selectdone != nil { - throw("runtime: sudog with non-nil selectdone") + if s.isSelect { + throw("runtime: sudog with non-false isSelect") } if s.next != nil { throw("runtime: sudog with non-nil next") @@ -419,7 +432,7 @@ func funcPC(f interface{}) uintptr { func lockedOSThread() bool { gp := getg() - return gp.lockedm != nil && gp.m.lockedg != nil + return gp.lockedm != 0 && gp.m.lockedg != 0 } var ( @@ -479,13 +492,21 @@ func schedinit() { if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { procs = n } - if procs > _MaxGomaxprocs { - procs = _MaxGomaxprocs - } if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } + // For cgocheck > 1, we turn on the write barrier at all times + // and check all pointer writes. We can't do this until after + // procresize because the write barrier needs a P. + if debug.cgocheck > 1 { + writeBarrier.cgo = true + writeBarrier.enabled = true + for _, p := range allp { + p.wbBuf.reset() + } + } + if buildVersion == "" { // Condition should never trigger. This code just serves // to ensure runtime·buildVersion is kept in the resulting binary. @@ -501,7 +522,7 @@ func dumpgstatus(gp *g) { func checkmcount() { // sched lock is held - if sched.mcount > sched.maxmcount { + if mcount() > sched.maxmcount { print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n") throw("thread exhaustion") } @@ -515,15 +536,20 @@ func mcommoninit(mp *m) { callers(1, mp.createstack[:]) } - mp.fastrand = 0x49f6428a + uint32(mp.id) + uint32(cputicks()) - if mp.fastrand == 0 { - mp.fastrand = 0x49f6428a - } - lock(&sched.lock) - mp.id = sched.mcount - sched.mcount++ + if sched.mnext+1 < sched.mnext { + throw("runtime: thread ID overflow") + } + mp.id = sched.mnext + sched.mnext++ checkmcount() + + mp.fastrand[0] = 1597334677 * uint32(mp.id) + mp.fastrand[1] = uint32(cputicks()) + if mp.fastrand[0]|mp.fastrand[1] == 0 { + mp.fastrand[1] = 1 + } + mpreinit(mp) // Add to allm so garbage collector doesn't free g->m @@ -735,8 +761,10 @@ func casgstatus(gp *g, oldval, newval uint32) { // _Grunning or _Grunning|_Gscan; either way, // we own gp.gcscanvalid, so it's safe to read. // gp.gcscanvalid must not be true when we are running. - print("runtime: casgstatus ", hex(oldval), "->", hex(newval), " gp.status=", hex(gp.atomicstatus), " gp.gcscanvalid=true\n") - throw("casgstatus") + systemstack(func() { + print("runtime: casgstatus ", hex(oldval), "->", hex(newval), " gp.status=", hex(gp.atomicstatus), " gp.gcscanvalid=true\n") + throw("casgstatus") + }) } // See http://golang.org/cl/21503 for justification of the yield delay. @@ -912,7 +940,7 @@ func stopTheWorld(reason string) { // startTheWorld undoes the effects of stopTheWorld. func startTheWorld() { - systemstack(startTheWorldWithSema) + systemstack(func() { startTheWorldWithSema(false) }) // worldsema must be held over startTheWorldWithSema to ensure // gomaxprocs cannot change while worldsema is held. semrelease(&worldsema) @@ -962,8 +990,7 @@ func stopTheWorldWithSema() { _g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic. sched.stopwait-- // try to retake all P's in Psyscall status - for i := 0; i < int(gomaxprocs); i++ { - p := allp[i] + for _, p := range allp { s := p.status if s == _Psyscall && atomic.Cas(&p.status, s, _Pgcstop) { if trace.enabled { @@ -1003,8 +1030,7 @@ func stopTheWorldWithSema() { if sched.stopwait != 0 { bad = "stopTheWorld: not stopped (stopwait != 0)" } else { - for i := 0; i < int(gomaxprocs); i++ { - p := allp[i] + for _, p := range allp { if p.status != _Pgcstop { bad = "stopTheWorld: not stopped (status != _Pgcstop)" } @@ -1028,12 +1054,14 @@ func mhelpgc() { _g_.m.helpgc = -1 } -func startTheWorldWithSema() { +func startTheWorldWithSema(emitTraceEvent bool) int64 { _g_ := getg() - _g_.m.locks++ // disable preemption because it can be holding p in a local var - gp := netpoll(false) // non-blocking - injectglist(gp) + _g_.m.locks++ // disable preemption because it can be holding p in a local var + if netpollinited() { + gp := netpoll(false) // non-blocking + injectglist(gp) + } add := needaddgcproc() lock(&sched.lock) @@ -1068,6 +1096,12 @@ func startTheWorldWithSema() { } } + // Capture start-the-world time before doing clean-up tasks. + startTime := nanotime() + if emitTraceEvent { + traceGCSTWDone() + } + // Wakeup an additional proc in case we have excessive runnable goroutines // in local queues or in the global queue. If we don't, the proc will park itself. // If we have lots of excessive work, resetspinning will unpark additional procs as necessary. @@ -1086,6 +1120,8 @@ func startTheWorldWithSema() { newm(mhelpgc, nil) } _g_.m.locks-- + + return startTime } // First function run by a new goroutine. @@ -1116,15 +1152,13 @@ func kickoff() { throw("no p in kickoff") } } - gp.param = nil fv(param) goexit1() } -// This is called from mstart. -func mstart1() { +func mstart1(dummy int32) { _g_ := getg() if _g_ != _g_.m.g0 { @@ -1137,12 +1171,7 @@ func mstart1() { // prepare the thread to be able to handle the signals. // For gccgo minit was called by C code. if _g_.m == &m0 { - // Create an extra M for callbacks on threads not created by Go. - if iscgo && !cgoHasExtraM { - cgoHasExtraM = true - newextram() - } - initsig(false) + mstartm0() } if fn := _g_.m.mstartfn; fn != nil { @@ -1159,6 +1188,114 @@ func mstart1() { schedule() } +// mstartm0 implements part of mstart1 that only runs on the m0. +// +// Write barriers are allowed here because we know the GC can't be +// running yet, so they'll be no-ops. +// +//go:yeswritebarrierrec +func mstartm0() { + // Create an extra M for callbacks on threads not created by Go. + if iscgo && !cgoHasExtraM { + cgoHasExtraM = true + newextram() + } + initsig(false) +} + +// mexit tears down and exits the current thread. +// +// Don't call this directly to exit the thread, since it must run at +// the top of the thread stack. Instead, use gogo(&_g_.m.g0.sched) to +// unwind the stack to the point that exits the thread. +// +// It is entered with m.p != nil, so write barriers are allowed. It +// will release the P before exiting. +// +//go:yeswritebarrierrec +func mexit(osStack bool) { + g := getg() + m := g.m + + if m == &m0 { + // This is the main thread. Just wedge it. + // + // On Linux, exiting the main thread puts the process + // into a non-waitable zombie state. On Plan 9, + // exiting the main thread unblocks wait even though + // other threads are still running. On Solaris we can + // neither exitThread nor return from mstart. Other + // bad things probably happen on other platforms. + // + // We could try to clean up this M more before wedging + // it, but that complicates signal handling. + handoffp(releasep()) + lock(&sched.lock) + sched.nmfreed++ + checkdead() + unlock(&sched.lock) + notesleep(&m.park) + throw("locked m0 woke up") + } + + sigblock() + unminit() + + // Free the gsignal stack. + if m.gsignal != nil { + stackfree(m.gsignal) + } + + // Remove m from allm. + lock(&sched.lock) + for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink { + if *pprev == m { + *pprev = m.alllink + goto found + } + } + throw("m not found in allm") +found: + if !osStack { + // Delay reaping m until it's done with the stack. + // + // If this is using an OS stack, the OS will free it + // so there's no need for reaping. + atomic.Store(&m.freeWait, 1) + // Put m on the free list, though it will not be reaped until + // freeWait is 0. Note that the free list must not be linked + // through alllink because some functions walk allm without + // locking, so may be using alllink. + m.freelink = sched.freem + sched.freem = m + } + unlock(&sched.lock) + + // Release the P. + handoffp(releasep()) + // After this point we must not have write barriers. + + // Invoke the deadlock detector. This must happen after + // handoffp because it may have started a new M to take our + // P's work. + lock(&sched.lock) + sched.nmfreed++ + checkdead() + unlock(&sched.lock) + + if osStack { + // Return from mstart and let the system thread + // library free the g0 stack and terminate the thread. + return + } + + // mstart is the thread's entry point, so there's nothing to + // return to. Exit the thread directly. exitThread will clear + // m.freeWait when it's done with the stack and the m can be + // reaped. + exitThread(&m.freeWait) +} + // forEachP calls fn(p) for every P p when p reaches a GC safe point. // If a P is currently executing code, this will bring the P to a GC // safe point and execute fn on that P. If the P is not executing code @@ -1182,7 +1319,7 @@ func forEachP(fn func(*p)) { sched.safePointFn = fn // Ask all Ps to run the safe point function. - for _, p := range allp[:gomaxprocs] { + for _, p := range allp { if p != _p_ { atomic.Store(&p.runSafePointFn, 1) } @@ -1210,8 +1347,7 @@ func forEachP(fn func(*p)) { // Force Ps currently in _Psyscall into _Pidle and hand them // off to induce safe point function execution. - for i := 0; i < int(gomaxprocs); i++ { - p := allp[i] + for _, p := range allp { s := p.status if s == _Psyscall && p.runSafePointFn == 1 && atomic.Cas(&p.status, s, _Pidle) { if trace.enabled { @@ -1240,8 +1376,7 @@ func forEachP(fn func(*p)) { if sched.safePointWait != 0 { throw("forEachP: not done") } - for i := 0; i < int(gomaxprocs); i++ { - p := allp[i] + for _, p := range allp { if p.runSafePointFn != 0 { throw("forEachP: P did not run fn") } @@ -1295,6 +1430,27 @@ func allocm(_p_ *p, fn func(), allocatestack bool) (mp *m, g0Stack unsafe.Pointe if _g_.m.p == 0 { acquirep(_p_) // temporarily borrow p for mallocs in this function } + + // Release the free M list. We need to do this somewhere and + // this may free up a stack we can use. + if sched.freem != nil { + lock(&sched.lock) + var newList *m + for freem := sched.freem; freem != nil; { + if freem.freeWait != 0 { + next := freem.freelink + freem.freelink = newList + newList = freem + freem = next + continue + } + stackfree(freem.g0) + freem = freem.freelink + } + sched.freem = newList + unlock(&sched.lock) + } + mp = new(m) mp.mstartfn = fn mcommoninit(mp) @@ -1431,9 +1587,9 @@ func oneNewExtraM() { casgstatus(gp, _Gidle, _Gdead) gp.m = mp mp.curg = gp - mp.locked = _LockInternal - mp.lockedg = gp - gp.lockedm = mp + mp.lockedInt++ + mp.lockedg.set(gp) + gp.lockedm.set(mp) gp.goid = int64(atomic.Xadd64(&sched.goidgen, 1)) // put on allg for garbage collector allgadd(gp) @@ -1574,6 +1730,27 @@ func unlockextra(mp *m) { // around exec'ing while creating/destroying threads. See issue #19546. var execLock rwmutex +// newmHandoff contains a list of m structures that need new OS threads. +// This is used by newm in situations where newm itself can't safely +// start an OS thread. +var newmHandoff struct { + lock mutex + + // newm points to a list of M structures that need new OS + // threads. The list is linked through m.schedlink. + newm muintptr + + // waiting indicates that wake needs to be notified when an m + // is put on the list. + waiting bool + wake note + + // haveTemplateThread indicates that the templateThread has + // been started. This is not protected by lock. Use cas to set + // to 1. + haveTemplateThread uint32 +} + // Create a new m. It will start off with a call to fn, or else the scheduler. // fn needs to be static and not a heap allocated closure. // May run with m.p==nil, so write barriers are not allowed. @@ -1582,11 +1759,90 @@ func newm(fn func(), _p_ *p) { mp, _, _ := allocm(_p_, fn, false) mp.nextp.set(_p_) mp.sigmask = initSigmask + if gp := getg(); gp != nil && gp.m != nil && (gp.m.lockedExt != 0 || gp.m.incgo) && GOOS != "plan9" { + // We're on a locked M or a thread that may have been + // started by C. The kernel state of this thread may + // be strange (the user may have locked it for that + // purpose). We don't want to clone that into another + // thread. Instead, ask a known-good thread to create + // the thread for us. + // + // This is disabled on Plan 9. See golang.org/issue/22227. + // + // TODO: This may be unnecessary on Windows, which + // doesn't model thread creation off fork. + lock(&newmHandoff.lock) + if newmHandoff.haveTemplateThread == 0 { + throw("on a locked thread with no template thread") + } + mp.schedlink = newmHandoff.newm + newmHandoff.newm.set(mp) + if newmHandoff.waiting { + newmHandoff.waiting = false + notewakeup(&newmHandoff.wake) + } + unlock(&newmHandoff.lock) + return + } + newm1(mp) +} + +func newm1(mp *m) { execLock.rlock() // Prevent process clone. newosproc(mp) execLock.runlock() } +// startTemplateThread starts the template thread if it is not already +// running. +// +// The calling thread must itself be in a known-good state. +func startTemplateThread() { + if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) { + return + } + newm(templateThread, nil) +} + +// tmeplateThread is a thread in a known-good state that exists solely +// to start new threads in known-good states when the calling thread +// may not be a a good state. +// +// Many programs never need this, so templateThread is started lazily +// when we first enter a state that might lead to running on a thread +// in an unknown state. +// +// templateThread runs on an M without a P, so it must not have write +// barriers. +// +//go:nowritebarrierrec +func templateThread() { + lock(&sched.lock) + sched.nmsys++ + checkdead() + unlock(&sched.lock) + + for { + lock(&newmHandoff.lock) + for newmHandoff.newm != 0 { + newm := newmHandoff.newm.ptr() + newmHandoff.newm = 0 + unlock(&newmHandoff.lock) + for newm != nil { + next := newm.schedlink.ptr() + newm.schedlink = 0 + newm1(newm) + newm = next + } + lock(&newmHandoff.lock) + } + newmHandoff.waiting = true + noteclear(&newmHandoff.wake) + unlock(&newmHandoff.lock) + notesleep(&newmHandoff.wake) + } +} + // Stops execution of the current m until new work is available. // Returns with acquired P. func stopm() { @@ -1609,7 +1865,9 @@ retry: notesleep(&_g_.m.park) noteclear(&_g_.m.park) if _g_.m.helpgc != 0 { + // helpgc() set _g_.m.p and _g_.m.mcache, so we have a P. gchelper() + // Undo the effects of helpgc(). _g_.m.helpgc = 0 _g_.m.mcache = nil _g_.m.p = 0 @@ -1743,7 +2001,7 @@ func wakep() { func stoplockedm() { _g_ := getg() - if _g_.m.lockedg == nil || _g_.m.lockedg.lockedm != _g_.m { + if _g_.m.lockedg == 0 || _g_.m.lockedg.ptr().lockedm.ptr() != _g_.m { throw("stoplockedm: inconsistent locking") } if _g_.m.p != 0 { @@ -1755,7 +2013,7 @@ func stoplockedm() { // Wait until another thread schedules lockedg again. notesleep(&_g_.m.park) noteclear(&_g_.m.park) - status := readgstatus(_g_.m.lockedg) + status := readgstatus(_g_.m.lockedg.ptr()) if status&^_Gscan != _Grunnable { print("runtime:stoplockedm: g is not Grunnable or Gscanrunnable\n") dumpgstatus(_g_) @@ -1771,7 +2029,7 @@ func stoplockedm() { func startlockedm(gp *g) { _g_ := getg() - mp := gp.lockedm + mp := gp.lockedm.ptr() if mp == _g_.m { throw("startlockedm: locked to me") } @@ -1896,11 +2154,12 @@ top: // Poll network. // This netpoll is only an optimization before we resort to stealing. - // We can safely skip it if there a thread blocked in netpoll already. - // If there is any kind of logical race with that blocked thread - // (e.g. it has already returned from netpoll, but does not set lastpoll yet), - // this thread will do blocking netpoll below anyway. - if netpollinited() && sched.lastpoll != 0 { + // We can safely skip it if there are no waiters or a thread is blocked + // in netpoll already. If there is any kind of logical race with that + // blocked thread (e.g. it has already returned from netpoll, but does + // not set lastpoll yet), this thread will do blocking netpoll below + // anyway. + if netpollinited() && atomic.Load(&netpollWaiters) > 0 && atomic.Load64(&sched.lastpoll) != 0 { if gp := netpoll(false); gp != nil { // non-blocking // netpoll returns list of goroutines linked by schedlink. injectglist(gp.schedlink.ptr()) @@ -1996,9 +2255,8 @@ stop: } // check all runqueues once again - for i := 0; i < int(gomaxprocs); i++ { - _p_ := allp[i] - if _p_ != nil && !runqempty(_p_) { + for _, _p_ := range allp { + if !runqempty(_p_) { lock(&sched.lock) _p_ = pidleget() unlock(&sched.lock) @@ -2137,9 +2395,15 @@ func schedule() { throw("schedule: holding locks") } - if _g_.m.lockedg != nil { + if _g_.m.lockedg != 0 { stoplockedm() - execute(_g_.m.lockedg, false) // Never returns. + execute(_g_.m.lockedg.ptr(), false) // Never returns. + } + + // We should not schedule away from a g that is executing a cgo call, + // since the cgo call is using the m's g0 stack. + if _g_.m.incgo { + throw("schedule: in cgo") } top: @@ -2205,7 +2469,7 @@ top: resetspinning() } - if gp.lockedm != nil { + if gp.lockedm != 0 { // Hands off own p to the locked m, // then blocks waiting for a new p. startlockedm(gp) @@ -2322,8 +2586,9 @@ func goexit0(gp *g) { gp.isSystemGoroutine = false } gp.m = nil - gp.lockedm = nil - _g_.m.lockedg = nil + locked := gp.lockedm != 0 + gp.lockedm = 0 + _g_.m.lockedg = 0 gp.entry = nil gp.paniconfault = false gp._defer = nil // should be true already but just in case. @@ -2334,17 +2599,38 @@ func goexit0(gp *g) { gp.labels = nil gp.timer = nil + if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 { + // Flush assist credit to the global pool. This gives + // better information to pacing if the application is + // rapidly creating an exiting goroutines. + scanCredit := int64(gcController.assistWorkPerByte * float64(gp.gcAssistBytes)) + atomic.Xaddint64(&gcController.bgScanCredit, scanCredit) + gp.gcAssistBytes = 0 + } + // Note that gp's stack scan is now "valid" because it has no // stack. gp.gcscanvalid = true dropg() - if _g_.m.locked&^_LockExternal != 0 { - print("invalid m->locked = ", _g_.m.locked, "\n") + if _g_.m.lockedInt != 0 { + print("invalid m->lockedInt = ", _g_.m.lockedInt, "\n") throw("internal lockOSThread error") } - _g_.m.locked = 0 + _g_.m.lockedExt = 0 gfput(_g_.m.p.ptr(), gp) + if locked { + // The goroutine may have locked this thread because + // it put it in an unusual kernel state. Kill it + // rather than returning it to the thread pool. + + // Return to mstart, which will release the P and exit + // the thread. + if GOOS != "plan9" { // See golang.org/issue/22227. + _g_.m.exiting = true + gogo(_g_.m.g0) + } + } schedule() } @@ -2481,7 +2767,9 @@ func exitsyscall(dummy int32) { oldp := _g_.m.p.ptr() if exitsyscallfast() { if _g_.m.mcache == nil { - throw("lost mcache") + systemstack(func() { + throw("lost mcache") + }) } if trace.enabled { if oldp != _g_.m.p.ptr() || _g_.m.syscalltick != _g_.m.p.ptr().syscalltick { @@ -2519,7 +2807,9 @@ func exitsyscall(dummy int32) { mcall(exitsyscall0) if _g_.m.mcache == nil { - throw("lost mcache") + systemstack(func() { + throw("lost mcache") + }) } // Scheduler returned, so we're allowed to run now. @@ -2644,7 +2934,7 @@ func exitsyscall0(gp *g) { acquirep(_p_) execute(gp, false) // Never returns. } - if _g_.m.lockedg != nil { + if _g_.m.lockedg != 0 { // Wait until another thread schedules gp and so m again. stoplockedm() execute(gp, false) // Never returns. @@ -2798,7 +3088,7 @@ func newproc(fn uintptr, arg unsafe.Pointer) *g { newg.entry = entry newg.param = arg - newg.gopc = getcallerpc(unsafe.Pointer(&fn)) + newg.gopc = getcallerpc() newg.startpc = fn if _g_.m.curg != nil { newg.labels = _g_.m.curg.labels @@ -2827,7 +3117,7 @@ func newproc(fn uintptr, arg unsafe.Pointer) *g { runqput(_p_, newg, true) - if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && runtimeInitTime != 0 { + if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && mainStarted { wakep() } _g_.m.locks-- @@ -2947,23 +3237,41 @@ func Breakpoint() { //go:nosplit func dolockOSThread() { _g_ := getg() - _g_.m.lockedg = _g_ - _g_.lockedm = _g_.m + _g_.m.lockedg.set(_g_) + _g_.lockedm.set(_g_.m) } //go:nosplit // LockOSThread wires the calling goroutine to its current operating system thread. -// Until the calling goroutine exits or calls UnlockOSThread, it will always -// execute in that thread, and no other goroutine can. +// The calling goroutine will always execute in that thread, +// and no other goroutine will execute in it, +// until the calling goroutine has made as many calls to +// UnlockOSThread as to LockOSThread. +// If the calling goroutine exits without unlocking the thread, +// the thread will be terminated. +// +// A goroutine should call LockOSThread before calling OS services or +// non-Go library functions that depend on per-thread state. func LockOSThread() { - getg().m.locked |= _LockExternal + if atomic.Load(&newmHandoff.haveTemplateThread) == 0 && GOOS != "plan9" { + // If we need to start a new thread from the locked + // thread, we need the template thread. Start it now + // while we're in a known-good state. + startTemplateThread() + } + _g_ := getg() + _g_.m.lockedExt++ + if _g_.m.lockedExt == 0 { + _g_.m.lockedExt-- + panic("LockOSThread nesting overflow") + } dolockOSThread() } //go:nosplit func lockOSThread() { - getg().m.locked += _LockInternal + getg().m.lockedInt++ dolockOSThread() } @@ -2973,29 +3281,43 @@ func lockOSThread() { //go:nosplit func dounlockOSThread() { _g_ := getg() - if _g_.m.locked != 0 { + if _g_.m.lockedInt != 0 || _g_.m.lockedExt != 0 { return } - _g_.m.lockedg = nil - _g_.lockedm = nil + _g_.m.lockedg = 0 + _g_.lockedm = 0 } //go:nosplit -// UnlockOSThread unwires the calling goroutine from its fixed operating system thread. -// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op. +// UnlockOSThread undoes an earlier call to LockOSThread. +// If this drops the number of active LockOSThread calls on the +// calling goroutine to zero, it unwires the calling goroutine from +// its fixed operating system thread. +// If there are no active LockOSThread calls, this is a no-op. +// +// Before calling UnlockOSThread, the caller must ensure that the OS +// thread is suitable for running other goroutines. If the caller made +// any permanent changes to the state of the thread that would affect +// other goroutines, it should not call this function and thus leave +// the goroutine locked to the OS thread until the goroutine (and +// hence the thread) exits. func UnlockOSThread() { - getg().m.locked &^= _LockExternal + _g_ := getg() + if _g_.m.lockedExt == 0 { + return + } + _g_.m.lockedExt-- dounlockOSThread() } //go:nosplit func unlockOSThread() { _g_ := getg() - if _g_.m.locked < _LockInternal { + if _g_.m.lockedInt == 0 { systemstack(badunlockosthread) } - _g_.m.locked -= _LockInternal + _g_.m.lockedInt-- dounlockOSThread() } @@ -3005,10 +3327,7 @@ func badunlockosthread() { func gcount() int32 { n := int32(allglen) - sched.ngfree - int32(atomic.Load(&sched.ngsys)) - for _, _p_ := range &allp { - if _p_ == nil { - break - } + for _, _p_ := range allp { n -= _p_.gfreecnt } @@ -3021,7 +3340,7 @@ func gcount() int32 { } func mcount() int32 { - return sched.mcount + return int32(sched.mnext - sched.nmfreed) } var prof struct { @@ -3190,7 +3509,7 @@ func setcpuprofilerate(hz int32) { // Returns list of Ps with local work, they need to be scheduled by the caller. func procresize(nprocs int32) *p { old := gomaxprocs - if old < 0 || old > _MaxGomaxprocs || nprocs <= 0 || nprocs > _MaxGomaxprocs { + if old < 0 || nprocs <= 0 { throw("procresize: invalid arg") } if trace.enabled { @@ -3204,6 +3523,23 @@ func procresize(nprocs int32) *p { } sched.procresizetime = now + // Grow allp if necessary. + if nprocs > int32(len(allp)) { + // Synchronize with retake, which could be running + // concurrently since it doesn't run on a P. + lock(&allpLock) + if nprocs <= int32(cap(allp)) { + allp = allp[:nprocs] + } else { + nallp := make([]*p, nprocs) + // Copy everything up to allp's cap so we + // never lose old allocated Ps. + copy(nallp, allp[:cap(allp)]) + allp = nallp + } + unlock(&allpLock) + } + // initialize new P's for i := int32(0); i < nprocs; i++ { pp := allp[i] @@ -3213,6 +3549,7 @@ func procresize(nprocs int32) *p { pp.status = _Pgcstop pp.sudogcache = pp.sudogbuf[:0] pp.deferpool = pp.deferpoolbuf[:0] + pp.wbBuf.reset() atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) } if pp.mcache == nil { @@ -3230,13 +3567,11 @@ func procresize(nprocs int32) *p { // free unused P's for i := nprocs; i < old; i++ { p := allp[i] - if trace.enabled { - if p == getg().m.p.ptr() { - // moving to p[0], pretend that we were descheduled - // and then scheduled again to keep the trace sane. - traceGoSched() - traceProcStop(p) - } + if trace.enabled && p == getg().m.p.ptr() { + // moving to p[0], pretend that we were descheduled + // and then scheduled again to keep the trace sane. + traceGoSched() + traceProcStop(p) } // move all runnable goroutines to the global queue for p.runqhead != p.runqtail { @@ -3262,6 +3597,11 @@ func procresize(nprocs int32) *p { // world is stopped. p.gcBgMarkWorker.set(nil) } + // Flush p's write barrier buffer. + if gcphase != _GCoff { + wbBufFlush1(p) + p.gcw.dispose() + } for i := range p.sudogbuf { p.sudogbuf[i] = nil } @@ -3274,10 +3614,18 @@ func procresize(nprocs int32) *p { p.mcache = nil gfpurge(p) traceProcFree(p) + p.gcAssistTime = 0 p.status = _Pdead // can't free P itself because it can be referenced by an M in syscall } + // Trim allp. + if int32(len(allp)) != nprocs { + lock(&allpLock) + allp = allp[:nprocs] + unlock(&allpLock) + } + _g_ := getg() if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs { // continue to use the current P @@ -3349,7 +3697,7 @@ func acquirep1(_p_ *p) { throw("acquirep: already in go") } if _p_.m != 0 || _p_.status != _Pidle { - id := int32(0) + id := int64(0) if _p_.m != 0 { id = _p_.m.ptr().id } @@ -3394,6 +3742,7 @@ func incidlelocked(v int32) { // Check for deadlock situation. // The check is based on number of running M's, if 0 -> deadlock. +// sched.lock must be held. func checkdead() { // For -buildmode=c-shared or -buildmode=c-archive it's OK if // there are no running goroutines. The calling program is @@ -3410,13 +3759,12 @@ func checkdead() { return } - // -1 for sysmon - run := sched.mcount - sched.nmidle - sched.nmidlelocked - 1 + run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys if run > 0 { return } if run < 0 { - print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", sched.mcount, "\n") + print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n") throw("checkdead: inconsistent counts") } @@ -3479,6 +3827,11 @@ var forcegcperiod int64 = 2 * 60 * 1e9 // //go:nowritebarrierrec func sysmon() { + lock(&sched.lock) + sched.nmsys++ + checkdead() + unlock(&sched.lock) + // If a heap span goes unused for 5 minutes after a garbage collection, // we hand it back to the operating system. scavengelimit := int64(5 * 60 * 1e9) @@ -3518,15 +3871,11 @@ func sysmon() { } shouldRelax := true if osRelaxMinNS > 0 { - lock(&timers.lock) - if timers.sleeping { - now := nanotime() - next := timers.sleepUntil - if next-now < osRelaxMinNS { - shouldRelax = false - } + next := timeSleepUntil() + now := nanotime() + if next-now < osRelaxMinNS { + shouldRelax = false } - unlock(&timers.lock) } if shouldRelax { osRelax(true) @@ -3550,7 +3899,7 @@ func sysmon() { // poll network if not polled for more than 10ms lastpoll := int64(atomic.Load64(&sched.lastpoll)) now := nanotime() - if lastpoll != 0 && lastpoll+10*1000*1000 < now { + if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now { atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now)) gp := netpoll(false) // non-blocking - returns list of goroutines if gp != nil { @@ -3607,9 +3956,17 @@ const forcePreemptNS = 10 * 1000 * 1000 // 10ms func retake(now int64) uint32 { n := 0 - for i := int32(0); i < gomaxprocs; i++ { + // Prevent allp slice changes. This lock will be completely + // uncontended unless we're already stopping the world. + lock(&allpLock) + // We can't use a range loop over allp because we may + // temporarily drop the allpLock. Hence, we need to re-fetch + // allp each time around the loop. + for i := 0; i < len(allp); i++ { _p_ := allp[i] if _p_ == nil { + // This can happen if procresize has grown + // allp but not yet created new Ps. continue } pd := &_p_.sysmontick @@ -3628,6 +3985,8 @@ func retake(now int64) uint32 { if runqempty(_p_) && atomic.Load(&sched.nmspinning)+atomic.Load(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now { continue } + // Drop allpLock so we can take sched.lock. + unlock(&allpLock) // Need to decrement number of idle locked M's // (pretending that one more is running) before the CAS. // Otherwise the M from which we retake can exit the syscall, @@ -3643,6 +4002,7 @@ func retake(now int64) uint32 { handoffp(_p_) } incidlelocked(1) + lock(&allpLock) } else if s == _Prunning { // Preempt G if it's running for too long. t := int64(_p_.schedtick) @@ -3657,6 +4017,7 @@ func retake(now int64) uint32 { preemptone(_p_) } } + unlock(&allpLock) return uint32(n) } @@ -3667,9 +4028,8 @@ func retake(now int64) uint32 { // Returns true if preemption request was issued to at least one goroutine. func preemptall() bool { res := false - for i := int32(0); i < gomaxprocs; i++ { - _p_ := allp[i] - if _p_ == nil || _p_.status != _Prunning { + for _, _p_ := range allp { + if _p_.status != _Prunning { continue } if preemptone(_p_) { @@ -3727,23 +4087,19 @@ func schedtrace(detailed bool) { } lock(&sched.lock) - print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle, " threads=", sched.mcount, " spinningthreads=", sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize) + print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle, " threads=", mcount(), " spinningthreads=", sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize) if detailed { print(" gcwaiting=", sched.gcwaiting, " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait, "\n") } // We must be careful while reading data from P's, M's and G's. // Even if we hold schedlock, most data can be changed concurrently. // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil. - for i := int32(0); i < gomaxprocs; i++ { - _p_ := allp[i] - if _p_ == nil { - continue - } + for i, _p_ := range allp { mp := _p_.m.ptr() h := atomic.Load(&_p_.runqhead) t := atomic.Load(&_p_.runqtail) if detailed { - id := int32(-1) + id := int64(-1) if mp != nil { id = mp.id } @@ -3756,7 +4112,7 @@ func schedtrace(detailed bool) { print("[") } print(t - h) - if i == gomaxprocs-1 { + if i == len(allp)-1 { print("]\n") } } @@ -3770,7 +4126,7 @@ func schedtrace(detailed bool) { for mp := allm; mp != nil; mp = mp.alllink { _p_ := mp.p.ptr() gp := mp.curg - lockedg := mp.lockedg + lockedg := mp.lockedg.ptr() id1 := int32(-1) if _p_ != nil { id1 = _p_.id @@ -3790,12 +4146,12 @@ func schedtrace(detailed bool) { for gi := 0; gi < len(allgs); gi++ { gp := allgs[gi] mp := gp.m - lockedm := gp.lockedm - id1 := int32(-1) + lockedm := gp.lockedm.ptr() + id1 := int64(-1) if mp != nil { id1 = mp.id } - id2 := int32(-1) + id2 := int64(-1) if lockedm != nil { id2 = lockedm.id } @@ -4077,22 +4433,25 @@ func runqgrab(_p_ *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool if stealRunNextG { // Try to steal from _p_.runnext. if next := _p_.runnext; next != 0 { - // Sleep to ensure that _p_ isn't about to run the g we - // are about to steal. - // The important use case here is when the g running on _p_ - // ready()s another g and then almost immediately blocks. - // Instead of stealing runnext in this window, back off - // to give _p_ a chance to schedule runnext. This will avoid - // thrashing gs between different Ps. - // A sync chan send/recv takes ~50ns as of time of writing, - // so 3us gives ~50x overshoot. - if GOOS != "windows" { - usleep(3) - } else { - // On windows system timer granularity is 1-15ms, - // which is way too much for this optimization. - // So just yield. - osyield() + if _p_.status == _Prunning { + // Sleep to ensure that _p_ isn't about to run the g + // we are about to steal. + // The important use case here is when the g running + // on _p_ ready()s another g and then almost + // immediately blocks. Instead of stealing runnext + // in this window, back off to give _p_ a chance to + // schedule runnext. This will avoid thrashing gs + // between different Ps. + // A sync chan send/recv takes ~50ns as of time of + // writing, so 3us gives ~50x overshoot. + if GOOS != "windows" { + usleep(3) + } else { + // On windows system timer granularity is + // 1-15ms, which is way too much for this + // optimization. So just yield. + osyield() + } } if !_p_.runnext.cas(next, 0) { continue diff --git a/libgo/go/runtime/proc_runtime_test.go b/libgo/go/runtime/proc_runtime_test.go index d56f9b14636..a7bde2c6df7 100644 --- a/libgo/go/runtime/proc_runtime_test.go +++ b/libgo/go/runtime/proc_runtime_test.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build ignore - // Proc unit tests. In runtime package so can use runtime guts. package runtime diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go index 313a9610e0e..672e1fa0148 100644 --- a/libgo/go/runtime/proc_test.go +++ b/libgo/go/runtime/proc_test.go @@ -658,6 +658,116 @@ func BenchmarkClosureCall(b *testing.B) { _ = sum } +func benchmarkWakeupParallel(b *testing.B, spin func(time.Duration)) { + if runtime.GOMAXPROCS(0) == 1 { + b.Skip("skipping: GOMAXPROCS=1") + } + + wakeDelay := 5 * time.Microsecond + for _, delay := range []time.Duration{ + 0, + 1 * time.Microsecond, + 2 * time.Microsecond, + 5 * time.Microsecond, + 10 * time.Microsecond, + 20 * time.Microsecond, + 50 * time.Microsecond, + 100 * time.Microsecond, + } { + b.Run(delay.String(), func(b *testing.B) { + if b.N == 0 { + return + } + // Start two goroutines, which alternate between being + // sender and receiver in the following protocol: + // + // - The receiver spins for `delay` and then does a + // blocking receive on a channel. + // + // - The sender spins for `delay+wakeDelay` and then + // sends to the same channel. (The addition of + // `wakeDelay` improves the probability that the + // receiver will be blocking when the send occurs when + // the goroutines execute in parallel.) + // + // In each iteration of the benchmark, each goroutine + // acts once as sender and once as receiver, so each + // goroutine spins for delay twice. + // + // BenchmarkWakeupParallel is used to estimate how + // efficiently the scheduler parallelizes goroutines in + // the presence of blocking: + // + // - If both goroutines are executed on the same core, + // an increase in delay by N will increase the time per + // iteration by 4*N, because all 4 delays are + // serialized. + // + // - Otherwise, an increase in delay by N will increase + // the time per iteration by 2*N, and the time per + // iteration is 2 * (runtime overhead + chan + // send/receive pair + delay + wakeDelay). This allows + // the runtime overhead, including the time it takes + // for the unblocked goroutine to be scheduled, to be + // estimated. + ping, pong := make(chan struct{}), make(chan struct{}) + start := make(chan struct{}) + done := make(chan struct{}) + go func() { + <-start + for i := 0; i < b.N; i++ { + // sender + spin(delay + wakeDelay) + ping <- struct{}{} + // receiver + spin(delay) + <-pong + } + done <- struct{}{} + }() + go func() { + for i := 0; i < b.N; i++ { + // receiver + spin(delay) + <-ping + // sender + spin(delay + wakeDelay) + pong <- struct{}{} + } + done <- struct{}{} + }() + b.ResetTimer() + start <- struct{}{} + <-done + <-done + }) + } +} + +func BenchmarkWakeupParallelSpinning(b *testing.B) { + benchmarkWakeupParallel(b, func(d time.Duration) { + end := time.Now().Add(d) + for time.Now().Before(end) { + // do nothing + } + }) +} + +// sysNanosleep is defined by OS-specific files (such as runtime_linux_test.go) +// to sleep for the given duration. If nil, dependent tests are skipped. +// The implementation should invoke a blocking system call and not +// call time.Sleep, which would deschedule the goroutine. +var sysNanosleep func(d time.Duration) + +func BenchmarkWakeupParallelSyscall(b *testing.B) { + if sysNanosleep == nil { + b.Skipf("skipping on %v; sysNanosleep not defined", runtime.GOOS) + } + benchmarkWakeupParallel(b, func(d time.Duration) { + sysNanosleep(d) + }) +} + type Matrix [][]float64 func BenchmarkMatmult(b *testing.B) { @@ -722,8 +832,47 @@ func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, thres } } -/* func TestStealOrder(t *testing.T) { runtime.RunStealOrderTest() } -*/ + +func TestLockOSThreadNesting(t *testing.T) { + go func() { + e, i := runtime.LockOSCounts() + if e != 0 || i != 0 { + t.Errorf("want locked counts 0, 0; got %d, %d", e, i) + return + } + runtime.LockOSThread() + runtime.LockOSThread() + runtime.UnlockOSThread() + e, i = runtime.LockOSCounts() + if e != 1 || i != 0 { + t.Errorf("want locked counts 1, 0; got %d, %d", e, i) + return + } + runtime.UnlockOSThread() + e, i = runtime.LockOSCounts() + if e != 0 || i != 0 { + t.Errorf("want locked counts 0, 0; got %d, %d", e, i) + return + } + }() +} + +func TestLockOSThreadExit(t *testing.T) { + testLockOSThreadExit(t, "testprog") +} + +func testLockOSThreadExit(t *testing.T, prog string) { + output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1") + want := "OK\n" + if output != want { + t.Errorf("want %s, got %s\n", want, output) + } + + output = runTestProg(t, prog, "LockOSThreadAlt") + if output != want { + t.Errorf("want %s, got %s\n", want, output) + } +} diff --git a/libgo/go/runtime/runtime-lldb_test.go b/libgo/go/runtime/runtime-lldb_test.go index 98bc9066662..9a287052eaf 100644 --- a/libgo/go/runtime/runtime-lldb_test.go +++ b/libgo/go/runtime/runtime-lldb_test.go @@ -5,11 +5,7 @@ package runtime_test import ( - "debug/elf" - "debug/macho" - "encoding/binary" "internal/testenv" - "io" "io/ioutil" "os" "os/exec" @@ -158,7 +154,7 @@ func TestLldbPython(t *testing.T) { t.Fatalf("failed to create file: %v", err) } - cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags", "-N -l", "-o", "a.exe") + cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=all=-N -l", "-o", "a.exe") cmd.Dir = dir out, err := cmd.CombinedOutput() if err != nil { @@ -182,81 +178,3 @@ func TestLldbPython(t *testing.T) { t.Fatalf("Unexpected lldb output:\n%s", got) } } - -// Check that aranges are valid even when lldb isn't installed. -func TestDwarfAranges(t *testing.T) { - testenv.MustHaveGoBuild(t) - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatalf("failed to create temp directory: %v", err) - } - defer os.RemoveAll(dir) - - src := filepath.Join(dir, "main.go") - err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644) - if err != nil { - t.Fatalf("failed to create file: %v", err) - } - - cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe") - cmd.Dir = dir - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("building source %v\n%s", err, out) - } - - filename := filepath.Join(dir, "a.exe") - if f, err := elf.Open(filename); err == nil { - sect := f.Section(".debug_aranges") - if sect == nil { - t.Fatal("Missing aranges section") - } - verifyAranges(t, f.ByteOrder, sect.Open()) - } else if f, err := macho.Open(filename); err == nil { - sect := f.Section("__debug_aranges") - if sect == nil { - t.Fatal("Missing aranges section") - } - verifyAranges(t, f.ByteOrder, sect.Open()) - } else { - t.Skip("Not an elf or macho binary.") - } -} - -func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) { - var header struct { - UnitLength uint32 // does not include the UnitLength field - Version uint16 - Offset uint32 - AddressSize uint8 - SegmentSize uint8 - } - for { - offset, err := data.Seek(0, io.SeekCurrent) - if err != nil { - t.Fatalf("Seek error: %v", err) - } - if err = binary.Read(data, byteorder, &header); err == io.EOF { - return - } else if err != nil { - t.Fatalf("Error reading arange header: %v", err) - } - tupleSize := int64(header.SegmentSize) + 2*int64(header.AddressSize) - lastTupleOffset := offset + int64(header.UnitLength) + 4 - tupleSize - if lastTupleOffset%tupleSize != 0 { - t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize) - } - if _, err = data.Seek(lastTupleOffset, io.SeekStart); err != nil { - t.Fatalf("Seek error: %v", err) - } - buf := make([]byte, tupleSize) - if n, err := data.Read(buf); err != nil || int64(n) < tupleSize { - t.Fatalf("Read error: %v", err) - } - for _, val := range buf { - if val != 0 { - t.Fatalf("Invalid terminator") - } - } - } -} diff --git a/libgo/go/runtime/runtime.go b/libgo/go/runtime/runtime.go index 58710de406c..d19d6afed38 100644 --- a/libgo/go/runtime/runtime.go +++ b/libgo/go/runtime/runtime.go @@ -61,6 +61,12 @@ func syscall_Getpagesize() int { return int(physPageSize) } //go:linkname os_runtime_args os.runtime_args func os_runtime_args() []string { return append([]string{}, argslice...) } +//go:linkname syscall_Exit syscall.Exit +//go:nosplit +func syscall_Exit(code int) { + exit(int32(code)) +} + // Temporary, for the gccgo runtime code written in C. //go:linkname get_envs runtime_get_envs func get_envs() []string { return envs } diff --git a/libgo/go/runtime/runtime1.go b/libgo/go/runtime/runtime1.go index 627adf74765..b617f8598fa 100644 --- a/libgo/go/runtime/runtime1.go +++ b/libgo/go/runtime/runtime1.go @@ -111,10 +111,6 @@ var test_z64, test_x64 uint64 func testAtomic64() { test_z64 = 42 test_x64 = 0 - prefetcht0(uintptr(unsafe.Pointer(&test_z64))) - prefetcht1(uintptr(unsafe.Pointer(&test_z64))) - prefetcht2(uintptr(unsafe.Pointer(&test_z64))) - prefetchnta(uintptr(unsafe.Pointer(&test_z64))) if atomic.Cas64(&test_z64, test_x64, 1) { throw("cas64 failed") } @@ -413,13 +409,6 @@ func parsedebugvars() { setTraceback(gogetenv("GOTRACEBACK")) traceback_env = traceback_cache - - // For cgocheck > 1, we turn on the write barrier at all times - // and check all pointer writes. - if debug.cgocheck > 1 { - writeBarrier.cgo = true - writeBarrier.enabled = true - } } //go:linkname setTraceback runtime_debug.SetTraceback diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go index 045e76ff4df..543086d09aa 100644 --- a/libgo/go/runtime/runtime2.go +++ b/libgo/go/runtime/runtime2.go @@ -173,9 +173,13 @@ func efaceOf(ep *interface{}) *eface { // a word that is completely ignored by the GC than to have one for which // only a few updates are ignored. // -// Gs, Ms, and Ps are always reachable via true pointers in the -// allgs, allm, and allp lists or (during allocation before they reach those lists) +// Gs and Ps are always reachable via true pointers in the +// allgs and allp lists or (during allocation before they reach those lists) // from stack variables. +// +// Ms are always reachable via true pointers either from allm or +// freem. Unlike Gs and Ps we do free Ms, so it's important that +// nothing ever hold an muintptr across a safe point. // A guintptr holds a goroutine pointer, but typed as a uintptr // to bypass write barriers. It is used in the Gobuf goroutine state @@ -225,6 +229,15 @@ func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) } //go:nosplit func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) } +// muintptr is a *m that is not tracked by the garbage collector. +// +// Because we do free Ms, there are some additional constrains on +// muintptrs: +// +// 1. Never hold an muintptr locally across a safe point. +// +// 2. Any muintptr in the heap must be owned by the M itself so it can +// ensure it is not in use when the last true *m is released. type muintptr uintptr //go:nosplit @@ -256,11 +269,14 @@ type sudog struct { // channel this sudog is blocking on. shrinkstack depends on // this for sudogs involved in channel ops. - g *g - selectdone *uint32 // CAS to 1 to win select race (may point to stack) - next *sudog - prev *sudog - elem unsafe.Pointer // data element (may point to stack) + g *g + + // isSelect indicates g is participating in a select, so + // g.selectDone must be CAS'd to win the wake-up race. + isSelect bool + next *sudog + prev *sudog + elem unsafe.Pointer // data element (may point to stack) // The following fields are never accessed concurrently. // For channels, waitlink is only accessed by g. @@ -351,7 +367,7 @@ type g struct { sysexitticks int64 // cputicks when syscall has returned (for tracing) traceseq uint64 // trace event sequencer tracelastp puintptr // last P emitted an event for this goroutine - lockedm *m + lockedm muintptr sig uint32 writebuf []byte sigcode0 uintptr @@ -362,8 +378,9 @@ type g struct { // Not for gccgo: racectx uintptr waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order // Not for gccgo: cgoCtxt []uintptr // cgo traceback context - labels unsafe.Pointer // profiler labels - timer *timer // cached timer for time.Sleep + labels unsafe.Pointer // profiler labels + timer *timer // cached timer for time.Sleep + selectDone uint32 // are we participating in a select and did someone win the race? // Per-G GC state @@ -381,13 +398,26 @@ type g struct { exception unsafe.Pointer // current exception being thrown isforeign bool // whether current exception is not from Go - // Fields that hold stack and context information if status is Gsyscall + // When using split-stacks, these fields holds the results of + // __splitstack_find while executing a syscall. These are used + // by the garbage collector to scan the goroutine's stack. + // + // When not using split-stacks, g0 stacks are allocated by the + // libc and other goroutine stacks are allocated by malg. + // gcstack: unused (sometimes cleared) + // gcstacksize: g0: 0; others: size of stack + // gcnextsegment: unused + // gcnextsp: current SP while executing a syscall + // gcinitialsp: g0: top of stack; others: start of stack memory gcstack uintptr gcstacksize uintptr gcnextsegment uintptr gcnextsp uintptr gcinitialsp unsafe.Pointer - gcregs g_ucontext_t + + // gcregs holds the register values while executing a syscall. + // This is set by getcontext and scanned by the garbage collector. + gcregs g_ucontext_t entry func(unsafe.Pointer) // goroutine function to run entryfn uintptr // function address passed to __go_go @@ -411,14 +441,15 @@ type m struct { // Fields not known to debuggers. procid uint64 // for debuggers, but offset not hard-coded gsignal *g // signal-handling g + // Not for gccgo: goSigStack gsignalStack // Go-allocated signal handling stack sigmask sigset // storage for saved signal mask - // Not for gccgo: tls [6]uintptr // thread-local storage (for x86 extern register) + // Not for gccgo: tls [6]uintptr // thread-local storage (for x86 extern register) mstartfn func() curg *g // current running goroutine caughtsig guintptr // goroutine running during fatal signal p puintptr // attached p for executing go code (nil if not executing go code) nextp puintptr - id int32 + id int64 mallocing int32 throwing int32 preemptoff string // if != "", keep curg running on this m @@ -432,8 +463,11 @@ type m struct { inwb bool // m is executing a write barrier newSigstack bool // minit on C thread called sigaltstack printlock int8 - incgo bool // m is executing a cgo call - fastrand uint32 + incgo bool // m is executing a cgo call + freeWait uint32 // if == 0, safe to free g0 and delete m (atomic) + fastrand [2]uint32 + needextram bool + traceback uint8 ncgocall uint64 // number of cgo calls in total ncgo int32 // number of cgo calls currently in progress // Not for gccgo: cgoCallersUse uint32 // if non-zero, cgoCallers in use temporarily @@ -442,15 +476,14 @@ type m struct { alllink *m // on allm schedlink muintptr mcache *mcache - lockedg *g + lockedg guintptr createstack [32]location // stack that created this thread. - // Not for gccgo: freglo [16]uint32 // d[i] lsb and f[i] - // Not for gccgo: freghi [16]uint32 // d[i] msb and f[i+16] - // Not for gccgo: fflag uint32 // floating point compare flags - locked uint32 // tracking for lockosthread - nextwaitm uintptr // next m waiting for lock - needextram bool - traceback uint8 + // Not for gccgo: freglo [16]uint32 // d[i] lsb and f[i] + // Not for gccgo: freghi [16]uint32 // d[i] msb and f[i+16] + // Not for gccgo: fflag uint32 // floating point compare flags + lockedExt uint32 // tracking for external LockOSThread + lockedInt uint32 // tracking for internal lockOSThread + nextwaitm muintptr // next m waiting for lock waitunlockf unsafe.Pointer // todo go func(*g, unsafe.pointer) bool waitlock unsafe.Pointer waittraceev byte @@ -458,6 +491,7 @@ type m struct { startingtrace bool syscalltick uint32 // Not for gccgo: thread uintptr // thread handle + freelink *m // on sched.freem // these are here because they are too large to be on the stack // of low-level NOSPLIT functions. @@ -475,6 +509,7 @@ type m struct { gsignalstacksize uintptr dropextram bool // drop after call is done + exiting bool // thread is exiting gcing int32 } @@ -490,7 +525,7 @@ type p struct { sysmontick sysmontick // last tick observed by sysmon m muintptr // back-link to associated m (nil if idle) mcache *mcache - // Not for gccgo: racectx uintptr + racectx uintptr // gccgo has only one size of defer. deferpool []*_defer @@ -535,26 +570,30 @@ type p struct { palloc persistentAlloc // per-P to avoid mutex // Per-P GC state - gcAssistTime int64 // Nanoseconds in assistAlloc - gcBgMarkWorker guintptr - gcMarkWorkerMode gcMarkWorkerMode + gcAssistTime int64 // Nanoseconds in assistAlloc + gcFractionalMarkTime int64 // Nanoseconds in fractional mark worker + gcBgMarkWorker guintptr + gcMarkWorkerMode gcMarkWorkerMode + + // gcMarkWorkerStartTime is the nanotime() at which this mark + // worker started. + gcMarkWorkerStartTime int64 // gcw is this P's GC work buffer cache. The work buffer is // filled by write barriers, drained by mutator assists, and // disposed on certain GC state transitions. gcw gcWork + // wbBuf is this P's GC write barrier buffer. + // + // TODO: Consider caching this in the running G. + wbBuf wbBuf + runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point pad [sys.CacheLineSize]byte } -const ( - // The max value of GOMAXPROCS. - // There are no fundamental restrictions on the value. - _MaxGomaxprocs = 1 << 10 -) - type schedt struct { // accessed atomically. keep at top to ensure alignment on 32-bit systems. goidgen uint64 @@ -562,11 +601,16 @@ type schedt struct { lock mutex + // When increasing nmidle, nmidlelocked, nmsys, or nmfreed, be + // sure to call checkdead(). + midle muintptr // idle m's waiting for work nmidle int32 // number of idle m's waiting for work nmidlelocked int32 // number of locked m's waiting for work - mcount int32 // number of m's that have been created + mnext int64 // number of m's that have been created and next M ID maxmcount int32 // maximum number of m's allowed (or die) + nmsys int32 // number of system m's not counted for deadlock + nmfreed int64 // cumulative number of freed m's ngsys uint32 // number of system goroutines; updated atomically @@ -592,6 +636,10 @@ type schedt struct { deferlock mutex deferpool *_defer + // freem is the list of m's waiting to be freed when their + // m.exited is set. Linked through m.freelink. + freem *m + gcwaiting uint32 // gc is waiting to run stopwait int32 stopnote note @@ -610,18 +658,7 @@ type schedt struct { totaltime int64 // ∫gomaxprocs dt up to procresizetime } -// The m.locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread. -// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active. -// External locks are not recursive; a second lock is silently ignored. -// The upper bits of m.locked record the nesting depth of calls to lockOSThread -// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal). -// Internal locks can be recursive. For instance, a lock for cgo can occur while the main -// goroutine is holding the lock during the initialization phase. -const ( - _LockExternal = 1 - _LockInternal = 2 -) - +// Values for the flags field of a sigTabT. const ( _SigNotify = 1 << iota // let signal.Notify have signal, even if from kernel _SigKill // if signal.Notify doesn't take it, exit quietly @@ -630,7 +667,8 @@ const ( _SigDefault // if the signal isn't explicitly requested, don't monitor it _SigGoExit // cause all runtime procs to exit (only used on Plan 9). _SigSetStack // add SA_ONSTACK to libc handler - _SigUnblock // unblocked in minit + _SigUnblock // always unblock; see blockableSig + _SigIgn // _SIG_DFL action is to ignore the signal ) // Lock-free stack node. @@ -671,8 +709,8 @@ func extendRandom(r []byte, n int) { } } -// deferred subroutine calls -// This is the gccgo version. +// A _defer holds an entry on the list of deferred calls. +// If you add a field here, add code to clear it in freedefer. type _defer struct { // The next entry in the stack. link *_defer @@ -743,7 +781,8 @@ const _TracebackMaxFrames = 100 var ( allglen uintptr allm *m - allp [_MaxGomaxprocs + 1]*p + allp []*p // len(allp) == gomaxprocs; may change at safe points, otherwise immutable + allpLock mutex // Protects P-less reads of allp and all writes gomaxprocs int32 ncpu int32 forcegc forcegcstate diff --git a/libgo/go/runtime/runtime_mmap_test.go b/libgo/go/runtime/runtime_mmap_test.go index 0141e81d4a0..c0040414d46 100644 --- a/libgo/go/runtime/runtime_mmap_test.go +++ b/libgo/go/runtime/runtime_mmap_test.go @@ -14,17 +14,10 @@ import ( // what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects. // See the uses of ENOMEM in sysMap in those files. func TestMmapErrorSign(t *testing.T) { - p := runtime.Mmap(nil, ^uintptr(0)&^(runtime.GetPhysPageSize()-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0) + p, err := runtime.Mmap(nil, ^uintptr(0)&^(runtime.GetPhysPageSize()-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0) - // The runtime.mmap function is nosplit, but t.Errorf is not. - // Reset the pointer so that we don't get an "invalid stack - // pointer" error from t.Errorf if we call it. - v := uintptr(p) - p = nil - - err := runtime.Errno() - if v != ^uintptr(0) || err != runtime.ENOMEM { - t.Errorf("mmap = %v, %v, want %v", v, err, runtime.ENOMEM) + if p != nil || err != runtime.ENOMEM { + t.Errorf("mmap = %v, %v, want nil, %v", p, err, runtime.ENOMEM) } } @@ -34,20 +27,20 @@ func TestPhysPageSize(t *testing.T) { ps := runtime.GetPhysPageSize() // Get a region of memory to play with. This should be page-aligned. - b := uintptr(runtime.Mmap(nil, 2*ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)) - if b == ^uintptr(0) { - t.Fatalf("Mmap: %v %v", b, runtime.Errno()) + b, err := runtime.Mmap(nil, 2*ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0) + if err != 0 { + t.Fatalf("Mmap: %v", err) } // Mmap should fail at a half page into the buffer. - err := uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps/2), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0)) - if err != ^uintptr(0) { + _, err = runtime.Mmap(unsafe.Pointer(uintptr(b)+ps/2), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0) + if err == 0 { t.Errorf("Mmap should have failed with half-page alignment %d, but succeeded: %v", ps/2, err) } // Mmap should succeed at a full page into the buffer. - err = uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0)) - if err == ^uintptr(0) { - t.Errorf("Mmap at full-page alignment %d failed: %v %v", ps, err, runtime.Errno()) + _, err = runtime.Mmap(unsafe.Pointer(uintptr(b)+ps), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0) + if err != 0 { + t.Errorf("Mmap at full-page alignment %d failed: %v", ps, err) } } diff --git a/libgo/go/runtime/runtime_test.go b/libgo/go/runtime/runtime_test.go index b8f6ac2aed4..0231043260b 100644 --- a/libgo/go/runtime/runtime_test.go +++ b/libgo/go/runtime/runtime_test.go @@ -5,6 +5,7 @@ package runtime_test import ( + "flag" "io" . "runtime" "runtime/debug" @@ -13,6 +14,8 @@ import ( "unsafe" ) +var flagQuick = flag.Bool("quick", false, "skip slow tests, for second run in all.bash") + func init() { // We're testing the runtime, so make tracebacks show things // in the runtime. This only raises the level, so it won't @@ -196,9 +199,9 @@ func eqstring_generic(s1, s2 string) bool { } func TestEqString(t *testing.T) { - // This isn't really an exhaustive test of eqstring, it's + // This isn't really an exhaustive test of == on strings, it's // just a convenient way of documenting (via eqstring_generic) - // what eqstring does. + // what == does. s := []string{ "", "a", @@ -213,7 +216,7 @@ func TestEqString(t *testing.T) { x := s1 == s2 y := eqstring_generic(s1, s2) if x != y { - t.Errorf(`eqstring("%s","%s") = %t, want %t`, s1, s2, x, y) + t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y) } } } diff --git a/libgo/go/runtime/rwmutex_test.go b/libgo/go/runtime/rwmutex_test.go index a69eca1511f..872b3b098e8 100644 --- a/libgo/go/runtime/rwmutex_test.go +++ b/libgo/go/runtime/rwmutex_test.go @@ -12,6 +12,7 @@ package runtime_test import ( "fmt" . "runtime" + "runtime/debug" "sync/atomic" "testing" ) @@ -47,6 +48,10 @@ func doTestParallelReaders(numReaders int) { func TestParallelRWMutexReaders(t *testing.T) { defer GOMAXPROCS(GOMAXPROCS(-1)) + // If runtime triggers a forced GC during this test then it will deadlock, + // since the goroutines can't be stopped/preempted. + // Disable GC for this test (see issue #10958). + defer debug.SetGCPercent(debug.SetGCPercent(-1)) doTestParallelReaders(1) doTestParallelReaders(3) doTestParallelReaders(4) diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go index 9f8ac49d972..096af52be35 100644 --- a/libgo/go/runtime/select.go +++ b/libgo/go/runtime/select.go @@ -88,7 +88,7 @@ func newselect(sel *hselect, selsize int64, size int32) { } func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) { - pc := getcallerpc(unsafe.Pointer(&sel)) + pc := getcallerpc() i := sel.ncase if i >= sel.tcase { throw("selectsend: too many cases") @@ -109,7 +109,7 @@ func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) { } func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) { - pc := getcallerpc(unsafe.Pointer(&sel)) + pc := getcallerpc() i := sel.ncase if i >= sel.tcase { throw("selectrecv: too many cases") @@ -131,7 +131,7 @@ func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) { } func selectdefault(sel *hselect) { - pc := getcallerpc(unsafe.Pointer(&sel)) + pc := getcallerpc() i := sel.ncase if i >= sel.tcase { throw("selectdefault: too many cases") @@ -301,7 +301,6 @@ func selectgo(sel *hselect) int { var ( gp *g - done uint32 sg *sudog c *hchan k *scase @@ -368,7 +367,6 @@ loop: // pass 2 - enqueue on all chans gp = getg() - done = 0 if gp.waiting != nil { throw("gp.waiting != nil") } @@ -382,8 +380,7 @@ loop: c = cas.c sg := acquireSudog() sg.g = gp - // Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs - sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done))) + sg.isSelect = true // No stack splits between assigning elem and enqueuing // sg on gp.waiting where copystack can find it. sg.elem = cas.elem @@ -409,62 +406,9 @@ loop: gp.param = nil gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 1) - // While we were asleep, some goroutine came along and completed - // one of the cases in the select and woke us up (called ready). - // As part of that process, the goroutine did a cas on done above - // (aka *sg.selectdone for all queued sg) to win the right to - // complete the select. Now done = 1. - // - // If we copy (grow) our own stack, we will update the - // selectdone pointers inside the gp.waiting sudog list to point - // at the new stack. Another goroutine attempting to - // complete one of our (still linked in) select cases might - // see the new selectdone pointer (pointing at the new stack) - // before the new stack has real data; if the new stack has done = 0 - // (before the old values are copied over), the goroutine might - // do a cas via sg.selectdone and incorrectly believe that it has - // won the right to complete the select, executing a second - // communication and attempting to wake us (call ready) again. - // - // Then things break. - // - // The best break is that the goroutine doing ready sees the - // _Gcopystack status and throws, as in #17007. - // A worse break would be for us to continue on, start running real code, - // block in a semaphore acquisition (sema.go), and have the other - // goroutine wake us up without having really acquired the semaphore. - // That would result in the goroutine spuriously running and then - // queue up another spurious wakeup when the semaphore really is ready. - // In general the situation can cascade until something notices the - // problem and causes a crash. - // - // A stack shrink does not have this problem, because it locks - // all the channels that are involved first, blocking out the - // possibility of a cas on selectdone. - // - // A stack growth before gopark above does not have this - // problem, because we hold those channel locks (released by - // selparkcommit). - // - // A stack growth after sellock below does not have this - // problem, because again we hold those channel locks. - // - // The only problem is a stack growth during sellock. - // To keep that from happening, run sellock on the system stack. - // - // It might be that we could avoid this if copystack copied the - // stack before calling adjustsudogs. In that case, - // syncadjustsudogs would need to recopy the tiny part that - // it copies today, resulting in a little bit of extra copying. - // - // An even better fix, not for the week before a release candidate, - // would be to put space in every sudog and make selectdone - // point at (say) the space in the first sudog. - - systemstack(func() { - sellock(scases, lockorder) - }) + sellock(scases, lockorder) + gp.selectDone = 0 sg = (*sudog)(gp.param) gp.param = nil @@ -477,7 +421,7 @@ loop: sglist = gp.waiting // Clear all elem before unlinking from gp.waiting. for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { - sg1.selectdone = nil + sg1.isSelect = false sg1.elem = nil sg1.c = nil } @@ -528,10 +472,8 @@ loop: print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") } - if cas.kind == caseRecv { - if cas.receivedp != nil { - *cas.receivedp = true - } + if cas.kind == caseRecv && cas.receivedp != nil { + *cas.receivedp = true } if raceenabled { diff --git a/libgo/go/runtime/sema.go b/libgo/go/runtime/sema.go index d04e6f592fc..6e2beeccee1 100644 --- a/libgo/go/runtime/sema.go +++ b/libgo/go/runtime/sema.go @@ -275,7 +275,10 @@ func (root *semaRoot) queue(addr *uint32, s *sudog, lifo bool) { // on the ticket: s.ticket <= both s.prev.ticket and s.next.ticket. // https://en.wikipedia.org/wiki/Treap // http://faculty.washington.edu/aragon/pubs/rst89.pdf - s.ticket = fastrand() + // + // s.ticket compared with zero in couple of places, therefore set lowest bit. + // It will not affect treap's quality noticeably. + s.ticket = fastrand() | 1 s.parent = last *pt = s diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go index 056be36a729..6fe7ba10aaf 100644 --- a/libgo/go/runtime/signal_gccgo.go +++ b/libgo/go/runtime/signal_gccgo.go @@ -46,11 +46,6 @@ func kill(pid _pid_t, sig uint32) int32 //extern setitimer func setitimer(which int32, new *_itimerval, old *_itimerval) int32 -type sigTabT struct { - flags int32 - name string -} - type sigctxt struct { info *_siginfo_t ctxt unsafe.Pointer diff --git a/libgo/go/runtime/signal_sighandler.go b/libgo/go/runtime/signal_sighandler.go index 378c68e1d90..c042162e7e6 100644 --- a/libgo/go/runtime/signal_sighandler.go +++ b/libgo/go/runtime/signal_sighandler.go @@ -92,9 +92,9 @@ func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) { } print("PC=", hex(sigpc), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n") - if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 { print("signal arrived during cgo execution\n") - gp = _g_.m.lockedg + gp = _g_.m.lockedg.ptr() } print("\n") @@ -111,7 +111,7 @@ func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) { if docrash { crashing++ - if crashing < sched.mcount-int32(extraMCount) { + if crashing < mcount()-int32(extraMCount) { // There are other m's that need to dump their stacks. // Relay SIGQUIT to the next m by sending it to the current process. // All m's that have already received SIGQUIT have signal masks blocking diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go index 3237e18765f..85171484a90 100644 --- a/libgo/go/runtime/signal_unix.go +++ b/libgo/go/runtime/signal_unix.go @@ -8,7 +8,6 @@ package runtime import ( "runtime/internal/atomic" - "runtime/internal/sys" "unsafe" ) @@ -16,6 +15,16 @@ import ( //go:linkname initsig runtime.initsig //go:linkname sigtrampgo runtime.sigtrampgo +// sigTabT is the type of an entry in the global sigtable array. +// sigtable is inherently system dependent, and appears in OS-specific files, +// but sigTabT is the same for all Unixy systems. +// The sigtable array is indexed by a system signal number to get the flags +// and printable name of each signal. +type sigTabT struct { + flags int32 + name string +} + //go:linkname os_sigpipe os.sigpipe func os_sigpipe() { systemstack(sigpipe) @@ -275,6 +284,12 @@ func sigpipe() { // sigtrampgo is called from the signal handler function, sigtramp, // written in assembly code. // This is called by the signal handler, and the world may be stopped. +// +// It must be nosplit because getg() is still the G that was running +// (if any) when the signal was delivered, but it's (usually) called +// on the gsignal stack. Until this switches the G to gsignal, the +// stack bounds check won't work. +// //go:nosplit //go:nowritebarrierrec func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) { @@ -355,8 +370,9 @@ func sigpanic() { //go:nosplit //go:nowritebarrierrec func dieFromSignal(sig uint32) { - setsig(sig, _SIG_DFL) unblocksig(sig) + // Mark the signal as unhandled to ensure it is forwarded. + atomic.Store(&handlingSig[sig], 0) raise(sig) // That should have killed us. On some systems, though, raise @@ -368,6 +384,22 @@ func dieFromSignal(sig uint32) { osyield() osyield() + // If that didn't work, try _SIG_DFL. + setsig(sig, _SIG_DFL) + raise(sig) + + osyield() + osyield() + osyield() + + // On Darwin we may still fail to die, because raise sends the + // signal to the whole process rather than just the current thread, + // and osyield just sleeps briefly rather than letting all other + // threads run. See issue 20315. Sleep longer. + if GOOS == "darwin" { + usleep(100) + } + // If we are still somehow running, just exit with the wrong status. exit(2) } @@ -434,7 +466,7 @@ func crash() { // this means the OS X core file will be >128 GB and even on a zippy // workstation can take OS X well over an hour to write (uninterruptible). // Save users from making that mistake. - if sys.PtrSize == 8 { + if GOARCH == "amd64" { return } } @@ -463,7 +495,7 @@ func ensureSigM() { var sigBlocked sigset sigfillset(&sigBlocked) for i := range sigtable { - if sigtable[i].flags&_SigUnblock != 0 { + if !blockableSig(uint32(i)) { sigdelset(&sigBlocked, i) } } @@ -475,7 +507,7 @@ func ensureSigM() { sigdelset(&sigBlocked, int(sig)) } case sig := <-disableSigChan: - if sig > 0 { + if sig > 0 && blockableSig(sig) { sigaddset(&sigBlocked, int(sig)) } } @@ -536,17 +568,23 @@ func sigfwdgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) bool { return false } fwdFn := atomic.Loaduintptr(&fwdSig[sig]) + flags := sigtable[sig].flags - if !signalsOK { - // The only way we can get here is if we are in a - // library or archive, we installed a signal handler - // at program startup, but the Go runtime has not yet - // been initialized. + // If we aren't handling the signal, forward it. + if atomic.Load(&handlingSig[sig]) == 0 || !signalsOK { + // If the signal is ignored, doing nothing is the same as forwarding. + if fwdFn == _SIG_IGN || (fwdFn == _SIG_DFL && flags&_SigIgn != 0) { + return true + } + // We are not handling the signal and there is no other handler to forward to. + // Crash with the default behavior. if fwdFn == _SIG_DFL { + setsig(sig, _SIG_DFL) dieFromSignal(sig) - } else { - sigfwd(fwdFn, sig, info, ctx) + return false } + + sigfwd(fwdFn, sig, info, ctx) return true } @@ -555,18 +593,6 @@ func sigfwdgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) bool { return false } - // If we aren't handling the signal, forward it. - // Really if we aren't handling the signal, we shouldn't get here, - // but on Darwin setsigstack can lead us here because it sets - // the sa_tramp field. The sa_tramp field is not returned by - // sigaction, so the fix for that is non-obvious. - if atomic.Load(&handlingSig[sig]) == 0 { - sigfwd(fwdFn, sig, info, ctx) - return true - } - - flags := sigtable[sig].flags - c := sigctxt{info, ctx} // Only forward synchronous signals and SIGPIPE. // Unfortunately, user generated SIGPIPEs will also be forwarded, because si_code @@ -678,7 +704,7 @@ func minitSignalStack() { func minitSignalMask() { nmask := getg().m.sigmask for i := range sigtable { - if sigtable[i].flags&_SigUnblock != 0 { + if !blockableSig(uint32(i)) { sigdelset(&nmask, i) } } @@ -694,3 +720,22 @@ func unminitSignals() { signalstack(nil, 0) } } + +// blockableSig returns whether sig may be blocked by the signal mask. +// We never want to block the signals marked _SigUnblock; +// these are the synchronous signals that turn into a Go panic. +// In a Go program--not a c-archive/c-shared--we never want to block +// the signals marked _SigKill or _SigThrow, as otherwise it's possible +// for all running threads to block them and delay their delivery until +// we start a new thread. When linked into a C program we let the C code +// decide on the disposition of those signals. +func blockableSig(sig uint32) bool { + flags := sigtable[sig].flags + if flags&_SigUnblock != 0 { + return false + } + if isarchive || islibrary { + return true + } + return flags&(_SigKill|_SigThrow) == 0 +} diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go index cd036ce364c..b108c39cc85 100644 --- a/libgo/go/runtime/sigqueue.go +++ b/libgo/go/runtime/sigqueue.go @@ -45,13 +45,14 @@ import ( // as there is no connection between handling a signal and receiving one, // but atomic instructions should minimize it. var sig struct { - note note - mask [(_NSIG + 31) / 32]uint32 - wanted [(_NSIG + 31) / 32]uint32 - ignored [(_NSIG + 31) / 32]uint32 - recv [(_NSIG + 31) / 32]uint32 - state uint32 - inuse bool + note note + mask [(_NSIG + 31) / 32]uint32 + wanted [(_NSIG + 31) / 32]uint32 + ignored [(_NSIG + 31) / 32]uint32 + recv [(_NSIG + 31) / 32]uint32 + state uint32 + delivering uint32 + inuse bool } const ( @@ -60,15 +61,20 @@ const ( sigSending ) -// Called from sighandler to send a signal back out of the signal handling thread. -// Reports whether the signal was sent. If not, the caller typically crashes the program. +// sigsend delivers a signal from sighandler to the internal signal delivery queue. +// It reports whether the signal was sent. If not, the caller typically crashes the program. +// It runs from the signal handler, so it's limited in what it can do. func sigsend(s uint32) bool { bit := uint32(1) << uint(s&31) if !sig.inuse || s >= uint32(32*len(sig.wanted)) { return false } + atomic.Xadd(&sig.delivering, 1) + // We are running in the signal handler; defer is not available. + if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 { + atomic.Xadd(&sig.delivering, -1) return false } @@ -76,6 +82,7 @@ func sigsend(s uint32) bool { for { mask := sig.mask[s/32] if mask&bit != 0 { + atomic.Xadd(&sig.delivering, -1) return true // signal already in queue } if atomic.Cas(&sig.mask[s/32], mask, mask|bit) { @@ -104,6 +111,7 @@ Send: } } + atomic.Xadd(&sig.delivering, -1) return true } @@ -155,6 +163,15 @@ func signal_recv() uint32 { // by the os/signal package. //go:linkname signalWaitUntilIdle os_signal.signalWaitUntilIdle func signalWaitUntilIdle() { + // Although the signals we care about have been removed from + // sig.wanted, it is possible that another thread has received + // a signal, has read from sig.wanted, is now updating sig.mask, + // and has not yet woken up the processor thread. We need to wait + // until all current signal deliveries have completed. + for atomic.Load(&sig.delivering) != 0 { + Gosched() + } + // Although WaitUntilIdle seems like the right name for this // function, the state we are looking for is sigReceiving, not // sigIdle. The sigIdle state is really more like sigProcessing. diff --git a/libgo/go/runtime/sizeclasses.go b/libgo/go/runtime/sizeclasses.go index 5366564afda..9e17b001d3e 100644 --- a/libgo/go/runtime/sizeclasses.go +++ b/libgo/go/runtime/sizeclasses.go @@ -3,73 +3,73 @@ package runtime -// class bytes/obj bytes/span objects waste bytes -// 1 8 8192 1024 0 -// 2 16 8192 512 0 -// 3 32 8192 256 0 -// 4 48 8192 170 32 -// 5 64 8192 128 0 -// 6 80 8192 102 32 -// 7 96 8192 85 32 -// 8 112 8192 73 16 -// 9 128 8192 64 0 -// 10 144 8192 56 128 -// 11 160 8192 51 32 -// 12 176 8192 46 96 -// 13 192 8192 42 128 -// 14 208 8192 39 80 -// 15 224 8192 36 128 -// 16 240 8192 34 32 -// 17 256 8192 32 0 -// 18 288 8192 28 128 -// 19 320 8192 25 192 -// 20 352 8192 23 96 -// 21 384 8192 21 128 -// 22 416 8192 19 288 -// 23 448 8192 18 128 -// 24 480 8192 17 32 -// 25 512 8192 16 0 -// 26 576 8192 14 128 -// 27 640 8192 12 512 -// 28 704 8192 11 448 -// 29 768 8192 10 512 -// 30 896 8192 9 128 -// 31 1024 8192 8 0 -// 32 1152 8192 7 128 -// 33 1280 8192 6 512 -// 34 1408 16384 11 896 -// 35 1536 8192 5 512 -// 36 1792 16384 9 256 -// 37 2048 8192 4 0 -// 38 2304 16384 7 256 -// 39 2688 8192 3 128 -// 40 3072 24576 8 0 -// 41 3200 16384 5 384 -// 42 3456 24576 7 384 -// 43 4096 8192 2 0 -// 44 4864 24576 5 256 -// 45 5376 16384 3 256 -// 46 6144 24576 4 0 -// 47 6528 32768 5 128 -// 48 6784 40960 6 256 -// 49 6912 49152 7 768 -// 50 8192 8192 1 0 -// 51 9472 57344 6 512 -// 52 9728 49152 5 512 -// 53 10240 40960 4 0 -// 54 10880 32768 3 128 -// 55 12288 24576 2 0 -// 56 13568 40960 3 256 -// 57 14336 57344 4 0 -// 58 16384 16384 1 0 -// 59 18432 73728 4 0 -// 60 19072 57344 3 128 -// 61 20480 40960 2 0 -// 62 21760 65536 3 256 -// 63 24576 24576 1 0 -// 64 27264 81920 3 128 -// 65 28672 57344 2 0 -// 66 32768 32768 1 0 +// class bytes/obj bytes/span objects tail waste max waste +// 1 8 8192 1024 0 87.50% +// 2 16 8192 512 0 43.75% +// 3 32 8192 256 0 46.88% +// 4 48 8192 170 32 31.52% +// 5 64 8192 128 0 23.44% +// 6 80 8192 102 32 19.07% +// 7 96 8192 85 32 15.95% +// 8 112 8192 73 16 13.56% +// 9 128 8192 64 0 11.72% +// 10 144 8192 56 128 11.82% +// 11 160 8192 51 32 9.73% +// 12 176 8192 46 96 9.59% +// 13 192 8192 42 128 9.25% +// 14 208 8192 39 80 8.12% +// 15 224 8192 36 128 8.15% +// 16 240 8192 34 32 6.62% +// 17 256 8192 32 0 5.86% +// 18 288 8192 28 128 12.16% +// 19 320 8192 25 192 11.80% +// 20 352 8192 23 96 9.88% +// 21 384 8192 21 128 9.51% +// 22 416 8192 19 288 10.71% +// 23 448 8192 18 128 8.37% +// 24 480 8192 17 32 6.82% +// 25 512 8192 16 0 6.05% +// 26 576 8192 14 128 12.33% +// 27 640 8192 12 512 15.48% +// 28 704 8192 11 448 13.93% +// 29 768 8192 10 512 13.94% +// 30 896 8192 9 128 15.52% +// 31 1024 8192 8 0 12.40% +// 32 1152 8192 7 128 12.41% +// 33 1280 8192 6 512 15.55% +// 34 1408 16384 11 896 14.00% +// 35 1536 8192 5 512 14.00% +// 36 1792 16384 9 256 15.57% +// 37 2048 8192 4 0 12.45% +// 38 2304 16384 7 256 12.46% +// 39 2688 8192 3 128 15.59% +// 40 3072 24576 8 0 12.47% +// 41 3200 16384 5 384 6.22% +// 42 3456 24576 7 384 8.83% +// 43 4096 8192 2 0 15.60% +// 44 4864 24576 5 256 16.65% +// 45 5376 16384 3 256 10.92% +// 46 6144 24576 4 0 12.48% +// 47 6528 32768 5 128 6.23% +// 48 6784 40960 6 256 4.36% +// 49 6912 49152 7 768 3.37% +// 50 8192 8192 1 0 15.61% +// 51 9472 57344 6 512 14.28% +// 52 9728 49152 5 512 3.64% +// 53 10240 40960 4 0 4.99% +// 54 10880 32768 3 128 6.24% +// 55 12288 24576 2 0 11.45% +// 56 13568 40960 3 256 9.99% +// 57 14336 57344 4 0 5.35% +// 58 16384 16384 1 0 12.49% +// 59 18432 73728 4 0 11.11% +// 60 19072 57344 3 128 3.57% +// 61 20480 40960 2 0 6.87% +// 62 21760 65536 3 256 6.25% +// 63 24576 24576 1 0 11.45% +// 64 27264 81920 3 128 10.00% +// 65 28672 57344 2 0 4.91% +// 66 32768 32768 1 0 12.50% const ( _MaxSmallSize = 32768 diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go index f61f85e0fcb..ec5aa640222 100644 --- a/libgo/go/runtime/slice.go +++ b/libgo/go/runtime/slice.go @@ -23,6 +23,13 @@ type slice struct { cap int } +// An notInHeapSlice is a slice backed by go:notinheap memory. +type notInHeapSlice struct { + array *notInHeap + len int + cap int +} + // maxElems is a lookup table containing the maximum capacity for a slice. // The index is the size of the slice element. var maxElems = [...]uintptr{ @@ -85,7 +92,7 @@ func makeslice64(et *_type, len64, cap64 int64) slice { // The new slice's length is set to the requested capacity. func growslice(et *_type, old slice, cap int) slice { if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&et)) + callerpc := getcallerpc() racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice)) } if msanenabled { @@ -109,12 +116,20 @@ func growslice(et *_type, old slice, cap int) slice { if old.len < 1024 { newcap = doublecap } else { - for newcap < cap { + // Check 0 < newcap to detect overflow + // and prevent an infinite loop. + for 0 < newcap && newcap < cap { newcap += newcap / 4 } + // Set newcap to the requested cap when + // the newcap calculation overflowed. + if newcap <= 0 { + newcap = cap + } } } + var overflow bool var lenmem, newlenmem, capmem uintptr const ptrSize = unsafe.Sizeof((*byte)(nil)) switch et.size { @@ -122,20 +137,37 @@ func growslice(et *_type, old slice, cap int) slice { lenmem = uintptr(old.len) newlenmem = uintptr(cap) capmem = roundupsize(uintptr(newcap)) + overflow = uintptr(newcap) > _MaxMem newcap = int(capmem) case ptrSize: lenmem = uintptr(old.len) * ptrSize newlenmem = uintptr(cap) * ptrSize capmem = roundupsize(uintptr(newcap) * ptrSize) + overflow = uintptr(newcap) > _MaxMem/ptrSize newcap = int(capmem / ptrSize) default: lenmem = uintptr(old.len) * et.size newlenmem = uintptr(cap) * et.size capmem = roundupsize(uintptr(newcap) * et.size) + overflow = uintptr(newcap) > maxSliceCap(et.size) newcap = int(capmem / et.size) } - if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) { + // The check of overflow (uintptr(newcap) > maxSliceCap(et.size)) + // in addition to capmem > _MaxMem is needed to prevent an overflow + // which can be used to trigger a segfault on 32bit architectures + // with this example program: + // + // type T [1<<27 + 1]int64 + // + // var d T + // var s []T + // + // func main() { + // s = append(s, d, d, d, d) + // print(len(s), "\n") + // } + if cap < old.cap || overflow || capmem > _MaxMem { panic(errorString("growslice: cap out of range")) } @@ -176,7 +208,7 @@ func slicecopy(to, fm slice, width uintptr) int { } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&to)) + callerpc := getcallerpc() pc := funcPC(slicecopy) racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) @@ -207,7 +239,7 @@ func slicestringcopy(to []byte, fm string) int { } if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&to)) + callerpc := getcallerpc() pc := funcPC(slicestringcopy) racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) } diff --git a/libgo/go/runtime/string.go b/libgo/go/runtime/string.go index 7436ddfdf4b..e8df9a6b7c4 100644 --- a/libgo/go/runtime/string.go +++ b/libgo/go/runtime/string.go @@ -99,7 +99,7 @@ func slicebytetostring(buf *tmpBuf, b []byte) (str string) { if raceenabled { racereadrangepc(unsafe.Pointer(&b[0]), uintptr(l), - getcallerpc(unsafe.Pointer(&buf)), + getcallerpc(), funcPC(slicebytetostring)) } if msanenabled { @@ -145,7 +145,7 @@ func slicebytetostringtmp(b []byte) string { if raceenabled && len(b) > 0 { racereadrangepc(unsafe.Pointer(&b[0]), uintptr(len(b)), - getcallerpc(unsafe.Pointer(&b)), + getcallerpc(), funcPC(slicebytetostringtmp)) } if msanenabled && len(b) > 0 { @@ -194,7 +194,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string { if raceenabled && len(a) > 0 { racereadrangepc(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]), - getcallerpc(unsafe.Pointer(&buf)), + getcallerpc(), funcPC(slicerunetostring)) } if msanenabled && len(a) > 0 { diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go index 84fa1c79689..c454356b838 100644 --- a/libgo/go/runtime/stubs.go +++ b/libgo/go/runtime/stubs.go @@ -107,16 +107,21 @@ func reflect_memmove(to, from unsafe.Pointer, n uintptr) { func memcmp(a, b unsafe.Pointer, size uintptr) int32 // exported value for testing -var hashLoad = loadFactor +var hashLoad = float32(loadFactorNum) / float32(loadFactorDen) //go:nosplit func fastrand() uint32 { mp := getg().m - fr := mp.fastrand - mx := uint32(int32(fr)>>31) & 0xa8888eef - fr = fr<<1 ^ mx - mp.fastrand = fr - return fr + // Implement xorshift64+: 2 32-bit xorshift sequences added together. + // Shift triplet [17,7,16] was calculated as indicated in Marsaglia's + // Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf + // This generator passes the SmallCrush suite, part of TestU01 framework: + // http://simul.iro.umontreal.ca/testu01/tu01.html + s1, s0 := mp.fastrand[0], mp.fastrand[1] + s1 ^= s1 << 17 + s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16 + mp.fastrand[0], mp.fastrand[1] = s0, s1 + return s0 + s1 } //go:nosplit @@ -192,14 +197,16 @@ func publicationBarrier() // getcallerpc returns the program counter (PC) of its caller's caller. // getcallersp returns the stack pointer (SP) of its caller's caller. -// For both, the argp must be a pointer to the caller's first function argument. +// argp must be a pointer to the caller's first function argument. // The implementation may or may not use argp, depending on -// the architecture. +// the architecture. The implementation may be a compiler +// intrinsic; there is not necessarily code implementing this +// on every platform. // // For example: // // func f(arg1, arg2, arg3 int) { -// pc := getcallerpc(unsafe.Pointer(&arg1)) +// pc := getcallerpc() // sp := getcallersp(unsafe.Pointer(&arg1)) // } // @@ -219,7 +226,7 @@ func publicationBarrier() // immediately and can only be passed to nosplit functions. //go:noescape -func getcallerpc(argp unsafe.Pointer) uintptr +func getcallerpc() uintptr //go:noescape func getcallersp(argp unsafe.Pointer) uintptr @@ -430,7 +437,7 @@ func setpagesize(s uintptr) { } } -// Temporary for gccgo until we port mgc.go. +// Called by C code during library initialization. //go:linkname runtime_m0 runtime.runtime_m0 func runtime_m0() *m { return &m0 diff --git a/libgo/go/runtime/stubs2.go b/libgo/go/runtime/stubs2.go index 490405d51fd..e7607722a64 100644 --- a/libgo/go/runtime/stubs2.go +++ b/libgo/go/runtime/stubs2.go @@ -23,3 +23,10 @@ func write(fd uintptr, p unsafe.Pointer, n int32) int32 //go:noescape func open(name *byte, mode, perm int32) int32 + +// exitThread terminates the current thread, writing *wait = 0 when +// the stack is safe to reclaim. +func exitThread(wait *uint32) { + // This is never used by gccgo. + throw("exitThread") +} diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go index 744b6108e2b..542451753b7 100644 --- a/libgo/go/runtime/testdata/testprog/gc.go +++ b/libgo/go/runtime/testdata/testprog/gc.go @@ -25,6 +25,7 @@ func GCSys() { runtime.GC() runtime.ReadMemStats(memstats) sys := memstats.Sys + fmt.Printf("original sys: %#x\n", sys) runtime.MemProfileRate = 0 // disable profiler @@ -36,6 +37,8 @@ func GCSys() { // Should only be using a few MB. // We allocated 100 MB or (if not short) 1 GB. runtime.ReadMemStats(memstats) + fmt.Printf("final sys: %#x\n", memstats.Sys) + fmt.Printf("%#v\n", *memstats) if sys > memstats.Sys { sys = 0 } else { diff --git a/libgo/go/runtime/testdata/testprog/gettid.go b/libgo/go/runtime/testdata/testprog/gettid.go new file mode 100644 index 00000000000..1b3e29ab08e --- /dev/null +++ b/libgo/go/runtime/testdata/testprog/gettid.go @@ -0,0 +1,29 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "syscall" +) + +func gettid() int { + return syscall.Gettid() +} + +func tidExists(tid int) (exists, supported bool) { + stat, err := ioutil.ReadFile(fmt.Sprintf("/proc/self/task/%d/stat", tid)) + if os.IsNotExist(err) { + return false, true + } + // Check if it's a zombie thread. + state := bytes.Fields(stat)[2] + return !(len(state) == 1 && state[0] == 'Z'), true +} diff --git a/libgo/go/runtime/testdata/testprog/gettid_none.go b/libgo/go/runtime/testdata/testprog/gettid_none.go new file mode 100644 index 00000000000..036db87e10e --- /dev/null +++ b/libgo/go/runtime/testdata/testprog/gettid_none.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !linux + +package main + +func gettid() int { + return 0 +} + +func tidExists(tid int) (exists, supported bool) { + return false, false +} diff --git a/libgo/go/runtime/testdata/testprog/lockosthread.go b/libgo/go/runtime/testdata/testprog/lockosthread.go new file mode 100644 index 00000000000..88c0d12e4c1 --- /dev/null +++ b/libgo/go/runtime/testdata/testprog/lockosthread.go @@ -0,0 +1,94 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "os" + "runtime" + "time" +) + +var mainTID int + +func init() { + registerInit("LockOSThreadMain", func() { + // init is guaranteed to run on the main thread. + mainTID = gettid() + }) + register("LockOSThreadMain", LockOSThreadMain) + + registerInit("LockOSThreadAlt", func() { + // Lock the OS thread now so main runs on the main thread. + runtime.LockOSThread() + }) + register("LockOSThreadAlt", LockOSThreadAlt) +} + +func LockOSThreadMain() { + // gettid only works on Linux, so on other platforms this just + // checks that the runtime doesn't do anything terrible. + + // This requires GOMAXPROCS=1 from the beginning to reliably + // start a goroutine on the main thread. + if runtime.GOMAXPROCS(-1) != 1 { + println("requires GOMAXPROCS=1") + os.Exit(1) + } + + ready := make(chan bool, 1) + go func() { + // Because GOMAXPROCS=1, this *should* be on the main + // thread. Stay there. + runtime.LockOSThread() + if mainTID != 0 && gettid() != mainTID { + println("failed to start goroutine on main thread") + os.Exit(1) + } + // Exit with the thread locked, which should exit the + // main thread. + ready <- true + }() + <-ready + time.Sleep(1 * time.Millisecond) + // Check that this goroutine is still running on a different + // thread. + if mainTID != 0 && gettid() == mainTID { + println("goroutine migrated to locked thread") + os.Exit(1) + } + println("OK") +} + +func LockOSThreadAlt() { + // This is running locked to the main OS thread. + + var subTID int + ready := make(chan bool, 1) + go func() { + // This goroutine must be running on a new thread. + runtime.LockOSThread() + subTID = gettid() + ready <- true + // Exit with the thread locked. + }() + <-ready + runtime.UnlockOSThread() + for i := 0; i < 100; i++ { + time.Sleep(1 * time.Millisecond) + // Check that this goroutine is running on a different thread. + if subTID != 0 && gettid() == subTID { + println("locked thread reused") + os.Exit(1) + } + exists, supported := tidExists(subTID) + if !supported || !exists { + goto ok + } + } + println("sub thread", subTID, "still running") + return +ok: + println("OK") +} diff --git a/libgo/go/runtime/testdata/testprog/syscall_windows.go b/libgo/go/runtime/testdata/testprog/syscall_windows.go index 6e6782e987a..b4b66441b83 100644 --- a/libgo/go/runtime/testdata/testprog/syscall_windows.go +++ b/libgo/go/runtime/testdata/testprog/syscall_windows.go @@ -4,11 +4,18 @@ package main -import "syscall" +import ( + "internal/syscall/windows" + "runtime" + "sync" + "syscall" + "unsafe" +) func init() { register("RaiseException", RaiseException) register("ZeroDivisionException", ZeroDivisionException) + register("StackMemory", StackMemory) } func RaiseException() { @@ -25,3 +32,39 @@ func ZeroDivisionException() { z := x / y println(z) } + +func getPagefileUsage() (uintptr, error) { + p, err := syscall.GetCurrentProcess() + if err != nil { + return 0, err + } + var m windows.PROCESS_MEMORY_COUNTERS + err = windows.GetProcessMemoryInfo(p, &m, uint32(unsafe.Sizeof(m))) + if err != nil { + return 0, err + } + return m.PagefileUsage, nil +} + +func StackMemory() { + mem1, err := getPagefileUsage() + if err != nil { + panic(err) + } + const threadCount = 100 + var wg sync.WaitGroup + for i := 0; i < threadCount; i++ { + wg.Add(1) + go func() { + runtime.LockOSThread() + wg.Done() + select {} + }() + } + wg.Wait() + mem2, err := getPagefileUsage() + if err != nil { + panic(err) + } + print((mem2 - mem1) / threadCount) +} diff --git a/libgo/go/runtime/testdata/testprogcgo/callback.go b/libgo/go/runtime/testdata/testprogcgo/callback.go index a49fc19b284..2f7568c2c4e 100644 --- a/libgo/go/runtime/testdata/testprogcgo/callback.go +++ b/libgo/go/runtime/testdata/testprogcgo/callback.go @@ -34,6 +34,7 @@ import "C" import ( "fmt" + "os" "runtime" ) @@ -68,7 +69,10 @@ func grow1(x, sum *int) int { } func CgoCallbackGC() { - const P = 100 + P := 100 + if os.Getenv("RUNTIME_TESTING_SHORT") != "" { + P = 10 + } done := make(chan bool) // allocate a bunch of stack frames and spray them with pointers for i := 0; i < P; i++ { diff --git a/libgo/go/runtime/testdata/testprogcgo/catchpanic.go b/libgo/go/runtime/testdata/testprogcgo/catchpanic.go new file mode 100644 index 00000000000..55a606d1bc8 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/catchpanic.go @@ -0,0 +1,46 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!windows + +package main + +/* +#include +#include +#include + +static void abrthandler(int signum) { + if (signum == SIGABRT) { + exit(0); // success + } +} + +void registerAbortHandler() { + struct sigaction act; + memset(&act, 0, sizeof act); + act.sa_handler = abrthandler; + sigaction(SIGABRT, &act, NULL); +} + +static void __attribute__ ((constructor)) sigsetup(void) { + if (getenv("CGOCATCHPANIC_EARLY_HANDLER") == NULL) + return; + registerAbortHandler(); +} +*/ +import "C" +import "os" + +func init() { + register("CgoCatchPanic", CgoCatchPanic) +} + +// Test that the SIGABRT raised by panic can be caught by an early signal handler. +func CgoCatchPanic() { + if _, ok := os.LookupEnv("CGOCATCHPANIC_EARLY_HANDLER"); !ok { + C.registerAbortHandler() + } + panic("catch me") +} diff --git a/libgo/go/runtime/testdata/testprogcgo/cgo.go b/libgo/go/runtime/testdata/testprogcgo/cgo.go index 209524a24db..a587db385b3 100644 --- a/libgo/go/runtime/testdata/testprogcgo/cgo.go +++ b/libgo/go/runtime/testdata/testprogcgo/cgo.go @@ -52,7 +52,11 @@ func CgoSignalDeadlock() { time.Sleep(time.Millisecond) start := time.Now() var times []time.Duration - for i := 0; i < 64; i++ { + n := 64 + if os.Getenv("RUNTIME_TEST_SHORT") != "" { + n = 16 + } + for i := 0; i < n; i++ { go func() { runtime.LockOSThread() select {} diff --git a/libgo/go/runtime/testdata/testprogcgo/lockosthread.c b/libgo/go/runtime/testdata/testprogcgo/lockosthread.c new file mode 100644 index 00000000000..b10cc4f3b92 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/lockosthread.c @@ -0,0 +1,13 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!windows + +#include + +uint32_t threadExited; + +void setExited(void *x) { + __sync_fetch_and_add(&threadExited, 1); +} diff --git a/libgo/go/runtime/testdata/testprogcgo/lockosthread.go b/libgo/go/runtime/testdata/testprogcgo/lockosthread.go new file mode 100644 index 00000000000..36423d9eb0c --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/lockosthread.go @@ -0,0 +1,111 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!windows + +package main + +import ( + "os" + "runtime" + "sync/atomic" + "time" + "unsafe" +) + +/* +#include +#include + +extern uint32_t threadExited; + +void setExited(void *x); +*/ +import "C" + +var mainThread C.pthread_t + +func init() { + registerInit("LockOSThreadMain", func() { + // init is guaranteed to run on the main thread. + mainThread = C.pthread_self() + }) + register("LockOSThreadMain", LockOSThreadMain) + + registerInit("LockOSThreadAlt", func() { + // Lock the OS thread now so main runs on the main thread. + runtime.LockOSThread() + }) + register("LockOSThreadAlt", LockOSThreadAlt) +} + +func LockOSThreadMain() { + // This requires GOMAXPROCS=1 from the beginning to reliably + // start a goroutine on the main thread. + if runtime.GOMAXPROCS(-1) != 1 { + println("requires GOMAXPROCS=1") + os.Exit(1) + } + + ready := make(chan bool, 1) + go func() { + // Because GOMAXPROCS=1, this *should* be on the main + // thread. Stay there. + runtime.LockOSThread() + self := C.pthread_self() + if C.pthread_equal(mainThread, self) == 0 { + println("failed to start goroutine on main thread") + os.Exit(1) + } + // Exit with the thread locked, which should exit the + // main thread. + ready <- true + }() + <-ready + time.Sleep(1 * time.Millisecond) + // Check that this goroutine is still running on a different + // thread. + self := C.pthread_self() + if C.pthread_equal(mainThread, self) != 0 { + println("goroutine migrated to locked thread") + os.Exit(1) + } + println("OK") +} + +func LockOSThreadAlt() { + // This is running locked to the main OS thread. + + var subThread C.pthread_t + ready := make(chan bool, 1) + C.threadExited = 0 + go func() { + // This goroutine must be running on a new thread. + runtime.LockOSThread() + subThread = C.pthread_self() + // Register a pthread destructor so we can tell this + // thread has exited. + var key C.pthread_key_t + C.pthread_key_create(&key, (*[0]byte)(unsafe.Pointer(C.setExited))) + C.pthread_setspecific(key, unsafe.Pointer(new(int))) + ready <- true + // Exit with the thread locked. + }() + <-ready + for i := 0; i < 100; i++ { + time.Sleep(1 * time.Millisecond) + // Check that this goroutine is running on a different thread. + self := C.pthread_self() + if C.pthread_equal(subThread, self) != 0 { + println("locked thread reused") + os.Exit(1) + } + if atomic.LoadUint32((*uint32)(&C.threadExited)) != 0 { + println("OK") + return + } + } + println("sub thread still running") + os.Exit(1) +} diff --git a/libgo/go/runtime/testdata/testprogcgo/sigstack.go b/libgo/go/runtime/testdata/testprogcgo/sigstack.go new file mode 100644 index 00000000000..e30a5592dcb --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/sigstack.go @@ -0,0 +1,95 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!windows + +// Test handling of Go-allocated signal stacks when calling from +// C-created threads with and without signal stacks. (See issue +// #22930.) + +package main + +/* +#include +#include +#include +#include +#include + +#ifndef MAP_STACK +#define MAP_STACK 0 +#endif + +extern void SigStackCallback(); + +static void* WithSigStack(void* arg __attribute__((unused))) { + // Set up an alternate system stack. + void* base = mmap(0, SIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON|MAP_STACK, -1, 0); + if (base == MAP_FAILED) { + perror("mmap failed"); + abort(); + } + stack_t st = {}, ost = {}; + st.ss_sp = (char*)base; + st.ss_flags = 0; + st.ss_size = SIGSTKSZ; + if (sigaltstack(&st, &ost) < 0) { + perror("sigaltstack failed"); + abort(); + } + + // Call Go. + SigStackCallback(); + + // Disable signal stack and protect it so we can detect reuse. + if (ost.ss_flags & SS_DISABLE) { + // Darwin libsystem has a bug where it checks ss_size + // even if SS_DISABLE is set. (The kernel gets it right.) + ost.ss_size = SIGSTKSZ; + } + if (sigaltstack(&ost, NULL) < 0) { + perror("sigaltstack restore failed"); + abort(); + } + mprotect(base, SIGSTKSZ, PROT_NONE); + return NULL; +} + +static void* WithoutSigStack(void* arg __attribute__((unused))) { + SigStackCallback(); + return NULL; +} + +static void DoThread(int sigstack) { + pthread_t tid; + if (sigstack) { + pthread_create(&tid, NULL, WithSigStack, NULL); + } else { + pthread_create(&tid, NULL, WithoutSigStack, NULL); + } + pthread_join(tid, NULL); +} +*/ +import "C" + +func init() { + register("SigStack", SigStack) +} + +func SigStack() { + C.DoThread(0) + C.DoThread(1) + C.DoThread(0) + C.DoThread(1) + println("OK") +} + +var BadPtr *int + +//export SigStackCallback +func SigStackCallback() { + // Cause the Go signal handler to run. + defer func() { recover() }() + *BadPtr = 42 +} diff --git a/libgo/go/runtime/testdata/testprogcgo/stack_windows.go b/libgo/go/runtime/testdata/testprogcgo/stack_windows.go new file mode 100644 index 00000000000..846297a960c --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/stack_windows.go @@ -0,0 +1,54 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "C" +import ( + "internal/syscall/windows" + "runtime" + "sync" + "syscall" + "unsafe" +) + +func init() { + register("StackMemory", StackMemory) +} + +func getPagefileUsage() (uintptr, error) { + p, err := syscall.GetCurrentProcess() + if err != nil { + return 0, err + } + var m windows.PROCESS_MEMORY_COUNTERS + err = windows.GetProcessMemoryInfo(p, &m, uint32(unsafe.Sizeof(m))) + if err != nil { + return 0, err + } + return m.PagefileUsage, nil +} + +func StackMemory() { + mem1, err := getPagefileUsage() + if err != nil { + panic(err) + } + const threadCount = 100 + var wg sync.WaitGroup + for i := 0; i < threadCount; i++ { + wg.Add(1) + go func() { + runtime.LockOSThread() + wg.Done() + select {} + }() + } + wg.Wait() + mem2, err := getPagefileUsage() + if err != nil { + panic(err) + } + print((mem2 - mem1) / threadCount) +} diff --git a/libgo/go/runtime/time.go b/libgo/go/runtime/time.go index f204830a6f7..93181fde600 100644 --- a/libgo/go/runtime/time.go +++ b/libgo/go/runtime/time.go @@ -6,14 +6,18 @@ package runtime -import "unsafe" +import ( + "runtime/internal/sys" + "unsafe" +) // Package time knows the layout of this structure. // If this struct changes, adjust ../time/sleep.go:/runtimeTimer. // For GOOS=nacl, package syscall knows the layout of this structure. // If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer. type timer struct { - i int // heap index + tb *timersBucket // the bucket the timer lives in + i int // heap index // Timer wakes up at when, and then at when+period, ... (period > 0 only) // each time calling f(arg, now) in the timer goroutine, so f must be @@ -25,7 +29,37 @@ type timer struct { seq uintptr } -var timers struct { +// timersLen is the length of timers array. +// +// Ideally, this would be set to GOMAXPROCS, but that would require +// dynamic reallocation +// +// The current value is a compromise between memory usage and performance +// that should cover the majority of GOMAXPROCS values used in the wild. +const timersLen = 64 + +// timers contains "per-P" timer heaps. +// +// Timers are queued into timersBucket associated with the current P, +// so each P may work with its own timers independently of other P instances. +// +// Each timersBucket may be associated with multiple P +// if GOMAXPROCS > timersLen. +var timers [timersLen]struct { + timersBucket + + // The padding should eliminate false sharing + // between timersBucket values. + pad [sys.CacheLineSize - unsafe.Sizeof(timersBucket{})%sys.CacheLineSize]byte +} + +func (t *timer) assignBucket() *timersBucket { + id := uint8(getg().m.p.ptr().id) % timersLen + t.tb = &timers[id].timersBucket + return t.tb +} + +type timersBucket struct { lock mutex gp *g created bool @@ -51,18 +85,20 @@ func timeSleep(ns int64) { return } - t := getg().timer + gp := getg() + t := gp.timer if t == nil { t = new(timer) - getg().timer = t + gp.timer = t } *t = timer{} t.when = nanotime() + ns t.f = goroutineReady - t.arg = getg() - lock(&timers.lock) - addtimerLocked(t) - goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2) + t.arg = gp + tb := t.assignBucket() + lock(&tb.lock) + tb.addtimerLocked(t) + goparkunlock(&tb.lock, "sleep", traceEvGoSleep, 2) } // startTimer adds t to the timer heap. @@ -89,90 +125,98 @@ func goroutineReady(arg interface{}, seq uintptr) { } func addtimer(t *timer) { - lock(&timers.lock) - addtimerLocked(t) - unlock(&timers.lock) + tb := t.assignBucket() + lock(&tb.lock) + tb.addtimerLocked(t) + unlock(&tb.lock) } // Add a timer to the heap and start or kick timerproc if the new timer is // earlier than any of the others. // Timers are locked. -func addtimerLocked(t *timer) { +func (tb *timersBucket) addtimerLocked(t *timer) { // when must never be negative; otherwise timerproc will overflow // during its delta calculation and never expire other runtime timers. if t.when < 0 { t.when = 1<<63 - 1 } - t.i = len(timers.t) - timers.t = append(timers.t, t) - siftupTimer(t.i) + t.i = len(tb.t) + tb.t = append(tb.t, t) + siftupTimer(tb.t, t.i) if t.i == 0 { // siftup moved to top: new earliest deadline. - if timers.sleeping { - timers.sleeping = false - notewakeup(&timers.waitnote) + if tb.sleeping { + tb.sleeping = false + notewakeup(&tb.waitnote) } - if timers.rescheduling { - timers.rescheduling = false - goready(timers.gp, 0) + if tb.rescheduling { + tb.rescheduling = false + goready(tb.gp, 0) } } - if !timers.created { - timers.created = true + if !tb.created { + tb.created = true expectSystemGoroutine() - go timerproc() + go timerproc(tb) } } // Delete timer t from the heap. // Do not need to update the timerproc: if it wakes up early, no big deal. func deltimer(t *timer) bool { - // Dereference t so that any panic happens before the lock is held. - // Discard result, because t might be moving in the heap. - _ = t.i + if t.tb == nil { + // t.tb can be nil if the user created a timer + // directly, without invoking startTimer e.g + // time.Ticker{C: c} + // In this case, return early without any deletion. + // See Issue 21874. + return false + } - lock(&timers.lock) + tb := t.tb + + lock(&tb.lock) // t may not be registered anymore and may have // a bogus i (typically 0, if generated by Go). // Verify it before proceeding. i := t.i - last := len(timers.t) - 1 - if i < 0 || i > last || timers.t[i] != t { - unlock(&timers.lock) + last := len(tb.t) - 1 + if i < 0 || i > last || tb.t[i] != t { + unlock(&tb.lock) return false } if i != last { - timers.t[i] = timers.t[last] - timers.t[i].i = i + tb.t[i] = tb.t[last] + tb.t[i].i = i } - timers.t[last] = nil - timers.t = timers.t[:last] + tb.t[last] = nil + tb.t = tb.t[:last] if i != last { - siftupTimer(i) - siftdownTimer(i) + siftupTimer(tb.t, i) + siftdownTimer(tb.t, i) } - unlock(&timers.lock) + unlock(&tb.lock) return true } // Timerproc runs the time-driven events. -// It sleeps until the next event in the timers heap. +// It sleeps until the next event in the tb heap. // If addtimer inserts a new earlier event, it wakes timerproc early. -func timerproc() { +func timerproc(tb *timersBucket) { setSystemGoroutine() - timers.gp = getg() + tb.gp = getg() for { - lock(&timers.lock) - timers.sleeping = false + lock(&tb.lock) + tb.sleeping = false now := nanotime() delta := int64(-1) for { - if len(timers.t) == 0 { + if len(tb.t) == 0 { delta = -1 break } - t := timers.t[0] + t := tb.t[0] delta = t.when - now if delta > 0 { break @@ -180,43 +224,43 @@ func timerproc() { if t.period > 0 { // leave in heap but adjust next time to fire t.when += t.period * (1 + -delta/t.period) - siftdownTimer(0) + siftdownTimer(tb.t, 0) } else { // remove from heap - last := len(timers.t) - 1 + last := len(tb.t) - 1 if last > 0 { - timers.t[0] = timers.t[last] - timers.t[0].i = 0 + tb.t[0] = tb.t[last] + tb.t[0].i = 0 } - timers.t[last] = nil - timers.t = timers.t[:last] + tb.t[last] = nil + tb.t = tb.t[:last] if last > 0 { - siftdownTimer(0) + siftdownTimer(tb.t, 0) } t.i = -1 // mark as removed } f := t.f arg := t.arg seq := t.seq - unlock(&timers.lock) + unlock(&tb.lock) if raceenabled { raceacquire(unsafe.Pointer(t)) } f(arg, seq) - lock(&timers.lock) + lock(&tb.lock) } if delta < 0 || faketime > 0 { // No timers left - put goroutine to sleep. - timers.rescheduling = true - goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1) + tb.rescheduling = true + goparkunlock(&tb.lock, "timer goroutine (idle)", traceEvGoBlock, 1) continue } // At least one timer pending. Sleep until then. - timers.sleeping = true - timers.sleepUntil = now + delta - noteclear(&timers.waitnote) - unlock(&timers.lock) - notetsleepg(&timers.waitnote, delta) + tb.sleeping = true + tb.sleepUntil = now + delta + noteclear(&tb.waitnote) + unlock(&tb.lock) + notetsleepg(&tb.waitnote, delta) } } @@ -225,28 +269,67 @@ func timejump() *g { return nil } - lock(&timers.lock) - if !timers.created || len(timers.t) == 0 { - unlock(&timers.lock) + for i := range timers { + lock(&timers[i].lock) + } + gp := timejumpLocked() + for i := range timers { + unlock(&timers[i].lock) + } + + return gp +} + +func timejumpLocked() *g { + // Determine a timer bucket with minimum when. + var minT *timer + for i := range timers { + tb := &timers[i] + if !tb.created || len(tb.t) == 0 { + continue + } + t := tb.t[0] + if minT == nil || t.when < minT.when { + minT = t + } + } + if minT == nil || minT.when <= faketime { + return nil + } + + faketime = minT.when + tb := minT.tb + if !tb.rescheduling { return nil } + tb.rescheduling = false + return tb.gp +} + +func timeSleepUntil() int64 { + next := int64(1<<63 - 1) - var gp *g - if faketime < timers.t[0].when { - faketime = timers.t[0].when - if timers.rescheduling { - timers.rescheduling = false - gp = timers.gp + // Determine minimum sleepUntil across all the timer buckets. + // + // The function can not return a precise answer, + // as another timer may pop in as soon as timers have been unlocked. + // So lock the timers one by one instead of all at once. + for i := range timers { + tb := &timers[i] + + lock(&tb.lock) + if tb.sleeping && tb.sleepUntil < next { + next = tb.sleepUntil } + unlock(&tb.lock) } - unlock(&timers.lock) - return gp + + return next } // Heap maintenance algorithms. -func siftupTimer(i int) { - t := timers.t +func siftupTimer(t []*timer, i int) { when := t[i].when tmp := t[i] for i > 0 { @@ -256,14 +339,15 @@ func siftupTimer(i int) { } t[i] = t[p] t[i].i = i - t[p] = tmp - t[p].i = p i = p } + if tmp != t[i] { + t[i] = tmp + t[i].i = i + } } -func siftdownTimer(i int) { - t := timers.t +func siftdownTimer(t []*timer, i int) { n := len(t) when := t[i].when tmp := t[i] @@ -294,10 +378,12 @@ func siftdownTimer(i int) { } t[i] = t[c] t[i].i = i - t[c] = tmp - t[c].i = c i = c } + if tmp != t[i] { + t[i] = tmp + t[i].i = i + } } // Entry points for net, time to call nanotime. @@ -312,4 +398,10 @@ func time_runtimeNano() int64 { return nanotime() } -var startNano int64 = nanotime() +// Monotonic times are reported as offsets from startNano. +// We initialize startNano to nanotime() - 1 so that on systems where +// monotonic time resolution is fairly low (e.g. Windows 2008 +// which appears to have a default resolution of 15ms), +// we avoid ever reporting a nanotime of 0. +// (Callers may want to use 0 as "time not set".) +var startNano int64 = nanotime() - 1 diff --git a/libgo/go/runtime/trace.go b/libgo/go/runtime/trace.go index af9313be37a..8427e76c5a3 100644 --- a/libgo/go/runtime/trace.go +++ b/libgo/go/runtime/trace.go @@ -28,8 +28,8 @@ const ( traceEvProcStop = 6 // stop of P [timestamp] traceEvGCStart = 7 // GC start [timestamp, seq, stack id] traceEvGCDone = 8 // GC done [timestamp] - traceEvGCScanStart = 9 // GC mark termination start [timestamp] - traceEvGCScanDone = 10 // GC mark termination done [timestamp] + traceEvGCSTWStart = 9 // GC STW start [timestamp, kind] + traceEvGCSTWDone = 10 // GC STW done [timestamp] traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id] traceEvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] @@ -235,21 +235,21 @@ func StartTrace() error { trace.timeStart = nanotime() trace.headerWritten = false trace.footerWritten = false - trace.strings = make(map[string]uint64) + + // string to id mapping + // 0 : reserved for an empty string + // remaining: other strings registered by traceString trace.stringSeq = 0 + trace.strings = make(map[string]uint64) + trace.seqGC = 0 _g_.m.startingtrace = false trace.enabled = true // Register runtime goroutine labels. _, pid, bufp := traceAcquireBuffer() - buf := (*bufp).ptr() - if buf == nil { - buf = traceFlush(0).ptr() - (*bufp).set(buf) - } for i, label := range gcMarkWorkerModeStrings[:] { - trace.markWorkerLabels[i], buf = traceString(buf, label) + trace.markWorkerLabels[i], bufp = traceString(bufp, pid, label) } traceReleaseBuffer(pid) @@ -277,10 +277,9 @@ func StopTrace() { traceGoSched() - for _, p := range &allp { - if p == nil { - break - } + // Loop over all allocated Ps because dead Ps may still have + // trace buffers. + for _, p := range allp[:cap(allp)] { buf := p.tracebuf if buf != 0 { traceFullQueue(buf) @@ -320,10 +319,7 @@ func StopTrace() { // The lock protects us from races with StartTrace/StopTrace because they do stop-the-world. lock(&trace.lock) - for _, p := range &allp { - if p == nil { - break - } + for _, p := range allp[:cap(allp)] { if p.tracebuf != 0 { throw("trace: non-empty trace buffer in proc") } @@ -382,7 +378,7 @@ func ReadTrace() []byte { trace.headerWritten = true trace.lockOwner = nil unlock(&trace.lock) - return []byte("go 1.9 trace\x00\x00\x00\x00") + return []byte("go 1.10 trace\x00\x00\x00") } // Wait for new data. if trace.fullHead == 0 && !trace.shutdown { @@ -408,9 +404,12 @@ func ReadTrace() []byte { var data []byte data = append(data, traceEvFrequency|0<= 0 { @@ -602,7 +595,7 @@ func traceReleaseBuffer(pid int32) { } // traceFlush puts buf onto stack of full buffers and returns an empty buffer. -func traceFlush(buf traceBufPtr) traceBufPtr { +func traceFlush(buf traceBufPtr, pid int32) traceBufPtr { owner := trace.lockOwner dolock := owner == nil || owner != getg().m.curg if dolock { @@ -623,34 +616,51 @@ func traceFlush(buf traceBufPtr) traceBufPtr { bufp := buf.ptr() bufp.link.set(nil) bufp.pos = 0 - bufp.lastTicks = 0 + + // initialize the buffer for a new batch + ticks := uint64(cputicks()) / traceTickDiv + bufp.lastTicks = ticks + bufp.byte(traceEvBatch | 1< maxLen { fn = fn[len(fn)-maxLen:] } - frame.funcID, buf = traceString(buf, fn) + frame.funcID, bufp = traceString(bufp, pid, fn) frame.line = uint64(f.lineno) file := f.filename if len(file) > maxLen { file = file[len(file)-maxLen:] } - frame.fileID, buf = traceString(buf, file) - return frame, buf + frame.fileID, bufp = traceString(bufp, pid, file) + return frame, (*bufp) } // traceAlloc is a non-thread-safe region allocator. @@ -917,12 +931,12 @@ func traceGCDone() { traceEvent(traceEvGCDone, -1) } -func traceGCScanStart() { - traceEvent(traceEvGCScanStart, -1) +func traceGCSTWStart(kind int) { + traceEvent(traceEvGCSTWStart, -1, uint64(kind)) } -func traceGCScanDone() { - traceEvent(traceEvGCScanDone, -1) +func traceGCSTWDone() { + traceEvent(traceEvGCSTWDone, -1) } // traceGCSweepStart prepares to trace a sweep loop. This does not diff --git a/libgo/go/runtime/trace/example_test.go b/libgo/go/runtime/trace/example_test.go new file mode 100644 index 00000000000..8e0ee5a1a3f --- /dev/null +++ b/libgo/go/runtime/trace/example_test.go @@ -0,0 +1,41 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package trace_test + +import ( + "fmt" + "log" + "os" + "runtime/trace" +) + +// Example demonstrates the use of the trace package to trace +// the execution of a Go program. The trace output will be +// written to the file trace.out +func Example() { + f, err := os.Create("trace.out") + if err != nil { + log.Fatalf("failed to create trace output file: %v", err) + } + defer func() { + if err := f.Close(); err != nil { + log.Fatalf("failed to close trace file: %v", err) + } + }() + + if err := trace.Start(f); err != nil { + log.Fatalf("failed to start trace: %v", err) + } + defer trace.Stop() + + // your program here + RunMyProgram() +} + +func RunMyProgram() { + fmt.Printf("this function will be traced") +} diff --git a/libgo/go/runtime/trace/trace.go b/libgo/go/runtime/trace/trace.go index 7cbb8a6e82c..439f998c03a 100644 --- a/libgo/go/runtime/trace/trace.go +++ b/libgo/go/runtime/trace/trace.go @@ -2,13 +2,36 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Go execution tracer. -// The tracer captures a wide range of execution events like goroutine -// creation/blocking/unblocking, syscall enter/exit/block, GC-related events, -// changes of heap size, processor start/stop, etc and writes them to an io.Writer -// in a compact form. A precise nanosecond-precision timestamp and a stack -// trace is captured for most events. A trace can be analyzed later with -// 'go tool trace' command. +// Package trace contains facilities for programs to generate trace +// for Go execution tracer. +// +// The execution trace captures a wide range of execution events such as +// goroutine creation/blocking/unblocking, syscall enter/exit/block, +// GC-related events, changes of heap size, processor start/stop, etc. +// A precise nanosecond-precision timestamp and a stack trace is +// captured for most events. The generated trace can be interpreted +// using `go tool trace`. +// +// Tracing a Go program +// +// Support for tracing tests and benchmarks built with the standard +// testing package is built into `go test`. For example, the following +// command runs the test in the current directory and writes the trace +// file (trace.out). +// +// go test -trace=test.out +// +// This runtime/trace package provides APIs to add equivalent tracing +// support to a standalone program. See the Example that demonstrates +// how to use this API to enable tracing. +// +// There is also a standard HTTP interface to profiling data. Adding the +// following line will install handlers under the /debug/pprof/trace URL +// to download live profiles: +// +// import _ "net/http/pprof" +// +// See the net/http/pprof package for more details. package trace import ( diff --git a/libgo/go/runtime/trace/trace_test.go b/libgo/go/runtime/trace/trace_test.go index c5f64fcf4cf..5fa5b82f8e2 100644 --- a/libgo/go/runtime/trace/trace_test.go +++ b/libgo/go/runtime/trace/trace_test.go @@ -7,6 +7,7 @@ package trace_test import ( "bytes" "flag" + "internal/race" "internal/trace" "io" "io/ioutil" @@ -14,6 +15,7 @@ import ( "os" "runtime" . "runtime/trace" + "strconv" "sync" "testing" "time" @@ -23,6 +25,61 @@ var ( saveTraces = flag.Bool("savetraces", false, "save traces collected by tests") ) +// TestEventBatch tests Flush calls that happen during Start +// don't produce corrupted traces. +func TestEventBatch(t *testing.T) { + if race.Enabled { + t.Skip("skipping in race mode") + } + if testing.Short() { + t.Skip("skipping in short mode") + } + // During Start, bunch of records are written to reflect the current + // snapshot of the program, including state of each goroutines. + // And some string constants are written to the trace to aid trace + // parsing. This test checks Flush of the buffer occurred during + // this process doesn't cause corrupted traces. + // When a Flush is called during Start is complicated + // so we test with a range of number of goroutines hoping that one + // of them triggers Flush. + // This range was chosen to fill up a ~64KB buffer with traceEvGoCreate + // and traceEvGoWaiting events (12~13bytes per goroutine). + for g := 4950; g < 5050; g++ { + n := g + t.Run("G="+strconv.Itoa(n), func(t *testing.T) { + var wg sync.WaitGroup + wg.Add(n) + + in := make(chan bool, 1000) + for i := 0; i < n; i++ { + go func() { + <-in + wg.Done() + }() + } + buf := new(bytes.Buffer) + if err := Start(buf); err != nil { + t.Fatalf("failed to start tracing: %v", err) + } + + for i := 0; i < n; i++ { + in <- true + } + wg.Wait() + Stop() + + _, err := trace.Parse(buf, "") + if err == trace.ErrTimeOrder { + t.Skipf("skipping trace: %v", err) + } + + if err != nil { + t.Fatalf("failed to parse trace: %v", err) + } + }) + } +} + func TestTraceStartStop(t *testing.T) { buf := new(bytes.Buffer) if err := Start(buf); err != nil { diff --git a/libgo/go/runtime/traceback_gccgo.go b/libgo/go/runtime/traceback_gccgo.go index 37c569887b0..79f78d8d247 100644 --- a/libgo/go/runtime/traceback_gccgo.go +++ b/libgo/go/runtime/traceback_gccgo.go @@ -52,7 +52,7 @@ func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32 // callers returns a stack trace of the current goroutine. // The gc version of callers takes []uintptr, but we take []location. func callers(skip int, locbuf []location) int { - n := c_callers(int32(skip), &locbuf[0], int32(len(locbuf)), false) + n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false) return int(n) } @@ -156,7 +156,7 @@ func goroutineheader(gp *g) { if waitfor >= 1 { print(", ", waitfor, " minutes") } - if gp.lockedm != nil { + if gp.lockedm != 0 { print(", locked to thread") } print("]:\n") diff --git a/libgo/go/sort/example_interface_test.go b/libgo/go/sort/example_interface_test.go index 442204ea9eb..72d3017a828 100644 --- a/libgo/go/sort/example_interface_test.go +++ b/libgo/go/sort/example_interface_test.go @@ -35,10 +35,24 @@ func Example() { } fmt.Println(people) + // There are two ways to sort a slice. First, one can define + // a set of methods for the slice type, as with ByAge, and + // call sort.Sort. In this first example we use that technique. sort.Sort(ByAge(people)) fmt.Println(people) + // The other way is to use sort.Slice with a custom Less + // function, which can be provided as a closure. In this + // case no methods are needed. (And if they exist, they + // are ignored.) Here we re-sort in reverse order: compare + // the closure with ByAge.Less. + sort.Slice(people, func(i, j int) bool { + return people[i].Age > people[j].Age + }) + fmt.Println(people) + // Output: // [Bob: 31 John: 42 Michael: 17 Jenny: 26] // [Michael: 17 Jenny: 26 Bob: 31 John: 42] + // [John: 42 Bob: 31 Jenny: 26 Michael: 17] } diff --git a/libgo/go/sort/example_keys_test.go b/libgo/go/sort/example_keys_test.go index a8e47e4926b..648f919e68d 100644 --- a/libgo/go/sort/example_keys_test.go +++ b/libgo/go/sort/example_keys_test.go @@ -73,7 +73,7 @@ func Example_sortKeys() { return p1.distance < p2.distance } decreasingDistance := func(p1, p2 *Planet) bool { - return !distance(p1, p2) + return distance(p2, p1) } // Sort the planets by the various criteria. diff --git a/libgo/go/sort/example_multi_test.go b/libgo/go/sort/example_multi_test.go index 40d12152ce2..de6ec142d1c 100644 --- a/libgo/go/sort/example_multi_test.go +++ b/libgo/go/sort/example_multi_test.go @@ -49,10 +49,11 @@ func (ms *multiSorter) Swap(i, j int) { } // Less is part of sort.Interface. It is implemented by looping along the -// less functions until it finds a comparison that is either Less or -// !Less. Note that it can call the less functions twice per call. We -// could change the functions to return -1, 0, 1 and reduce the -// number of calls for greater efficiency: an exercise for the reader. +// less functions until it finds a comparison that discriminates between +// the two items (one is less than the other). Note that it can call the +// less functions twice per call. We could change the functions to return +// -1, 0, 1 and reduce the number of calls for greater efficiency: an +// exercise for the reader. func (ms *multiSorter) Less(i, j int) bool { p, q := &ms.changes[i], &ms.changes[j] // Try all but the last comparison. diff --git a/libgo/go/sort/example_test.go b/libgo/go/sort/example_test.go index f8d8491bc4c..1f85dbcbfba 100644 --- a/libgo/go/sort/example_test.go +++ b/libgo/go/sort/example_test.go @@ -6,6 +6,7 @@ package sort_test import ( "fmt" + "math" "sort" ) @@ -16,6 +17,49 @@ func ExampleInts() { // Output: [1 2 3 4 5 6] } +func ExampleIntsAreSorted() { + s := []int{1, 2, 3, 4, 5, 6} // sorted ascending + fmt.Println(sort.IntsAreSorted(s)) + + s = []int{6, 5, 4, 3, 2, 1} // sorted descending + fmt.Println(sort.IntsAreSorted(s)) + + s = []int{3, 2, 4, 1, 5} // unsorted + fmt.Println(sort.IntsAreSorted(s)) + + // Output: true + // false + // false +} + +func ExampleFloat64s() { + s := []float64{5.2, -1.3, 0.7, -3.8, 2.6} // unsorted + sort.Float64s(s) + fmt.Println(s) + + s = []float64{math.Inf(1), math.NaN(), math.Inf(-1), 0.0} // unsorted + sort.Float64s(s) + fmt.Println(s) + + // Output: [-3.8 -1.3 0.7 2.6 5.2] + // [NaN -Inf 0 +Inf] +} + +func ExampleFloat64sAreSorted() { + s := []float64{0.7, 1.3, 2.6, 3.8, 5.2} // sorted ascending + fmt.Println(sort.Float64sAreSorted(s)) + + s = []float64{5.2, 3.8, 2.6, 1.3, 0.7} // sorted descending + fmt.Println(sort.Float64sAreSorted(s)) + + s = []float64{5.2, 1.3, 0.7, 3.8, 2.6} // unsorted + fmt.Println(sort.Float64sAreSorted(s)) + + // Output: true + // false + // false +} + func ExampleReverse() { s := []int{5, 2, 6, 3, 1, 4} // unsorted sort.Sort(sort.Reverse(sort.IntSlice(s))) diff --git a/libgo/go/sort/slice.go b/libgo/go/sort/slice.go new file mode 100644 index 00000000000..206f12173de --- /dev/null +++ b/libgo/go/sort/slice.go @@ -0,0 +1,46 @@ +// Copyright 2017 The Go 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 !compiler_bootstrap go1.8 + +package sort + +import "reflect" + +// Slice sorts the provided slice given the provided less function. +// +// The sort is not guaranteed to be stable. For a stable sort, use +// SliceStable. +// +// The function panics if the provided interface is not a slice. +func Slice(slice interface{}, less func(i, j int) bool) { + rv := reflect.ValueOf(slice) + swap := reflect.Swapper(slice) + length := rv.Len() + quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length)) +} + +// SliceStable sorts the provided slice given the provided less +// function while keeping the original order of equal elements. +// +// The function panics if the provided interface is not a slice. +func SliceStable(slice interface{}, less func(i, j int) bool) { + rv := reflect.ValueOf(slice) + swap := reflect.Swapper(slice) + stable_func(lessSwap{less, swap}, rv.Len()) +} + +// SliceIsSorted tests whether a slice is sorted. +// +// The function panics if the provided interface is not a slice. +func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool { + rv := reflect.ValueOf(slice) + n := rv.Len() + for i := n - 1; i > 0; i-- { + if less(i, i-1) { + return false + } + } + return true +} diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go index 081b7007989..a7304af53de 100644 --- a/libgo/go/sort/sort.go +++ b/libgo/go/sort/sort.go @@ -8,8 +8,6 @@ // collections. package sort -import "reflect" - // A type, typically a collection, that satisfies sort.Interface can be // sorted by the routines in this package. The methods require that the // elements of the collection be enumerated by an integer index. @@ -238,43 +236,6 @@ type lessSwap struct { Swap func(i, j int) } -// Slice sorts the provided slice given the provided less function. -// -// The sort is not guaranteed to be stable. For a stable sort, use -// SliceStable. -// -// The function panics if the provided interface is not a slice. -func Slice(slice interface{}, less func(i, j int) bool) { - rv := reflect.ValueOf(slice) - swap := reflect.Swapper(slice) - length := rv.Len() - quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length)) -} - -// SliceStable sorts the provided slice given the provided less -// function while keeping the original order of equal elements. -// -// The function panics if the provided interface is not a slice. -func SliceStable(slice interface{}, less func(i, j int) bool) { - rv := reflect.ValueOf(slice) - swap := reflect.Swapper(slice) - stable_func(lessSwap{less, swap}, rv.Len()) -} - -// SliceIsSorted tests whether a slice is sorted. -// -// The function panics if the provided interface is not a slice. -func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool { - rv := reflect.ValueOf(slice) - n := rv.Len() - for i := n - 1; i > 0; i-- { - if less(i, i-1) { - return false - } - } - return true -} - type reverse struct { // This embedded Interface permits Reverse to use the methods of // another Interface implementation. diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go index 45713a28cc4..092135e588d 100644 --- a/libgo/go/sort/sort_test.go +++ b/libgo/go/sort/sort_test.go @@ -458,49 +458,69 @@ func TestStableBM(t *testing.T) { // This is based on the "antiquicksort" implementation by M. Douglas McIlroy. // See http://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info. type adversaryTestingData struct { - data []int - keys map[int]int - candidate int + t *testing.T + data []int // item values, initialized to special gas value and changed by Less + maxcmp int // number of comparisons allowed + ncmp int // number of comparisons (calls to Less) + nsolid int // number of elements that have been set to non-gas values + candidate int // guess at current pivot + gas int // special value for unset elements, higher than everything else } func (d *adversaryTestingData) Len() int { return len(d.data) } func (d *adversaryTestingData) Less(i, j int) bool { - if _, present := d.keys[i]; !present { - if _, present := d.keys[j]; !present { - if i == d.candidate { - d.keys[i] = len(d.keys) - } else { - d.keys[j] = len(d.keys) - } + if d.ncmp >= d.maxcmp { + d.t.Fatalf("used %d comparisons sorting adversary data with size %d", d.ncmp, len(d.data)) + } + d.ncmp++ + + if d.data[i] == d.gas && d.data[j] == d.gas { + if i == d.candidate { + // freeze i + d.data[i] = d.nsolid + d.nsolid++ + } else { + // freeze j + d.data[j] = d.nsolid + d.nsolid++ } } - if _, present := d.keys[i]; !present { + if d.data[i] == d.gas { d.candidate = i - return false - } - if _, present := d.keys[j]; !present { + } else if d.data[j] == d.gas { d.candidate = j - return true } - return d.keys[i] >= d.keys[j] + return d.data[i] < d.data[j] } func (d *adversaryTestingData) Swap(i, j int) { d.data[i], d.data[j] = d.data[j], d.data[i] } -func TestAdversary(t *testing.T) { - const size = 100 +func newAdversaryTestingData(t *testing.T, size int, maxcmp int) *adversaryTestingData { + gas := size - 1 data := make([]int, size) for i := 0; i < size; i++ { - data[i] = i + data[i] = gas } + return &adversaryTestingData{t: t, data: data, maxcmp: maxcmp, gas: gas} +} - d := &adversaryTestingData{data, make(map[int]int), 0} +func TestAdversary(t *testing.T) { + const size = 10000 // large enough to distinguish between O(n^2) and O(n*log(n)) + maxcmp := size * lg(size) * 4 // the factor 4 was found by trial and error + d := newAdversaryTestingData(t, size, maxcmp) Sort(d) // This should degenerate to heapsort. + // Check data is fully populated and sorted. + for i, v := range d.data { + if v != i { + t.Errorf("adversary data not fully sorted") + t.FailNow() + } + } } func TestStableInts(t *testing.T) { diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go index 66df149172d..bebed048204 100644 --- a/libgo/go/strconv/atoi.go +++ b/libgo/go/strconv/atoi.go @@ -16,7 +16,7 @@ var ErrSyntax = errors.New("invalid syntax") type NumError struct { Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) Num string // the input - Err error // the reason the conversion failed (ErrRange, ErrSyntax) + Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.) } func (e *NumError) Error() string { @@ -31,6 +31,14 @@ func rangeError(fn, str string) *NumError { return &NumError{fn, str, ErrRange} } +func baseError(fn, str string, base int) *NumError { + return &NumError{fn, str, errors.New("invalid base " + Itoa(base))} +} + +func bitSizeError(fn, str string, bitSize int) *NumError { + return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))} +} + const intSize = 32 << (^uint(0) >> 63) // IntSize is the size in bits of an int or uint value. @@ -40,20 +48,14 @@ const maxUint64 = (1<<64 - 1) // ParseUint is like ParseInt but for unsigned numbers. func ParseUint(s string, base int, bitSize int) (uint64, error) { - var n uint64 - var err error - var cutoff, maxVal uint64 + const fnParseUint = "ParseUint" - if bitSize == 0 { - bitSize = int(IntSize) + if len(s) == 0 { + return 0, syntaxError(fnParseUint, s) } - i := 0 + s0 := s switch { - case len(s) < 1: - err = ErrSyntax - goto Error - case 2 <= base && base <= 36: // valid base; nothing to do @@ -62,25 +64,30 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { switch { case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): if len(s) < 3 { - err = ErrSyntax - goto Error + return 0, syntaxError(fnParseUint, s0) } base = 16 - i = 2 + s = s[2:] case s[0] == '0': base = 8 - i = 1 + s = s[1:] default: base = 10 } default: - err = errors.New("invalid base " + Itoa(base)) - goto Error + return 0, baseError(fnParseUint, s0, base) + } + + if bitSize == 0 { + bitSize = int(IntSize) + } else if bitSize < 0 || bitSize > 64 { + return 0, bitSizeError(fnParseUint, s0, bitSize) } // Cutoff is the smallest number such that cutoff*base > maxUint64. // Use compile-time constants for common cases. + var cutoff uint64 switch base { case 10: cutoff = maxUint64/10 + 1 @@ -90,61 +97,54 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { cutoff = maxUint64/uint64(base) + 1 } - maxVal = 1<= byte(base) { - n = 0 - err = ErrSyntax - goto Error + + if d >= byte(base) { + return 0, syntaxError(fnParseUint, s0) } if n >= cutoff { // n*base overflows - n = maxUint64 - err = ErrRange - goto Error + return maxVal, rangeError(fnParseUint, s0) } n *= uint64(base) - n1 := n + uint64(v) + n1 := n + uint64(d) if n1 < n || n1 > maxVal { // n+v overflows - n = maxUint64 - err = ErrRange - goto Error + return maxVal, rangeError(fnParseUint, s0) } n = n1 } return n, nil - -Error: - return n, &NumError{"ParseUint", s, err} } -// ParseInt interprets a string s in the given base (2 to 36) and -// returns the corresponding value i. If base == 0, the base is -// implied by the string's prefix: base 16 for "0x", base 8 for -// "0", and base 10 otherwise. +// ParseInt interprets a string s in the given base (0, 2 to 36) and +// bit size (0 to 64) and returns the corresponding value i. +// +// If base == 0, the base is implied by the string's prefix: +// base 16 for "0x", base 8 for "0", and base 10 otherwise. +// For bases 1, below 0 or above 36 an error is returned. // // The bitSize argument specifies the integer type // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 // correspond to int, int8, int16, int32, and int64. +// For a bitSize below 0 or above 64 an error is returned. // // The errors that ParseInt returns have concrete type *NumError // and include err.Num = s. If s is empty or contains invalid @@ -156,10 +156,6 @@ Error: func ParseInt(s string, base int, bitSize int) (i int64, err error) { const fnParseInt = "ParseInt" - if bitSize == 0 { - bitSize = int(IntSize) - } - // Empty string bad. if len(s) == 0 { return 0, syntaxError(fnParseInt, s) @@ -183,6 +179,11 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) { err.(*NumError).Num = s0 return 0, err } + + if bitSize == 0 { + bitSize = int(IntSize) + } + cutoff := uint64(1 << uint(bitSize-1)) if !neg && un >= cutoff { return int64(cutoff - 1), rangeError(fnParseInt, s0) @@ -200,6 +201,34 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) { // Atoi returns the result of ParseInt(s, 10, 0) converted to type int. func Atoi(s string) (int, error) { const fnAtoi = "Atoi" + + sLen := len(s) + if intSize == 32 && (0 < sLen && sLen < 10) || + intSize == 64 && (0 < sLen && sLen < 19) { + // Fast path for small integers that fit int type. + s0 := s + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) < 1 { + return 0, &NumError{fnAtoi, s0, ErrSyntax} + } + } + + n := 0 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, &NumError{fnAtoi, s0, ErrSyntax} + } + n = n*10 + int(ch) + } + if s0[0] == '-' { + n = -n + } + return n, nil + } + + // Slow path for invalid or big integers. i64, err := ParseInt(s, 10, 0) if nerr, ok := err.(*NumError); ok { nerr.Func = fnAtoi diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go index d608505da21..e2f505a6651 100644 --- a/libgo/go/strconv/atoi_test.go +++ b/libgo/go/strconv/atoi_test.go @@ -6,18 +6,19 @@ package strconv_test import ( "errors" + "fmt" "reflect" . "strconv" "testing" ) -type atoui64Test struct { +type parseUint64Test struct { in string out uint64 err error } -var atoui64tests = []atoui64Test{ +var parseUint64Tests = []parseUint64Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, {"1", 1, nil}, @@ -30,38 +31,45 @@ var atoui64tests = []atoui64Test{ {"18446744073709551620", 1<<64 - 1, ErrRange}, } -var btoui64tests = []atoui64Test{ - {"", 0, ErrSyntax}, - {"0", 0, nil}, - {"0x", 0, ErrSyntax}, - {"0X", 0, ErrSyntax}, - {"1", 1, nil}, - {"12345", 12345, nil}, - {"012345", 012345, nil}, - {"0x12345", 0x12345, nil}, - {"0X12345", 0x12345, nil}, - {"12345x", 0, ErrSyntax}, - {"0xabcdefg123", 0, ErrSyntax}, - {"123456789abc", 0, ErrSyntax}, - {"98765432100", 98765432100, nil}, - {"18446744073709551615", 1<<64 - 1, nil}, - {"18446744073709551616", 1<<64 - 1, ErrRange}, - {"18446744073709551620", 1<<64 - 1, ErrRange}, - {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil}, - {"0x10000000000000000", 1<<64 - 1, ErrRange}, - {"01777777777777777777777", 1<<64 - 1, nil}, - {"01777777777777777777778", 0, ErrSyntax}, - {"02000000000000000000000", 1<<64 - 1, ErrRange}, - {"0200000000000000000000", 1 << 61, nil}, +type parseUint64BaseTest struct { + in string + base int + out uint64 + err error +} + +var parseUint64BaseTests = []parseUint64BaseTest{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"0x", 0, 0, ErrSyntax}, + {"0X", 0, 0, ErrSyntax}, + {"1", 0, 1, nil}, + {"12345", 0, 12345, nil}, + {"012345", 0, 012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"0X12345", 0, 0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"0xabcdefg123", 0, 0, ErrSyntax}, + {"123456789abc", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"18446744073709551615", 0, 1<<64 - 1, nil}, + {"18446744073709551616", 0, 1<<64 - 1, ErrRange}, + {"18446744073709551620", 0, 1<<64 - 1, ErrRange}, + {"0xFFFFFFFFFFFFFFFF", 0, 1<<64 - 1, nil}, + {"0x10000000000000000", 0, 1<<64 - 1, ErrRange}, + {"01777777777777777777777", 0, 1<<64 - 1, nil}, + {"01777777777777777777778", 0, 0, ErrSyntax}, + {"02000000000000000000000", 0, 1<<64 - 1, ErrRange}, + {"0200000000000000000000", 0, 1 << 61, nil}, } -type atoi64Test struct { +type parseInt64Test struct { in string out int64 err error } -var atoi64tests = []atoi64Test{ +var parseInt64Tests = []parseInt64Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, {"-0", 0, nil}, @@ -81,14 +89,14 @@ var atoi64tests = []atoi64Test{ {"-9223372036854775809", -1 << 63, ErrRange}, } -type btoi64Test struct { +type parseInt64BaseTest struct { in string base int out int64 err error } -var btoi64tests = []btoi64Test{ +var parseInt64BaseTests = []parseInt64BaseTest{ {"", 0, 0, ErrSyntax}, {"0", 0, 0, nil}, {"-0", 0, 0, nil}, @@ -138,13 +146,13 @@ var btoi64tests = []btoi64Test{ {"7fffffffffffffff", 16, 1<<63 - 1, nil}, } -type atoui32Test struct { +type parseUint32Test struct { in string out uint32 err error } -var atoui32tests = []atoui32Test{ +var parseUint32Tests = []parseUint32Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, {"1", 1, nil}, @@ -156,13 +164,13 @@ var atoui32tests = []atoui32Test{ {"4294967296", 1<<32 - 1, ErrRange}, } -type atoi32Test struct { +type parseInt32Test struct { in string out int32 err error } -var atoi32tests = []atoi32Test{ +var parseInt32Tests = []parseInt32Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, {"-0", 0, nil}, @@ -195,86 +203,108 @@ var numErrorTests = []numErrorTest{ } func init() { - // The atoi routines return NumErrors wrapping + // The parse routines return NumErrors wrapping // the error and the string. Convert the tables above. - for i := range atoui64tests { - test := &atoui64tests[i] + for i := range parseUint64Tests { + test := &parseUint64Tests[i] if test.err != nil { test.err = &NumError{"ParseUint", test.in, test.err} } } - for i := range btoui64tests { - test := &btoui64tests[i] + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] if test.err != nil { test.err = &NumError{"ParseUint", test.in, test.err} } } - for i := range atoi64tests { - test := &atoi64tests[i] + for i := range parseInt64Tests { + test := &parseInt64Tests[i] if test.err != nil { test.err = &NumError{"ParseInt", test.in, test.err} } } - for i := range btoi64tests { - test := &btoi64tests[i] + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] if test.err != nil { test.err = &NumError{"ParseInt", test.in, test.err} } } - for i := range atoui32tests { - test := &atoui32tests[i] + for i := range parseUint32Tests { + test := &parseUint32Tests[i] if test.err != nil { test.err = &NumError{"ParseUint", test.in, test.err} } } - for i := range atoi32tests { - test := &atoi32tests[i] + for i := range parseInt32Tests { + test := &parseInt32Tests[i] if test.err != nil { test.err = &NumError{"ParseInt", test.in, test.err} } } } +func TestParseUint32(t *testing.T) { + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + out, err := ParseUint(test.in, 10, 32) + if uint64(test.out) != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 32) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + func TestParseUint64(t *testing.T) { - for i := range atoui64tests { - test := &atoui64tests[i] + for i := range parseUint64Tests { + test := &parseUint64Tests[i] out, err := ParseUint(test.in, 10, 64) if test.out != out || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoui64(%q) = %v, %v want %v, %v", + t.Errorf("ParseUint(%q, 10, 64) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } } func TestParseUint64Base(t *testing.T) { - for i := range btoui64tests { - test := &btoui64tests[i] - out, err := ParseUint(test.in, 0, 64) + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] + out, err := ParseUint(test.in, test.base, 64) if test.out != out || !reflect.DeepEqual(test.err, err) { - t.Errorf("ParseUint(%q) = %v, %v want %v, %v", + t.Errorf("ParseUint(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) + } + } +} + +func TestParseInt32(t *testing.T) { + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := ParseInt(test.in, 10, 32) + if int64(test.out) != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10 ,32) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } } func TestParseInt64(t *testing.T) { - for i := range atoi64tests { - test := &atoi64tests[i] + for i := range parseInt64Tests { + test := &parseInt64Tests[i] out, err := ParseInt(test.in, 10, 64) if test.out != out || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoi64(%q) = %v, %v want %v, %v", + t.Errorf("ParseInt(%q, 10, 64) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } } func TestParseInt64Base(t *testing.T) { - for i := range btoi64tests { - test := &btoi64tests[i] + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] out, err := ParseInt(test.in, test.base, 64) if test.out != out || !reflect.DeepEqual(test.err, err) { - t.Errorf("ParseInt(%q) = %v, %v want %v, %v", - test.in, out, err, test.out, test.err) + t.Errorf("ParseInt(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) } } } @@ -282,20 +312,20 @@ func TestParseInt64Base(t *testing.T) { func TestParseUint(t *testing.T) { switch IntSize { case 32: - for i := range atoui32tests { - test := &atoui32tests[i] + for i := range parseUint32Tests { + test := &parseUint32Tests[i] out, err := ParseUint(test.in, 10, 0) - if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoui(%q) = %v, %v want %v, %v", + if uint64(test.out) != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } case 64: - for i := range atoui64tests { - test := &atoui64tests[i] + for i := range parseUint64Tests { + test := &parseUint64Tests[i] out, err := ParseUint(test.in, 10, 0) - if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoui(%q) = %v, %v want %v, %v", + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } @@ -305,26 +335,138 @@ func TestParseUint(t *testing.T) { func TestParseInt(t *testing.T) { switch IntSize { case 32: - for i := range atoi32tests { - test := &atoi32tests[i] + for i := range parseInt32Tests { + test := &parseInt32Tests[i] out, err := ParseInt(test.in, 10, 0) - if test.out != int32(out) || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoi(%q) = %v, %v want %v, %v", + if int64(test.out) != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } case 64: - for i := range atoi64tests { - test := &atoi64tests[i] + for i := range parseInt64Tests { + test := &parseInt64Tests[i] out, err := ParseInt(test.in, 10, 0) - if test.out != int64(out) || !reflect.DeepEqual(test.err, err) { - t.Errorf("Atoi(%q) = %v, %v want %v, %v", + if test.out != out || !reflect.DeepEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) } } } } +func TestAtoi(t *testing.T) { + switch IntSize { + case 32: + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if int(test.out) != out || !reflect.DeepEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + case 64: + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if test.out != int64(out) || !reflect.DeepEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + } +} + +func bitSizeErrStub(name string, bitSize int) error { + return BitSizeError(name, "0", bitSize) +} + +func baseErrStub(name string, base int) error { + return BaseError(name, "0", base) +} + +func noErrStub(name string, arg int) error { + return nil +} + +type parseErrorTest struct { + arg int + errStub func(name string, arg int) error +} + +var parseBitSizeTests = []parseErrorTest{ + {-1, bitSizeErrStub}, + {0, noErrStub}, + {64, noErrStub}, + {65, bitSizeErrStub}, +} + +var parseBaseTests = []parseErrorTest{ + {-1, baseErrStub}, + {0, noErrStub}, + {1, baseErrStub}, + {2, noErrStub}, + {36, noErrStub}, + {37, baseErrStub}, +} + +func TestParseIntBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", 0, test.arg) + if !reflect.DeepEqual(testErr, err) { + t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", 0, test.arg) + if !reflect.DeepEqual(testErr, err) { + t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseIntBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", test.arg, 0) + if !reflect.DeepEqual(testErr, err) { + t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", test.arg, 0) + if !reflect.DeepEqual(testErr, err) { + t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + func TestNumError(t *testing.T) { for _, test := range numErrorTests { err := &NumError{ @@ -338,26 +480,67 @@ func TestNumError(t *testing.T) { } } -func BenchmarkAtoi(b *testing.B) { - for i := 0; i < b.N; i++ { - ParseInt("12345678", 10, 0) - } +func BenchmarkParseInt(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkParseInt(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkParseInt(b, -1) + }) } -func BenchmarkAtoiNeg(b *testing.B) { - for i := 0; i < b.N; i++ { - ParseInt("-12345678", 10, 0) - } +type benchCase struct { + name string + num int64 } -func BenchmarkAtoi64(b *testing.B) { - for i := 0; i < b.N; i++ { - ParseInt("12345678901234", 10, 64) +func benchmarkParseInt(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := ParseInt(s, 10, 64) + BenchSink += int(out) + } + }) + } +} + +func BenchmarkAtoi(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkAtoi(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkAtoi(b, -1) + }) } -func BenchmarkAtoi64Neg(b *testing.B) { - for i := 0; i < b.N; i++ { - ParseInt("-12345678901234", 10, 64) +func benchmarkAtoi(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + } + if IntSize == 64 { + cases = append(cases, []benchCase{ + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, + }...) + } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := Atoi(s) + BenchSink += out + } + }) } } diff --git a/libgo/go/strconv/export_test.go b/libgo/go/strconv/export_test.go new file mode 100644 index 00000000000..8c03a7ffb4f --- /dev/null +++ b/libgo/go/strconv/export_test.go @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. 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 + +var ( + BitSizeError = bitSizeError + BaseError = baseError +) diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go index 7033e96c39e..7f17bc6a0df 100644 --- a/libgo/go/strconv/extfloat.go +++ b/libgo/go/strconv/extfloat.go @@ -641,7 +641,7 @@ func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool // adjustLastDigit modifies d = x-currentDiff*ε, to get closest to // d = x-targetDiff*ε, without becoming smaller than x-maxDiff*ε. // It assumes that a decimal digit is worth ulpDecimal*ε, and that -// all data is known with a error estimate of ulpBinary*ε. +// all data is known with an error estimate of ulpBinary*ε. func adjustLastDigit(d *decimalSlice, currentDiff, targetDiff, maxDiff, ulpDecimal, ulpBinary uint64) bool { if ulpDecimal < 2*ulpBinary { // Approximation is too wide. diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go index a30d8d8b59c..58371422011 100644 --- a/libgo/go/strconv/isprint.go +++ b/libgo/go/strconv/isprint.go @@ -7,7 +7,7 @@ package strconv -// (462+139+82)*2 + (378)*4 = 2878 bytes +// (456+140+86)*2 + (396)*4 = 2948 bytes var isPrint16 = []uint16{ 0x0020, 0x007e, @@ -25,7 +25,7 @@ var isPrint16 = []uint16{ 0x07c0, 0x07fa, 0x0800, 0x082d, 0x0830, 0x085b, - 0x085e, 0x085e, + 0x085e, 0x086a, 0x08a0, 0x08bd, 0x08d4, 0x098c, 0x098f, 0x0990, @@ -36,7 +36,7 @@ var isPrint16 = []uint16{ 0x09cb, 0x09ce, 0x09d7, 0x09d7, 0x09dc, 0x09e3, - 0x09e6, 0x09fb, + 0x09e6, 0x09fd, 0x0a01, 0x0a0a, 0x0a0f, 0x0a10, 0x0a13, 0x0a39, @@ -51,8 +51,7 @@ var isPrint16 = []uint16{ 0x0ad0, 0x0ad0, 0x0ae0, 0x0ae3, 0x0ae6, 0x0af1, - 0x0af9, 0x0af9, - 0x0b01, 0x0b0c, + 0x0af9, 0x0b0c, 0x0b0f, 0x0b10, 0x0b13, 0x0b39, 0x0b3c, 0x0b44, @@ -82,8 +81,7 @@ var isPrint16 = []uint16{ 0x0cd5, 0x0cd6, 0x0cde, 0x0ce3, 0x0ce6, 0x0cf2, - 0x0d01, 0x0d3a, - 0x0d3d, 0x0d4f, + 0x0d00, 0x0d4f, 0x0d54, 0x0d63, 0x0d66, 0x0d7f, 0x0d82, 0x0d96, @@ -154,8 +152,7 @@ var isPrint16 = []uint16{ 0x1c4d, 0x1c88, 0x1cc0, 0x1cc7, 0x1cd0, 0x1cf9, - 0x1d00, 0x1df5, - 0x1dfb, 0x1f15, + 0x1d00, 0x1f15, 0x1f18, 0x1f1d, 0x1f20, 0x1f45, 0x1f48, 0x1f4d, @@ -167,7 +164,7 @@ var isPrint16 = []uint16{ 0x2030, 0x205e, 0x2070, 0x2071, 0x2074, 0x209c, - 0x20a0, 0x20be, + 0x20a0, 0x20bf, 0x20d0, 0x20f0, 0x2100, 0x218b, 0x2190, 0x2426, @@ -175,7 +172,7 @@ var isPrint16 = []uint16{ 0x2460, 0x2b73, 0x2b76, 0x2b95, 0x2b98, 0x2bb9, - 0x2bbd, 0x2bd1, + 0x2bbd, 0x2bd2, 0x2bec, 0x2bef, 0x2c00, 0x2cf3, 0x2cf9, 0x2d27, @@ -183,17 +180,17 @@ var isPrint16 = []uint16{ 0x2d30, 0x2d67, 0x2d6f, 0x2d70, 0x2d7f, 0x2d96, - 0x2da0, 0x2e44, + 0x2da0, 0x2e49, 0x2e80, 0x2ef3, 0x2f00, 0x2fd5, 0x2ff0, 0x2ffb, 0x3001, 0x3096, 0x3099, 0x30ff, - 0x3105, 0x312d, + 0x3105, 0x312e, 0x3131, 0x31ba, 0x31c0, 0x31e3, 0x31f0, 0x4db5, - 0x4dc0, 0x9fd5, + 0x4dc0, 0x9fea, 0xa000, 0xa48c, 0xa490, 0xa4c6, 0xa4d0, 0xa62b, @@ -254,6 +251,7 @@ var isNotPrint16 = []uint16{ 0x0590, 0x06dd, 0x083f, + 0x085f, 0x08b5, 0x08e2, 0x0984, @@ -275,6 +273,7 @@ var isNotPrint16 = []uint16{ 0x0ab4, 0x0ac6, 0x0aca, + 0x0b00, 0x0b04, 0x0b29, 0x0b31, @@ -341,7 +340,7 @@ var isNotPrint16 = []uint16{ 0x1771, 0x191f, 0x1a5f, - 0x1cf7, + 0x1dfa, 0x1f58, 0x1f5a, 0x1f5c, @@ -351,7 +350,6 @@ var isNotPrint16 = []uint16{ 0x1fdc, 0x1ff5, 0x208f, - 0x23ff, 0x2bc9, 0x2c2f, 0x2c5f, @@ -398,7 +396,7 @@ var isPrint32 = []uint32{ 0x0102a0, 0x0102d0, 0x0102e0, 0x0102fb, 0x010300, 0x010323, - 0x010330, 0x01034a, + 0x01032d, 0x01034a, 0x010350, 0x01037a, 0x010380, 0x0103c3, 0x0103c8, 0x0103d5, @@ -481,11 +479,17 @@ var isPrint32 = []uint32{ 0x011730, 0x01173f, 0x0118a0, 0x0118f2, 0x0118ff, 0x0118ff, + 0x011a00, 0x011a47, + 0x011a50, 0x011a83, + 0x011a86, 0x011aa2, 0x011ac0, 0x011af8, 0x011c00, 0x011c45, 0x011c50, 0x011c6c, 0x011c70, 0x011c8f, 0x011c92, 0x011cb6, + 0x011d00, 0x011d36, + 0x011d3a, 0x011d47, + 0x011d50, 0x011d59, 0x012000, 0x012399, 0x012400, 0x012474, 0x012480, 0x012543, @@ -502,10 +506,11 @@ var isPrint32 = []uint32{ 0x016f00, 0x016f44, 0x016f50, 0x016f7e, 0x016f8f, 0x016f9f, - 0x016fe0, 0x016fe0, + 0x016fe0, 0x016fe1, 0x017000, 0x0187ec, 0x018800, 0x018af2, - 0x01b000, 0x01b001, + 0x01b000, 0x01b11e, + 0x01b170, 0x01b2fb, 0x01bc00, 0x01bc6a, 0x01bc70, 0x01bc7c, 0x01bc80, 0x01bc88, @@ -553,9 +558,10 @@ var isPrint32 = []uint32{ 0x01f210, 0x01f23b, 0x01f240, 0x01f248, 0x01f250, 0x01f251, - 0x01f300, 0x01f6d2, + 0x01f260, 0x01f265, + 0x01f300, 0x01f6d4, 0x01f6e0, 0x01f6ec, - 0x01f6f0, 0x01f6f6, + 0x01f6f0, 0x01f6f8, 0x01f700, 0x01f773, 0x01f780, 0x01f7d4, 0x01f800, 0x01f80b, @@ -563,16 +569,17 @@ var isPrint32 = []uint32{ 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, - 0x01f910, 0x01f927, - 0x01f930, 0x01f930, - 0x01f933, 0x01f94b, - 0x01f950, 0x01f95e, - 0x01f980, 0x01f991, + 0x01f900, 0x01f90b, + 0x01f910, 0x01f94c, + 0x01f950, 0x01f96b, + 0x01f980, 0x01f997, 0x01f9c0, 0x01f9c0, + 0x01f9d0, 0x01f9e6, 0x020000, 0x02a6d6, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, 0x02b820, 0x02cea1, + 0x02ceb0, 0x02ebe0, 0x02f800, 0x02fa1d, 0x0e0100, 0x0e01ef, } @@ -605,9 +612,14 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0x1334, 0x145a, 0x145c, + 0x1a9d, 0x1c09, 0x1c37, 0x1ca8, + 0x1d07, + 0x1d0a, + 0x1d3b, + 0x1d3e, 0x246f, 0x6a5f, 0x6b5a, @@ -658,7 +670,6 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0xf0c0, 0xf0d0, 0xf12f, - 0xf91f, 0xf93f, } diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go index db57065cac1..156a510d213 100644 --- a/libgo/go/strconv/quote.go +++ b/libgo/go/strconv/quote.go @@ -381,7 +381,7 @@ func Unquote(s string) (string, error) { return "", ErrSyntax } - // Is it trivial? Avoid allocation. + // Is it trivial? Avoid allocation. if !contains(s, '\\') && !contains(s, quote) { switch quote { case '"': diff --git a/libgo/go/strings/builder.go b/libgo/go/strings/builder.go new file mode 100644 index 00000000000..594f3db5132 --- /dev/null +++ b/libgo/go/strings/builder.go @@ -0,0 +1,120 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import ( + "errors" + "io" + "unicode/utf8" + "unsafe" +) + +// A Builder is used to efficiently build a string using Write methods. +// It minimizes memory copying. The zero value is ready to use. +type Builder struct { + buf []byte +} + +// String returns the accumulated string. +func (b *Builder) String() string { + return *(*string)(unsafe.Pointer(&b.buf)) +} + +// Len returns the number of accumulated bytes; b.Len() == len(b.String()). +func (b *Builder) Len() int { return len(b.buf) } + +// Reset resets the Builder to be empty. +func (b *Builder) Reset() { b.buf = nil } + +const maxInt = int(^uint(0) >> 1) + +// grow copies the buffer to a new, larger buffer so that there are at least n +// bytes of capacity beyond len(b.buf). +func (b *Builder) grow(n int) { + buf := make([]byte, len(b.buf), 2*cap(b.buf)+n) + copy(buf, b.buf) + b.buf = buf +} + +// Grow grows b's capacity, if necessary, to guarantee space for +// another n bytes. After Grow(n), at least n bytes can be written to b +// without another allocation. If n is negative, Grow panics. +func (b *Builder) Grow(n int) { + if n < 0 { + panic("strings.Builder.Grow: negative count") + } + if cap(b.buf)-len(b.buf) < n { + b.grow(n) + } +} + +// Write appends the contents of p to b's buffer. +// Write always returns len(p), nil. +func (b *Builder) Write(p []byte) (int, error) { + b.buf = append(b.buf, p...) + return len(p), nil +} + +// WriteByte appends the byte c to b's buffer. +// The returned error is always nil. +func (b *Builder) WriteByte(c byte) error { + b.buf = append(b.buf, c) + return nil +} + +// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer. +// It returns the length of r and a nil error. +func (b *Builder) WriteRune(r rune) (int, error) { + if r < utf8.RuneSelf { + b.buf = append(b.buf, byte(r)) + return 1, nil + } + l := len(b.buf) + if cap(b.buf)-l < utf8.UTFMax { + b.grow(utf8.UTFMax) + } + n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r) + b.buf = b.buf[:l+n] + return n, nil +} + +// WriteString appends the contents of s to b's buffer. +// It returns the length of s and a nil error. +func (b *Builder) WriteString(s string) (int, error) { + b.buf = append(b.buf, s...) + return len(s), nil +} + +// minRead is the minimum slice passed to a Read call by Builder.ReadFrom. +// It is the same as bytes.MinRead. +const minRead = 512 + +// errNegativeRead is the panic value if the reader passed to Builder.ReadFrom +// returns a negative count. +var errNegativeRead = errors.New("strings.Builder: reader returned negative count from Read") + +// ReadFrom reads data from r until EOF and appends it to b's buffer. +// The return value n is the number of bytes read. +// Any error except io.EOF encountered during the read is also returned. +func (b *Builder) ReadFrom(r io.Reader) (n int64, err error) { + for { + l := len(b.buf) + if cap(b.buf)-l < minRead { + b.grow(minRead) + } + m, e := r.Read(b.buf[l:cap(b.buf)]) + if m < 0 { + panic(errNegativeRead) + } + b.buf = b.buf[:l+m] + n += int64(m) + if e == io.EOF { + return n, nil + } + if e != nil { + return n, e + } + } +} diff --git a/libgo/go/strings/builder_test.go b/libgo/go/strings/builder_test.go new file mode 100644 index 00000000000..df557082a79 --- /dev/null +++ b/libgo/go/strings/builder_test.go @@ -0,0 +1,282 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +import ( + "bytes" + "errors" + "io" + "runtime" + . "strings" + "testing" + "testing/iotest" +) + +func check(t *testing.T, b *Builder, want string) { + t.Helper() + got := b.String() + if got != want { + t.Errorf("String: got %#q; want %#q", got, want) + return + } + if n := b.Len(); n != len(got) { + t.Errorf("Len: got %d; but len(String()) is %d", n, len(got)) + } +} + +func TestBuilder(t *testing.T) { + var b Builder + check(t, &b, "") + n, err := b.WriteString("hello") + if err != nil || n != 5 { + t.Errorf("WriteString: got %d,%s; want 5,nil", n, err) + } + check(t, &b, "hello") + if err = b.WriteByte(' '); err != nil { + t.Errorf("WriteByte: %s", err) + } + check(t, &b, "hello ") + n, err = b.WriteString("world") + if err != nil || n != 5 { + t.Errorf("WriteString: got %d,%s; want 5,nil", n, err) + } + check(t, &b, "hello world") +} + +func TestBuilderString(t *testing.T) { + var b Builder + b.WriteString("alpha") + check(t, &b, "alpha") + s1 := b.String() + b.WriteString("beta") + check(t, &b, "alphabeta") + s2 := b.String() + b.WriteString("gamma") + check(t, &b, "alphabetagamma") + s3 := b.String() + + // Check that subsequent operations didn't change the returned strings. + if want := "alpha"; s1 != want { + t.Errorf("first String result is now %q; want %q", s1, want) + } + if want := "alphabeta"; s2 != want { + t.Errorf("second String result is now %q; want %q", s2, want) + } + if want := "alphabetagamma"; s3 != want { + t.Errorf("third String result is now %q; want %q", s3, want) + } +} + +func TestBuilderReset(t *testing.T) { + var b Builder + check(t, &b, "") + b.WriteString("aaa") + s := b.String() + check(t, &b, "aaa") + b.Reset() + check(t, &b, "") + + // Ensure that writing after Reset doesn't alter + // previously returned strings. + b.WriteString("bbb") + check(t, &b, "bbb") + if want := "aaa"; s != want { + t.Errorf("previous String result changed after Reset: got %q; want %q", s, want) + } +} + +func TestBuilderGrow(t *testing.T) { + for _, growLen := range []int{0, 100, 1000, 10000, 100000} { + var b Builder + b.Grow(growLen) + p := bytes.Repeat([]byte{'a'}, growLen) + allocs := numAllocs(func() { b.Write(p) }) + if allocs > 0 { + t.Errorf("growLen=%d: allocation occurred during write", growLen) + } + if b.String() != string(p) { + t.Errorf("growLen=%d: bad data written after Grow", growLen) + } + } +} + +func TestBuilderWrite2(t *testing.T) { + const s0 = "hello 世界" + for _, tt := range []struct { + name string + fn func(b *Builder) (int, error) + n int + want string + }{ + { + "Write", + func(b *Builder) (int, error) { return b.Write([]byte(s0)) }, + len(s0), + s0, + }, + { + "WriteRune", + func(b *Builder) (int, error) { return b.WriteRune('a') }, + 1, + "a", + }, + { + "WriteRuneWide", + func(b *Builder) (int, error) { return b.WriteRune('世') }, + 3, + "世", + }, + { + "WriteString", + func(b *Builder) (int, error) { return b.WriteString(s0) }, + len(s0), + s0, + }, + } { + t.Run(tt.name, func(t *testing.T) { + var b Builder + n, err := tt.fn(&b) + if err != nil { + t.Fatalf("first call: got %s", err) + } + if n != tt.n { + t.Errorf("first call: got n=%d; want %d", n, tt.n) + } + check(t, &b, tt.want) + + n, err = tt.fn(&b) + if err != nil { + t.Fatalf("second call: got %s", err) + } + if n != tt.n { + t.Errorf("second call: got n=%d; want %d", n, tt.n) + } + check(t, &b, tt.want+tt.want) + }) + } +} + +func TestBuilderWriteByte(t *testing.T) { + var b Builder + if err := b.WriteByte('a'); err != nil { + t.Error(err) + } + if err := b.WriteByte(0); err != nil { + t.Error(err) + } + check(t, &b, "a\x00") +} + +func TestBuilderReadFrom(t *testing.T) { + for _, tt := range []struct { + name string + fn func(io.Reader) io.Reader + }{ + {"Reader", func(r io.Reader) io.Reader { return r }}, + {"DataErrReader", iotest.DataErrReader}, + {"OneByteReader", iotest.OneByteReader}, + } { + t.Run(tt.name, func(t *testing.T) { + var b Builder + + r := tt.fn(NewReader("hello")) + n, err := b.ReadFrom(r) + if err != nil { + t.Fatalf("first call: got %s", err) + } + if n != 5 { + t.Errorf("first call: got n=%d; want 5", n) + } + check(t, &b, "hello") + + r = tt.fn(NewReader(" world")) + n, err = b.ReadFrom(r) + if err != nil { + t.Fatalf("first call: got %s", err) + } + if n != 6 { + t.Errorf("first call: got n=%d; want 6", n) + } + check(t, &b, "hello world") + }) + } +} + +var errRead = errors.New("boom") + +// errorReader sends reads to the underlying reader +// but returns errRead instead of io.EOF. +type errorReader struct { + r io.Reader +} + +func (r errorReader) Read(b []byte) (int, error) { + n, err := r.r.Read(b) + if err == io.EOF { + err = errRead + } + return n, err +} + +func TestBuilderReadFromError(t *testing.T) { + var b Builder + r := errorReader{NewReader("hello")} + n, err := b.ReadFrom(r) + if n != 5 { + t.Errorf("got n=%d; want 5", n) + } + if err != errRead { + t.Errorf("got err=%q; want %q", err, errRead) + } + check(t, &b, "hello") +} + +type negativeReader struct{} + +func (r negativeReader) Read([]byte) (int, error) { return -1, nil } + +func TestBuilderReadFromNegativeReader(t *testing.T) { + var b Builder + defer func() { + switch err := recover().(type) { + case nil: + t.Fatal("ReadFrom didn't panic") + case error: + wantErr := "strings.Builder: reader returned negative count from Read" + if err.Error() != wantErr { + t.Fatalf("recovered panic: got %v; want %v", err.Error(), wantErr) + } + default: + t.Fatalf("unexpected panic value: %#v", err) + } + }() + + b.ReadFrom(negativeReader{}) +} + +func TestBuilderAllocs(t *testing.T) { + var b Builder + b.Grow(5) + var s string + allocs := numAllocs(func() { + b.WriteString("hello") + s = b.String() + }) + if want := "hello"; s != want { + t.Errorf("String: got %#q; want %#q", s, want) + } + if allocs > 0 { + t.Fatalf("got %d alloc(s); want 0", allocs) + } +} + +func numAllocs(fn func()) uint64 { + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) + var m1, m2 runtime.MemStats + runtime.ReadMemStats(&m1) + fn() + runtime.ReadMemStats(&m2) + return m2.Mallocs - m1.Mallocs +} diff --git a/libgo/go/strings/example_test.go b/libgo/go/strings/example_test.go index e9621522ef2..607e4a0a70e 100644 --- a/libgo/go/strings/example_test.go +++ b/libgo/go/strings/example_test.go @@ -166,6 +166,26 @@ func ExampleLastIndexAny() { // -1 } +func ExampleLastIndexByte() { + fmt.Println(strings.LastIndexByte("Hello, world", 'l')) + fmt.Println(strings.LastIndexByte("Hello, world", 'o')) + fmt.Println(strings.LastIndexByte("Hello, world", 'x')) + // Output: + // 10 + // 8 + // -1 +} + +func ExampleLastIndexFunc() { + fmt.Println(strings.LastIndexFunc("go 123", unicode.IsNumber)) + fmt.Println(strings.LastIndexFunc("123 go", unicode.IsNumber)) + fmt.Println(strings.LastIndexFunc("go", unicode.IsNumber)) + // Output: + // 5 + // 2 + // -1 +} + func ExampleJoin() { s := []string{"foo", "bar", "baz"} fmt.Println(strings.Join(s, ", ")) @@ -229,17 +249,10 @@ func ExampleToTitle() { // ХЛЕБ } -func ExampleTrim() { - fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! ")) - // Output: ["Achtung! Achtung"] -} - -func ExampleTrimFunc() { - f := func(c rune) bool { - return !unicode.IsLetter(c) && !unicode.IsNumber(c) - } - fmt.Printf("[%q]", strings.TrimFunc(" Achtung1! Achtung2,...", f)) - // Output: ["Achtung1! Achtung2"] +func ExampleToTitleSpecial() { + fmt.Println(strings.ToTitleSpecial(unicode.TurkishCase, "dünyanın ilk borsa yapısı Aizonai kabul edilir")) + // Output: + // DÜNYANIN İLK BORSA YAPISI AİZONAİ KABUL EDİLİR } func ExampleMap() { @@ -256,11 +269,6 @@ func ExampleMap() { // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure... } -func ExampleTrimSpace() { - fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n")) - // Output: a lone gopher -} - func ExampleNewReplacer() { r := strings.NewReplacer("<", "<", ">", ">") fmt.Println(r.Replace("This is HTML!")) @@ -272,23 +280,85 @@ func ExampleToUpper() { // Output: GOPHER } +func ExampleToUpperSpecial() { + fmt.Println(strings.ToUpperSpecial(unicode.TurkishCase, "örnek iş")) + // Output: ÖRNEK İŞ +} + func ExampleToLower() { fmt.Println(strings.ToLower("Gopher")) // Output: gopher } -func ExampleTrimSuffix() { - var s = "Hello, goodbye, etc!" - s = strings.TrimSuffix(s, "goodbye, etc!") - s = strings.TrimSuffix(s, "planet") - fmt.Print(s, "world!") - // Output: Hello, world! +func ExampleToLowerSpecial() { + fmt.Println(strings.ToLowerSpecial(unicode.TurkishCase, "Önnek İş")) + // Output: önnek iş +} + +func ExampleTrim() { + fmt.Print(strings.Trim("¡¡¡Hello, Gophers!!!", "!¡")) + // Output: Hello, Gophers +} + +func ExampleTrimSpace() { + fmt.Println(strings.TrimSpace(" \t\n Hello, Gophers \n\t\r\n")) + // Output: Hello, Gophers } func ExampleTrimPrefix() { - var s = "Goodbye,, world!" - s = strings.TrimPrefix(s, "Goodbye,") - s = strings.TrimPrefix(s, "Howdy,") - fmt.Print("Hello" + s) - // Output: Hello, world! + var s = "¡¡¡Hello, Gophers!!!" + s = strings.TrimPrefix(s, "¡¡¡Hello, ") + s = strings.TrimPrefix(s, "¡¡¡Howdy, ") + fmt.Print(s) + // Output: Gophers!!! +} + +func ExampleTrimSuffix() { + var s = "¡¡¡Hello, Gophers!!!" + s = strings.TrimSuffix(s, ", Gophers!!!") + s = strings.TrimSuffix(s, ", Marmots!!!") + fmt.Print(s) + // Output: ¡¡¡Hello +} + +func ExampleTrimFunc() { + fmt.Print(strings.TrimFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool { + return !unicode.IsLetter(r) && !unicode.IsNumber(r) + })) + // Output: Hello, Gophers +} + +func ExampleTrimLeft() { + fmt.Print(strings.TrimLeft("¡¡¡Hello, Gophers!!!", "!¡")) + // Output: Hello, Gophers!!! +} + +func ExampleTrimLeftFunc() { + fmt.Print(strings.TrimLeftFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool { + return !unicode.IsLetter(r) && !unicode.IsNumber(r) + })) + // Output: Hello, Gophers!!! +} + +func ExampleTrimRight() { + fmt.Print(strings.TrimRight("¡¡¡Hello, Gophers!!!", "!¡")) + // Output: ¡¡¡Hello, Gophers +} + +func ExampleTrimRightFunc() { + fmt.Print(strings.TrimRightFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool { + return !unicode.IsLetter(r) && !unicode.IsNumber(r) + })) + // Output: ¡¡¡Hello, Gophers +} + +func ExampleBuilder() { + var b strings.Builder + for i := 3; i >= 1; i-- { + fmt.Fprintf(&b, "%d...", i) + } + b.WriteString("ignition") + fmt.Println(b.String()) + + // Output: 3...2...1...ignition } diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go index 0c836c09d46..02c032046b7 100644 --- a/libgo/go/strings/strings.go +++ b/libgo/go/strings/strings.go @@ -166,22 +166,24 @@ func IndexRune(s string, r rune) int { // IndexAny returns the index of the first instance of any Unicode code point // from chars in s, or -1 if no Unicode code point from chars is present in s. func IndexAny(s, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := 0; i < len(s); i++ { - if as.contains(s[i]) { - return i - } + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i := 0; i < len(s); i++ { + if as.contains(s[i]) { + return i } - return -1 } + return -1 } - for i, c := range s { - for _, m := range chars { - if c == m { - return i - } + } + for i, c := range s { + for _, m := range chars { + if c == m { + return i } } } @@ -192,24 +194,26 @@ func IndexAny(s, chars string) int { // point from chars in s, or -1 if no Unicode code point from chars is // present in s. func LastIndexAny(s, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := len(s) - 1; i >= 0; i-- { - if as.contains(s[i]) { - return i - } + if chars == "" { + // Avoid scanning all of s. + return -1 + } + if len(s) > 8 { + if as, isASCII := makeASCIISet(chars); isASCII { + for i := len(s) - 1; i >= 0; i-- { + if as.contains(s[i]) { + return i } - return -1 } + return -1 } - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRuneInString(s[:i]) - i -= size - for _, c := range chars { - if r == c { - return i - } + } + for i := len(s); i > 0; { + r, size := utf8.DecodeLastRuneInString(s[:i]) + i -= size + for _, c := range chars { + if r == c { + return i } } } @@ -310,8 +314,8 @@ func SplitAfter(s, sep string) []string { var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} // Fields splits the string s around each instance of one or more consecutive white space -// characters, as defined by unicode.IsSpace, returning an array of substrings of s or an -// empty list if s contains only white space. +// characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an +// empty slice if s contains only white space. func Fields(s string) []string { // First count the fields. // This is an exact count if s is ASCII, otherwise it is an approximation. @@ -358,67 +362,7 @@ func Fields(s string) []string { } // Some runes in the input string are not ASCII. - // Same general approach as in the ASCII path but - // uses DecodeRuneInString and unicode.IsSpace if - // a non-ASCII rune needs to be decoded and checked - // if it corresponds to a space. - a := make([]string, 0, n) - fieldStart := 0 - i := 0 - // Skip spaces in the front of the input. - for i < len(s) { - if c := s[i]; c < utf8.RuneSelf { - if asciiSpace[c] == 0 { - break - } - i++ - } else { - r, w := utf8.DecodeRuneInString(s[i:]) - if !unicode.IsSpace(r) { - break - } - i += w - } - } - fieldStart = i - for i < len(s) { - if c := s[i]; c < utf8.RuneSelf { - if asciiSpace[c] == 0 { - i++ - continue - } - a = append(a, s[fieldStart:i]) - i++ - } else { - r, w := utf8.DecodeRuneInString(s[i:]) - if !unicode.IsSpace(r) { - i += w - continue - } - a = append(a, s[fieldStart:i]) - i += w - } - // Skip spaces in between fields. - for i < len(s) { - if c := s[i]; c < utf8.RuneSelf { - if asciiSpace[c] == 0 { - break - } - i++ - } else { - r, w := utf8.DecodeRuneInString(s[i:]) - if !unicode.IsSpace(r) { - break - } - i += w - } - } - fieldStart = i - } - if fieldStart < len(s) { // Last field might end at EOF. - a = append(a, s[fieldStart:]) - } - return a + return FieldsFunc(s, unicode.IsSpace) } // FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c) @@ -427,35 +371,42 @@ func Fields(s string) []string { // FieldsFunc makes no guarantees about the order in which it calls f(c). // If f does not return consistent results for a given c, FieldsFunc may crash. func FieldsFunc(s string, f func(rune) bool) []string { - // First count the fields. - n := 0 - inField := false - for _, rune := range s { - wasInField := inField - inField = !f(rune) - if inField && !wasInField { - n++ - } + // A span is used to record a slice of s of the form s[start:end]. + // The start index is inclusive and the end index is exclusive. + type span struct { + start int + end int } + spans := make([]span, 0, 32) - // Now create them. - a := make([]string, n) - na := 0 - fieldStart := -1 // Set to -1 when looking for start of field. + // Find the field start and end indices. + wasField := false + fromIndex := 0 for i, rune := range s { if f(rune) { - if fieldStart >= 0 { - a[na] = s[fieldStart:i] - na++ - fieldStart = -1 + if wasField { + spans = append(spans, span{start: fromIndex, end: i}) + wasField = false + } + } else { + if !wasField { + fromIndex = i + wasField = true } - } else if fieldStart == -1 { - fieldStart = i } } - if fieldStart >= 0 { // Last field might end at EOF. - a[na] = s[fieldStart:] + + // Last field might end at EOF. + if wasField { + spans = append(spans, span{fromIndex, len(s)}) + } + + // Create strings from recorded field indices. + a := make([]string, len(spans)) + for i, span := range spans { + a[i] = s[span.start:span.end] } + return a } @@ -599,10 +550,62 @@ func Repeat(s string, count int) string { } // ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case. -func ToUpper(s string) string { return Map(unicode.ToUpper, s) } +func ToUpper(s string) string { + isASCII, hasLower := true, false + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf { + isASCII = false + break + } + hasLower = hasLower || (c >= 'a' && c <= 'z') + } + + if isASCII { // optimize for ASCII-only strings. + if !hasLower { + return s + } + b := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if c >= 'a' && c <= 'z' { + c -= 'a' - 'A' + } + b[i] = c + } + return string(b) + } + return Map(unicode.ToUpper, s) +} // ToLower returns a copy of the string s with all Unicode letters mapped to their lower case. -func ToLower(s string) string { return Map(unicode.ToLower, s) } +func ToLower(s string) string { + isASCII, hasUpper := true, false + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf { + isASCII = false + break + } + hasUpper = hasUpper || (c >= 'A' && c <= 'Z') + } + + if isASCII { // optimize for ASCII-only strings. + if !hasUpper { + return s + } + b := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if c >= 'A' && c <= 'Z' { + c += 'a' - 'A' + } + b[i] = c + } + return string(b) + } + return Map(unicode.ToLower, s) +} // ToTitle returns a copy of the string s with all Unicode letters mapped to their title case. func ToTitle(s string) string { return Map(unicode.ToTitle, s) } @@ -923,3 +926,27 @@ func EqualFold(s, t string) bool { // One string is empty. Are both? return s == t } + +func indexRabinKarp(s, substr string) int { + // Rabin-Karp search + hashss, pow := hashStr(substr) + n := len(substr) + var h uint32 + for i := 0; i < n; i++ { + h = h*primeRK + uint32(s[i]) + } + if h == hashss && s[:n] == substr { + return 0 + } + for i := n; i < len(s); { + h *= primeRK + h += uint32(s[i]) + h -= pow * uint32(s[i-n]) + i++ + if h == hashss && s[i-n:i] == substr { + return i - n + } + } + return -1 + +} diff --git a/libgo/go/strings/strings_amd64.go b/libgo/go/strings/strings_amd64.go index 9648912fd5b..24415693271 100644 --- a/libgo/go/strings/strings_amd64.go +++ b/libgo/go/strings/strings_amd64.go @@ -77,25 +77,7 @@ func Index(s, substr string) int { } return -1 } - // Rabin-Karp search - hashss, pow := hashStr(substr) - var h uint32 - for i := 0; i < n; i++ { - h = h*primeRK + uint32(s[i]) - } - if h == hashss && s[:n] == substr { - return 0 - } - for i := n; i < len(s); { - h *= primeRK - h += uint32(s[i]) - h -= pow * uint32(s[i-n]) - i++ - if h == hashss && s[i-n:i] == substr { - return i - n - } - } - return -1 + return indexRabinKarp(s, substr) } // Count counts the number of non-overlapping instances of substr in s. diff --git a/libgo/go/strings/strings_generic.go b/libgo/go/strings/strings_generic.go index 9844201db30..60a6f7866d6 100644 --- a/libgo/go/strings/strings_generic.go +++ b/libgo/go/strings/strings_generic.go @@ -25,22 +25,30 @@ func Index(s, substr string) int { case n > len(s): return -1 } - // Rabin-Karp search - hashss, pow := hashStr(substr) - var h uint32 - for i := 0; i < n; i++ { - h = h*primeRK + uint32(s[i]) - } - if h == hashss && s[:n] == substr { - return 0 - } - for i := n; i < len(s); { - h *= primeRK - h += uint32(s[i]) - h -= pow * uint32(s[i-n]) + c := substr[0] + i := 0 + t := s[:len(s)-n+1] + fails := 0 + for i < len(t) { + if t[i] != c { + o := IndexByte(t[i:], c) + if o < 0 { + return -1 + } + i += o + } + if s[i:i+n] == substr { + return i + } i++ - if h == hashss && s[i-n:i] == substr { - return i - n + fails++ + if fails >= 4+i>>4 && i < len(t) { + // See comment in ../bytes/bytes_generic.go. + j := indexRabinKarp(s[i:], substr) + if j < 0 { + return -1 + } + return i + j } } return -1 diff --git a/libgo/go/strings/strings_s390x.go b/libgo/go/strings/strings_s390x.go index b05fb2b025a..e74e4cd2fef 100644 --- a/libgo/go/strings/strings_s390x.go +++ b/libgo/go/strings/strings_s390x.go @@ -78,25 +78,7 @@ func Index(s, substr string) int { } return -1 } - // Rabin-Karp search - hashss, pow := hashStr(substr) - var h uint32 - for i := 0; i < n; i++ { - h = h*primeRK + uint32(s[i]) - } - if h == hashss && s[:n] == substr { - return 0 - } - for i := n; i < len(s); { - h *= primeRK - h += uint32(s[i]) - h -= pow * uint32(s[i-n]) - i++ - if h == hashss && s[i-n:i] == substr { - return i - n - } - } - return -1 + return indexRabinKarp(s, substr) } // Count counts the number of non-overlapping instances of substr in s. diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index 0fddaf0e4a6..f2399f41b02 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -126,6 +126,9 @@ var indexTests = []IndexTest{ {"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1}, {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1}, {"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65}, + // test fallback to Rabin-Karp. + {"oxoxoxoxoxoxoxoxoxoxoxoy", "oy", 22}, + {"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1}, } var lastIndexTests = []IndexTest{ @@ -522,9 +525,12 @@ func runStringTests(t *testing.T, f func(string) string, funcName string, testCa var upperTests = []StringTest{ {"", ""}, + {"ONLYUPPER", "ONLYUPPER"}, {"abc", "ABC"}, {"AbC123", "ABC123"}, {"azAZ09_", "AZAZ09_"}, + {"longStrinGwitHmixofsmaLLandcAps", "LONGSTRINGWITHMIXOFSMALLANDCAPS"}, + {"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", "LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS"}, {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char } @@ -533,6 +539,8 @@ var lowerTests = []StringTest{ {"abc", "abc"}, {"AbC123", "abc123"}, {"azAZ09_", "azaz09_"}, + {"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"}, + {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"}, {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char } @@ -652,6 +660,32 @@ func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTest func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) } +func BenchmarkToUpper(b *testing.B) { + for _, tc := range upperTests { + b.Run(tc.in, func(b *testing.B) { + for i := 0; i < b.N; i++ { + actual := ToUpper(tc.in) + if actual != tc.out { + b.Errorf("ToUpper(%q) = %q; want %q", tc.in, actual, tc.out) + } + } + }) + } +} + +func BenchmarkToLower(b *testing.B) { + for _, tc := range lowerTests { + b.Run(tc.in, func(b *testing.B) { + for i := 0; i < b.N; i++ { + actual := ToLower(tc.in) + if actual != tc.out { + b.Errorf("ToLower(%q) = %q; want %q", tc.in, actual, tc.out) + } + } + }) + } +} + func BenchmarkMapNoChanges(b *testing.B) { identity := func(r rune) rune { return r @@ -1614,3 +1648,15 @@ func BenchmarkTrimASCII(b *testing.B) { } } } + +func BenchmarkIndexPeriodic(b *testing.B) { + key := "aa" + for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { + b.Run(fmt.Sprintf("IndexPeriodic%d", skip), func(b *testing.B) { + s := Repeat("a"+Repeat(" ", skip-1), 1<<16/skip) + for i := 0; i < b.N; i++ { + Index(s, key) + } + }) + } +} diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go index 17baccb4683..39c40c6aaf5 100644 --- a/libgo/go/sync/atomic/atomic_test.go +++ b/libgo/go/sync/atomic/atomic_test.go @@ -30,7 +30,7 @@ const ( magic64 = 0xdeddeadbeefbeef ) -// Do the 64-bit functions panic? If so, don't bother testing. +// Do the 64-bit functions panic? If so, don't bother testing. var test64err = func() (err interface{}) { defer func() { err = recover() @@ -772,10 +772,8 @@ func init() { if uintptr(v) != 0 { // 64-bit system; clear uintptr tests delete(hammer32, "SwapUintptr") - delete(hammer32, "SwapPointer") delete(hammer32, "AddUintptr") delete(hammer32, "CompareAndSwapUintptr") - delete(hammer32, "CompareAndSwapPointer") } } @@ -923,10 +921,8 @@ func init() { if uintptr(v) == 0 { // 32-bit system; clear uintptr tests delete(hammer64, "SwapUintptr") - delete(hammer64, "SwapPointer") delete(hammer64, "AddUintptr") delete(hammer64, "CompareAndSwapUintptr") - delete(hammer64, "CompareAndSwapPointer") } } diff --git a/libgo/go/sync/atomic/value.go b/libgo/go/sync/atomic/value.go index 1fc1f681f20..eab7e70c9b0 100644 --- a/libgo/go/sync/atomic/value.go +++ b/libgo/go/sync/atomic/value.go @@ -14,8 +14,6 @@ import ( // // A Value must not be copied after first use. type Value struct { - noCopy noCopy - v interface{} } @@ -86,13 +84,3 @@ func (v *Value) Store(x interface{}) { // Disable/enable preemption, implemented in runtime. func runtime_procPin() func runtime_procUnpin() - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://github.com/golang/go/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} diff --git a/libgo/go/sync/cond.go b/libgo/go/sync/cond.go index 14e2f6b24d4..3dcbf1c3512 100644 --- a/libgo/go/sync/cond.go +++ b/libgo/go/sync/cond.go @@ -89,7 +89,7 @@ func (c *copyChecker) check() { // noCopy may be embedded into structs which must not be copied // after the first use. // -// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// See https://golang.org/issues/8005#issuecomment-190753527 // for details. type noCopy struct{} diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go index f266f7c2b97..2fa7c3e07ed 100644 --- a/libgo/go/sync/waitgroup.go +++ b/libgo/go/sync/waitgroup.go @@ -63,13 +63,11 @@ func (wg *WaitGroup) Add(delta int) { state := atomic.AddUint64(statep, uint64(delta)<<32) v := int32(state >> 32) w := uint32(state) - if race.Enabled { - if delta > 0 && v == int32(delta) { - // The first increment must be synchronized with Wait. - // Need to model this as a read, because there can be - // several concurrent wg.counter transitions from 0. - race.Read(unsafe.Pointer(&wg.sema)) - } + if race.Enabled && delta > 0 && v == int32(delta) { + // The first increment must be synchronized with Wait. + // Need to model this as a read, because there can be + // several concurrent wg.counter transitions from 0. + race.Read(unsafe.Pointer(&wg.sema)) } if v < 0 { panic("sync: negative WaitGroup counter") diff --git a/libgo/go/syscall/creds_test.go b/libgo/go/syscall/creds_test.go index 7c6ab1de1de..524689ae2d2 100644 --- a/libgo/go/syscall/creds_test.go +++ b/libgo/go/syscall/creds_test.go @@ -19,101 +19,116 @@ import ( // sockets. The SO_PASSCRED socket option is enabled on the sending // socket for this to work. func TestSCMCredentials(t *testing.T) { - fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) - if err != nil { - t.Fatalf("Socketpair: %v", err) + socketTypeTests := []struct { + socketType int + dataLen int + }{ + { + syscall.SOCK_STREAM, + 1, + }, { + syscall.SOCK_DGRAM, + 0, + }, } - defer syscall.Close(fds[0]) - defer syscall.Close(fds[1]) - err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) - if err != nil { - t.Fatalf("SetsockoptInt: %v", err) - } + for _, tt := range socketTypeTests { + fds, err := syscall.Socketpair(syscall.AF_LOCAL, tt.socketType, 0) + if err != nil { + t.Fatalf("Socketpair: %v", err) + } + defer syscall.Close(fds[0]) + defer syscall.Close(fds[1]) - srvFile := os.NewFile(uintptr(fds[0]), "server") - defer srvFile.Close() - srv, err := net.FileConn(srvFile) - if err != nil { - t.Errorf("FileConn: %v", err) - return - } - defer srv.Close() + err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) + if err != nil { + t.Fatalf("SetsockoptInt: %v", err) + } - cliFile := os.NewFile(uintptr(fds[1]), "client") - defer cliFile.Close() - cli, err := net.FileConn(cliFile) - if err != nil { - t.Errorf("FileConn: %v", err) - return - } - defer cli.Close() + srvFile := os.NewFile(uintptr(fds[0]), "server") + defer srvFile.Close() + srv, err := net.FileConn(srvFile) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer srv.Close() + + cliFile := os.NewFile(uintptr(fds[1]), "client") + defer cliFile.Close() + cli, err := net.FileConn(cliFile) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer cli.Close() + + var ucred syscall.Ucred + if os.Getuid() != 0 { + ucred.Pid = int32(os.Getpid()) + ucred.Uid = 0 + ucred.Gid = 0 + oob := syscall.UnixCredentials(&ucred) + _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) + if op, ok := err.(*net.OpError); ok { + err = op.Err + } + if sys, ok := err.(*os.SyscallError); ok { + err = sys.Err + } + if err != syscall.EPERM { + t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) + } + } - var ucred syscall.Ucred - if os.Getuid() != 0 { ucred.Pid = int32(os.Getpid()) - ucred.Uid = 0 - ucred.Gid = 0 + ucred.Uid = uint32(os.Getuid()) + ucred.Gid = uint32(os.Getgid()) oob := syscall.UnixCredentials(&ucred) - _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) - if op, ok := err.(*net.OpError); ok { - err = op.Err + + // On SOCK_STREAM, this is internally going to send a dummy byte + n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) + if err != nil { + t.Fatalf("WriteMsgUnix: %v", err) } - if sys, ok := err.(*os.SyscallError); ok { - err = sys.Err + if n != 0 { + t.Fatalf("WriteMsgUnix n = %d, want 0", n) } - if err != syscall.EPERM { - t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) + if oobn != len(oob) { + t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) } - } - - ucred.Pid = int32(os.Getpid()) - ucred.Uid = uint32(os.Getuid()) - ucred.Gid = uint32(os.Getgid()) - oob := syscall.UnixCredentials(&ucred) - - // this is going to send a dummy byte - n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) - if err != nil { - t.Fatalf("WriteMsgUnix: %v", err) - } - if n != 0 { - t.Fatalf("WriteMsgUnix n = %d, want 0", n) - } - if oobn != len(oob) { - t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) - } - oob2 := make([]byte, 10*len(oob)) - n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) - if err != nil { - t.Fatalf("ReadMsgUnix: %v", err) - } - if flags != 0 { - t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) - } - if n != 1 { - t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) - } - if oobn2 != oobn { - // without SO_PASSCRED set on the socket, ReadMsgUnix will - // return zero oob bytes - t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) - } - oob2 = oob2[:oobn2] - if !bytes.Equal(oob, oob2) { - t.Fatal("ReadMsgUnix oob bytes don't match") - } + oob2 := make([]byte, 10*len(oob)) + n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) + if err != nil { + t.Fatalf("ReadMsgUnix: %v", err) + } + if flags != 0 { + t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) + } + if n != tt.dataLen { + t.Fatalf("ReadMsgUnix n = %d, want %d", n, tt.dataLen) + } + if oobn2 != oobn { + // without SO_PASSCRED set on the socket, ReadMsgUnix will + // return zero oob bytes + t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) + } + oob2 = oob2[:oobn2] + if !bytes.Equal(oob, oob2) { + t.Fatal("ReadMsgUnix oob bytes don't match") + } - scm, err := syscall.ParseSocketControlMessage(oob2) - if err != nil { - t.Fatalf("ParseSocketControlMessage: %v", err) - } - newUcred, err := syscall.ParseUnixCredentials(&scm[0]) - if err != nil { - t.Fatalf("ParseUnixCredentials: %v", err) - } - if *newUcred != ucred { - t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) + scm, err := syscall.ParseSocketControlMessage(oob2) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + newUcred, err := syscall.ParseUnixCredentials(&scm[0]) + if err != nil { + t.Fatalf("ParseUnixCredentials: %v", err) + } + if *newUcred != ucred { + t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) + } } } diff --git a/libgo/go/syscall/exec_freebsd.go b/libgo/go/syscall/exec_freebsd.go index 4ed32c0614f..1654b4ba2a6 100644 --- a/libgo/go/syscall/exec_freebsd.go +++ b/libgo/go/syscall/exec_freebsd.go @@ -5,21 +5,5 @@ package syscall func forkExecPipe(p []int) error { - err := Pipe2(p, O_CLOEXEC) - if err == nil { - return nil - } - - // FreeBSD 9 fallback. - // TODO: remove this for Go 1.10 per Issue 19072 - 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 + return Pipe2(p, O_CLOEXEC) } diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index 6e2f83e9416..4cc018b4961 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -208,14 +208,6 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att } } - // Enable tracing if requested. - if sys.Ptrace { - err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil) - if err1 != 0 { - goto childerror - } - } - // Session ID if sys.Setsid { err1 = raw_setsid() @@ -406,6 +398,16 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att } } + // Enable tracing if requested. + // Do this right before exec so that we don't unnecessarily trace the runtime + // setting up after the fork. See issue #21428. + if sys.Ptrace { + err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil) + if err1 != 0 { + goto childerror + } + } + // Time to exec. err1 = raw_execve(argv0, &argv[0], &envv[0]) diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go index 114deec5bbe..17df8f445ee 100644 --- a/libgo/go/syscall/exec_linux_test.go +++ b/libgo/go/syscall/exec_linux_test.go @@ -23,6 +23,24 @@ import ( "unsafe" ) +func isDocker() bool { + _, err := os.Stat("/.dockerenv") + return err == nil +} + +func isLXC() bool { + return os.Getenv("container") == "lxc" +} + +func skipInContainer(t *testing.T) { + if isDocker() { + t.Skip("skip this test in Docker container") + } + if isLXC() { + t.Skip("skip this test in LXC container") + } +} + // Check if we are in a chroot by checking if the inode of / is // different from 2 (there is no better test available to non-root on // linux). @@ -35,6 +53,7 @@ func isChrooted(t *testing.T) bool { } func checkUserNS(t *testing.T) { + skipInContainer(t) if _, err := os.Stat("/proc/self/ns/user"); err != nil { if os.IsNotExist(err) { t.Skip("kernel doesn't support user namespaces") @@ -114,7 +133,7 @@ func TestCloneNEWUSERAndRemapRootEnableSetgroups(t *testing.T) { if os.Getuid() != 0 { t.Skip("skipping root only test") } - testNEWUSERRemap(t, 0, 0, false) + testNEWUSERRemap(t, 0, 0, true) } func TestCloneNEWUSERAndRemapNoRootDisableSetgroups(t *testing.T) { @@ -147,6 +166,7 @@ func TestEmptyCredGroupsDisableSetgroups(t *testing.T) { } func TestUnshare(t *testing.T) { + skipInContainer(t) // Make sure we are running as root so we have permissions to use unshare // and create a network namespace. if os.Getuid() != 0 { @@ -293,6 +313,7 @@ func TestUnshareMountNameSpaceHelper(*testing.T) { // Test for Issue 38471: unshare fails because systemd has forced / to be shared func TestUnshareMountNameSpace(t *testing.T) { + skipInContainer(t) // Make sure we are running as root so we have permissions to use unshare // and create a network namespace. if os.Getuid() != 0 { @@ -342,6 +363,7 @@ func TestUnshareMountNameSpace(t *testing.T) { // Test for Issue 20103: unshare fails when chroot is used func TestUnshareMountNameSpaceChroot(t *testing.T) { + skipInContainer(t) // Make sure we are running as root so we have permissions to use unshare // and create a network namespace. if os.Getuid() != 0 { @@ -477,6 +499,7 @@ func TestAmbientCapsHelper(*testing.T) { } func TestAmbientCaps(t *testing.T) { + skipInContainer(t) // Make sure we are running as root so we have permissions to use unshare // and create a network namespace. if os.Getuid() != 0 { diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go index cafce1eff69..91b0e84857d 100644 --- a/libgo/go/syscall/exec_windows.go +++ b/libgo/go/syscall/exec_windows.go @@ -222,6 +222,7 @@ type SysProcAttr struct { HideWindow bool CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess CreationFlags uint32 + Token Token // if set, runs new process in the security context represented by the token } var zeroProcAttr ProcAttr @@ -321,7 +322,11 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle pi := new(ProcessInformation) flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT - err = CreateProcess(argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi) + if sys.Token != 0 { + err = CreateProcessAsUser(sys.Token, argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi) + } else { + err = CreateProcess(argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi) + } if err != nil { return 0, 0, err } diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go index 76941c89b6f..01eb1789ae6 100644 --- a/libgo/go/syscall/libcall_posix.go +++ b/libgo/go/syscall/libcall_posix.go @@ -193,9 +193,6 @@ func FDZero(set *FdSet) { //sysnb Dup2(oldfd int, newfd int) (err error) //dup2(oldfd _C_int, newfd _C_int) _C_int -//sys Exit(code int) -//exit(code _C_int) - //sys Fchdir(fd int) (err error) //fchdir(fd _C_int) _C_int diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go index 93bbc389f4d..d3ff6363ae4 100644 --- a/libgo/go/syscall/socket.go +++ b/libgo/go/syscall/socket.go @@ -79,7 +79,7 @@ type SockaddrUnix struct { func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, error) { name := sa.Name n := len(name) - if n >= len(sa.raw.Path) { + if n > len(sa.raw.Path) { return nil, 0, EINVAL } sa.raw.Family = AF_UNIX @@ -93,6 +93,11 @@ func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, error) { sl += Socklen_t(n) + 1 } sl = sa.raw.adjustAbstract(sl) + // Check again after adjustAbstract adjusts the length. + // This is testing whether the +1 for NUL puts us out of range. + if sl-2 > Socklen_t(len(sa.raw.Path)) { + return nil, 0, EINVAL + } // length is family (uint16), name, NUL. return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), sl, nil @@ -343,8 +348,13 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from } var dummy byte if len(oob) > 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return + } // receive at least one normal byte - if len(p) == 0 { + if sockType != SOCK_DGRAM && len(p) == 0 { iov.Base = &dummy iov.SetLen(1) } @@ -390,8 +400,13 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) } var dummy byte if len(oob) > 0 { + var sockType int + sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) + if err != nil { + return 0, err + } // send at least one normal byte - if len(p) == 0 { + if sockType != SOCK_DGRAM && len(p) == 0 { iov.Base = &dummy iov.SetLen(1) } diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go index 84153835d47..8e785ddfd5d 100644 --- a/libgo/go/syscall/syscall.go +++ b/libgo/go/syscall/syscall.go @@ -86,22 +86,29 @@ var dummy *byte const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy)) +// Unix returns ts as the number of seconds and nanoseconds elapsed since the +// Unix epoch. func (ts *Timespec) Unix() (sec int64, nsec int64) { return int64(ts.Sec), int64(ts.Nsec) } +// Unix returns tv as the number of seconds and nanoseconds elapsed since the +// Unix epoch. func (tv *Timeval) Unix() (sec int64, nsec int64) { return int64(tv.Sec), int64(tv.Usec) * 1000 } +// Nano returns ts as the number of nanoseconds elapsed since the Unix epoch. func (ts *Timespec) Nano() int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } +// Nano returns tv as the number of nanoseconds elapsed since the Unix epoch. func (tv *Timeval) Nano() int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 } -// Getpagesize is provided by the runtime. +// Getpagesize and Exit are provided by the runtime. func Getpagesize() int +func Exit(code int) diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go index b1fe78deba4..637aece4395 100644 --- a/libgo/go/syscall/syscall_unix_test.go +++ b/libgo/go/syscall/syscall_unix_test.go @@ -180,6 +180,9 @@ func TestPassFD(t *testing.T) { uc.Close() }) _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) + if err != nil { + t.Fatalf("ReadMsgUnix: %v", err) + } closeUnix.Stop() scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index 84005aa3223..4d569b79712 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -86,7 +86,7 @@ func (b *B) StartTimer() { // want to measure. func (b *B) StopTimer() { if b.timerOn { - b.duration += time.Now().Sub(b.start) + b.duration += time.Since(b.start) runtime.ReadMemStats(&memStats) b.netAllocs += memStats.Mallocs - b.startAllocs b.netBytes += memStats.TotalAlloc - b.startBytes @@ -238,7 +238,7 @@ var labelsOnce sync.Once // run executes the benchmark in a separate goroutine, including all of its // subbenchmarks. b must not have subbenchmarks. -func (b *B) run() BenchmarkResult { +func (b *B) run() { labelsOnce.Do(func() { fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) @@ -253,7 +253,6 @@ func (b *B) run() BenchmarkResult { // Running func Benchmark. b.doBench() } - return b.result } func (b *B) doBench() BenchmarkResult { @@ -427,44 +426,46 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e // processBench runs bench b for the configured CPU counts and prints the results. func (ctx *benchContext) processBench(b *B) { for i, procs := range cpuList { - runtime.GOMAXPROCS(procs) - benchName := benchmarkName(b.name, procs) - fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName) - // Recompute the running time for all but the first iteration. - if i > 0 { - b = &B{ - common: common{ - signal: make(chan bool), - name: b.name, - w: b.w, - chatty: b.chatty, - }, - benchFunc: b.benchFunc, - benchTime: b.benchTime, + for j := uint(0); j < *count; j++ { + runtime.GOMAXPROCS(procs) + benchName := benchmarkName(b.name, procs) + fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName) + // Recompute the running time for all but the first iteration. + if i > 0 || j > 0 { + b = &B{ + common: common{ + signal: make(chan bool), + name: b.name, + w: b.w, + chatty: b.chatty, + }, + benchFunc: b.benchFunc, + benchTime: b.benchTime, + } + b.run1() + } + r := b.doBench() + if b.failed { + // The output could be very long here, but probably isn't. + // We print it all, regardless, because we don't want to trim the reason + // the benchmark failed. + fmt.Fprintf(b.w, "--- FAIL: %s\n%s", benchName, b.output) + continue + } + results := r.String() + if *benchmarkMemory || b.showAllocResult { + results += "\t" + r.MemString() + } + fmt.Fprintln(b.w, results) + // Unlike with tests, we ignore the -chatty flag and always print output for + // benchmarks since the output generation time will skew the results. + if len(b.output) > 0 { + b.trimOutput() + fmt.Fprintf(b.w, "--- BENCH: %s\n%s", benchName, b.output) + } + if p := runtime.GOMAXPROCS(-1); p != procs { + fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) } - b.run1() - } - r := b.doBench() - if b.failed { - // The output could be very long here, but probably isn't. - // We print it all, regardless, because we don't want to trim the reason - // the benchmark failed. - fmt.Fprintf(b.w, "--- FAIL: %s\n%s", benchName, b.output) - continue - } - results := r.String() - if *benchmarkMemory || b.showAllocResult { - results += "\t" + r.MemString() - } - fmt.Fprintln(b.w, results) - // Unlike with tests, we ignore the -chatty flag and always print output for - // benchmarks since the output generation time will skew the results. - if len(b.output) > 0 { - b.trimOutput() - fmt.Fprintf(b.w, "--- BENCH: %s\n%s", benchName, b.output) - } - if p := runtime.GOMAXPROCS(-1); p != procs { - fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) } } } @@ -474,9 +475,6 @@ func (ctx *benchContext) processBench(b *B) { // // A subbenchmark is like any other benchmark. A benchmark that calls Run at // least once will not be measured itself and will be called once with N=1. -// -// Run may be called simultaneously from multiple goroutines, but all such -// calls must return before the outer benchmark function for b returns. func (b *B) Run(name string, f func(b *B)) bool { // Since b has subbenchmarks, we will no longer run it as a benchmark itself. // Release the lock and acquire it on exit to ensure locks stay paired. diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go index e5bce7af4e7..b9955500e66 100644 --- a/libgo/go/testing/example.go +++ b/libgo/go/testing/example.go @@ -87,7 +87,7 @@ func runExample(eg InternalExample) (ok bool) { // Clean up in a deferred call so we can recover if the example panics. defer func() { - dstr := fmtDuration(time.Now().Sub(start)) + dstr := fmtDuration(time.Since(start)) // Close pipe, restore stdout, get output. w.Close() diff --git a/libgo/go/testing/iotest/logger.go b/libgo/go/testing/iotest/logger.go index 0aec15c575e..99548dcfed3 100644 --- a/libgo/go/testing/iotest/logger.go +++ b/libgo/go/testing/iotest/logger.go @@ -47,7 +47,7 @@ func (l *readLogger) Read(p []byte) (n int, err error) { } // NewReadLogger returns a reader that behaves like r except -// that it logs (using log.Print) each read to standard error, +// that it logs (using log.Printf) each read to standard error, // printing the prefix and the hexadecimal data read. func NewReadLogger(prefix string, r io.Reader) io.Reader { return &readLogger{prefix, r} diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index a62974211fb..d049b6cbc68 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -242,6 +242,9 @@ var ( // full test of the package. short = flag.Bool("test.short", false, "run smaller test suite to save time") + // The failfast flag requests that test execution stop after the first test failure. + failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure") + // The directory in which to create profile files and the like. When run from // "go test", the binary always runs in the source directory for the package; // this flag lets "go test" tell the binary to write the files in the directory where @@ -252,7 +255,7 @@ var ( chatty = flag.Bool("test.v", false, "verbose: print additional output") count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times") coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`") - matchList = flag.String("test.list", "", "list tests, examples, and benchmarch maching `regexp` then exit") + matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit") match = flag.String("test.run", "", "run only tests and examples matching `regexp`") memProfile = flag.String("test.memprofile", "", "write a memory profile to `file`") memProfileRate = flag.Int("test.memprofilerate", 0, "set memory profiling `rate` (see runtime.MemProfileRate)") @@ -262,13 +265,15 @@ var ( mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution") mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()") traceFile = flag.String("test.trace", "", "write an execution trace to `file`") - timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (0 means unlimited)") + timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)") cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with") parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel") haveExamples bool // are there examples? cpuList []int + + numFailed uint32 // number of test failures ) // common holds the elements common between T and B and @@ -512,7 +517,8 @@ func (c *common) Failed() bool { return failed || c.raceErrors+race.Errors() > 0 } -// FailNow marks the function as having failed and stops its execution. +// FailNow marks the function as having failed and stops its execution +// by calling runtime.Goexit. // Execution will continue at the next test or benchmark. // FailNow must be called from the goroutine running the // test or benchmark function, not from other goroutines @@ -600,7 +606,8 @@ func (c *common) Skipf(format string, args ...interface{}) { c.SkipNow() } -// SkipNow marks the test as having been skipped and stops its execution. +// SkipNow marks the test as having been skipped and stops its execution +// by calling runtime.Goexit. // If a test fails (see Error, Errorf, Fail) and is then skipped, // it is still considered to have failed. // Execution will continue at the next test or benchmark. See also FailNow. @@ -673,9 +680,30 @@ func (t *T) Parallel() { t.parent.sub = append(t.parent.sub, t) t.raceErrors += race.Errors() + if t.chatty { + // Print directly to root's io.Writer so there is no delay. + root := t.parent + for ; root.parent != nil; root = root.parent { + } + root.mu.Lock() + fmt.Fprintf(root.w, "=== PAUSE %s\n", t.name) + root.mu.Unlock() + } + t.signal <- true // Release calling test. <-t.parent.barrier // Wait for the parent test to complete. t.context.waitParallel() + + if t.chatty { + // Print directly to root's io.Writer so there is no delay. + root := t.parent + for ; root.parent != nil; root = root.parent { + } + root.mu.Lock() + fmt.Fprintf(root.w, "=== CONT %s\n", t.name) + root.mu.Unlock() + } + t.start = time.Now() t.raceErrors += -race.Errors() } @@ -699,7 +727,7 @@ func tRunner(t *T, fn func(t *T)) { t.Errorf("race detected during execution of test") } - t.duration += time.Now().Sub(t.start) + t.duration += time.Since(t.start) // If the test panicked, print any test output before dying. err := recover() if !t.finished && err == nil { @@ -744,6 +772,10 @@ func tRunner(t *T, fn func(t *T)) { t.start = time.Now() t.raceErrors = -race.Errors() fn(t) + + if t.failed { + atomic.AddUint32(&numFailed, 1) + } t.finished = true } @@ -756,7 +788,7 @@ func tRunner(t *T, fn func(t *T)) { func (t *T) Run(name string, f func(t *T)) bool { atomic.StoreInt32(&t.hasSub, 1) testName, ok, _ := t.context.match.fullName(&t.common, name) - if !ok { + if !ok || shouldFailFast() { return true } t = &T{ @@ -874,6 +906,9 @@ type M struct { tests []InternalTest benchmarks []InternalBenchmark examples []InternalExample + + timer *time.Timer + afterOnce sync.Once } // testDeps is an internal interface of functionality that is @@ -908,6 +943,12 @@ func (m *M) Run() int { flag.Parse() } + if *parallel < 1 { + fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer") + flag.Usage() + return 2 + } + if len(*matchList) != 0 { listTests(m.deps.MatchString, m.tests, m.benchmarks, m.examples) return 0 @@ -916,22 +957,21 @@ func (m *M) Run() int { parseCpuList() m.before() - startAlarm() + defer m.after() + m.startAlarm() haveExamples = len(m.examples) > 0 testRan, testOk := runTests(m.deps.MatchString, m.tests) exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples) - stopAlarm() + m.stopAlarm() if !testRan && !exampleRan && *matchBenchmarks == "" { fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") } if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 { fmt.Println("FAIL") - m.after() return 1 } fmt.Println("PASS") - m.after() return 0 } @@ -989,27 +1029,32 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT ok = true for _, procs := range cpuList { runtime.GOMAXPROCS(procs) - ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run")) - t := &T{ - common: common{ - signal: make(chan bool), - barrier: make(chan bool), - w: os.Stdout, - chatty: *chatty, - }, - context: ctx, - } - tRunner(t, func(t *T) { - for _, test := range tests { - t.Run(test.Name, test.F) + for i := uint(0); i < *count; i++ { + if shouldFailFast() { + break } - // Run catching the signal rather than the tRunner as a separate - // goroutine to avoid adding a goroutine during the sequential - // phase as this pollutes the stacktrace output when aborting. - go func() { <-t.signal }() - }) - ok = ok && !t.Failed() - ran = ran || t.ran + ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run")) + t := &T{ + common: common{ + signal: make(chan bool), + barrier: make(chan bool), + w: os.Stdout, + chatty: *chatty, + }, + context: ctx, + } + tRunner(t, func(t *T) { + for _, test := range tests { + t.Run(test.Name, test.F) + } + // Run catching the signal rather than the tRunner as a separate + // goroutine to avoid adding a goroutine during the sequential + // phase as this pollutes the stacktrace output when aborting. + go func() { <-t.signal }() + }) + ok = ok && !t.Failed() + ran = ran || t.ran + } } return ran, ok } @@ -1059,6 +1104,12 @@ func (m *M) before() { // after runs after all testing. func (m *M) after() { + m.afterOnce.Do(func() { + m.writeProfiles() + }) +} + +func (m *M) writeProfiles() { if *cpuProfile != "" { m.deps.StopCPUProfile() // flushes profile to disk } @@ -1135,12 +1186,11 @@ func toOutputDir(path string) string { return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path) } -var timer *time.Timer - // startAlarm starts an alarm if requested. -func startAlarm() { +func (m *M) startAlarm() { if *timeout > 0 { - timer = time.AfterFunc(*timeout, func() { + m.timer = time.AfterFunc(*timeout, func() { + m.after() debug.SetTraceback("all") panic(fmt.Sprintf("test timed out after %v", *timeout)) }) @@ -1148,9 +1198,9 @@ func startAlarm() { } // stopAlarm turns off the alarm. -func stopAlarm() { +func (m *M) stopAlarm() { if *timeout > 0 { - timer.Stop() + m.timer.Stop() } } @@ -1165,13 +1215,13 @@ func parseCpuList() { fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val) os.Exit(1) } - for i := uint(0); i < *count; i++ { - cpuList = append(cpuList, cpu) - } + cpuList = append(cpuList, cpu) } if cpuList == nil { - for i := uint(0); i < *count; i++ { - cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) - } + cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) } } + +func shouldFailFast() bool { + return *failFast && atomic.LoadUint32(&numFailed) > 0 +} diff --git a/libgo/go/text/tabwriter/tabwriter.go b/libgo/go/text/tabwriter/tabwriter.go index 752c9b8e9fb..ae6c7a29493 100644 --- a/libgo/go/text/tabwriter/tabwriter.go +++ b/libgo/go/text/tabwriter/tabwriter.go @@ -333,52 +333,52 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int) { for this := line0; this < line1; this++ { line := b.lines[this] - if column < len(line)-1 { - // cell exists in this column => this line - // has more cells than the previous line - // (the last cell per line is ignored because cells are - // tab-terminated; the last cell per line describes the - // text before the newline/formfeed and does not belong - // to a column) - - // print unprinted lines until beginning of block - pos = b.writeLines(pos, line0, this) - line0 = this - - // column block begin - width := b.minwidth // minimal column width - discardable := true // true if all cells in this column are empty and "soft" - for ; this < line1; this++ { - line = b.lines[this] - if column < len(line)-1 { - // cell exists in this column - c := line[column] - // update width - if w := c.width + b.padding; w > width { - width = w - } - // update discardable - if c.width > 0 || c.htab { - discardable = false - } - } else { - break - } + if column >= len(line)-1 { + continue + } + // cell exists in this column => this line + // has more cells than the previous line + // (the last cell per line is ignored because cells are + // tab-terminated; the last cell per line describes the + // text before the newline/formfeed and does not belong + // to a column) + + // print unprinted lines until beginning of block + pos = b.writeLines(pos, line0, this) + line0 = this + + // column block begin + width := b.minwidth // minimal column width + discardable := true // true if all cells in this column are empty and "soft" + for ; this < line1; this++ { + line = b.lines[this] + if column >= len(line)-1 { + break } - // column block end - - // discard empty columns if necessary - if discardable && b.flags&DiscardEmptyColumns != 0 { - width = 0 + // cell exists in this column + c := line[column] + // update width + if w := c.width + b.padding; w > width { + width = w + } + // update discardable + if c.width > 0 || c.htab { + discardable = false } + } + // column block end - // format and print all columns to the right of this column - // (we know the widths of this column and all columns to the left) - b.widths = append(b.widths, width) // push width - pos = b.format(pos, line0, this) - b.widths = b.widths[0 : len(b.widths)-1] // pop width - line0 = this + // discard empty columns if necessary + if discardable && b.flags&DiscardEmptyColumns != 0 { + width = 0 } + + // format and print all columns to the right of this column + // (we know the widths of this column and all columns to the left) + b.widths = append(b.widths, width) // push width + pos = b.format(pos, line0, this) + b.widths = b.widths[0 : len(b.widths)-1] // pop width + line0 = this } // print unprinted lines until end diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go index d174ebd9cfe..f7609293cea 100644 --- a/libgo/go/text/template/doc.go +++ b/libgo/go/text/template/doc.go @@ -110,6 +110,12 @@ data, defined in detail in the corresponding sections that follow. T0 is executed; otherwise, dot is set to the successive elements of the array, slice, or map and T1 is executed. + {{break}} + Break out of the surrounding range loop. + + {{continue}} + Begin the next iteration of the surrounding range loop. + {{template "name"}} The template with the specified name is executed with nil data. diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index 29eb68fba75..90810090e29 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -27,11 +27,12 @@ const maxExecDepth = 1000 // template so that multiple executions of the same template // can execute in parallel. type state struct { - tmpl *Template - wr io.Writer - node parse.Node // current node, for errors - vars []variable // push-down stack of variable values. - depth int // the height of the stack of executing templates. + tmpl *Template + wr io.Writer + node parse.Node // current node, for errors. + vars []variable // push-down stack of variable values. + depth int // the height of the stack of executing templates. + rangeDepth int // nesting level of range loops. } // variable holds the dynamic value of a variable such as $, $x etc. @@ -81,10 +82,7 @@ func (s *state) at(node parse.Node) { // doublePercent returns the string with %'s replaced by %%, if necessary, // so it can be used safely inside a Printf format string. func doublePercent(str string) string { - if strings.Contains(str, "%") { - str = strings.Replace(str, "%", "%%", -1) - } - return str + return strings.Replace(str, "%", "%%", -1) } // TODO: It would be nice if ExecError was more broken down, but @@ -225,9 +223,17 @@ func (t *Template) DefinedTemplates() string { return s } +type rangeControl int8 + +const ( + rangeNone rangeControl = iota // no action. + rangeBreak // break out of range. + rangeContinue // continues next range iteration. +) + // Walk functions step through the major pieces of the template structure, // generating output as they go. -func (s *state) walk(dot reflect.Value, node parse.Node) { +func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl { s.at(node) switch node := node.(type) { case *parse.ActionNode: @@ -238,13 +244,15 @@ func (s *state) walk(dot reflect.Value, node parse.Node) { s.printValue(node, val) } case *parse.IfNode: - s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + return s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) case *parse.ListNode: for _, node := range node.Nodes { - s.walk(dot, node) + if c := s.walk(dot, node); c != rangeNone { + return c + } } case *parse.RangeNode: - s.walkRange(dot, node) + return s.walkRange(dot, node) case *parse.TemplateNode: s.walkTemplate(dot, node) case *parse.TextNode: @@ -252,15 +260,26 @@ func (s *state) walk(dot reflect.Value, node parse.Node) { s.writeError(err) } case *parse.WithNode: - s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) + return s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) + case *parse.BreakNode: + if s.rangeDepth == 0 { + s.errorf("invalid break outside of range") + } + return rangeBreak + case *parse.ContinueNode: + if s.rangeDepth == 0 { + s.errorf("invalid continue outside of range") + } + return rangeContinue default: s.errorf("unknown node: %s", node) } + return rangeNone } // walkIfOrWith walks an 'if' or 'with' node. The two control structures // are identical in behavior except that 'with' sets dot. -func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { +func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) rangeControl { defer s.pop(s.mark()) val := s.evalPipeline(dot, pipe) truth, ok := isTrue(val) @@ -269,13 +288,14 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse. } if truth { if typ == parse.NodeWith { - s.walk(val, list) + return s.walk(val, list) } else { - s.walk(dot, list) + return s.walk(dot, list) } } else if elseList != nil { - s.walk(dot, elseList) + return s.walk(dot, elseList) } + return rangeNone } // IsTrue reports whether the value is 'true', in the sense of not the zero of its type, @@ -313,13 +333,14 @@ func isTrue(val reflect.Value) (truth, ok bool) { return truth, true } -func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { +func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl { s.at(r) defer s.pop(s.mark()) val, _ := indirect(s.evalPipeline(dot, r.Pipe)) // mark top of stack before any variables in the body are pushed. mark := s.mark() - oneIteration := func(index, elem reflect.Value) { + s.rangeDepth++ + oneIteration := func(index, elem reflect.Value) rangeControl { // Set top var (lexically the second if there are two) to the element. if len(r.Pipe.Decl) > 0 { s.setVar(1, elem) @@ -328,8 +349,9 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { if len(r.Pipe.Decl) > 1 { s.setVar(2, index) } - s.walk(elem, r.List) + ctrl := s.walk(elem, r.List) s.pop(mark) + return ctrl } switch val.Kind() { case reflect.Array, reflect.Slice: @@ -337,17 +359,23 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { break } for i := 0; i < val.Len(); i++ { - oneIteration(reflect.ValueOf(i), val.Index(i)) + if ctrl := oneIteration(reflect.ValueOf(i), val.Index(i)); ctrl == rangeBreak { + break + } } - return + s.rangeDepth-- + return rangeNone case reflect.Map: if val.Len() == 0 { break } for _, key := range sortKeys(val.MapKeys()) { - oneIteration(key, val.MapIndex(key)) + if ctrl := oneIteration(key, val.MapIndex(key)); ctrl == rangeBreak { + break + } } - return + s.rangeDepth-- + return rangeNone case reflect.Chan: if val.IsNil() { break @@ -358,20 +386,25 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { if !ok { break } - oneIteration(reflect.ValueOf(i), elem) + if ctrl := oneIteration(reflect.ValueOf(i), elem); ctrl == rangeBreak { + break + } } if i == 0 { break } - return + s.rangeDepth-- + return rangeNone case reflect.Invalid: break // An invalid value is likely a nil map, etc. and acts like an empty map. default: s.errorf("range can't iterate over %v", val) } + s.rangeDepth-- if r.ElseList != nil { - s.walk(dot, r.ElseList) + return s.walk(dot, r.ElseList) } + return rangeNone } func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { @@ -932,29 +965,6 @@ func printableValue(v reflect.Value) (interface{}, bool) { return v.Interface(), true } -// Types to help sort the keys in a map for reproducible output. - -type rvs []reflect.Value - -func (x rvs) Len() int { return len(x) } -func (x rvs) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -type rvInts struct{ rvs } - -func (x rvInts) Less(i, j int) bool { return x.rvs[i].Int() < x.rvs[j].Int() } - -type rvUints struct{ rvs } - -func (x rvUints) Less(i, j int) bool { return x.rvs[i].Uint() < x.rvs[j].Uint() } - -type rvFloats struct{ rvs } - -func (x rvFloats) Less(i, j int) bool { return x.rvs[i].Float() < x.rvs[j].Float() } - -type rvStrings struct{ rvs } - -func (x rvStrings) Less(i, j int) bool { return x.rvs[i].String() < x.rvs[j].String() } - // sortKeys sorts (if it can) the slice of reflect.Values, which is a slice of map keys. func sortKeys(v []reflect.Value) []reflect.Value { if len(v) <= 1 { @@ -962,13 +972,21 @@ func sortKeys(v []reflect.Value) []reflect.Value { } switch v[0].Kind() { case reflect.Float32, reflect.Float64: - sort.Sort(rvFloats{v}) + sort.Slice(v, func(i, j int) bool { + return v[i].Float() < v[j].Float() + }) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - sort.Sort(rvInts{v}) + sort.Slice(v, func(i, j int) bool { + return v[i].Int() < v[j].Int() + }) case reflect.String: - sort.Sort(rvStrings{v}) + sort.Slice(v, func(i, j int) bool { + return v[i].String() < v[j].String() + }) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - sort.Sort(rvUints{v}) + sort.Slice(v, func(i, j int) bool { + return v[i].Uint() < v[j].Uint() + }) } return v } diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go index 9f7e637c190..79b504f8a4d 100644 --- a/libgo/go/text/template/exec_test.go +++ b/libgo/go/text/template/exec_test.go @@ -44,6 +44,12 @@ type T struct { MSIEmpty map[string]int MXI map[interface{}]int MII map[int]int + MI32S map[int32]string + MI64S map[int64]string + MUI32S map[uint32]string + MUI64S map[uint64]string + MI8S map[int8]string + MUI8S map[uint8]string SMSI []map[string]int // Empty interfaces; used to see if we can dig inside one. Empty0 interface{} // nil @@ -124,6 +130,12 @@ var tVal = &T{ MSIone: map[string]int{"one": 1}, MXI: map[interface{}]int{"one": 1}, MII: map[int]int{1: 1}, + MI32S: map[int32]string{1: "one", 2: "two"}, + MI64S: map[int64]string{2: "i642", 3: "i643"}, + MUI32S: map[uint32]string{2: "u322", 3: "u323"}, + MUI64S: map[uint64]string{2: "ui642", 3: "ui643"}, + MI8S: map[int8]string{2: "i82", 3: "i83"}, + MUI8S: map[uint8]string{2: "u82", 3: "u83"}, SMSI: []map[string]int{ {"one": 1, "two": 2}, {"eleven": 11, "twelve": 12}, @@ -448,6 +460,11 @@ var execTests = []execTest{ {"map[WRONG]", "{{index .MSI 10}}", "", tVal, false}, {"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true}, {"nil[1]", "{{index nil 1}}", "", tVal, false}, + {"map MI64S", "{{index .MI64S 2}}", "i642", tVal, true}, + {"map MI32S", "{{index .MI32S 2}}", "two", tVal, true}, + {"map MUI64S", "{{index .MUI64S 3}}", "ui643", tVal, true}, + {"map MI8S", "{{index .MI8S 3}}", "i83", tVal, true}, + {"map MUI8S", "{{index .MUI8S 2}}", "u82", tVal, true}, // Len. {"slice", "{{len .SI}}", "3", tVal, true}, @@ -496,6 +513,10 @@ var execTests = []execTest{ {"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true}, {"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true}, {"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true}, + {"range quick break", `{{range .SI}}{{break}}{{.}}{{end}}`, "", tVal, true}, + {"range break after two", `{{range $i, $x := .SI}}{{if ge $i 2}}{{break}}{{end}}{{.}}{{end}}`, "34", tVal, true}, + {"range continue", `{{range .SI}}{{continue}}{{.}}{{end}}`, "", tVal, true}, + {"range continue condition", `{{range .SI}}{{if eq . 3 }}{{continue}}{{end}}{{.}}{{end}}`, "45", tVal, true}, // Cute examples. {"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true}, diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go index 91074310374..abddfa1141b 100644 --- a/libgo/go/text/template/funcs.go +++ b/libgo/go/text/template/funcs.go @@ -139,10 +139,24 @@ func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error } value = reflect.Zero(argType) } - if !value.Type().AssignableTo(argType) { - return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType) + if value.Type().AssignableTo(argType) { + return value, nil } - return value, nil + if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) { + value = value.Convert(argType) + return value, nil + } + return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType) +} + +func intLike(typ reflect.Kind) bool { + switch typ { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return true + } + return false } // Indexing. diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go index 5d8c08f06f1..5769470ff90 100644 --- a/libgo/go/text/template/multi_test.go +++ b/libgo/go/text/template/multi_test.go @@ -247,6 +247,9 @@ func TestAddParseTree(t *testing.T) { t.Fatal(err) } added, err := root.AddParseTree("c", tree["c"]) + if err != nil { + t.Fatal(err) + } // Execute. var b bytes.Buffer err = added.ExecuteTemplate(&b, "a", 0) diff --git a/libgo/go/text/template/parse/lex.go b/libgo/go/text/template/parse/lex.go index 6fbf36d7a4a..da766cc7c32 100644 --- a/libgo/go/text/template/parse/lex.go +++ b/libgo/go/text/template/parse/lex.go @@ -60,6 +60,8 @@ const ( // Keywords appear after all the rest. itemKeyword // used only to delimit the keywords itemBlock // block keyword + itemBreak // break keyword + itemContinue // continue keyword itemDot // the cursor, spelled '.' itemDefine // define keyword itemElse // else keyword @@ -74,6 +76,8 @@ const ( var key = map[string]itemType{ ".": itemDot, "block": itemBlock, + "break": itemBreak, + "continue": itemContinue, "define": itemDefine, "else": itemElse, "end": itemEnd, @@ -110,11 +114,9 @@ type lexer struct { input string // the string being scanned leftDelim string // start of action rightDelim string // end of action - state stateFn // the next lexing function to enter pos Pos // current position in the input start Pos // start position of this item width Pos // width of last rune read from input - lastPos Pos // position of most recent item returned by nextItem items chan item // channel of scanned items parenDepth int // nesting depth of ( ) exprs line int // 1+number of newlines seen @@ -164,6 +166,7 @@ func (l *lexer) emit(t itemType) { // ignore skips over the pending input before this point. func (l *lexer) ignore() { + l.line += strings.Count(l.input[l.start:l.pos], "\n") l.start = l.pos } @@ -193,9 +196,7 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn { // nextItem returns the next item from the input. // Called by the parser, not in the lexing goroutine. func (l *lexer) nextItem() item { - item := <-l.items - l.lastPos = item.pos - return item + return <-l.items } // drain drains the output so the lexing goroutine will exit. @@ -227,8 +228,8 @@ func lex(name, input, left, right string) *lexer { // run runs the state machine for the lexer. func (l *lexer) run() { - for l.state = lexText; l.state != nil; { - l.state = l.state(l) + for state := lexText; state != nil; { + state = state(l) } close(l.items) } @@ -281,10 +282,9 @@ func (l *lexer) atRightDelim() (delim, trimSpaces bool) { return true, false } // The right delim might have the marker before. - if strings.HasPrefix(l.input[l.pos:], rightTrimMarker) { - if strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { - return true, true - } + if strings.HasPrefix(l.input[l.pos:], rightTrimMarker) && + strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { + return true, true } return false, false } diff --git a/libgo/go/text/template/parse/lex_test.go b/libgo/go/text/template/parse/lex_test.go index 2c73bb623ae..ca7c3f64bc7 100644 --- a/libgo/go/text/template/parse/lex_test.go +++ b/libgo/go/text/template/parse/lex_test.go @@ -192,7 +192,7 @@ var lexTests = []lexTest{ tRight, tEOF, }}, - {"keywords", "{{range if else end with}}", []item{ + {"keywords", "{{range if else end with break continue}}", []item{ tLeft, mkItem(itemRange, "range"), tSpace, @@ -203,6 +203,10 @@ var lexTests = []lexTest{ mkItem(itemEnd, "end"), tSpace, mkItem(itemWith, "with"), + tSpace, + mkItem(itemBreak, "break"), + tSpace, + mkItem(itemContinue, "continue"), tRight, tEOF, }}, @@ -404,6 +408,9 @@ func equal(i1, i2 []item, checkPos bool) bool { if checkPos && i1[k].pos != i2[k].pos { return false } + if checkPos && i1[k].line != i2[k].line { + return false + } } return true } @@ -452,7 +459,7 @@ func TestDelims(t *testing.T) { } var lexPosTests = []lexTest{ - {"empty", "", []item{tEOF}}, + {"empty", "", []item{{itemEOF, 0, "", 1}}}, {"punctuation", "{{,@%#}}", []item{ {itemLeftDelim, 0, "{{", 1}, {itemChar, 2, ",", 1}, @@ -470,6 +477,24 @@ var lexPosTests = []lexTest{ {itemText, 13, "xyz", 1}, {itemEOF, 16, "", 1}, }}, + {"trimafter", "{{x -}}\n{{y}}", []item{ + {itemLeftDelim, 0, "{{", 1}, + {itemIdentifier, 2, "x", 1}, + {itemRightDelim, 5, "}}", 1}, + {itemLeftDelim, 8, "{{", 2}, + {itemIdentifier, 10, "y", 2}, + {itemRightDelim, 11, "}}", 2}, + {itemEOF, 13, "", 2}, + }}, + {"trimbefore", "{{x}}\n{{- y}}", []item{ + {itemLeftDelim, 0, "{{", 1}, + {itemIdentifier, 2, "x", 1}, + {itemRightDelim, 3, "}}", 1}, + {itemLeftDelim, 6, "{{", 2}, + {itemIdentifier, 10, "y", 2}, + {itemRightDelim, 11, "}}", 2}, + {itemEOF, 13, "", 2}, + }}, } // The other tests don't check position, to make the test cases easier to construct. @@ -485,7 +510,8 @@ func TestPos(t *testing.T) { if !equal(items[i:i+1], test.items[i:i+1], true) { i1 := items[i] i2 := test.items[i] - t.Errorf("\t#%d: got {%v %d %q} expected {%v %d %q}", i, i1.typ, i1.pos, i1.val, i2.typ, i2.pos, i2.val) + t.Errorf("\t#%d: got {%v %d %q %d} expected {%v %d %q %d}", + i, i1.typ, i1.pos, i1.val, i1.line, i2.typ, i2.pos, i2.val, i2.line) } } } diff --git a/libgo/go/text/template/parse/node.go b/libgo/go/text/template/parse/node.go index 55ff46c17ab..7e16349b31e 100644 --- a/libgo/go/text/template/parse/node.go +++ b/libgo/go/text/template/parse/node.go @@ -69,6 +69,8 @@ const ( NodeTemplate // A template invocation action. NodeVariable // A $ variable. NodeWith // A with action. + NodeBreak // A break action. + NodeContinue // A continue action. ) // Nodes. @@ -796,6 +798,68 @@ func (r *RangeNode) Copy() Node { return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList()) } +// BreakNode represents a {{break}} action. +type BreakNode struct { + NodeType + Pos + tr *Tree +} + +func (t *Tree) newBreak(pos Pos) *BreakNode { + return &BreakNode{NodeType: NodeBreak, Pos: pos, tr: t} +} + +func (b *BreakNode) Type() NodeType { + return b.NodeType +} + +func (b *BreakNode) String() string { + return "{{break}}" +} + +func (b *BreakNode) Copy() Node { + return b.tr.newBreak(b.Pos) +} + +func (b *BreakNode) Position() Pos { + return b.Pos +} + +func (b *BreakNode) tree() *Tree { + return b.tr +} + +// ContinueNode represents a {{continue}} action. +type ContinueNode struct { + NodeType + Pos + tr *Tree +} + +func (t *Tree) newContinue(pos Pos) *ContinueNode { + return &ContinueNode{NodeType: NodeContinue, Pos: pos, tr: t} +} + +func (c *ContinueNode) Type() NodeType { + return c.NodeType +} + +func (c *ContinueNode) String() string { + return "{{continue}}" +} + +func (c *ContinueNode) Copy() Node { + return c.tr.newContinue(c.Pos) +} + +func (c *ContinueNode) Position() Pos { + return c.Pos +} + +func (c *ContinueNode) tree() *Tree { + return c.tr +} + // WithNode represents a {{with}} action and its commands. type WithNode struct { BranchNode diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go index a91a544ce01..ad9c0519789 100644 --- a/libgo/go/text/template/parse/parse.go +++ b/libgo/go/text/template/parse/parse.go @@ -23,12 +23,13 @@ type Tree struct { Root *ListNode // top-level root of the tree. text string // text parsed to create the template (or its parent) // Parsing only; cleared after parse. - funcs []map[string]interface{} - lex *lexer - token [3]item // three-token lookahead for parser. - peekCount int - vars []string // variables defined at the moment. - treeSet map[string]*Tree + funcs []map[string]interface{} + lex *lexer + token [3]item // three-token lookahead for parser. + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree + rangeDepth int // nesting level of range loops. } // Copy returns a copy of the Tree. Any parsing state is discarded. @@ -219,6 +220,7 @@ func (t *Tree) stopParse() { t.vars = nil t.funcs = nil t.treeSet = nil + t.rangeDepth = 0 } // Parse parses the template definition string to construct a representation of @@ -373,6 +375,10 @@ func (t *Tree) action() (n Node) { return t.templateControl() case itemWith: return t.withControl() + case itemBreak: + return t.breakControl() + case itemContinue: + return t.continueControl() } t.backup() token := t.peek() @@ -453,7 +459,13 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int defer t.popVars(len(t.vars)) pipe = t.pipeline(context) var next Node + if context == "range" { + t.rangeDepth++ + } list, next = t.itemList() + if context == "range" { + t.rangeDepth-- + } switch next.Type() { case nodeEnd: //done case nodeElse: @@ -498,6 +510,26 @@ func (t *Tree) rangeControl() Node { return t.newRange(t.parseControl(false, "range")) } +// Break: +// {{break}} +// Break keyword is past. +func (t *Tree) breakControl() Node { + if t.rangeDepth == 0 { + t.errorf("unexpected break outside of range") + } + return t.newBreak(t.expect(itemRightDelim, "break").pos) +} + +// Continue: +// {{continue}} +// Continue keyword is past. +func (t *Tree) continueControl() Node { + if t.rangeDepth == 0 { + t.errorf("unexpected continue outside of range") + } + return t.newContinue(t.expect(itemRightDelim, "continue").pos) +} + // With: // {{with pipeline}} itemList {{end}} // {{with pipeline}} itemList {{else}} itemList {{end}} diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go index 81f14aca986..aade33ea48e 100644 --- a/libgo/go/text/template/parse/parse_test.go +++ b/libgo/go/text/template/parse/parse_test.go @@ -218,6 +218,12 @@ var parseTests = []parseTest{ `{{range $x := .SI}}{{.}}{{end}}`}, {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError, `{{range $x, $y := .SI}}{{.}}{{end}}`}, + {"range []int with break", "{{range .SI}}{{break}}{{.}}{{end}}", noError, + `{{range .SI}}{{break}}{{.}}{{end}}`}, + {"range []int with break in else", "{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}", noError, + `{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}`}, + {"range []int with continue", "{{range .SI}}{{continue}}{{.}}{{end}}", noError, + `{{range .SI}}{{continue}}{{.}}{{end}}`}, {"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError, `{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`}, {"template", "{{template `x`}}", noError, @@ -288,6 +294,12 @@ var parseTests = []parseTest{ {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""}, // Missing pipeline in block {"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""}, + // Invalid range control + {"break outside of range", `{{break}}`, hasError, ""}, + {"break in range else, outside of range", `{{range .}}{{.}}{{else}}{{break}}{{end}}`, hasError, ""}, + {"continue outside of range", `{{continue}}`, hasError, ""}, + {"continue in range else, outside of range", `{{range .}}{{.}}{{else}}{{continue}}{{end}}`, hasError, ""}, + {"additional break data", `{{range .}}{{break label}}{{end}}`, hasError, ""}, } var builtins = map[string]interface{}{ diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go index aeb63caa552..8c64506027f 100644 --- a/libgo/go/time/example_test.go +++ b/libgo/go/time/example_test.go @@ -18,6 +18,112 @@ func ExampleDuration() { fmt.Printf("The call took %v to run.\n", t1.Sub(t0)) } +func ExampleDuration_Round() { + d, err := time.ParseDuration("1h15m30.918273645s") + if err != nil { + panic(err) + } + + round := []time.Duration{ + time.Nanosecond, + time.Microsecond, + time.Millisecond, + time.Second, + 2 * time.Second, + time.Minute, + 10 * time.Minute, + time.Hour, + } + + for _, r := range round { + fmt.Printf("d.Round(%6s) = %s\n", r, d.Round(r).String()) + } + // Output: + // d.Round( 1ns) = 1h15m30.918273645s + // d.Round( 1µs) = 1h15m30.918274s + // d.Round( 1ms) = 1h15m30.918s + // d.Round( 1s) = 1h15m31s + // d.Round( 2s) = 1h15m30s + // d.Round( 1m0s) = 1h16m0s + // d.Round( 10m0s) = 1h20m0s + // d.Round(1h0m0s) = 1h0m0s +} + +func ExampleDuration_String() { + t1 := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC) + t2 := time.Date(2017, time.February, 16, 0, 0, 0, 0, time.UTC) + fmt.Println(t2.Sub(t1).String()) + // Output: 4440h0m0s +} + +func ExampleDuration_Truncate() { + d, err := time.ParseDuration("1h15m30.918273645s") + if err != nil { + panic(err) + } + + trunc := []time.Duration{ + time.Nanosecond, + time.Microsecond, + time.Millisecond, + time.Second, + 2 * time.Second, + time.Minute, + 10 * time.Minute, + time.Hour, + } + + for _, t := range trunc { + fmt.Printf("t.Truncate(%6s) = %s\n", t, d.Truncate(t).String()) + } + // Output: + // t.Truncate( 1ns) = 1h15m30.918273645s + // t.Truncate( 1µs) = 1h15m30.918273s + // t.Truncate( 1ms) = 1h15m30.918s + // t.Truncate( 1s) = 1h15m30s + // t.Truncate( 2s) = 1h15m30s + // t.Truncate( 1m0s) = 1h15m0s + // t.Truncate( 10m0s) = 1h10m0s + // t.Truncate(1h0m0s) = 1h0m0s +} + +func ExampleParseDuration() { + hours, _ := time.ParseDuration("10h") + complex, _ := time.ParseDuration("1h10m10s") + + fmt.Println(hours) + fmt.Println(complex) + fmt.Printf("there are %.0f seconds in %v\n", complex.Seconds(), complex) + // Output: + // 10h0m0s + // 1h10m10s + // there are 4210 seconds in 1h10m10s +} + +func ExampleDuration_Hours() { + h, _ := time.ParseDuration("4h30m") + fmt.Printf("I've got %.1f hours of work left.", h.Hours()) + // Output: I've got 4.5 hours of work left. +} + +func ExampleDuration_Minutes() { + m, _ := time.ParseDuration("1h30m") + fmt.Printf("The movie is %.0f minutes long.", m.Minutes()) + // Output: The movie is 90 minutes long. +} + +func ExampleDuration_Nanoseconds() { + ns, _ := time.ParseDuration("1000ns") + fmt.Printf("one microsecond has %d nanoseconds.", ns.Nanoseconds()) + // Output: one microsecond has 1000 nanoseconds. +} + +func ExampleDuration_Seconds() { + m, _ := time.ParseDuration("1m30s") + fmt.Printf("take off in t-%.0f seconds.", m.Seconds()) + // Output: take off in t-90 seconds. +} + var c chan int func handle(int) {} @@ -57,6 +163,25 @@ func ExampleDate() { // Output: Go launched at 2009-11-10 15:00:00 -0800 PST } +func ExampleNewTicker() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + done := make(chan bool) + go func() { + time.Sleep(10 * time.Second) + done <- true + }() + for { + select { + case <-done: + fmt.Println("Done!") + return + case t := <-ticker.C: + fmt.Println("Current time: ", t) + } + } +} + func ExampleTime_Format() { // Parse a time value from a string in the standard Unix format. t, err := time.Parse(time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") @@ -113,10 +238,10 @@ func ExampleTime_Format() { // value. do("No pad", "<2>", "<7>") - // An underscore represents a zero pad, if required. + // An underscore represents a space pad, if the date only has one digit. do("Spaces", "<_2>", "< 7>") - // Similarly, a 0 indicates zero padding. + // A "0" indicates zero padding for single-digit values. do("Zeros", "<02>", "<07>") // If the value is already the right width, padding is not used. @@ -175,7 +300,7 @@ func ExampleTime_Format() { } func ExampleParse() { - // See the example for time.Format for a thorough description of how + // See the example for Time.Format for a thorough description of how // to define the layout string to parse a time.Time value; Parse and // Format use the same model to describe their input and output. @@ -192,9 +317,25 @@ func ExampleParse() { t, _ = time.Parse(shortForm, "2013-Feb-03") fmt.Println(t) + // Some valid layouts are invalid time values, due to format specifiers + // such as _ for space padding and Z for zone information. + // For example the RFC3339 layout 2006-01-02T15:04:05Z07:00 + // contains both Z and a time zone offset in order to handle both valid options: + // 2006-01-02T15:04:05Z + // 2006-01-02T15:04:05+07:00 + t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") + fmt.Println(t) + t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00") + fmt.Println(t) + _, err := time.Parse(time.RFC3339, time.RFC3339) + fmt.Println("error", err) // Returns an error as the layout is not a valid time value + // Output: // 2013-02-03 19:54:00 -0800 PST // 2013-02-03 00:00:00 +0000 UTC + // 2006-01-02 15:04:05 +0000 UTC + // 2006-01-02 15:04:05 +0700 +0700 + // error parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00 } func ExampleParseInLocation() { @@ -214,6 +355,24 @@ func ExampleParseInLocation() { // 2012-07-09 00:00:00 +0200 CEST } +func ExampleTime_Unix() { + // 1 billion seconds of Unix, three ways. + fmt.Println(time.Unix(1e9, 0).UTC()) // 1e9 seconds + fmt.Println(time.Unix(0, 1e18).UTC()) // 1e18 nanoseconds + fmt.Println(time.Unix(2e9, -1e18).UTC()) // 2e9 seconds - 1e18 nanoseconds + + t := time.Date(2001, time.September, 9, 1, 46, 40, 0, time.UTC) + fmt.Println(t.Unix()) // seconds since 1970 + fmt.Println(t.UnixNano()) // nanoseconds since 1970 + + // Output: + // 2001-09-09 01:46:40 +0000 UTC + // 2001-09-09 01:46:40 +0000 UTC + // 2001-09-09 01:46:40 +0000 UTC + // 1000000000 + // 1000000000000000000 +} + func ExampleTime_Round() { t := time.Date(0, 0, 0, 12, 15, 30, 918273645, time.UTC) round := []time.Duration{ @@ -269,3 +428,173 @@ func ExampleTime_Truncate() { // t.Truncate( 1m0s) = 12:15:00 // t.Truncate(10m0s) = 12:10:00 } + +func ExampleLocation() { + // China doesn't have daylight saving. It uses a fixed 8 hour offset from UTC. + secondsEastOfUTC := int((8 * time.Hour).Seconds()) + beijing := time.FixedZone("Beijing Time", secondsEastOfUTC) + + // If the system has a timezone database present, it's possible to load a location + // from that, e.g.: + // newYork, err := time.LoadLocation("America/New_York") + + // Creating a time requires a location. Common locations are time.Local and time.UTC. + timeInUTC := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC) + sameTimeInBeijing := time.Date(2009, 1, 1, 20, 0, 0, 0, beijing) + + // Although the UTC clock time is 1200 and the Beijing clock time is 2000, Beijing is + // 8 hours ahead so the two dates actually represent the same instant. + timesAreEqual := timeInUTC.Equal(sameTimeInBeijing) + fmt.Println(timesAreEqual) + + // Output: + // true +} + +func ExampleTime_Add() { + start := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC) + afterTenSeconds := start.Add(time.Second * 10) + afterTenMinutes := start.Add(time.Minute * 10) + afterTenHours := start.Add(time.Hour * 10) + afterTenDays := start.Add(time.Hour * 24 * 10) + + fmt.Printf("start = %v\n", start) + fmt.Printf("start.Add(time.Second * 10) = %v\n", afterTenSeconds) + fmt.Printf("start.Add(time.Minute * 10) = %v\n", afterTenMinutes) + fmt.Printf("start.Add(time.Hour * 10) = %v\n", afterTenHours) + fmt.Printf("start.Add(time.Hour * 24 * 10) = %v\n", afterTenDays) + + // Output: + // start = 2009-01-01 12:00:00 +0000 UTC + // start.Add(time.Second * 10) = 2009-01-01 12:00:10 +0000 UTC + // start.Add(time.Minute * 10) = 2009-01-01 12:10:00 +0000 UTC + // start.Add(time.Hour * 10) = 2009-01-01 22:00:00 +0000 UTC + // start.Add(time.Hour * 24 * 10) = 2009-01-11 12:00:00 +0000 UTC +} + +func ExampleTime_AddDate() { + start := time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC) + oneDayLater := start.AddDate(0, 0, 1) + oneMonthLater := start.AddDate(0, 1, 0) + oneYearLater := start.AddDate(1, 0, 0) + + fmt.Printf("oneDayLater: start.AddDate(0, 0, 1) = %v\n", oneDayLater) + fmt.Printf("oneMonthLater: start.AddDate(0, 1, 0) = %v\n", oneMonthLater) + fmt.Printf("oneYearLater: start.AddDate(1, 0, 0) = %v\n", oneYearLater) + + // Output: + // oneDayLater: start.AddDate(0, 0, 1) = 2009-01-02 00:00:00 +0000 UTC + // oneMonthLater: start.AddDate(0, 1, 0) = 2009-02-01 00:00:00 +0000 UTC + // oneYearLater: start.AddDate(1, 0, 0) = 2010-01-01 00:00:00 +0000 UTC +} + +func ExampleTime_After() { + year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) + year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC) + + isYear3000AfterYear2000 := year3000.After(year2000) // True + isYear2000AfterYear3000 := year2000.After(year3000) // False + + fmt.Printf("year3000.After(year2000) = %v\n", isYear3000AfterYear2000) + fmt.Printf("year2000.After(year3000) = %v\n", isYear2000AfterYear3000) + + // Output: + // year3000.After(year2000) = true + // year2000.After(year3000) = false +} + +func ExampleTime_Before() { + year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) + year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC) + + isYear2000BeforeYear3000 := year2000.Before(year3000) // True + isYear3000BeforeYear2000 := year3000.Before(year2000) // False + + fmt.Printf("year2000.Before(year3000) = %v\n", isYear2000BeforeYear3000) + fmt.Printf("year3000.Before(year2000) = %v\n", isYear3000BeforeYear2000) + + // Output: + // year2000.Before(year3000) = true + // year3000.Before(year2000) = false +} + +func ExampleTime_Date() { + d := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC) + year, month, day := d.Date() + + fmt.Printf("year = %v\n", year) + fmt.Printf("month = %v\n", month) + fmt.Printf("day = %v\n", day) + + // Output: + // year = 2000 + // month = February + // day = 1 +} + +func ExampleTime_Day() { + d := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC) + day := d.Day() + + fmt.Printf("day = %v\n", day) + + // Output: + // day = 1 +} + +func ExampleTime_Equal() { + secondsEastOfUTC := int((8 * time.Hour).Seconds()) + beijing := time.FixedZone("Beijing Time", secondsEastOfUTC) + + // Unlike the equal operator, Equal is aware that d1 and d2 are the + // same instant but in different time zones. + d1 := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC) + d2 := time.Date(2000, 2, 1, 20, 30, 0, 0, beijing) + + datesEqualUsingEqualOperator := d1 == d2 + datesEqualUsingFunction := d1.Equal(d2) + + fmt.Printf("datesEqualUsingEqualOperator = %v\n", datesEqualUsingEqualOperator) + fmt.Printf("datesEqualUsingFunction = %v\n", datesEqualUsingFunction) + + // Output: + // datesEqualUsingEqualOperator = false + // datesEqualUsingFunction = true +} + +func ExampleTime_String() { + timeWithNanoseconds := time.Date(2000, 2, 1, 12, 13, 14, 15, time.UTC) + withNanoseconds := timeWithNanoseconds.String() + + timeWithoutNanoseconds := time.Date(2000, 2, 1, 12, 13, 14, 0, time.UTC) + withoutNanoseconds := timeWithoutNanoseconds.String() + + fmt.Printf("withNanoseconds = %v\n", string(withNanoseconds)) + fmt.Printf("withoutNanoseconds = %v\n", string(withoutNanoseconds)) + + // Output: + // withNanoseconds = 2000-02-01 12:13:14.000000015 +0000 UTC + // withoutNanoseconds = 2000-02-01 12:13:14 +0000 UTC +} + +func ExampleTime_Sub() { + start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) + end := time.Date(2000, 1, 1, 12, 0, 0, 0, time.UTC) + + difference := end.Sub(start) + fmt.Printf("difference = %v\n", difference) + + // Output: + // difference = 12h0m0s +} + +func ExampleTime_AppendFormat() { + t := time.Date(2017, time.November, 4, 11, 0, 0, 0, time.UTC) + text := []byte("Time: ") + + text = t.AppendFormat(text, time.Kitchen) + fmt.Println(string(text)) + + // Output: + // Time: 11:00AM +} diff --git a/libgo/go/time/export_android_test.go b/libgo/go/time/export_android_test.go index fa6a058a73b..f80e7da7176 100644 --- a/libgo/go/time/export_android_test.go +++ b/libgo/go/time/export_android_test.go @@ -5,8 +5,8 @@ package time func ForceAndroidTzdataForTest(tzdata bool) { - tzdataPaths = origTzdataPaths + forceZipFileForTesting(false) if tzdata { - tzdataPaths = tzdataPaths[:1] + zoneSources = zoneSources[:len(zoneSources)-1] } } diff --git a/libgo/go/time/export_test.go b/libgo/go/time/export_test.go index 4c08ab13afc..ae24ceb99ab 100644 --- a/libgo/go/time/export_test.go +++ b/libgo/go/time/export_test.go @@ -34,4 +34,5 @@ var ( GetMono = (*Time).mono ErrLocation = errLocation ReadFile = readFile + LoadTzinfo = loadTzinfo ) diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 8c16e873f64..a60474f0268 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -6,7 +6,7 @@ package time import "errors" -// These are predefined layouts for use in Time.Format and Time.Parse. +// These are predefined layouts for use in Time.Format and time.Parse. // The reference time used in the layouts is the specific time: // Mon Jan 2 15:04:05 MST 2006 // which is Unix time 1136239445. Since MST is GMT-0700, @@ -18,6 +18,9 @@ import "errors" // reference time looks like so that the Format and Parse methods can apply // the same transformation to a general time value. // +// Some valid layouts are invalid time values for time.Parse, due to formats +// such as _ for space padding and Z for zone information. +// // Within the format string, an underscore _ represents a space that may be // replaced by a digit if the following number (a day) has two digits; for // compatibility with fixed-width Unix time formats. @@ -49,7 +52,7 @@ import "errors" // time is echoed verbatim during Format and expected to appear verbatim // in the input to Parse. // -// The executable example for time.Format demonstrates the working +// The executable example for Time.Format demonstrates the working // of the layout string in detail and is a good reference. // // Note that the RFC822, RFC850, and RFC1123 formats should be applied @@ -58,7 +61,7 @@ import "errors" // use of "GMT" in that case. // In general RFC1123Z should be used instead of RFC1123 for servers // that insist on that format, and RFC3339 should be preferred for new protocols. -// RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; +// RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; // when used with time.Parse they do not accept all the time formats // permitted by the RFCs. // The RFC3339Nano format removes trailing zeros from the seconds field @@ -289,7 +292,6 @@ var shortDayNames = []string{ } var shortMonthNames = []string{ - "---", "Jan", "Feb", "Mar", @@ -305,7 +307,6 @@ var shortMonthNames = []string{ } var longMonthNames = []string{ - "---", "January", "February", "March", @@ -732,7 +733,7 @@ func skip(value, prefix string) (string, error) { } // Parse parses a formatted string and returns the time value it represents. -// The layout defines the format by showing how the reference time, +// The layout defines the format by showing how the reference time, // defined to be // Mon Jan 2 15:04:05 -0700 MST 2006 // would be interpreted if it were the value; it serves as an example of @@ -743,7 +744,7 @@ func skip(value, prefix string) (string, error) { // and convenient representations of the reference time. For more information // about the formats and the definition of the reference time, see the // documentation for ANSIC and the other constants defined by this package. -// Also, the executable example for time.Format demonstrates the working +// Also, the executable example for Time.Format demonstrates the working // of the layout string in detail and is a good reference. // // Elements omitted from the value are assumed to be zero or, when @@ -841,8 +842,10 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) year, err = atoi(p) case stdMonth: month, value, err = lookup(shortMonthNames, value) + month++ case stdLongMonth: month, value, err = lookup(longMonthNames, value) + month++ case stdNumMonth, stdZeroMonth: month, value, err = getnum(value, std == stdZeroMonth) if month <= 0 || 12 < month { @@ -1071,7 +1074,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) // Look for local zone with the given offset. // If that zone was in effect at the given time, use it. - offset, _, ok := local.lookupName(zoneName, t.unixSec()) + offset, ok := local.lookupName(zoneName, t.unixSec()) if ok { t.addSec(-int64(offset)) t.setLoc(local) diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go index abaeb506096..d6cf6749a83 100644 --- a/libgo/go/time/format_test.go +++ b/libgo/go/time/format_test.go @@ -467,6 +467,9 @@ var parseErrorTests = []ParseErrorTest{ {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`}, // invalid second followed by optional fractional seconds {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"}, + // issue 21113 + {"_2 Jan 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"}, + {"_2 January 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"}, } func TestParseErrors(t *testing.T) { diff --git a/libgo/go/time/genzabbrs.go b/libgo/go/time/genzabbrs.go index 824a67f15af..e062cc2efd0 100644 --- a/libgo/go/time/genzabbrs.go +++ b/libgo/go/time/genzabbrs.go @@ -52,12 +52,6 @@ type zone struct { DSTime string } -type zones []*zone - -func (zs zones) Len() int { return len(zs) } -func (zs zones) Swap(i, j int) { zs[i], zs[j] = zs[j], zs[i] } -func (zs zones) Less(i, j int) bool { return zs[i].UnixName < zs[j].UnixName } - const wzURL = "http://unicode.org/cldr/data/common/supplemental/windowsZones.xml" type MapZone struct { @@ -70,7 +64,7 @@ type SupplementalData struct { Zones []MapZone `xml:"windowsZones>mapTimezones>mapZone"` } -func readWindowsZones() (zones, error) { +func readWindowsZones() ([]*zone, error) { r, err := http.Get(wzURL) if err != nil { return nil, err @@ -87,7 +81,7 @@ func readWindowsZones() (zones, error) { if err != nil { return nil, err } - zs := make(zones, 0) + zs := make([]*zone, 0) for _, z := range sd.Zones { if z.Territory != "001" { // to avoid dups. I don't know why. @@ -114,10 +108,12 @@ func main() { if err != nil { log.Fatal(err) } - sort.Sort(zs) + sort.Slice(zs, func(i, j int) bool { + return zs[i].UnixName < zs[j].UnixName + }) var v = struct { URL string - Zs zones + Zs []*zone }{ wzURL, zs, diff --git a/libgo/go/time/internal_test.go b/libgo/go/time/internal_test.go index edd523bc80c..e3f458fad09 100644 --- a/libgo/go/time/internal_test.go +++ b/libgo/go/time/internal_test.go @@ -4,11 +4,35 @@ package time +import "runtime" + func init() { // force US/Pacific for time zone tests ForceUSPacificForTesting() } +func initTestingZone() { + z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:]) + if runtime.Compiler == "gccgo" && err != nil { + z, err = loadLocation("America/Los_Angeles", zoneSources) + } + if err != nil { + panic("cannot load America/Los_Angeles for testing: " + err.Error()) + } + z.name = "Local" + localLoc = *z +} + +var OrigZoneSources = zoneSources + +func forceZipFileForTesting(zipOnly bool) { + zoneSources = make([]string, len(OrigZoneSources)) + copy(zoneSources, OrigZoneSources) + if zipOnly { + zoneSources = zoneSources[len(zoneSources)-1:] + } +} + var Interrupt = interrupt var DaysIn = daysIn diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go index 4b01404896e..b8c81b437c0 100644 --- a/libgo/go/time/sleep.go +++ b/libgo/go/time/sleep.go @@ -14,7 +14,9 @@ func runtimeNano() int64 // Interface to timers implemented in package runtime. // Must be in sync with ../runtime/time.go:/^type timer type runtimeTimer struct { - i int + tb uintptr + i int + when int64 period int64 f func(interface{}, uintptr) // NOTE: must not be closure diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go index 546b28a28ac..670ff1de290 100644 --- a/libgo/go/time/sleep_test.go +++ b/libgo/go/time/sleep_test.go @@ -82,21 +82,36 @@ func TestAfterStress(t *testing.T) { } func benchmark(b *testing.B, bench func(n int)) { - garbage := make([]*Timer, 1<<17) - for i := 0; i < len(garbage); i++ { - garbage[i] = AfterFunc(Hour, nil) + + // Create equal number of garbage timers on each P before starting + // the benchmark. + var wg sync.WaitGroup + garbageAll := make([][]*Timer, runtime.GOMAXPROCS(0)) + for i := range garbageAll { + wg.Add(1) + go func(i int) { + defer wg.Done() + garbage := make([]*Timer, 1<<15) + for j := range garbage { + garbage[j] = AfterFunc(Hour, nil) + } + garbageAll[i] = garbage + }(i) } - b.ResetTimer() + wg.Wait() + b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { bench(1000) } }) - b.StopTimer() - for i := 0; i < len(garbage); i++ { - garbage[i].Stop() + + for _, garbage := range garbageAll { + for _, t := range garbage { + t.Stop() + } } } @@ -158,6 +173,30 @@ func BenchmarkStartStop(b *testing.B) { }) } +func BenchmarkReset(b *testing.B) { + benchmark(b, func(n int) { + t := NewTimer(Hour) + for i := 0; i < n; i++ { + t.Reset(Hour) + } + t.Stop() + }) +} + +func BenchmarkSleep(b *testing.B) { + benchmark(b, func(n int) { + var wg sync.WaitGroup + wg.Add(n) + for i := 0; i < n; i++ { + go func() { + Sleep(Nanosecond) + wg.Done() + }() + } + wg.Wait() + }) +} + func TestAfter(t *testing.T) { const delay = 100 * Millisecond start := Now() diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go index 9086a6e835f..b7fba0802c2 100644 --- a/libgo/go/time/sys_plan9.go +++ b/libgo/go/time/sys_plan9.go @@ -16,36 +16,6 @@ func interrupt() { // cannot predict pid, don't want to kill group } -// readFile reads and returns the content of the named file. -// It is a trivial implementation of ioutil.ReadFile, reimplemented -// here to avoid depending on io/ioutil or os. -// It returns an error if name exceeds maxFileSize bytes. -func readFile(name string) ([]byte, error) { - f, err := syscall.Open(name, syscall.O_RDONLY) - if err != nil { - return nil, err - } - defer syscall.Close(f) - var ( - buf [4096]byte - ret []byte - n int - ) - for { - n, err = syscall.Read(f, buf[:]) - if n > 0 { - ret = append(ret, buf[:n]...) - } - if n == 0 || err != nil { - break - } - if len(ret) > maxFileSize { - return nil, fileSizeError(name) - } - } - return ret, err -} - func open(name string) (uintptr, error) { fd, err := syscall.Open(name, syscall.O_RDONLY) if err != nil { @@ -54,6 +24,10 @@ func open(name string) (uintptr, error) { return uintptr(fd), nil } +func read(fd uintptr, buf []byte) (int, error) { + return syscall.Read(int(fd), buf) +} + func closefd(fd uintptr) { syscall.Close(int(fd)) } diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go index 57152751800..382796568d8 100644 --- a/libgo/go/time/sys_unix.go +++ b/libgo/go/time/sys_unix.go @@ -16,36 +16,6 @@ func interrupt() { syscall.Kill(syscall.Getpid(), syscall.SIGCHLD) } -// readFile reads and returns the content of the named file. -// It is a trivial implementation of ioutil.ReadFile, reimplemented -// here to avoid depending on io/ioutil or os. -// It returns an error if name exceeds maxFileSize bytes. -func readFile(name string) ([]byte, error) { - f, err := syscall.Open(name, syscall.O_RDONLY, 0) - if err != nil { - return nil, err - } - defer syscall.Close(f) - var ( - buf [4096]byte - ret []byte - n int - ) - for { - n, err = syscall.Read(f, buf[:]) - if n > 0 { - ret = append(ret, buf[:n]...) - } - if n == 0 || err != nil { - break - } - if len(ret) > maxFileSize { - return nil, fileSizeError(name) - } - } - return ret, err -} - func open(name string) (uintptr, error) { fd, err := syscall.Open(name, syscall.O_RDONLY, 0) if err != nil { @@ -54,6 +24,10 @@ func open(name string) (uintptr, error) { return uintptr(fd), nil } +func read(fd uintptr, buf []byte) (int, error) { + return syscall.Read(int(fd), buf) +} + func closefd(fd uintptr) { syscall.Close(int(fd)) } @@ -78,5 +52,3 @@ func preadn(fd uintptr, buf []byte, off int) error { } return nil } - -func isNotExist(err error) bool { return err == syscall.ENOENT } diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go index 9e381653937..481aea562e8 100644 --- a/libgo/go/time/sys_windows.go +++ b/libgo/go/time/sys_windows.go @@ -13,36 +13,6 @@ import ( func interrupt() { } -// readFile reads and returns the content of the named file. -// It is a trivial implementation of ioutil.ReadFile, reimplemented -// here to avoid depending on io/ioutil or os. -// It returns an error if name exceeds maxFileSize bytes. -func readFile(name string) ([]byte, error) { - f, err := syscall.Open(name, syscall.O_RDONLY, 0) - if err != nil { - return nil, err - } - defer syscall.Close(f) - var ( - buf [4096]byte - ret []byte - n int - ) - for { - n, err = syscall.Read(f, buf[:]) - if n > 0 { - ret = append(ret, buf[:n]...) - } - if n == 0 || err != nil { - break - } - if len(ret) > maxFileSize { - return nil, fileSizeError(name) - } - } - return ret, err -} - func open(name string) (uintptr, error) { fd, err := syscall.Open(name, syscall.O_RDONLY, 0) if err != nil { @@ -51,6 +21,10 @@ func open(name string) (uintptr, error) { return uintptr(fd), nil } +func read(fd uintptr, buf []byte) (int, error) { + return syscall.Read(syscall.Handle(fd), buf) +} + func closefd(fd uintptr) { syscall.Close(syscall.Handle(fd)) } diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go index 2ab77f60255..dd17aab1b15 100644 --- a/libgo/go/time/tick_test.go +++ b/libgo/go/time/tick_test.go @@ -35,6 +35,13 @@ func TestTicker(t *testing.T) { } } +// Issue 21874 +func TestTickerStopWithDirectInitialization(t *testing.T) { + c := make(chan Time) + tk := &Ticker{C: c} + tk.Stop() +} + // Test that a bug tearing down a ticker has been fixed. This routine should not deadlock. func TestTeardown(t *testing.T) { Delta := 100 * Millisecond @@ -67,12 +74,11 @@ func TestNewTickerLtZeroDuration(t *testing.T) { } func BenchmarkTicker(b *testing.B) { - ticker := NewTicker(1) - b.ResetTimer() - b.StartTimer() - for i := 0; i < b.N; i++ { - <-ticker.C - } - b.StopTimer() - ticker.Stop() + benchmark(b, func(n int) { + ticker := NewTicker(Nanosecond) + for i := 0; i < n; i++ { + <-ticker.C + } + ticker.Stop() + }) } diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index 8a29eef2631..93909682f51 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -98,6 +98,11 @@ import "errors" // change the instant in time being denoted and therefore does not affect the // computations described in earlier paragraphs. // +// In addition to the required “wall clock” reading, a Time may contain an optional +// reading of the current process's monotonic clock, to provide additional precision +// for comparison or subtraction. +// See the “Monotonic Clocks” section in the package documentation for details. +// // Note that the Go == operator compares not just the time instant but also the // Location and the monotonic clock reading. Therefore, Time values should not // be used as map or database keys without first guaranteeing that the @@ -108,11 +113,6 @@ import "errors" // correctly handles the case when only one of its arguments has a monotonic // clock reading. // -// In addition to the required “wall clock” reading, a Time may contain an optional -// reading of the current process's monotonic clock, to provide additional precision -// for comparison or subtraction. -// See the “Monotonic Clocks” section in the package documentation for details. -// type Time struct { // wall and ext encode the wall time seconds, wall time nanoseconds, // and optional monotonic clock reading in nanoseconds. @@ -722,7 +722,7 @@ func (d Duration) String() string { } // fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the -// tail of buf, omitting trailing zeros. it omits the decimal +// tail of buf, omitting trailing zeros. It omits the decimal // point too when the fraction is 0. It returns the index where the // output bytes begin and the value v/10**prec. func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { @@ -1383,7 +1383,7 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T } // Truncate returns the result of rounding t down to a multiple of d (since the zero time). -// If d <= 0, Truncate returns t unchanged. +// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. // // Truncate operates on the time as an absolute duration since the // zero time; it does not operate on the presentation form of the @@ -1400,7 +1400,7 @@ func (t Time) Truncate(d Duration) Time { // Round returns the result of rounding t to the nearest multiple of d (since the zero time). // The rounding behavior for halfway values is to round up. -// If d <= 0, Round returns t unchanged. +// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. // // Round operates on the time as an absolute duration since the // zero time; it does not operate on the presentation form of the diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go index dba8e0dadcd..fd464c0b184 100644 --- a/libgo/go/time/time_test.go +++ b/libgo/go/time/time_test.go @@ -575,6 +575,7 @@ var dateTests = []struct { {2011, 3, 13, 1, 59, 59, 0, Local, 1300010399}, // 1:59:59 PST {2011, 3, 13, 3, 0, 0, 0, Local, 1300010400}, // 3:00:00 PDT {2011, 3, 13, 2, 30, 0, 0, Local, 1300008600}, // 2:30:00 PDT ≡ 1:30 PST + {2012, 12, 24, 0, 0, 0, 0, Local, 1356336000}, // Leap year // Many names for Fri Nov 18 7:56:35 PST 2011 {2011, 11, 18, 7, 56, 35, 0, Local, 1321631795}, // Nov 18 7:56:35 @@ -1202,8 +1203,8 @@ var defaultLocTests = []struct { } func TestDefaultLoc(t *testing.T) { - //This test verifyes that all Time's methods behaves identical if loc is set - //as nil or UTC + // Verify that all of Time's methods behave identically if loc is set to + // nil or UTC. for _, tt := range defaultLocTests { t1 := Time{} t2 := Time{}.UTC() diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go index f4d4df95d36..96ff8d39708 100644 --- a/libgo/go/time/zoneinfo.go +++ b/libgo/go/time/zoneinfo.go @@ -223,7 +223,7 @@ func (l *Location) firstZoneUsed() bool { // 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). -func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool, ok bool) { +func (l *Location) lookupName(name string, unix int64) (offset int, ok bool) { l = l.get() // First try for a zone with the right name that was actually @@ -235,9 +235,9 @@ func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool, for i := range l.zone { zone := &l.zone[i] if zone.name == name { - nam, offset, isDST, _, _ := l.lookup(unix - int64(zone.offset)) + nam, offset, _, _, _ := l.lookup(unix - int64(zone.offset)) if nam == zone.name { - return offset, isDST, true + return offset, true } } } @@ -246,7 +246,7 @@ func (l *Location) lookupName(name string, unix int64) (offset int, isDST bool, for i := range l.zone { zone := &l.zone[i] if zone.name == name { - return zone.offset, zone.isDST, true + return zone.offset, true } } @@ -292,13 +292,14 @@ func LoadLocation(name string) (*Location, error) { env, _ := syscall.Getenv("ZONEINFO") zoneinfo = &env }) - if zoneinfo != nil && *zoneinfo != "" { - if z, err := loadZoneFile(*zoneinfo, name); err == nil { - z.name = name - return z, nil + if *zoneinfo != "" { + if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil { + if z, err := LoadLocationFromTZData(name, zoneData); err == nil { + return z, nil + } } } - return loadLocation(name) + return loadLocation(name, zoneSources) } // containsDotDot reports whether s contains "..". diff --git a/libgo/go/time/zoneinfo_android.go b/libgo/go/time/zoneinfo_android.go index 695a8adfaa3..65e0975ab02 100644 --- a/libgo/go/time/zoneinfo_android.go +++ b/libgo/go/time/zoneinfo_android.go @@ -13,62 +13,22 @@ import ( "runtime" ) -var tzdataPaths = []string{ +var zoneSources = []string{ "/system/usr/share/zoneinfo/tzdata", "/data/misc/zoneinfo/current/tzdata", runtime.GOROOT() + "/lib/time/zoneinfo.zip", } -var origTzdataPaths = tzdataPaths - -func forceZipFileForTesting(zipOnly bool) { - tzdataPaths = make([]string, len(origTzdataPaths)) - copy(tzdataPaths, origTzdataPaths) - if zipOnly { - for i := 0; i < len(tzdataPaths)-1; i++ { - tzdataPaths[i] = "/XXXNOEXIST" - } - } -} - -func initTestingZone() { - z, err := loadLocation("America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z -} - func initLocal() { // TODO(elias.naur): getprop persist.sys.timezone localLoc = *UTC } -func loadLocation(name string) (*Location, error) { - var firstErr error - for _, path := range tzdataPaths { - var z *Location - var err error - if len(path) > 4 && path[len(path)-4:] == ".zip" { - z, err = loadZoneZip(path, name) - } else { - z, err = loadTzdataFile(path, name) - } - if err == nil { - z.name = name - return z, nil - } else if firstErr == nil && !isNotExist(err) { - firstErr = err - } - } - if firstErr != nil { - return nil, firstErr - } - return nil, errors.New("unknown time zone " + name) +func init() { + loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata } -func loadTzdataFile(file, name string) (*Location, error) { +func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) { const ( headersize = 12 + 3*4 namesize = 40 @@ -87,11 +47,11 @@ func loadTzdataFile(file, name string) (*Location, error) { if err := preadn(fd, buf, 0); err != nil { return nil, errors.New("corrupt tzdata file " + file) } - d := data{buf, false} + d := dataIO{buf, false} if magic := d.read(6); string(magic) != "tzdata" { return nil, errors.New("corrupt tzdata file " + file) } - d = data{buf[12:], false} + d = dataIO{buf[12:], false} indexOff, _ := d.big4() dataOff, _ := d.big4() indexSize := dataOff - indexOff @@ -106,14 +66,14 @@ func loadTzdataFile(file, name string) (*Location, error) { if string(entry[:len(name)]) != name { continue } - d := data{entry[namesize:], false} + d := dataIO{entry[namesize:], false} off, _ := d.big4() size, _ := d.big4() buf := make([]byte, size) if err := preadn(fd, buf, int(off+dataOff)); err != nil { return nil, errors.New("corrupt tzdata file " + file) } - return loadZoneData(buf) + return buf, nil } return nil, errors.New("cannot find " + name + " in tzdata file " + file) } diff --git a/libgo/go/time/zoneinfo_ios.go b/libgo/go/time/zoneinfo_ios.go index f09166c89e9..6d7f975a114 100644 --- a/libgo/go/time/zoneinfo_ios.go +++ b/libgo/go/time/zoneinfo_ios.go @@ -9,43 +9,23 @@ package time import "syscall" -var zoneFile string +var zoneSources = []string{ + getZipParent() + "/zoneinfo.zip", +} -func init() { +func getZipParent() string { wd, err := syscall.Getwd() if err != nil { - return + return "/XXXNOEXIST" } // The working directory at initialization is the root of the // app bundle: "/private/.../bundlename.app". That's where we // keep zoneinfo.zip. - zoneFile = wd + "/zoneinfo.zip" -} - -func forceZipFileForTesting(zipOnly bool) { - // On iOS we only have the zip file. -} - -func initTestingZone() { - z, err := loadZoneFile(zoneFile, "America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z + return wd } func initLocal() { // TODO(crawshaw): [NSTimeZone localTimeZone] localLoc = *UTC } - -func loadLocation(name string) (*Location, error) { - z, err := loadZoneFile(zoneFile, name) - if err != nil { - return nil, err - } - z.name = name - return z, nil -} diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go index 26637a151f0..4ae718c59e1 100644 --- a/libgo/go/time/zoneinfo_plan9.go +++ b/libgo/go/time/zoneinfo_plan9.go @@ -11,6 +11,10 @@ import ( "syscall" ) +var zoneSources = []string{ + runtime.GOROOT() + "/lib/time/zoneinfo.zip", +} + func isSpace(r rune) bool { return r == ' ' || r == '\t' || r == '\n' } @@ -118,15 +122,6 @@ func loadZoneFilePlan9(name string) (*Location, error) { return loadZoneDataPlan9(string(b)) } -func initTestingZone() { - z, err := loadLocation("America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z -} - func initLocal() { t, ok := syscall.Getenv("timezone") if ok { @@ -145,16 +140,3 @@ func initLocal() { // Fall back to UTC. localLoc.name = "UTC" } - -func loadLocation(name string) (*Location, error) { - z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name) - if err != nil { - return nil, err - } - z.name = name - return z, nil -} - -func forceZipFileForTesting(zipOnly bool) { - // We only use the zip file anyway. -} diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go index b0cd9da9230..839b37aac4e 100644 --- a/libgo/go/time/zoneinfo_read.go +++ b/libgo/go/time/zoneinfo_read.go @@ -9,7 +9,10 @@ package time -import "errors" +import ( + "errors" + "syscall" +) // maxFileSize is the max permitted size of files read by readFile. // As reference, the zoneinfo.zip distributed by Go is ~350 KB, @@ -30,12 +33,12 @@ const ( ) // Simple I/O interface to binary blob of data. -type data struct { +type dataIO struct { p []byte error bool } -func (d *data) read(n int) []byte { +func (d *dataIO) read(n int) []byte { if len(d.p) < n { d.p = nil d.error = true @@ -46,7 +49,7 @@ func (d *data) read(n int) []byte { return p } -func (d *data) big4() (n uint32, ok bool) { +func (d *dataIO) big4() (n uint32, ok bool) { p := d.read(4) if len(p) < 4 { d.error = true @@ -55,7 +58,7 @@ func (d *data) big4() (n uint32, ok bool) { return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true } -func (d *data) byte() (n byte, ok bool) { +func (d *dataIO) byte() (n byte, ok bool) { p := d.read(1) if len(p) < 1 { d.error = true @@ -76,8 +79,12 @@ func byteString(p []byte) string { var badData = errors.New("malformed time zone information") -func loadZoneData(bytes []byte) (l *Location, err error) { - d := data{bytes, false} +// LoadLocationFromTZData returns a Location with the given name +// initialized from the IANA Time Zone database-formatted data. +// The data should be in the format of a standard IANA time zone file +// (for example, the content of /etc/localtime on Unix systems). +func LoadLocationFromTZData(name string, data []byte) (*Location, error) { + d := dataIO{data, false} // 4-byte magic "TZif" if magic := d.read(4); string(magic) != "TZif" { @@ -115,13 +122,13 @@ func loadZoneData(bytes []byte) (l *Location, err error) { } // Transition times. - txtimes := data{d.read(n[NTime] * 4), false} + txtimes := dataIO{d.read(n[NTime] * 4), false} // Time zone indices for transition times. txzones := d.read(n[NTime]) // Zone info structures - zonedata := data{d.read(n[NZone] * 6), false} + zonedata := dataIO{d.read(n[NZone] * 6), false} // Time zone abbreviations. abbrev := d.read(n[NChar]) @@ -195,7 +202,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) { } // Committed to succeed. - l = &Location{zone: zone, tx: tx} + l := &Location{zone: zone, tx: tx, name: name} // Fill in the cache with information about right now, // since that will be the most common lookup. @@ -214,18 +221,16 @@ func loadZoneData(bytes []byte) (l *Location, err error) { return l, nil } -func loadZoneFile(dir, name string) (l *Location, err error) { +// loadTzinfoFromDirOrZip returns the contents of the file with the given name +// in dir. dir can either be an uncompressed zip file, or a directory. +func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) { if len(dir) > 4 && dir[len(dir)-4:] == ".zip" { - return loadZoneZip(dir, name) + return loadTzinfoFromZip(dir, name) } if dir != "" { name = dir + "/" + name } - buf, err := readFile(name) - if err != nil { - return - } - return loadZoneData(buf) + return readFile(name) } // There are 500+ zoneinfo files. Rather than distribute them all @@ -252,7 +257,9 @@ func get2(b []byte) int { return int(b[0]) | int(b[1])<<8 } -func loadZoneZip(zipfile, name string) (l *Location, err error) { +// loadTzinfoFromZip returns the contents of the file with the given name +// in the given uncompressed zip file. +func loadTzinfoFromZip(zipfile, name string) ([]byte, error) { fd, err := open(zipfile) if err != nil { return nil, errors.New("open " + zipfile + ": " + err.Error()) @@ -354,8 +361,76 @@ func loadZoneZip(zipfile, name string) (l *Location, err error) { return nil, errors.New("corrupt zip file " + zipfile) } - return loadZoneData(buf) + return buf, nil } return nil, errors.New("cannot find " + name + " in zip file " + zipfile) } + +// loadTzinfoFromTzdata returns the time zone information of the time zone +// with the given name, from a tzdata database file as they are typically +// found on android. +var loadTzinfoFromTzdata func(file, name string) ([]byte, error) + +// loadTzinfo returns the time zone information of the time zone +// with the given name, from a given source. A source may be a +// timezone database directory, tzdata database file or an uncompressed +// zip file, containing the contents of such a directory. +func loadTzinfo(name string, source string) ([]byte, error) { + if len(source) >= 6 && source[len(source)-6:] == "tzdata" { + return loadTzinfoFromTzdata(source, name) + } + return loadTzinfoFromDirOrZip(source, name) +} + +// loadLocation returns the Location with the given name from one of +// the specified sources. See loadTzinfo for a list of supported sources. +// The first timezone data matching the given name that is successfully loaded +// and parsed is returned as a Location. +func loadLocation(name string, sources []string) (z *Location, firstErr error) { + for _, source := range sources { + var zoneData, err = loadTzinfo(name, source) + if err == nil { + if z, err = LoadLocationFromTZData(name, zoneData); err == nil { + return z, nil + } + } + if firstErr == nil && err != syscall.ENOENT { + firstErr = err + } + } + if firstErr != nil { + return nil, firstErr + } + return nil, errors.New("unknown time zone " + name) +} + +// readFile reads and returns the content of the named file. +// It is a trivial implementation of ioutil.ReadFile, reimplemented +// here to avoid depending on io/ioutil or os. +// It returns an error if name exceeds maxFileSize bytes. +func readFile(name string) ([]byte, error) { + f, err := open(name) + if err != nil { + return nil, err + } + defer closefd(f) + var ( + buf [4096]byte + ret []byte + n int + ) + for { + n, err = read(f, buf[:]) + if n > 0 { + ret = append(ret, buf[:n]...) + } + if n == 0 || err != nil { + break + } + if len(ret) > maxFileSize { + return nil, fileSizeError(name) + } + } + return ret, err +} diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go index 8a4caa0c445..de96416ed93 100644 --- a/libgo/go/time/zoneinfo_test.go +++ b/libgo/go/time/zoneinfo_test.go @@ -7,6 +7,7 @@ package time_test import ( "fmt" "os" + "reflect" "testing" "time" ) @@ -119,3 +120,29 @@ func TestLocationNames(t *testing.T) { t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC) } } + +func TestLoadLocationFromTZData(t *testing.T) { + t.Skip("gccgo does not use the zip file") + + time.ForceZipFileForTesting(true) + defer time.ForceZipFileForTesting(false) + + const locationName = "Asia/Jerusalem" + reference, err := time.LoadLocation(locationName) + if err != nil { + t.Fatal(err) + } + + tzinfo, err := time.LoadTzinfo(locationName, time.OrigZoneSources[len(time.OrigZoneSources)-1]) + if err != nil { + t.Fatal(err) + } + sample, err := time.LoadLocationFromTZData(locationName, tzinfo) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(reference, sample) { + t.Errorf("return values of LoadLocationFromTZData and LoadLocation don't match") + } +} diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go index a876e27c54e..32dc7d50408 100644 --- a/libgo/go/time/zoneinfo_unix.go +++ b/libgo/go/time/zoneinfo_unix.go @@ -12,41 +12,19 @@ package time import ( - "errors" "runtime" "syscall" ) -func initTestingZone() { - z, err := loadLocation("America/Los_Angeles") - if err != nil { - panic("cannot load America/Los_Angeles for testing: " + err.Error()) - } - z.name = "Local" - localLoc = *z -} - // Many systems use /usr/share/zoneinfo, Solaris 2 has // /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ. -var zoneDirs = []string{ +var zoneSources = []string{ "/usr/share/zoneinfo/", "/usr/share/lib/zoneinfo/", "/usr/lib/locale/TZ/", runtime.GOROOT() + "/lib/time/zoneinfo.zip", } -var origZoneDirs = zoneDirs - -func forceZipFileForTesting(zipOnly bool) { - zoneDirs = make([]string, len(origZoneDirs)) - copy(zoneDirs, origZoneDirs) - if zipOnly { - for i := 0; i < len(zoneDirs)-1; i++ { - zoneDirs[i] = "/XXXNOEXIST" - } - } -} - func initLocal() { // consult $TZ to find the time zone to use. // no $TZ means use the system default /etc/localtime. @@ -56,14 +34,14 @@ func initLocal() { tz, ok := syscall.Getenv("TZ") switch { case !ok: - z, err := loadZoneFile("", "/etc/localtime") + z, err := loadLocation("localtime", []string{"/etc/"}) if err == nil { localLoc = *z localLoc.name = "Local" return } case tz != "" && tz != "UTC": - if z, err := loadLocation(tz); err == nil { + if z, err := loadLocation(tz, zoneSources); err == nil { localLoc = *z return } @@ -72,19 +50,3 @@ func initLocal() { // Fall back to UTC. localLoc.name = "UTC" } - -func loadLocation(name string) (*Location, error) { - var firstErr error - for _, zoneDir := range zoneDirs { - if z, err := loadZoneFile(zoneDir, name); err == nil { - z.name = name - return z, nil - } else if firstErr == nil && !isNotExist(err) { - firstErr = err - } - } - if firstErr != nil { - return nil, firstErr - } - return nil, errors.New("unknown time zone " + name) -} diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go index c201f4b55ee..2b69d06a1dd 100644 --- a/libgo/go/time/zoneinfo_windows.go +++ b/libgo/go/time/zoneinfo_windows.go @@ -11,6 +11,10 @@ import ( "syscall" ) +var zoneSources = []string{ + runtime.GOROOT() + "/lib/time/zoneinfo.zip", +} + // TODO(rsc): Fall back to copy of zoneinfo files. // BUG(brainman,rsc): On Windows, the operating system does not provide complete @@ -228,14 +232,6 @@ var aus = syscall.Timezoneinformation{ DaylightBias: -60, } -func initTestingZone() { - initLocalFromTZI(&usPacific) -} - -func initAusTestingZone() { - initLocalFromTZI(&aus) -} - func initLocal() { var i syscall.Timezoneinformation if _, err := syscall.GetTimeZoneInformation(&i); err != nil { @@ -244,16 +240,3 @@ func initLocal() { } initLocalFromTZI(&i) } - -func loadLocation(name string) (*Location, error) { - z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name) - if err != nil { - return nil, err - } - z.name = name - return z, nil -} - -func forceZipFileForTesting(zipOnly bool) { - // We only use the zip file anyway. -} diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go index 90b0b414da2..4d9fc67165c 100644 --- a/libgo/go/unicode/letter.go +++ b/libgo/go/unicode/letter.go @@ -97,7 +97,7 @@ func is16(ranges []Range16, r uint16) bool { return false } if r <= range_.Hi { - return (r-range_.Lo)%range_.Stride == 0 + return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0 } } return false @@ -110,7 +110,7 @@ func is16(ranges []Range16, r uint16) bool { m := lo + (hi-lo)/2 range_ := &ranges[m] if range_.Lo <= r && r <= range_.Hi { - return (r-range_.Lo)%range_.Stride == 0 + return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0 } if r < range_.Lo { hi = m @@ -130,7 +130,7 @@ func is32(ranges []Range32, r uint32) bool { return false } if r <= range_.Hi { - return (r-range_.Lo)%range_.Stride == 0 + return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0 } } return false @@ -143,7 +143,7 @@ func is32(ranges []Range32, r uint32) bool { m := lo + (hi-lo)/2 range_ := ranges[m] if range_.Lo <= r && r <= range_.Hi { - return (r-range_.Lo)%range_.Stride == 0 + return range_.Stride == 1 || (r-range_.Lo)%range_.Stride == 0 } if r < range_.Lo { hi = m diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go index 1fe4581e6c2..7d760fc5e30 100644 --- a/libgo/go/unicode/script_test.go +++ b/libgo/go/unicode/script_test.go @@ -14,8 +14,13 @@ type T struct { script string } -// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0, 7.0.0 and 8.0.0 +// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0, 7.0.0, 8.0.0, +// 9.0.0, 10.0.0. // mostly to discover when new scripts and categories arise. +// If this tests fails, add the missing scripts to the test and add entries +// of the form +// pkg unicode, var *RangeTable +// to api/next.txt. var inTest = []T{ {0x11711, "Ahom"}, {0x1e900, "Adlam"}, @@ -92,6 +97,7 @@ var inTest = []T{ {0x0843, "Mandaic"}, {0x10ac8, "Manichaean"}, {0x11cB6, "Marchen"}, + {0x11d59, "Masaram_Gondi"}, {0xabd0, "Meetei_Mayek"}, {0x1e800, "Mende_Kikakui"}, {0x1099f, "Meroitic_Hieroglyphs"}, @@ -106,6 +112,7 @@ var inTest = []T{ {0x11400, "Newa"}, {0x19c3, "New_Tai_Lue"}, {0x07f8, "Nko"}, + {0x1b170, "Nushu"}, {0x169b, "Ogham"}, {0x1c6a, "Ol_Chiki"}, {0x10C80, "Old_Hungarian"}, @@ -134,6 +141,7 @@ var inTest = []T{ {0x1D920, "SignWriting"}, {0x0dbd, "Sinhala"}, {0x110d0, "Sora_Sompeng"}, + {0x11a99, "Soyombo"}, {0x1ba3, "Sundanese"}, {0xa803, "Syloti_Nagri"}, {0x070f, "Syriac"}, @@ -155,6 +163,7 @@ var inTest = []T{ {0xa60e, "Vai"}, {0x118ff, "Warang_Citi"}, {0xa216, "Yi"}, + {0x11a0a, "Zanabazar_Square"}, } var outTest = []T{ // not really worth being thorough @@ -229,6 +238,7 @@ var inPropTest = []T{ {0x06DD, "Prepended_Concatenation_Mark"}, {0x300D, "Quotation_Mark"}, {0x2EF3, "Radical"}, + {0x1f1ff, "Regional_Indicator"}, {0x061F, "STerm"}, // Deprecated alias of Sentence_Terminal {0x061F, "Sentence_Terminal"}, {0x2071, "Soft_Dotted"}, diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go index 90323367d55..dd2f70b6519 100644 --- a/libgo/go/unicode/tables.go +++ b/libgo/go/unicode/tables.go @@ -4,12 +4,12 @@ // Code generated by maketables; DO NOT EDIT. // To regenerate, run: -// maketables --tables=all --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt +// maketables --tables=all --data=http://www.unicode.org/Public/10.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/10.0.0/ucd/CaseFolding.txt package unicode // Version is the Unicode edition from which the tables are derived. -const Version = "9.0.0" +const Version = "10.0.0" // Categories is the set of Unicode category tables. var Categories = map[string]*RangeTable{ @@ -172,6 +172,7 @@ var _L = &RangeTable{ {0x081a, 0x0824, 10}, {0x0828, 0x0840, 24}, {0x0841, 0x0858, 1}, + {0x0860, 0x086a, 1}, {0x08a0, 0x08b4, 1}, {0x08b6, 0x08bd, 1}, {0x0904, 0x0939, 1}, @@ -188,7 +189,8 @@ var _L = &RangeTable{ {0x09dc, 0x09dd, 1}, {0x09df, 0x09e1, 1}, {0x09f0, 0x09f1, 1}, - {0x0a05, 0x0a0a, 1}, + {0x09fc, 0x0a05, 9}, + {0x0a06, 0x0a0a, 1}, {0x0a0f, 0x0a10, 1}, {0x0a13, 0x0a28, 1}, {0x0a2a, 0x0a30, 1}, @@ -403,12 +405,12 @@ var _L = &RangeTable{ {0x309d, 0x309f, 1}, {0x30a1, 0x30fa, 1}, {0x30fc, 0x30ff, 1}, - {0x3105, 0x312d, 1}, + {0x3105, 0x312e, 1}, {0x3131, 0x318e, 1}, {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fd5, 1}, + {0x4e00, 0x9fea, 1}, {0xa000, 0xa48c, 1}, {0xa4d0, 0xa4fd, 1}, {0xa500, 0xa60c, 1}, @@ -498,7 +500,7 @@ var _L = &RangeTable{ {0x10280, 0x1029c, 1}, {0x102a0, 0x102d0, 1}, {0x10300, 0x1031f, 1}, - {0x10330, 0x10340, 1}, + {0x1032d, 0x10340, 1}, {0x10342, 0x10349, 1}, {0x10350, 0x10375, 1}, {0x10380, 0x1039d, 1}, @@ -578,13 +580,21 @@ var _L = &RangeTable{ {0x11681, 0x116aa, 1}, {0x11700, 0x11719, 1}, {0x118a0, 0x118df, 1}, - {0x118ff, 0x11ac0, 449}, - {0x11ac1, 0x11af8, 1}, + {0x118ff, 0x11a00, 257}, + {0x11a0b, 0x11a32, 1}, + {0x11a3a, 0x11a50, 22}, + {0x11a5c, 0x11a83, 1}, + {0x11a86, 0x11a89, 1}, + {0x11ac0, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, {0x11c73, 0x11c8f, 1}, - {0x12000, 0x12399, 1}, + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d30, 1}, + {0x11d46, 0x12000, 698}, + {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, {0x13000, 0x1342e, 1}, {0x14400, 0x14646, 1}, @@ -598,10 +608,11 @@ var _L = &RangeTable{ {0x16f00, 0x16f44, 1}, {0x16f50, 0x16f93, 67}, {0x16f94, 0x16f9f, 1}, - {0x16fe0, 0x17000, 32}, - {0x17001, 0x187ec, 1}, + {0x16fe0, 0x16fe1, 1}, + {0x17000, 0x187ec, 1}, {0x18800, 0x18af2, 1}, - {0x1b000, 0x1b001, 1}, + {0x1b000, 0x1b11e, 1}, + {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, {0x1bc80, 0x1bc88, 1}, @@ -666,6 +677,7 @@ var _L = &RangeTable{ {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, }, LatinOffset: 6, @@ -876,7 +888,7 @@ var _Lm = &RangeTable{ {0x16b40, 0x16b40, 1}, {0x16b41, 0x16b43, 1}, {0x16f93, 0x16f9f, 1}, - {0x16fe0, 0x16fe0, 1}, + {0x16fe0, 0x16fe1, 1}, }, } @@ -902,6 +914,7 @@ var _Lo = &RangeTable{ {0x07cb, 0x07ea, 1}, {0x0800, 0x0815, 1}, {0x0840, 0x0858, 1}, + {0x0860, 0x086a, 1}, {0x08a0, 0x08b4, 1}, {0x08b6, 0x08bd, 1}, {0x0904, 0x0939, 1}, @@ -918,7 +931,8 @@ var _Lo = &RangeTable{ {0x09dc, 0x09dd, 1}, {0x09df, 0x09e1, 1}, {0x09f0, 0x09f1, 1}, - {0x0a05, 0x0a0a, 1}, + {0x09fc, 0x0a05, 9}, + {0x0a06, 0x0a0a, 1}, {0x0a0f, 0x0a10, 1}, {0x0a13, 0x0a28, 1}, {0x0a2a, 0x0a30, 1}, @@ -1086,12 +1100,12 @@ var _Lo = &RangeTable{ {0x309f, 0x30a1, 2}, {0x30a2, 0x30fa, 1}, {0x30ff, 0x3105, 6}, - {0x3106, 0x312d, 1}, + {0x3106, 0x312e, 1}, {0x3131, 0x318e, 1}, {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fd5, 1}, + {0x4e00, 0x9fea, 1}, {0xa000, 0xa014, 1}, {0xa016, 0xa48c, 1}, {0xa4d0, 0xa4f7, 1}, @@ -1174,7 +1188,7 @@ var _Lo = &RangeTable{ {0x10280, 0x1029c, 1}, {0x102a0, 0x102d0, 1}, {0x10300, 0x1031f, 1}, - {0x10330, 0x10340, 1}, + {0x1032d, 0x10340, 1}, {0x10342, 0x10349, 1}, {0x10350, 0x10375, 1}, {0x10380, 0x1039d, 1}, @@ -1249,13 +1263,21 @@ var _Lo = &RangeTable{ {0x11644, 0x11680, 60}, {0x11681, 0x116aa, 1}, {0x11700, 0x11719, 1}, - {0x118ff, 0x11ac0, 449}, - {0x11ac1, 0x11af8, 1}, + {0x118ff, 0x11a00, 257}, + {0x11a0b, 0x11a32, 1}, + {0x11a3a, 0x11a50, 22}, + {0x11a5c, 0x11a83, 1}, + {0x11a86, 0x11a89, 1}, + {0x11ac0, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, {0x11c73, 0x11c8f, 1}, - {0x12000, 0x12399, 1}, + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d30, 1}, + {0x11d46, 0x12000, 698}, + {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, {0x13000, 0x1342e, 1}, {0x14400, 0x14646, 1}, @@ -1269,7 +1291,8 @@ var _Lo = &RangeTable{ {0x16f50, 0x17000, 176}, {0x17001, 0x187ec, 1}, {0x18800, 0x18af2, 1}, - {0x1b000, 0x1b001, 1}, + {0x1b000, 0x1b11e, 1}, + {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, {0x1bc80, 0x1bc88, 1}, @@ -1303,6 +1326,7 @@ var _Lo = &RangeTable{ {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, }, LatinOffset: 1, @@ -1516,6 +1540,7 @@ var _M = &RangeTable{ {0x0ac7, 0x0ac9, 1}, {0x0acb, 0x0acd, 1}, {0x0ae2, 0x0ae3, 1}, + {0x0afa, 0x0aff, 1}, {0x0b01, 0x0b03, 1}, {0x0b3c, 0x0b3e, 2}, {0x0b3f, 0x0b44, 1}, @@ -1541,7 +1566,8 @@ var _M = &RangeTable{ {0x0cca, 0x0ccd, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d01, 0x0d03, 1}, + {0x0d00, 0x0d03, 1}, + {0x0d3b, 0x0d3c, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4d, 1}, @@ -1604,8 +1630,8 @@ var _M = &RangeTable{ {0x1cd4, 0x1ce8, 1}, {0x1ced, 0x1cf2, 5}, {0x1cf3, 0x1cf4, 1}, - {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df5, 1}, + {0x1cf7, 0x1cf9, 1}, + {0x1dc0, 0x1df9, 1}, {0x1dfb, 0x1dff, 1}, {0x20d0, 0x20f0, 1}, {0x2cef, 0x2cf1, 1}, @@ -1684,11 +1710,22 @@ var _M = &RangeTable{ {0x11630, 0x11640, 1}, {0x116ab, 0x116b7, 1}, {0x1171d, 0x1172b, 1}, + {0x11a01, 0x11a0a, 1}, + {0x11a33, 0x11a39, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a47, 0x11a51, 10}, + {0x11a52, 0x11a5b, 1}, + {0x11a8a, 0x11a99, 1}, {0x11c2f, 0x11c36, 1}, {0x11c38, 0x11c3f, 1}, {0x11c92, 0x11ca7, 1}, {0x11ca9, 0x11cb6, 1}, - {0x16af0, 0x16af4, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d45, 1}, + {0x11d47, 0x16af0, 19881}, + {0x16af1, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f51, 0x16f7e, 1}, {0x16f8f, 0x16f92, 1}, @@ -1794,11 +1831,12 @@ var _Mc = &RangeTable{ {0x1c25, 0x1c2b, 1}, {0x1c34, 0x1c35, 1}, {0x1ce1, 0x1cf2, 17}, - {0x1cf3, 0x302e, 4923}, - {0x302f, 0xa823, 30708}, - {0xa824, 0xa827, 3}, - {0xa880, 0xa881, 1}, - {0xa8b4, 0xa8c3, 1}, + {0x1cf3, 0x1cf7, 4}, + {0x302e, 0x302f, 1}, + {0xa823, 0xa824, 1}, + {0xa827, 0xa880, 89}, + {0xa881, 0xa8b4, 51}, + {0xa8b5, 0xa8c3, 1}, {0xa952, 0xa953, 1}, {0xa983, 0xa9b4, 49}, {0xa9b5, 0xa9ba, 5}, @@ -1849,6 +1887,9 @@ var _Mc = &RangeTable{ {0x116ae, 0x116af, 1}, {0x116b6, 0x11720, 106}, {0x11721, 0x11726, 5}, + {0x11a07, 0x11a08, 1}, + {0x11a39, 0x11a57, 30}, + {0x11a58, 0x11a97, 63}, {0x11c2f, 0x11c3e, 15}, {0x11ca9, 0x11cb1, 8}, {0x11cb4, 0x16f51, 21149}, @@ -1914,9 +1955,11 @@ var _Mn = &RangeTable{ {0x0ac2, 0x0ac5, 1}, {0x0ac7, 0x0ac8, 1}, {0x0acd, 0x0ae2, 21}, - {0x0ae3, 0x0b01, 30}, - {0x0b3c, 0x0b3f, 3}, - {0x0b41, 0x0b44, 1}, + {0x0ae3, 0x0afa, 23}, + {0x0afb, 0x0aff, 1}, + {0x0b01, 0x0b3c, 59}, + {0x0b3f, 0x0b41, 2}, + {0x0b42, 0x0b44, 1}, {0x0b4d, 0x0b56, 9}, {0x0b62, 0x0b63, 1}, {0x0b82, 0x0bc0, 62}, @@ -1930,8 +1973,9 @@ var _Mn = &RangeTable{ {0x0cbf, 0x0cc6, 7}, {0x0ccc, 0x0ccd, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d01, 0x0d41, 64}, - {0x0d42, 0x0d44, 1}, + {0x0d00, 0x0d01, 1}, + {0x0d3b, 0x0d3c, 1}, + {0x0d41, 0x0d44, 1}, {0x0d4d, 0x0d62, 21}, {0x0d63, 0x0dca, 103}, {0x0dd2, 0x0dd4, 1}, @@ -2004,7 +2048,7 @@ var _Mn = &RangeTable{ {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df5, 1}, + {0x1dc0, 0x1df9, 1}, {0x1dfb, 0x1dff, 1}, {0x20d0, 0x20dc, 1}, {0x20e1, 0x20e5, 4}, @@ -2093,6 +2137,15 @@ var _Mn = &RangeTable{ {0x1171e, 0x1171f, 1}, {0x11722, 0x11725, 1}, {0x11727, 0x1172b, 1}, + {0x11a01, 0x11a06, 1}, + {0x11a09, 0x11a0a, 1}, + {0x11a33, 0x11a38, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a47, 0x11a51, 10}, + {0x11a52, 0x11a56, 1}, + {0x11a59, 0x11a5b, 1}, + {0x11a8a, 0x11a96, 1}, + {0x11a98, 0x11a99, 1}, {0x11c30, 0x11c36, 1}, {0x11c38, 0x11c3d, 1}, {0x11c3f, 0x11c92, 83}, @@ -2100,7 +2153,12 @@ var _Mn = &RangeTable{ {0x11caa, 0x11cb0, 1}, {0x11cb2, 0x11cb3, 1}, {0x11cb5, 0x11cb6, 1}, - {0x16af0, 0x16af4, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3c, 2}, + {0x11d3d, 0x11d3f, 2}, + {0x11d40, 0x11d45, 1}, + {0x11d47, 0x16af0, 19881}, + {0x16af1, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f8f, 0x16f92, 1}, {0x1bc9d, 0x1bc9e, 1}, @@ -2233,6 +2291,7 @@ var _N = &RangeTable{ {0x11730, 0x1173b, 1}, {0x118e0, 0x118f2, 1}, {0x11c50, 0x11c6c, 1}, + {0x11d50, 0x11d59, 1}, {0x12400, 0x1246e, 1}, {0x16a60, 0x16a69, 1}, {0x16b50, 0x16b59, 1}, @@ -2300,6 +2359,7 @@ var _Nd = &RangeTable{ {0x11730, 0x11739, 1}, {0x118e0, 0x118e9, 1}, {0x11c50, 0x11c59, 1}, + {0x11d50, 0x11d59, 1}, {0x16a60, 0x16a69, 1}, {0x16b50, 0x16b59, 1}, {0x1d7ce, 0x1d7ff, 1}, @@ -2423,10 +2483,10 @@ var _P = &RangeTable{ {0x0830, 0x083e, 1}, {0x085e, 0x0964, 262}, {0x0965, 0x0970, 11}, - {0x0af0, 0x0df4, 772}, - {0x0e4f, 0x0e5a, 11}, - {0x0e5b, 0x0f04, 169}, - {0x0f05, 0x0f12, 1}, + {0x09fd, 0x0af0, 243}, + {0x0df4, 0x0e4f, 91}, + {0x0e5a, 0x0e5b, 1}, + {0x0f04, 0x0f12, 1}, {0x0f14, 0x0f3a, 38}, {0x0f3b, 0x0f3d, 1}, {0x0f85, 0x0fd0, 75}, @@ -2471,7 +2531,7 @@ var _P = &RangeTable{ {0x2cfe, 0x2cff, 1}, {0x2d70, 0x2e00, 144}, {0x2e01, 0x2e2e, 1}, - {0x2e30, 0x2e44, 1}, + {0x2e30, 0x2e49, 1}, {0x3001, 0x3003, 1}, {0x3008, 0x3011, 1}, {0x3014, 0x301f, 1}, @@ -2535,6 +2595,9 @@ var _P = &RangeTable{ {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, {0x1173c, 0x1173e, 1}, + {0x11a3f, 0x11a46, 1}, + {0x11a9a, 0x11a9c, 1}, + {0x11a9e, 0x11aa2, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x12470, 0x12474, 1}, @@ -2650,10 +2713,10 @@ var _Po = &RangeTable{ {0x0830, 0x083e, 1}, {0x085e, 0x0964, 262}, {0x0965, 0x0970, 11}, - {0x0af0, 0x0df4, 772}, - {0x0e4f, 0x0e5a, 11}, - {0x0e5b, 0x0f04, 169}, - {0x0f05, 0x0f12, 1}, + {0x09fd, 0x0af0, 243}, + {0x0df4, 0x0e4f, 91}, + {0x0e5a, 0x0e5b, 1}, + {0x0f04, 0x0f12, 1}, {0x0f14, 0x0f85, 113}, {0x0fd0, 0x0fd4, 1}, {0x0fd9, 0x0fda, 1}, @@ -2699,8 +2762,8 @@ var _Po = &RangeTable{ {0x2e30, 0x2e39, 1}, {0x2e3c, 0x2e3f, 1}, {0x2e41, 0x2e43, 2}, - {0x2e44, 0x3001, 445}, - {0x3002, 0x3003, 1}, + {0x2e44, 0x2e49, 1}, + {0x3001, 0x3003, 1}, {0x303d, 0x30fb, 190}, {0xa4fe, 0xa4ff, 1}, {0xa60d, 0xa60f, 1}, @@ -2763,6 +2826,9 @@ var _Po = &RangeTable{ {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, {0x1173c, 0x1173e, 1}, + {0x11a3f, 0x11a46, 1}, + {0x11a9a, 0x11a9c, 1}, + {0x11a9e, 0x11aa2, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x12470, 0x12474, 1}, @@ -2863,7 +2929,7 @@ var _S = &RangeTable{ {0x2044, 0x2052, 14}, {0x207a, 0x207c, 1}, {0x208a, 0x208c, 1}, - {0x20a0, 0x20be, 1}, + {0x20a0, 0x20bf, 1}, {0x2100, 0x2101, 1}, {0x2103, 0x2106, 1}, {0x2108, 0x2109, 1}, @@ -2879,8 +2945,7 @@ var _S = &RangeTable{ {0x218b, 0x2190, 5}, {0x2191, 0x2307, 1}, {0x230c, 0x2328, 1}, - {0x232b, 0x23fe, 1}, - {0x2400, 0x2426, 1}, + {0x232b, 0x2426, 1}, {0x2440, 0x244a, 1}, {0x249c, 0x24e9, 1}, {0x2500, 0x2767, 1}, @@ -2893,7 +2958,7 @@ var _S = &RangeTable{ {0x2b76, 0x2b95, 1}, {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, - {0x2bca, 0x2bd1, 1}, + {0x2bca, 0x2bd2, 1}, {0x2bec, 0x2bef, 1}, {0x2ce5, 0x2cea, 1}, {0x2e80, 0x2e99, 1}, @@ -2982,9 +3047,10 @@ var _S = &RangeTable{ {0x1f210, 0x1f23b, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, - {0x1f300, 0x1f6d2, 1}, + {0x1f260, 0x1f265, 1}, + {0x1f300, 0x1f6d4, 1}, {0x1f6e0, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6f6, 1}, + {0x1f6f0, 0x1f6f8, 1}, {0x1f700, 0x1f773, 1}, {0x1f780, 0x1f7d4, 1}, {0x1f800, 0x1f80b, 1}, @@ -2992,14 +3058,13 @@ var _S = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, - {0x1f910, 0x1f91e, 1}, - {0x1f920, 0x1f927, 1}, - {0x1f930, 0x1f933, 3}, - {0x1f934, 0x1f93e, 1}, - {0x1f940, 0x1f94b, 1}, - {0x1f950, 0x1f95e, 1}, - {0x1f980, 0x1f991, 1}, - {0x1f9c0, 0x1f9c0, 1}, + {0x1f900, 0x1f90b, 1}, + {0x1f910, 0x1f93e, 1}, + {0x1f940, 0x1f94c, 1}, + {0x1f950, 0x1f96b, 1}, + {0x1f980, 0x1f997, 1}, + {0x1f9c0, 0x1f9d0, 16}, + {0x1f9d1, 0x1f9e6, 1}, }, LatinOffset: 10, } @@ -3013,7 +3078,7 @@ var _Sc = &RangeTable{ {0x09fb, 0x0af1, 246}, {0x0bf9, 0x0e3f, 582}, {0x17db, 0x20a0, 2245}, - {0x20a1, 0x20be, 1}, + {0x20a1, 0x20bf, 1}, {0xa838, 0xfdfc, 21956}, {0xfe69, 0xff04, 155}, {0xffe0, 0xffe1, 1}, @@ -3167,8 +3232,7 @@ var _So = &RangeTable{ {0x232b, 0x237b, 1}, {0x237d, 0x239a, 1}, {0x23b4, 0x23db, 1}, - {0x23e2, 0x23fe, 1}, - {0x2400, 0x2426, 1}, + {0x23e2, 0x2426, 1}, {0x2440, 0x244a, 1}, {0x249c, 0x24e9, 1}, {0x2500, 0x25b6, 1}, @@ -3184,7 +3248,7 @@ var _So = &RangeTable{ {0x2b76, 0x2b95, 1}, {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, - {0x2bca, 0x2bd1, 1}, + {0x2bca, 0x2bd2, 1}, {0x2bec, 0x2bef, 1}, {0x2ce5, 0x2cea, 1}, {0x2e80, 0x2e99, 1}, @@ -3256,10 +3320,11 @@ var _So = &RangeTable{ {0x1f210, 0x1f23b, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, + {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f3fa, 1}, - {0x1f400, 0x1f6d2, 1}, + {0x1f400, 0x1f6d4, 1}, {0x1f6e0, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6f6, 1}, + {0x1f6f0, 0x1f6f8, 1}, {0x1f700, 0x1f773, 1}, {0x1f780, 0x1f7d4, 1}, {0x1f800, 0x1f80b, 1}, @@ -3267,14 +3332,13 @@ var _So = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, - {0x1f910, 0x1f91e, 1}, - {0x1f920, 0x1f927, 1}, - {0x1f930, 0x1f933, 3}, - {0x1f934, 0x1f93e, 1}, - {0x1f940, 0x1f94b, 1}, - {0x1f950, 0x1f95e, 1}, - {0x1f980, 0x1f991, 1}, - {0x1f9c0, 0x1f9c0, 1}, + {0x1f900, 0x1f90b, 1}, + {0x1f910, 0x1f93e, 1}, + {0x1f940, 0x1f94c, 1}, + {0x1f950, 0x1f96b, 1}, + {0x1f980, 0x1f997, 1}, + {0x1f9c0, 0x1f9d0, 16}, + {0x1f9d1, 0x1f9e6, 1}, }, LatinOffset: 2, } @@ -3366,7 +3430,7 @@ var ( ) // Generated by running -// maketables --scripts=all --url=http://www.unicode.org/Public/9.0.0/ucd/ +// maketables --scripts=all --url=http://www.unicode.org/Public/10.0.0/ucd/ // DO NOT EDIT // Scripts is the set of Unicode script tables. @@ -3445,6 +3509,7 @@ var Scripts = map[string]*RangeTable{ "Mandaic": Mandaic, "Manichaean": Manichaean, "Marchen": Marchen, + "Masaram_Gondi": Masaram_Gondi, "Meetei_Mayek": Meetei_Mayek, "Mende_Kikakui": Mende_Kikakui, "Meroitic_Cursive": Meroitic_Cursive, @@ -3459,6 +3524,7 @@ var Scripts = map[string]*RangeTable{ "New_Tai_Lue": New_Tai_Lue, "Newa": Newa, "Nko": Nko, + "Nushu": Nushu, "Ogham": Ogham, "Ol_Chiki": Ol_Chiki, "Old_Hungarian": Old_Hungarian, @@ -3487,6 +3553,7 @@ var Scripts = map[string]*RangeTable{ "SignWriting": SignWriting, "Sinhala": Sinhala, "Sora_Sompeng": Sora_Sompeng, + "Soyombo": Soyombo, "Sundanese": Sundanese, "Syloti_Nagri": Syloti_Nagri, "Syriac": Syriac, @@ -3508,6 +3575,7 @@ var Scripts = map[string]*RangeTable{ "Vai": Vai, "Warang_Citi": Warang_Citi, "Yi": Yi, + "Zanabazar_Square": Zanabazar_Square, } var _Adlam = &RangeTable{ @@ -3540,6 +3608,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}, @@ -3663,7 +3732,7 @@ var _Bengali = &RangeTable{ {0x09d7, 0x09d7, 1}, {0x09dc, 0x09dd, 1}, {0x09df, 0x09e3, 1}, - {0x09e6, 0x09fb, 1}, + {0x09e6, 0x09fd, 1}, }, } @@ -3680,7 +3749,7 @@ var _Bhaiksuki = &RangeTable{ var _Bopomofo = &RangeTable{ R16: []Range16{ {0x02ea, 0x02eb, 1}, - {0x3105, 0x312d, 1}, + {0x3105, 0x312e, 1}, {0x31a0, 0x31ba, 1}, }, } @@ -3779,7 +3848,7 @@ var _Common = &RangeTable{ {0x0589, 0x0589, 1}, {0x0605, 0x0605, 1}, {0x060c, 0x060c, 1}, - {0x061b, 0x061c, 1}, + {0x061b, 0x061b, 1}, {0x061f, 0x061f, 1}, {0x0640, 0x0640, 1}, {0x06dd, 0x06dd, 1}, @@ -3796,30 +3865,29 @@ var _Common = &RangeTable{ {0x1ce1, 0x1ce1, 1}, {0x1ce9, 0x1cec, 1}, {0x1cee, 0x1cf3, 1}, - {0x1cf5, 0x1cf6, 1}, + {0x1cf5, 0x1cf7, 1}, {0x2000, 0x200b, 1}, {0x200e, 0x2064, 1}, {0x2066, 0x2070, 1}, {0x2074, 0x207e, 1}, {0x2080, 0x208e, 1}, - {0x20a0, 0x20be, 1}, + {0x20a0, 0x20bf, 1}, {0x2100, 0x2125, 1}, {0x2127, 0x2129, 1}, {0x212c, 0x2131, 1}, {0x2133, 0x214d, 1}, {0x214f, 0x215f, 1}, {0x2189, 0x218b, 1}, - {0x2190, 0x23fe, 1}, - {0x2400, 0x2426, 1}, + {0x2190, 0x2426, 1}, {0x2440, 0x244a, 1}, {0x2460, 0x27ff, 1}, {0x2900, 0x2b73, 1}, {0x2b76, 0x2b95, 1}, {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, - {0x2bca, 0x2bd1, 1}, + {0x2bca, 0x2bd2, 1}, {0x2bec, 0x2bef, 1}, - {0x2e00, 0x2e44, 1}, + {0x2e00, 0x2e49, 1}, {0x2ff0, 0x2ffb, 1}, {0x3000, 0x3004, 1}, {0x3006, 0x3006, 1}, @@ -3909,9 +3977,10 @@ var _Common = &RangeTable{ {0x1f210, 0x1f23b, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, - {0x1f300, 0x1f6d2, 1}, + {0x1f260, 0x1f265, 1}, + {0x1f300, 0x1f6d4, 1}, {0x1f6e0, 0x1f6ec, 1}, - {0x1f6f0, 0x1f6f6, 1}, + {0x1f6f0, 0x1f6f8, 1}, {0x1f700, 0x1f773, 1}, {0x1f780, 0x1f7d4, 1}, {0x1f800, 0x1f80b, 1}, @@ -3919,14 +3988,13 @@ var _Common = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, - {0x1f910, 0x1f91e, 1}, - {0x1f920, 0x1f927, 1}, - {0x1f930, 0x1f930, 1}, - {0x1f933, 0x1f93e, 1}, - {0x1f940, 0x1f94b, 1}, - {0x1f950, 0x1f95e, 1}, - {0x1f980, 0x1f991, 1}, + {0x1f900, 0x1f90b, 1}, + {0x1f910, 0x1f93e, 1}, + {0x1f940, 0x1f94c, 1}, + {0x1f950, 0x1f96b, 1}, + {0x1f980, 0x1f997, 1}, {0x1f9c0, 0x1f9c0, 1}, + {0x1f9d0, 0x1f9e6, 1}, {0xe0001, 0xe0001, 1}, {0xe0020, 0xe007f, 1}, }, @@ -4167,7 +4235,7 @@ var _Gujarati = &RangeTable{ {0x0ad0, 0x0ad0, 1}, {0x0ae0, 0x0ae3, 1}, {0x0ae6, 0x0af1, 1}, - {0x0af9, 0x0af9, 1}, + {0x0af9, 0x0aff, 1}, }, } @@ -4202,7 +4270,7 @@ var _Han = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303b, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fd5, 1}, + {0x4e00, 0x9fea, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, @@ -4211,6 +4279,7 @@ var _Han = &RangeTable{ {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, }, } @@ -4269,7 +4338,7 @@ var _Hiragana = &RangeTable{ {0x309d, 0x309f, 1}, }, R32: []Range32{ - {0x1b001, 0x1b001, 1}, + {0x1b001, 0x1b11e, 1}, {0x1f200, 0x1f200, 1}, }, } @@ -4296,7 +4365,7 @@ var _Inherited = &RangeTable{ {0x1ced, 0x1ced, 1}, {0x1cf4, 0x1cf4, 1}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df5, 1}, + {0x1dc0, 0x1df9, 1}, {0x1dfb, 0x1dff, 1}, {0x200c, 0x200d, 1}, {0x20d0, 0x20f0, 1}, @@ -4557,11 +4626,10 @@ var _Mahajani = &RangeTable{ var _Malayalam = &RangeTable{ R16: []Range16{ - {0x0d01, 0x0d03, 1}, + {0x0d00, 0x0d03, 1}, {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d3a, 1}, - {0x0d3d, 0x0d44, 1}, + {0x0d12, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4f, 1}, {0x0d54, 0x0d63, 1}, @@ -4593,6 +4661,19 @@ var _Marchen = &RangeTable{ }, } +var _Masaram_Gondi = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11d00, 0x11d06, 1}, + {0x11d08, 0x11d09, 1}, + {0x11d0b, 0x11d36, 1}, + {0x11d3a, 0x11d3a, 1}, + {0x11d3c, 0x11d3d, 1}, + {0x11d3f, 0x11d47, 1}, + {0x11d50, 0x11d59, 1}, + }, +} + var _Meetei_Mayek = &RangeTable{ R16: []Range16{ {0xaae0, 0xaaf6, 1}, @@ -4716,6 +4797,14 @@ var _Nko = &RangeTable{ }, } +var _Nushu = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x16fe1, 0x16fe1, 1}, + {0x1b170, 0x1b2fb, 1}, + }, +} + var _Ogham = &RangeTable{ R16: []Range16{ {0x1680, 0x169c, 1}, @@ -4741,6 +4830,7 @@ var _Old_Italic = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x10300, 0x10323, 1}, + {0x1032d, 0x1032f, 1}, }, } @@ -4951,6 +5041,15 @@ var _Sora_Sompeng = &RangeTable{ }, } +var _Soyombo = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11a50, 0x11a83, 1}, + {0x11a86, 0x11a9c, 1}, + {0x11a9e, 0x11aa2, 1}, + }, +} + var _Sundanese = &RangeTable{ R16: []Range16{ {0x1b80, 0x1bbf, 1}, @@ -4969,6 +5068,7 @@ var _Syriac = &RangeTable{ {0x0700, 0x070d, 1}, {0x070f, 0x074a, 1}, {0x074d, 0x074f, 1}, + {0x0860, 0x086a, 1}, }, } @@ -5137,6 +5237,13 @@ var _Yi = &RangeTable{ }, } +var _Zanabazar_Square = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11a00, 0x11a47, 1}, + }, +} + // These variables have type *RangeTable. var ( Adlam = _Adlam // Adlam is the set of Unicode characters in script Adlam. @@ -5213,6 +5320,7 @@ var ( Mandaic = _Mandaic // Mandaic is the set of Unicode characters in script Mandaic. Manichaean = _Manichaean // Manichaean is the set of Unicode characters in script Manichaean. Marchen = _Marchen // Marchen is the set of Unicode characters in script Marchen. + Masaram_Gondi = _Masaram_Gondi // Masaram_Gondi is the set of Unicode characters in script Masaram_Gondi. Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek. Mende_Kikakui = _Mende_Kikakui // Mende_Kikakui is the set of Unicode characters in script Mende_Kikakui. Meroitic_Cursive = _Meroitic_Cursive // Meroitic_Cursive is the set of Unicode characters in script Meroitic_Cursive. @@ -5227,6 +5335,7 @@ var ( New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue. Newa = _Newa // Newa is the set of Unicode characters in script Newa. Nko = _Nko // Nko is the set of Unicode characters in script Nko. + Nushu = _Nushu // Nushu is the set of Unicode characters in script Nushu. Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham. Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki. Old_Hungarian = _Old_Hungarian // Old_Hungarian is the set of Unicode characters in script Old_Hungarian. @@ -5255,6 +5364,7 @@ var ( SignWriting = _SignWriting // SignWriting is the set of Unicode characters in script SignWriting. Sinhala = _Sinhala // Sinhala is the set of Unicode characters in script Sinhala. Sora_Sompeng = _Sora_Sompeng // Sora_Sompeng is the set of Unicode characters in script Sora_Sompeng. + Soyombo = _Soyombo // Soyombo is the set of Unicode characters in script Soyombo. Sundanese = _Sundanese // Sundanese is the set of Unicode characters in script Sundanese. Syloti_Nagri = _Syloti_Nagri // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri. Syriac = _Syriac // Syriac is the set of Unicode characters in script Syriac. @@ -5276,10 +5386,11 @@ var ( Vai = _Vai // Vai is the set of Unicode characters in script Vai. Warang_Citi = _Warang_Citi // Warang_Citi is the set of Unicode characters in script Warang_Citi. Yi = _Yi // Yi is the set of Unicode characters in script Yi. + Zanabazar_Square = _Zanabazar_Square // Zanabazar_Square is the set of Unicode characters in script Zanabazar_Square. ) // Generated by running -// maketables --props=all --url=http://www.unicode.org/Public/9.0.0/ucd/ +// maketables --props=all --url=http://www.unicode.org/Public/10.0.0/ucd/ // DO NOT EDIT // Properties is the set of Unicode property tables. @@ -5311,6 +5422,7 @@ var Properties = map[string]*RangeTable{ "Prepended_Concatenation_Mark": Prepended_Concatenation_Mark, "Quotation_Mark": Quotation_Mark, "Radical": Radical, + "Regional_Indicator": Regional_Indicator, "Sentence_Terminal": Sentence_Terminal, "STerm": Sentence_Terminal, "Soft_Dotted": Soft_Dotted, @@ -5421,12 +5533,14 @@ var _Diacritic = &RangeTable{ {0x0a4d, 0x0a4d, 1}, {0x0abc, 0x0abc, 1}, {0x0acd, 0x0acd, 1}, + {0x0afd, 0x0aff, 1}, {0x0b3c, 0x0b3c, 1}, {0x0b4d, 0x0b4d, 1}, {0x0bcd, 0x0bcd, 1}, {0x0c4d, 0x0c4d, 1}, {0x0cbc, 0x0cbc, 1}, {0x0ccd, 0x0ccd, 1}, + {0x0d3b, 0x0d3c, 1}, {0x0d4d, 0x0d4d, 1}, {0x0dca, 0x0dca, 1}, {0x0e47, 0x0e4c, 1}, @@ -5460,10 +5574,10 @@ var _Diacritic = &RangeTable{ {0x1cd0, 0x1ce8, 1}, {0x1ced, 0x1ced, 1}, {0x1cf4, 0x1cf4, 1}, - {0x1cf8, 0x1cf9, 1}, + {0x1cf7, 0x1cf9, 1}, {0x1d2c, 0x1d6a, 1}, {0x1dc4, 0x1dcf, 1}, - {0x1df5, 0x1df5, 1}, + {0x1df5, 0x1df9, 1}, {0x1dfd, 0x1dff, 1}, {0x1fbd, 0x1fbd, 1}, {0x1fbf, 0x1fc1, 1}, @@ -5525,7 +5639,12 @@ var _Diacritic = &RangeTable{ {0x1163f, 0x1163f, 1}, {0x116b6, 0x116b7, 1}, {0x1172b, 0x1172b, 1}, + {0x11a34, 0x11a34, 1}, + {0x11a47, 0x11a47, 1}, + {0x11a99, 0x11a99, 1}, {0x11c3f, 0x11c3f, 1}, + {0x11d42, 0x11d42, 1}, + {0x11d44, 0x11d45, 1}, {0x16af0, 0x16af4, 1}, {0x16f8f, 0x16f9f, 1}, {0x1d167, 0x1d169, 1}, @@ -5569,8 +5688,9 @@ var _Extender = &RangeTable{ R32: []Range32{ {0x1135d, 0x1135d, 1}, {0x115c6, 0x115c8, 1}, + {0x11a98, 0x11a98, 1}, {0x16b42, 0x16b43, 1}, - {0x16fe0, 0x16fe0, 1}, + {0x16fe0, 0x16fe1, 1}, {0x1e944, 0x1e946, 1}, }, LatinOffset: 1, @@ -5623,17 +5743,19 @@ var _Ideographic = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303a, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fd5, 1}, + {0x4e00, 0x9fea, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, R32: []Range32{ {0x17000, 0x187ec, 1}, {0x18800, 0x18af2, 1}, + {0x1b170, 0x1b2fb, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, }, } @@ -5730,6 +5852,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0ac7, 0x0ac9, 1}, {0x0acb, 0x0acc, 1}, {0x0ae2, 0x0ae3, 1}, + {0x0afa, 0x0afc, 1}, {0x0b01, 0x0b03, 1}, {0x0b3e, 0x0b44, 1}, {0x0b47, 0x0b48, 1}, @@ -5753,7 +5876,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0cca, 0x0ccc, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d01, 0x0d03, 1}, + {0x0d00, 0x0d03, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4c, 1}, @@ -5863,10 +5986,21 @@ var _Other_Alphabetic = &RangeTable{ {0x11640, 0x11640, 1}, {0x116ab, 0x116b5, 1}, {0x1171d, 0x1172a, 1}, + {0x11a01, 0x11a0a, 1}, + {0x11a35, 0x11a39, 1}, + {0x11a3b, 0x11a3e, 1}, + {0x11a51, 0x11a5b, 1}, + {0x11a8a, 0x11a97, 1}, {0x11c2f, 0x11c36, 1}, {0x11c38, 0x11c3e, 1}, {0x11c92, 0x11ca7, 1}, {0x11ca9, 0x11cb6, 1}, + {0x11d31, 0x11d36, 1}, + {0x11d3a, 0x11d3a, 1}, + {0x11d3c, 0x11d3d, 1}, + {0x11d3f, 0x11d41, 1}, + {0x11d43, 0x11d43, 1}, + {0x11d47, 0x11d47, 1}, {0x16b30, 0x16b36, 1}, {0x16f51, 0x16f7e, 1}, {0x1bc9e, 0x1bc9e, 1}, @@ -6213,6 +6347,13 @@ var _Radical = &RangeTable{ }, } +var _Regional_Indicator = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1f1e6, 0x1f1ff, 1}, + }, +} + var _Sentence_Terminal = &RangeTable{ R16: []Range16{ {0x0021, 0x0021, 1}, @@ -6276,6 +6417,8 @@ var _Sentence_Terminal = &RangeTable{ {0x115c9, 0x115d7, 1}, {0x11641, 0x11642, 1}, {0x1173c, 0x1173e, 1}, + {0x11a42, 0x11a43, 1}, + {0x11a9b, 0x11a9c, 1}, {0x11c41, 0x11c42, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16af5, 1}, @@ -6415,6 +6558,9 @@ var _Terminal_Punctuation = &RangeTable{ {0x115c9, 0x115d7, 1}, {0x11641, 0x11642, 1}, {0x1173c, 0x1173e, 1}, + {0x11a42, 0x11a43, 1}, + {0x11a9b, 0x11a9c, 1}, + {0x11aa1, 0x11aa2, 1}, {0x11c41, 0x11c43, 1}, {0x11c71, 0x11c71, 1}, {0x12470, 0x12474, 1}, @@ -6431,7 +6577,7 @@ var _Terminal_Punctuation = &RangeTable{ var _Unified_Ideograph = &RangeTable{ R16: []Range16{ {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fd5, 1}, + {0x4e00, 0x9fea, 1}, {0xfa0e, 0xfa0f, 1}, {0xfa11, 0xfa11, 1}, {0xfa13, 0xfa14, 1}, @@ -6445,6 +6591,7 @@ var _Unified_Ideograph = &RangeTable{ {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, + {0x2ceb0, 0x2ebe0, 1}, }, } @@ -6503,6 +6650,7 @@ var ( Prepended_Concatenation_Mark = _Prepended_Concatenation_Mark // Prepended_Concatenation_Mark is the set of Unicode characters with property Prepended_Concatenation_Mark. Quotation_Mark = _Quotation_Mark // Quotation_Mark is the set of Unicode characters with property Quotation_Mark. Radical = _Radical // Radical is the set of Unicode characters with property Radical. + Regional_Indicator = _Regional_Indicator // Regional_Indicator is the set of Unicode characters with property Regional_Indicator. STerm = _Sentence_Terminal // STerm is an alias for Sentence_Terminal. Sentence_Terminal = _Sentence_Terminal // Sentence_Terminal is the set of Unicode characters with property Sentence_Terminal. Soft_Dotted = _Soft_Dotted // Soft_Dotted is the set of Unicode characters with property Soft_Dotted. @@ -6513,7 +6661,7 @@ var ( ) // Generated by running -// maketables --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt +// maketables --data=http://www.unicode.org/Public/10.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/10.0.0/ucd/CaseFolding.txt // DO NOT EDIT // CaseRanges is the table describing case mappings for all letters with @@ -7612,7 +7760,7 @@ var foldInherited = &RangeTable{ }, } -// Range entries: 3576 16-bit, 1454 32-bit, 5030 total. -// Range bytes: 21456 16-bit, 17448 32-bit, 38904 total. +// Range entries: 3587 16-bit, 1554 32-bit, 5141 total. +// Range bytes: 21522 16-bit, 18648 32-bit, 40170 total. // Fold orbit bytes: 88 pairs, 352 bytes diff --git a/libgo/go/unicode/utf8/utf8.go b/libgo/go/unicode/utf8/utf8.go index 6ccd4643738..db845ab2f2d 100644 --- a/libgo/go/unicode/utf8/utf8.go +++ b/libgo/go/unicode/utf8/utf8.go @@ -110,12 +110,10 @@ func FullRune(p []byte) bool { } // Must be short or invalid. accept := acceptRanges[x>>4] - if n > 1 { - if c := p[1]; c < accept.lo || accept.hi < c { - return true - } else if n > 2 && (p[2] < locb || hicb < p[2]) { - return true - } + if n > 1 && (p[1] < accept.lo || accept.hi < p[1]) { + return true + } else if n > 2 && (p[2] < locb || hicb < p[2]) { + return true } return false } @@ -132,12 +130,10 @@ func FullRuneInString(s string) bool { } // Must be short or invalid. accept := acceptRanges[x>>4] - if n > 1 { - if c := s[1]; c < accept.lo || accept.hi < c { - return true - } else if n > 2 && (s[2] < locb || hicb < s[2]) { - return true - } + if n > 1 && (s[1] < accept.lo || accept.hi < s[1]) { + return true + } else if n > 2 && (s[2] < locb || hicb < s[2]) { + return true } return false } diff --git a/libgo/godeps.sh b/libgo/godeps.sh index 87cd09e3d9d..5db96826615 100644 --- a/libgo/godeps.sh +++ b/libgo/godeps.sh @@ -25,9 +25,10 @@ shift files=$* deps=`for f in $files; do cat $f; done | sed -n -e '/^import.*"/p; /^import[ ]*(/,/^)/p' | - sed -e 's/^import //' | + sed -e 's/^import //' -e 's/^[^"]*"/"/' | grep '^[ ]*"' | grep -v '"unsafe"' | + grep -v '%' | sed -e 's/^.*"\([^"]*\)".*$/\1/' -e 's/$/.gox/' | sort -u` diff --git a/libgo/merge.sh b/libgo/merge.sh index 66686654476..4ee57d6486d 100755 --- a/libgo/merge.sh +++ b/libgo/merge.sh @@ -74,13 +74,13 @@ merge() { if ! cmp -s ${old} ${new}; then echo "merge.sh: $name: skipping: exists in old and new git, but not in libgo" fi - continue + return fi if cmp -s ${old} ${libgo}; then # The libgo file is unchanged from the old version. if cmp -s ${new} ${libgo}; then # File is unchanged from old to new version. - continue + return fi # Update file in libgo. echo "merge.sh: $name: updating" @@ -128,7 +128,7 @@ echo ${rev} > VERSION (cd ${NEWDIR}/src && find . -name '*.go' -print) | while read f; do skip=false case "$f" in - ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/internal/browser/* | ./cmd/internal/objabi/*) + ./cmd/cgo/* | ./cmd/go/* | ./cmd/gofmt/* | ./cmd/internal/browser/* | ./cmd/internal/objabi/* | ./cmd/internal/buildid/*) ;; ./cmd/*) skip=true @@ -155,7 +155,7 @@ done ./cmd/*) skip=true ;; - ./runtime/race/*) + ./runtime/race/* | ./runtime/cgo/*) skip=true ;; esac diff --git a/libgo/misc/cgo/errors/errors_test.go b/libgo/misc/cgo/errors/errors_test.go new file mode 100644 index 00000000000..118187f23b8 --- /dev/null +++ b/libgo/misc/cgo/errors/errors_test.go @@ -0,0 +1,161 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package errorstest + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "testing" +) + +func path(file string) string { + return filepath.Join("src", file) +} + +func check(t *testing.T, file string) { + t.Run(file, func(t *testing.T) { + t.Parallel() + + contents, err := ioutil.ReadFile(path(file)) + if err != nil { + t.Fatal(err) + } + var errors []*regexp.Regexp + for i, line := range bytes.Split(contents, []byte("\n")) { + if bytes.HasSuffix(line, []byte("ERROR HERE")) { + re := regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf("%s:%d:", file, i+1))) + errors = append(errors, re) + continue + } + + frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2) + if len(frags) == 1 { + continue + } + re, err := regexp.Compile(string(frags[1])) + if err != nil { + t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1]) + continue + } + errors = append(errors, re) + } + if len(errors) == 0 { + t.Fatalf("cannot find ERROR HERE") + } + expect(t, file, errors) + }) +} + +func expect(t *testing.T, file string, errors []*regexp.Regexp) { + dir, err := ioutil.TempDir("", filepath.Base(t.Name())) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + dst := filepath.Join(dir, strings.TrimSuffix(file, ".go")) + cmd := exec.Command("go", "build", "-gcflags=-L", "-o="+dst, path(file)) // TODO(gri) no need for -gcflags=-L if go tool is adjusted + out, err := cmd.CombinedOutput() + if err == nil { + t.Errorf("expected cgo to fail but it succeeded") + } + + lines := bytes.Split(out, []byte("\n")) + for _, re := range errors { + found := false + for _, line := range lines { + if re.Match(line) { + t.Logf("found match for %#q: %q", re, line) + found = true + break + } + } + if !found { + t.Errorf("expected error output to contain %#q", re) + } + } + + if t.Failed() { + t.Logf("actual output:\n%s", out) + } +} + +func sizeofLongDouble(t *testing.T) int { + cmd := exec.Command("go", "run", path("long_double_size.go")) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out) + } + + i, err := strconv.Atoi(strings.TrimSpace(string(out))) + if err != nil { + t.Fatalf("long_double_size.go printed invalid size: %s", out) + } + return i +} + +func TestReportsTypeErrors(t *testing.T) { + for _, file := range []string{ + "err1.go", + "err2.go", + "err3.go", + "issue7757.go", + "issue8442.go", + "issue11097a.go", + "issue11097b.go", + "issue13129.go", + "issue13423.go", + "issue13467.go", + "issue13635.go", + "issue13830.go", + "issue16116.go", + "issue16591.go", + "issue18452.go", + "issue18889.go", + } { + check(t, file) + } + + if sizeofLongDouble(t) > 8 { + check(t, "err4.go") + } +} + +func TestToleratesOptimizationFlag(t *testing.T) { + for _, cflags := range []string{ + "", + "-O", + } { + cflags := cflags + t.Run(cflags, func(t *testing.T) { + t.Parallel() + + cmd := exec.Command("go", "build", path("issue14669.go")) + cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags) + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out) + } + }) + } +} + +func TestMallocCrashesOnNil(t *testing.T) { + t.Parallel() + + cmd := exec.Command("go", "run", path("malloc.go")) + out, err := cmd.CombinedOutput() + if err == nil { + t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out) + t.Fatalf("succeeded unexpectedly") + } +} diff --git a/libgo/misc/cgo/errors/issue13635.go b/libgo/misc/cgo/errors/issue13635.go deleted file mode 100644 index 0ce2b1e83a1..00000000000 --- a/libgo/misc/cgo/errors/issue13635.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// issue 13635: used to output error about C.unsignedchar. -// This test tests all such types. - -package pkg - -import "C" - -func main() { - var ( - _ C.uchar = "uc" // ERROR HERE - _ C.schar = "sc" // ERROR HERE - _ C.ushort = "us" // ERROR HERE - _ C.uint = "ui" // ERROR HERE - _ C.ulong = "ul" // ERROR HERE - _ C.longlong = "ll" // ERROR HERE - _ C.ulonglong = "ull" // ERROR HERE - _ C.complexfloat = "cf" // ERROR HERE - _ C.complexdouble = "cd" // ERROR HERE - ) -} diff --git a/libgo/misc/cgo/errors/ptr.go b/libgo/misc/cgo/errors/ptr_test.go similarity index 79% rename from libgo/misc/cgo/errors/ptr.go rename to libgo/misc/cgo/errors/ptr_test.go index 3e117666bff..d295a5849db 100644 --- a/libgo/misc/cgo/errors/ptr.go +++ b/libgo/misc/cgo/errors/ptr_test.go @@ -4,20 +4,18 @@ // Tests that cgo detects invalid pointer passing at runtime. -package main +package errorstest import ( "bufio" "bytes" "fmt" - "io" "io/ioutil" "os" "os/exec" "path/filepath" - "runtime" "strings" - "sync" + "testing" ) // ptrTest is the tests without the boilerplate. @@ -344,7 +342,7 @@ var ptrTests = []ptrTest{ fail: false, }, { - // Issue #21306. + // Test preemption while entering a cgo call. Issue #21306. name: "preempt-during-call", c: `void f() {}`, imports: []string{"runtime", "sync"}, @@ -353,219 +351,145 @@ var ptrTests = []ptrTest{ }, } -func main() { - os.Exit(doTests()) +func TestPointerChecks(t *testing.T) { + for _, pt := range ptrTests { + pt := pt + t.Run(pt.name, func(t *testing.T) { + testOne(t, pt) + }) + } } -func doTests() int { - gopath, err := ioutil.TempDir("", "cgoerrors") +func testOne(t *testing.T, pt ptrTest) { + t.Parallel() + + gopath, err := ioutil.TempDir("", filepath.Base(t.Name())) if err != nil { - fmt.Fprintln(os.Stderr, err) - return 2 + t.Fatal(err) } defer os.RemoveAll(gopath) - if err := os.MkdirAll(filepath.Join(gopath, "src"), 0777); err != nil { - fmt.Fprintln(os.Stderr, err) - return 2 - } - - workers := runtime.NumCPU() + 1 - - var wg sync.WaitGroup - c := make(chan int) - errs := make(chan int) - for i := 0; i < workers; i++ { - wg.Add(1) - go func() { - worker(gopath, c, errs) - wg.Done() - }() - } - - for i := range ptrTests { - c <- i - } - close(c) - - go func() { - wg.Wait() - close(errs) - }() - - tot := 0 - for e := range errs { - tot += e - } - return tot -} - -func worker(gopath string, c, errs chan int) { - e := 0 - for i := range c { - if !doOne(gopath, i) { - e++ - } - } - if e > 0 { - errs <- e - } -} - -func doOne(gopath string, i int) bool { - t := &ptrTests[i] - - dir := filepath.Join(gopath, "src", fmt.Sprintf("dir%d", i)) - if err := os.Mkdir(dir, 0777); err != nil { - fmt.Fprintln(os.Stderr, err) - return false + src := filepath.Join(gopath, "src") + if err := os.Mkdir(src, 0777); err != nil { + t.Fatal(err) } - name := filepath.Join(dir, fmt.Sprintf("t%d.go", i)) + name := filepath.Join(src, fmt.Sprintf("%s.go", filepath.Base(t.Name()))) f, err := os.Create(name) if err != nil { - fmt.Fprintln(os.Stderr, err) - return false + t.Fatal(err) } b := bufio.NewWriter(f) fmt.Fprintln(b, `package main`) fmt.Fprintln(b) fmt.Fprintln(b, `/*`) - fmt.Fprintln(b, t.c) + fmt.Fprintln(b, pt.c) fmt.Fprintln(b, `*/`) fmt.Fprintln(b, `import "C"`) fmt.Fprintln(b) - for _, imp := range t.imports { + for _, imp := range pt.imports { fmt.Fprintln(b, `import "`+imp+`"`) } - if len(t.imports) > 0 { + if len(pt.imports) > 0 { fmt.Fprintln(b) } - if len(t.support) > 0 { - fmt.Fprintln(b, t.support) + if len(pt.support) > 0 { + fmt.Fprintln(b, pt.support) fmt.Fprintln(b) } fmt.Fprintln(b, `func main() {`) - fmt.Fprintln(b, t.body) + fmt.Fprintln(b, pt.body) fmt.Fprintln(b, `}`) if err := b.Flush(); err != nil { - fmt.Fprintf(os.Stderr, "flushing %s: %v\n", name, err) - return false + t.Fatalf("flushing %s: %v", name, err) } if err := f.Close(); err != nil { - fmt.Fprintf(os.Stderr, "closing %s: %v\n", name, err) - return false + t.Fatalf("closing %s: %v", name, err) } - for _, e := range t.extra { - if err := ioutil.WriteFile(filepath.Join(dir, e.name), []byte(e.contents), 0644); err != nil { - fmt.Fprintf(os.Stderr, "writing %s: %v\n", e.name, err) - return false + for _, e := range pt.extra { + if err := ioutil.WriteFile(filepath.Join(src, e.name), []byte(e.contents), 0644); err != nil { + t.Fatalf("writing %s: %v", e.name, err) } } - ok := true + args := func(cmd *exec.Cmd) string { + return strings.Join(cmd.Args, " ") + } cmd := exec.Command("go", "build") - cmd.Dir = dir + cmd.Dir = src cmd.Env = addEnv("GOPATH", gopath) buf, err := cmd.CombinedOutput() if err != nil { - fmt.Fprintf(os.Stderr, "test %s failed to build: %v\n%s", t.name, err, buf) - return false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("failed to build: %v", err) } - exe := filepath.Join(dir, filepath.Base(dir)) + exe := filepath.Join(src, filepath.Base(src)) cmd = exec.Command(exe) - cmd.Dir = dir + cmd.Dir = src - if t.expensive { + if pt.expensive { cmd.Env = cgocheckEnv("1") buf, err := cmd.CombinedOutput() if err != nil { - var errbuf bytes.Buffer - if t.fail { - fmt.Fprintf(&errbuf, "test %s marked expensive but failed when not expensive: %v\n", t.name, err) + t.Logf("%#q:\n%s", args(cmd), buf) + if pt.fail { + t.Fatalf("test marked expensive, but failed when not expensive: %v", err) } else { - fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=1: %v\n", t.name, err) + t.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err) } - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false } cmd = exec.Command(exe) - cmd.Dir = dir + cmd.Dir = src } - if t.expensive { + if pt.expensive { cmd.Env = cgocheckEnv("2") } buf, err = cmd.CombinedOutput() - - if t.fail { + if pt.fail { if err == nil { - var errbuf bytes.Buffer - fmt.Fprintf(&errbuf, "test %s did not fail as expected\n", t.name) - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("did not fail as expected") } else if !bytes.Contains(buf, []byte("Go pointer")) { - var errbuf bytes.Buffer - fmt.Fprintf(&errbuf, "test %s output does not contain expected error (failed with %v)\n", t.name, err) - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("did not print expected error (failed with %v)", err) } } else { if err != nil { - var errbuf bytes.Buffer - fmt.Fprintf(&errbuf, "test %s failed unexpectedly: %v\n", t.name, err) - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("failed unexpectedly: %v", err) } - if !t.expensive && ok { + if !pt.expensive { // Make sure it passes with the expensive checks. cmd := exec.Command(exe) - cmd.Dir = dir + cmd.Dir = src cmd.Env = cgocheckEnv("2") buf, err := cmd.CombinedOutput() if err != nil { - var errbuf bytes.Buffer - fmt.Fprintf(&errbuf, "test %s failed unexpectedly with expensive checks: %v\n", t.name, err) - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("failed unexpectedly with expensive checks: %v", err) } } } - if t.fail && ok { + if pt.fail { cmd = exec.Command(exe) - cmd.Dir = dir + cmd.Dir = src cmd.Env = cgocheckEnv("0") buf, err := cmd.CombinedOutput() if err != nil { - var errbuf bytes.Buffer - fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=0: %v\n", t.name, err) - reportTestOutput(&errbuf, t.name, buf) - os.Stderr.Write(errbuf.Bytes()) - ok = false + t.Logf("%#q:\n%s", args(cmd), buf) + t.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err) } } - - return ok -} - -func reportTestOutput(w io.Writer, name string, buf []byte) { - fmt.Fprintf(w, "=== test %s output ===\n", name) - fmt.Fprintf(w, "%s", buf) - fmt.Fprintf(w, "=== end of test %s output ===\n", name) } func cgocheckEnv(val string) []string { diff --git a/libgo/misc/cgo/errors/err1.go b/libgo/misc/cgo/errors/src/err1.go similarity index 100% rename from libgo/misc/cgo/errors/err1.go rename to libgo/misc/cgo/errors/src/err1.go diff --git a/libgo/misc/cgo/errors/err2.go b/libgo/misc/cgo/errors/src/err2.go similarity index 100% rename from libgo/misc/cgo/errors/err2.go rename to libgo/misc/cgo/errors/src/err2.go diff --git a/libgo/misc/cgo/errors/err3.go b/libgo/misc/cgo/errors/src/err3.go similarity index 100% rename from libgo/misc/cgo/errors/err3.go rename to libgo/misc/cgo/errors/src/err3.go diff --git a/libgo/misc/cgo/errors/src/err4.go b/libgo/misc/cgo/errors/src/err4.go new file mode 100644 index 00000000000..8e5f78e987b --- /dev/null +++ b/libgo/misc/cgo/errors/src/err4.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +long double x = 0; +*/ +import "C" + +func main() { + _ = C.x // ERROR HERE + _ = C.x +} diff --git a/libgo/misc/cgo/errors/issue11097a.go b/libgo/misc/cgo/errors/src/issue11097a.go similarity index 100% rename from libgo/misc/cgo/errors/issue11097a.go rename to libgo/misc/cgo/errors/src/issue11097a.go diff --git a/libgo/misc/cgo/errors/issue11097b.go b/libgo/misc/cgo/errors/src/issue11097b.go similarity index 100% rename from libgo/misc/cgo/errors/issue11097b.go rename to libgo/misc/cgo/errors/src/issue11097b.go diff --git a/libgo/misc/cgo/errors/issue13129.go b/libgo/misc/cgo/errors/src/issue13129.go similarity index 88% rename from libgo/misc/cgo/errors/issue13129.go rename to libgo/misc/cgo/errors/src/issue13129.go index f7ad7a7e149..057bce4b829 100644 --- a/libgo/misc/cgo/errors/issue13129.go +++ b/libgo/misc/cgo/errors/src/issue13129.go @@ -10,5 +10,5 @@ import "C" func main() { var x C.ushort - x = int(0) // ERROR HERE + x = int(0) // ERROR HERE: C\.ushort } diff --git a/libgo/misc/cgo/errors/issue13423.go b/libgo/misc/cgo/errors/src/issue13423.go similarity index 100% rename from libgo/misc/cgo/errors/issue13423.go rename to libgo/misc/cgo/errors/src/issue13423.go diff --git a/libgo/misc/cgo/errors/src/issue13467.go b/libgo/misc/cgo/errors/src/issue13467.go new file mode 100644 index 00000000000..e061880ddab --- /dev/null +++ b/libgo/misc/cgo/errors/src/issue13467.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +/* +static int transform(int x) { return x; } +*/ +import "C" + +func F() { + var x rune = '✈' + var _ rune = C.transform(x) // ERROR HERE: C\.int +} diff --git a/libgo/misc/cgo/errors/src/issue13635.go b/libgo/misc/cgo/errors/src/issue13635.go new file mode 100644 index 00000000000..3f38f5df4b5 --- /dev/null +++ b/libgo/misc/cgo/errors/src/issue13635.go @@ -0,0 +1,24 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// issue 13635: used to output error about C.unsignedchar. +// This test tests all such types. + +package pkg + +import "C" + +func main() { + var ( + _ C.uchar = "uc" // ERROR HERE: C\.uchar + _ C.schar = "sc" // ERROR HERE: C\.schar + _ C.ushort = "us" // ERROR HERE: C\.ushort + _ C.uint = "ui" // ERROR HERE: C\.uint + _ C.ulong = "ul" // ERROR HERE: C\.ulong + _ C.longlong = "ll" // ERROR HERE: C\.longlong + _ C.ulonglong = "ull" // ERROR HERE: C\.ulonglong + _ C.complexfloat = "cf" // ERROR HERE: C\.complexfloat + _ C.complexdouble = "cd" // ERROR HERE: C\.complexdouble + ) +} diff --git a/libgo/misc/cgo/errors/issue13830.go b/libgo/misc/cgo/errors/src/issue13830.go similarity index 100% rename from libgo/misc/cgo/errors/issue13830.go rename to libgo/misc/cgo/errors/src/issue13830.go diff --git a/libgo/misc/cgo/errors/issue14669.go b/libgo/misc/cgo/errors/src/issue14669.go similarity index 100% rename from libgo/misc/cgo/errors/issue14669.go rename to libgo/misc/cgo/errors/src/issue14669.go diff --git a/libgo/misc/cgo/errors/issue16116.go b/libgo/misc/cgo/errors/src/issue16116.go similarity index 100% rename from libgo/misc/cgo/errors/issue16116.go rename to libgo/misc/cgo/errors/src/issue16116.go diff --git a/libgo/misc/cgo/errors/issue16591.go b/libgo/misc/cgo/errors/src/issue16591.go similarity index 100% rename from libgo/misc/cgo/errors/issue16591.go rename to libgo/misc/cgo/errors/src/issue16591.go diff --git a/libgo/misc/cgo/errors/issue18452.go b/libgo/misc/cgo/errors/src/issue18452.go similarity index 75% rename from libgo/misc/cgo/errors/issue18452.go rename to libgo/misc/cgo/errors/src/issue18452.go index 36ef7f54e12..0386d768927 100644 --- a/libgo/misc/cgo/errors/issue18452.go +++ b/libgo/misc/cgo/errors/src/issue18452.go @@ -13,6 +13,6 @@ import ( func a() { fmt.Println("Hello, world!") - C.function_that_does_not_exist() // line 16 - C.pi // line 17 + C.function_that_does_not_exist() // ERROR HERE + C.pi // ERROR HERE } diff --git a/libgo/misc/cgo/errors/issue18889.go b/libgo/misc/cgo/errors/src/issue18889.go similarity index 100% rename from libgo/misc/cgo/errors/issue18889.go rename to libgo/misc/cgo/errors/src/issue18889.go diff --git a/libgo/misc/cgo/errors/issue7757.go b/libgo/misc/cgo/errors/src/issue7757.go similarity index 100% rename from libgo/misc/cgo/errors/issue7757.go rename to libgo/misc/cgo/errors/src/issue7757.go diff --git a/libgo/misc/cgo/errors/issue8442.go b/libgo/misc/cgo/errors/src/issue8442.go similarity index 100% rename from libgo/misc/cgo/errors/issue8442.go rename to libgo/misc/cgo/errors/src/issue8442.go diff --git a/libgo/misc/cgo/errors/src/long_double_size.go b/libgo/misc/cgo/errors/src/long_double_size.go new file mode 100644 index 00000000000..8b797f886ae --- /dev/null +++ b/libgo/misc/cgo/errors/src/long_double_size.go @@ -0,0 +1,16 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +const int sizeofLongDouble = sizeof(long double); +*/ +import "C" + +import "fmt" + +func main() { + fmt.Println(C.sizeofLongDouble) +} diff --git a/libgo/misc/cgo/errors/malloc.go b/libgo/misc/cgo/errors/src/malloc.go similarity index 100% rename from libgo/misc/cgo/errors/malloc.go rename to libgo/misc/cgo/errors/src/malloc.go diff --git a/libgo/misc/cgo/errors/test.bash b/libgo/misc/cgo/errors/test.bash deleted file mode 100644 index ed0b0946925..00000000000 --- a/libgo/misc/cgo/errors/test.bash +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env 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. - -check() { - file=$1 - line=$(grep -n 'ERROR HERE' $file | sed 's/:.*//') - if [ "$line" = "" ]; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file - exit 1 - fi - expect $file $file:$line: -} - -expect() { - file=$1 - shift - if go build -gcflags=-C $file >errs 2>&1; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded - exit 1 - fi - if ! test -s errs; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none - exit 1 - fi - for error; do - if ! fgrep $error errs >/dev/null 2>&1; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw: - cat 1>&2 errs - exit 1 - fi - done -} - -check err1.go -check err2.go -check err3.go -check issue7757.go -check issue8442.go -check issue11097a.go -check issue11097b.go -expect issue13129.go C.ushort -check issue13423.go -expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble -check issue13830.go -check issue16116.go -check issue16591.go -check issue18889.go -expect issue18452.go issue18452.go:16 issue18452.go:17 - -if ! go build issue14669.go; then - exit 1 -fi -if ! CGO_CFLAGS="-O" go build issue14669.go; then - exit 1 -fi - -if ! go run ptr.go; then - exit 1 -fi - -# The malloc.go test should crash. -rm -f malloc.out -if go run malloc.go >malloc.out 2>&1; then - echo '`go run malloc.go` succeeded unexpectedly' - cat malloc.out - rm -f malloc.out - exit 1 -fi -rm -f malloc.out - -rm -rf errs _obj -exit 0 diff --git a/libgo/misc/cgo/life/main.go b/libgo/misc/cgo/life/main.go index aa2f6d116b3..45376fd05a9 100644 --- a/libgo/misc/cgo/life/main.go +++ b/libgo/misc/cgo/life/main.go @@ -1,4 +1,4 @@ -// cmpout +// cmpout -tags=use_go_run // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,9 +11,10 @@ package main import ( - "." "flag" "fmt" + + "." ) const MAXDIM = 100 diff --git a/libgo/misc/cgo/stdio/chain.go b/libgo/misc/cgo/stdio/chain.go index 03cddb76888..0fa813cab70 100644 --- a/libgo/misc/cgo/stdio/chain.go +++ b/libgo/misc/cgo/stdio/chain.go @@ -1,4 +1,4 @@ -// cmpout +// cmpout -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/misc/cgo/stdio/fib.go b/libgo/misc/cgo/stdio/fib.go index 61a1b83728c..56e32552ee6 100644 --- a/libgo/misc/cgo/stdio/fib.go +++ b/libgo/misc/cgo/stdio/fib.go @@ -1,4 +1,4 @@ -// cmpout +// cmpout -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/misc/cgo/stdio/hello.go b/libgo/misc/cgo/stdio/hello.go index 47179ba4827..63bff4c617a 100644 --- a/libgo/misc/cgo/stdio/hello.go +++ b/libgo/misc/cgo/stdio/hello.go @@ -1,4 +1,4 @@ -// cmpout +// cmpout -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go index f7cf6f613c4..67abfff2c03 100644 --- a/libgo/misc/cgo/test/cgo_test.go +++ b/libgo/misc/cgo/test/cgo_test.go @@ -80,5 +80,11 @@ func Test20369(t *testing.T) { test20369(t) } func Test18720(t *testing.T) { test18720(t) } func Test20266(t *testing.T) { test20266(t) } func Test20129(t *testing.T) { test20129(t) } +func Test20910(t *testing.T) { test20910(t) } +func Test21708(t *testing.T) { test21708(t) } +func Test21809(t *testing.T) { test21809(t) } +func Test6907(t *testing.T) { test6907(t) } +func Test6907Go(t *testing.T) { test6907Go(t) } +func Test21897(t *testing.T) { test21897(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/libgo/misc/cgo/test/issue18720.go b/libgo/misc/cgo/test/issue18720.go index a93304498e0..3d64003be74 100644 --- a/libgo/misc/cgo/test/issue18720.go +++ b/libgo/misc/cgo/test/issue18720.go @@ -12,13 +12,39 @@ package cgotest struct foo { char c; }; #define SIZE_OF(x) sizeof(x) #define SIZE_OF_FOO SIZE_OF(struct foo) +#define VAR1 VAR +#define VAR var +int var = 5; + +#define ADDR &var + +#define CALL fn() +int fn(void) { + return ++var; +} */ import "C" import "testing" func test18720(t *testing.T) { - if C.HELLO_WORLD != "hello\000world" { - t.Fatalf(`expected "hello\000world", but got %q`, C.HELLO_WORLD) + if got, want := C.HELLO_WORLD, "hello\000world"; got != want { + t.Errorf("C.HELLO_WORLD == %q, expected %q", got, want) + } + + if got, want := C.VAR1, C.int(5); got != want { + t.Errorf("C.VAR1 == %v, expected %v", got, want) + } + + if got, want := *C.ADDR, C.int(5); got != want { + t.Errorf("*C.ADDR == %v, expected %v", got, want) + } + + if got, want := C.CALL, C.int(6); got != want { + t.Errorf("C.CALL == %v, expected %v", got, want) + } + + if got, want := C.CALL, C.int(7); got != want { + t.Errorf("C.CALL == %v, expected %v", got, want) } // Issue 20125. diff --git a/libgo/misc/cgo/test/issue19832.go b/libgo/misc/cgo/test/issue19832.go new file mode 100644 index 00000000000..44587770af4 --- /dev/null +++ b/libgo/misc/cgo/test/issue19832.go @@ -0,0 +1,16 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 19832. Functions taking a pointer typedef were being expanded and triggering a compiler error. + +package cgotest + +// typedef struct { int i; } *PS; +// void T19832(PS p) {} +import "C" +import "testing" + +func test19832(t *testing.T) { + C.T19832(nil) +} diff --git a/libgo/misc/cgo/test/issue20910.c b/libgo/misc/cgo/test/issue20910.c new file mode 100644 index 00000000000..e8d623fc983 --- /dev/null +++ b/libgo/misc/cgo/test/issue20910.c @@ -0,0 +1,19 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include +#include +#include "_cgo_export.h" + +/* Test calling a Go function with multiple return values. */ + +void +callMulti(void) +{ + struct multi_return result = multi(); + assert(strcmp(result.r0, "multi") == 0); + assert(result.r1 == 0); + free(result.r0); +} diff --git a/libgo/misc/cgo/test/issue20910.go b/libgo/misc/cgo/test/issue20910.go new file mode 100644 index 00000000000..69d7d9249ac --- /dev/null +++ b/libgo/misc/cgo/test/issue20910.go @@ -0,0 +1,19 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +//void callMulti(void); +import "C" + +import "testing" + +//export multi +func multi() (*C.char, C.int) { + return C.CString("multi"), 0 +} + +func test20910(t *testing.T) { + C.callMulti() +} diff --git a/libgo/misc/cgo/test/issue21668.go b/libgo/misc/cgo/test/issue21668.go new file mode 100644 index 00000000000..f15b9202acc --- /dev/null +++ b/libgo/misc/cgo/test/issue21668.go @@ -0,0 +1,13 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Fail to guess the kind of the constant "x". +// No runtime test; just make sure it compiles. + +package cgotest + +// const int x = 42; +import "C" + +var issue21668_X = C.x diff --git a/libgo/misc/cgo/test/issue21708.go b/libgo/misc/cgo/test/issue21708.go new file mode 100644 index 00000000000..d413e3c57a9 --- /dev/null +++ b/libgo/misc/cgo/test/issue21708.go @@ -0,0 +1,16 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// #include +// #define CAST_TO_INT64 (int64_t)(-1) +import "C" +import "testing" + +func test21708(t *testing.T) { + if got, want := C.CAST_TO_INT64, -1; got != want { + t.Errorf("C.CAST_TO_INT64 == %v, expected %v", got, want) + } +} diff --git a/libgo/misc/cgo/test/issue21809.go b/libgo/misc/cgo/test/issue21809.go new file mode 100644 index 00000000000..a3a6b88897e --- /dev/null +++ b/libgo/misc/cgo/test/issue21809.go @@ -0,0 +1,45 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// Issue 21809. Compile C `typedef` to go type aliases. + +// typedef long MySigned_t; +// /* tests alias-to-alias */ +// typedef MySigned_t MySigned2_t; +// +// long takes_long(long x) { return x * x; } +// MySigned_t takes_typedef(MySigned_t x) { return x * x; } +import "C" + +import "testing" + +func test21809(t *testing.T) { + longVar := C.long(3) + typedefVar := C.MySigned_t(4) + typedefTypedefVar := C.MySigned2_t(5) + + // all three should be considered identical to `long` + if ret := C.takes_long(longVar); ret != 9 { + t.Errorf("got %v but expected %v", ret, 9) + } + if ret := C.takes_long(typedefVar); ret != 16 { + t.Errorf("got %v but expected %v", ret, 16) + } + if ret := C.takes_long(typedefTypedefVar); ret != 25 { + t.Errorf("got %v but expected %v", ret, 25) + } + + // They should also be identical to the typedef'd type + if ret := C.takes_typedef(longVar); ret != 9 { + t.Errorf("got %v but expected %v", ret, 9) + } + if ret := C.takes_typedef(typedefVar); ret != 16 { + t.Errorf("got %v but expected %v", ret, 16) + } + if ret := C.takes_typedef(typedefTypedefVar); ret != 25 { + t.Errorf("got %v but expected %v", ret, 25) + } +} diff --git a/libgo/misc/cgo/test/issue21897.go b/libgo/misc/cgo/test/issue21897.go new file mode 100644 index 00000000000..d13246bd84a --- /dev/null +++ b/libgo/misc/cgo/test/issue21897.go @@ -0,0 +1,56 @@ +// Copyright 2017 The Go 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,!internal + +package cgotest + +/* +#cgo LDFLAGS: -framework CoreFoundation +#include +*/ +import "C" +import ( + "runtime/debug" + "testing" + "unsafe" +) + +func test21897(t *testing.T) { + // Please write barrier, kick in soon. + defer debug.SetGCPercent(debug.SetGCPercent(1)) + + for i := 0; i < 10000; i++ { + testCFNumberRef() + testCFDateRef() + testCFBooleanRef() + // Allocate some memory, so eventually the write barrier is enabled + // and it will see writes of bad pointers in the test* functions below. + byteSliceSink = make([]byte, 1024) + } +} + +var byteSliceSink []byte + +func testCFNumberRef() { + var v int64 = 0 + xCFNumberRef = C.CFNumberCreate(C.kCFAllocatorSystemDefault, C.kCFNumberSInt64Type, unsafe.Pointer(&v)) + //fmt.Printf("CFNumberRef: %x\n", uintptr(unsafe.Pointer(xCFNumberRef))) +} + +var xCFNumberRef C.CFNumberRef + +func testCFDateRef() { + xCFDateRef = C.CFDateCreate(C.kCFAllocatorSystemDefault, 0) // 0 value is 1 Jan 2001 00:00:00 GMT + //fmt.Printf("CFDateRef: %x\n", uintptr(unsafe.Pointer(xCFDateRef))) +} + +var xCFDateRef C.CFDateRef + +func testCFBooleanRef() { + xCFBooleanRef = C.kCFBooleanFalse + //fmt.Printf("CFBooleanRef: %x\n", uintptr(unsafe.Pointer(xCFBooleanRef))) +} + +var xCFBooleanRef C.CFBooleanRef diff --git a/libgo/misc/cgo/test/issue21897b.go b/libgo/misc/cgo/test/issue21897b.go new file mode 100644 index 00000000000..08b5f4d808e --- /dev/null +++ b/libgo/misc/cgo/test/issue21897b.go @@ -0,0 +1,13 @@ +// Copyright 2017 The Go 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 internal + +package cgotest + +import "testing" + +func test21897(t *testing.T) { + t.Skip("test runs only on darwin+cgo") +} diff --git a/libgo/misc/cgo/test/issue22958.go b/libgo/misc/cgo/test/issue22958.go new file mode 100644 index 00000000000..a5f058fdae1 --- /dev/null +++ b/libgo/misc/cgo/test/issue22958.go @@ -0,0 +1,24 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// Test handling of bitfields. + +/* +typedef struct { + unsigned long long f8 : 8; + unsigned long long f16 : 16; + unsigned long long f24 : 24; + unsigned long long f32 : 32; + unsigned long long f40 : 40; + unsigned long long f48 : 48; + unsigned long long f56 : 56; + unsigned long long f64 : 64; +} issue22958Type; +*/ +import "C" + +// Nothing to run, just make sure this compiles. +var Vissue22958 C.issue22958Type diff --git a/libgo/misc/cgo/test/issue6907.go b/libgo/misc/cgo/test/issue6907.go new file mode 100644 index 00000000000..00495ab8e2e --- /dev/null +++ b/libgo/misc/cgo/test/issue6907.go @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +/* +#include +#include + +char* Issue6907CopyString(_GoString_ s) { + size_t n; + const char *p; + char *r; + + n = _GoStringLen(s); + p = _GoStringPtr(s); + r = malloc(n + 1); + memmove(r, p, n); + r[n] = '\0'; + return r; +} +*/ +import "C" + +import "testing" + +func test6907(t *testing.T) { + want := "yarn" + if got := C.GoString(C.Issue6907CopyString(want)); got != want { + t.Errorf("C.GoString(C.Issue6907CopyString(%q)) == %q, want %q", want, got, want) + } +} diff --git a/libgo/misc/cgo/test/issue6907export.go b/libgo/misc/cgo/test/issue6907export.go new file mode 100644 index 00000000000..d41899e1a62 --- /dev/null +++ b/libgo/misc/cgo/test/issue6907export.go @@ -0,0 +1,30 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +/* +extern int CheckIssue6907C(_GoString_); +*/ +import "C" + +import ( + "testing" +) + +const CString = "C string" + +//export CheckIssue6907Go +func CheckIssue6907Go(s string) C.int { + if s == CString { + return 1 + } + return 0 +} + +func test6907Go(t *testing.T) { + if got := C.CheckIssue6907C(CString); got != 1 { + t.Errorf("C.CheckIssue6907C() == %d, want %d", got, 1) + } +} diff --git a/libgo/misc/cgo/test/issue6907export_c.c b/libgo/misc/cgo/test/issue6907export_c.c new file mode 100644 index 00000000000..9b1a4fc630b --- /dev/null +++ b/libgo/misc/cgo/test/issue6907export_c.c @@ -0,0 +1,11 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include + +#include "_cgo_export.h" + +int CheckIssue6907C(_GoString_ s) { + return CheckIssue6907Go(s); +} diff --git a/libgo/misc/cgo/test/issue7978.go b/libgo/misc/cgo/test/issue7978.go index 7fb62e807ba..b057e3eacb2 100644 --- a/libgo/misc/cgo/test/issue7978.go +++ b/libgo/misc/cgo/test/issue7978.go @@ -44,8 +44,8 @@ static void issue7978c(uint32_t *sync) { import "C" import ( - "os" "runtime" + "runtime/debug" "strings" "sync/atomic" "testing" @@ -114,12 +114,7 @@ func test7978(t *testing.T) { if C.HAS_SYNC_FETCH_AND_ADD == 0 { t.Skip("clang required for __sync_fetch_and_add support on darwin/arm") } - if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { - t.Skip("GOTRACEBACK is not passed on to the exec wrapper") - } - if os.Getenv("GOTRACEBACK") != "2" { - t.Fatalf("GOTRACEBACK must be 2") - } + debug.SetTraceback("2") issue7978sync = 0 go issue7978go() // test in c code, before callback diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go index 4865b806a3e..e3f67955802 100644 --- a/libgo/misc/cgo/testcarchive/carchive_test.go +++ b/libgo/misc/cgo/testcarchive/carchive_test.go @@ -6,6 +6,7 @@ package carchive_test import ( "bufio" + "bytes" "debug/elf" "fmt" "io/ioutil" @@ -139,8 +140,10 @@ func cmdToRun(name string) []string { } func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) { + t.Helper() cmd := exec.Command(buildcmd[0], buildcmd[1:]...) cmd.Env = gopathEnv + t.Log(buildcmd) if out, err := cmd.CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -188,7 +191,7 @@ func TestInstall(t *testing.T) { testInstall(t, "./testp1"+exeSuffix, filepath.Join("pkg", libgodir, libgoa), filepath.Join("pkg", libgodir, "libgo.h"), - "go", "install", "-buildmode=c-archive", "libgo") + "go", "install", "-i", "-buildmode=c-archive", "libgo") // Test building libgo other than installing it. // Header files are now present. @@ -523,7 +526,7 @@ func TestPIE(t *testing.T) { os.RemoveAll("pkg") }() - cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo") + cmd := exec.Command("go", "install", "-i", "-buildmode=c-archive", "libgo") cmd.Env = gopathEnv if out, err := cmd.CombinedOutput(); err != nil { t.Logf("%s", out) @@ -596,6 +599,8 @@ func TestSIGPROF(t *testing.T) { switch GOOS { case "windows", "plan9": t.Skipf("skipping SIGPROF test on %s", GOOS) + case "darwin": + t.Skipf("skipping SIGPROF test on %s; see https://golang.org/issue/19320", GOOS) } t.Parallel() @@ -655,12 +660,29 @@ func TestCompileWithoutShared(t *testing.T) { } exe := "./testnoshared" + exeSuffix - ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a") + + // In some cases, -no-pie is needed here, but not accepted everywhere. First try + // if -no-pie is accepted. See #22126. + ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a") if runtime.Compiler == "gccgo" { ccArgs = append(ccArgs, "-lgo") } t.Log(ccArgs) out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() + + // If -no-pie unrecognized, try -nopie if this is possibly clang + if err != nil && bytes.Contains(out, []byte("unknown")) && !strings.Contains(cc[0], "gcc") { + ccArgs = append(cc, "-o", exe, "-nopie", "main5.c", "libgo2.a") + t.Log(ccArgs) + out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() + } + + // Don't use either -no-pie or -nopie + if err != nil && bytes.Contains(out, []byte("unrecognized")) { + ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a") + t.Log(ccArgs) + out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() + } t.Logf("%s", out) if err != nil { t.Fatal(err) diff --git a/libgo/misc/cgo/testcshared/cshared_test.go b/libgo/misc/cgo/testcshared/cshared_test.go new file mode 100644 index 00000000000..49be0923966 --- /dev/null +++ b/libgo/misc/cgo/testcshared/cshared_test.go @@ -0,0 +1,479 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cshared_test + +import ( + "debug/elf" + "fmt" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "sync" + "testing" + "unicode" +) + +// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)). +var cc []string + +// An environment with GOPATH=$(pwd). +var gopathEnv []string + +// ".exe" on Windows. +var exeSuffix string + +var GOOS, GOARCH, GOROOT string +var installdir, androiddir string +var libSuffix, libgoname string + +func TestMain(m *testing.M) { + GOOS = goEnv("GOOS") + GOARCH = goEnv("GOARCH") + GOROOT = goEnv("GOROOT") + + if _, err := os.Stat(GOROOT); os.IsNotExist(err) { + log.Fatalf("Unable able to find GOROOT at '%s'", GOROOT) + } + + // Directory where cgo headers and outputs will be installed. + // The installation directory format varies depending on the platform. + installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared", GOOS, GOARCH)) + switch GOOS { + case "darwin": + libSuffix = "dylib" + case "windows": + libSuffix = "dll" + default: + libSuffix = "so" + installdir = path.Join("pkg", fmt.Sprintf("%s_%s_testcshared_shared", GOOS, GOARCH)) + } + + androiddir = fmt.Sprintf("/data/local/tmp/testcshared-%d", os.Getpid()) + if GOOS == "android" { + cmd := exec.Command("adb", "shell", "mkdir", "-p", androiddir) + out, err := cmd.CombinedOutput() + if err != nil { + log.Fatalf("setupAndroid failed: %v\n%s\n", err, out) + } + } + + libgoname = "libgo." + libSuffix + + cc = []string{goEnv("CC")} + + out := goEnv("GOGCCFLAGS") + quote := '\000' + start := 0 + lastSpace := true + backslash := false + s := string(out) + for i, c := range s { + if quote == '\000' && unicode.IsSpace(c) { + if !lastSpace { + cc = append(cc, s[start:i]) + lastSpace = true + } + } else { + if lastSpace { + start = i + lastSpace = false + } + if quote == '\000' && !backslash && (c == '"' || c == '\'') { + quote = c + backslash = false + } else if !backslash && quote == c { + quote = '\000' + } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' { + backslash = true + } else { + backslash = false + } + } + } + if !lastSpace { + cc = append(cc, s[start:]) + } + + switch GOOS { + case "darwin": + // For Darwin/ARM. + // TODO(crawshaw): can we do better? + cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) + case "android": + cc = append(cc, "-pie", "-fuse-ld=gold") + } + libgodir := GOOS + "_" + GOARCH + switch GOOS { + case "darwin": + if GOARCH == "arm" || GOARCH == "arm64" { + libgodir += "_shared" + } + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + libgodir += "_shared" + } + cc = append(cc, "-I", filepath.Join("pkg", libgodir)) + + // Build an environment with GOPATH=$(pwd) + dir, err := os.Getwd() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + gopathEnv = append(os.Environ(), "GOPATH="+dir) + + if GOOS == "windows" { + exeSuffix = ".exe" + } + + st := m.Run() + + os.Remove(libgoname) + os.RemoveAll("pkg") + cleanupHeaders() + cleanupAndroid() + + os.Exit(st) +} + +func goEnv(key string) string { + out, err := exec.Command("go", "env", key).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err) + fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr) + os.Exit(2) + } + return strings.TrimSpace(string(out)) +} + +func cmdToRun(name string) string { + return "./" + name + exeSuffix +} + +func adbPush(t *testing.T, filename string) { + if GOOS != "android" { + return + } + args := []string{"adb", "push", filename, fmt.Sprintf("%s/%s", androiddir, filename)} + cmd := exec.Command(args[0], args[1:]...) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("adb command failed: %v\n%s\n", err, out) + } +} + +func adbRun(t *testing.T, env []string, adbargs ...string) string { + if GOOS != "android" { + t.Fatalf("trying to run adb command when operating system is not android.") + } + args := []string{"adb", "shell"} + // Propagate LD_LIBRARY_PATH to the adb shell invocation. + for _, e := range env { + if strings.Index(e, "LD_LIBRARY_PATH=") != -1 { + adbargs = append([]string{e}, adbargs...) + break + } + } + shellcmd := fmt.Sprintf("cd %s; %s", androiddir, strings.Join(adbargs, " ")) + args = append(args, shellcmd) + cmd := exec.Command(args[0], args[1:]...) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("adb command failed: %v\n%s\n", err, out) + } + return strings.Replace(string(out), "\r", "", -1) +} + +func run(t *testing.T, env []string, args ...string) string { + t.Helper() + cmd := exec.Command(args[0], args[1:]...) + cmd.Env = env + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("command failed: %v\n%v\n%s\n", args, err, out) + } else { + t.Logf("run: %v", args) + } + return string(out) +} + +func runExe(t *testing.T, env []string, args ...string) string { + t.Helper() + if GOOS == "android" { + return adbRun(t, env, args...) + } + return run(t, env, args...) +} + +func runCC(t *testing.T, args ...string) string { + t.Helper() + // This function is run in parallel, so append to a copy of cc + // rather than cc itself. + return run(t, nil, append(append([]string(nil), cc...), args...)...) +} + +func createHeaders() error { + args := []string{"go", "install", "-i", "-buildmode=c-shared", + "-installsuffix", "testcshared", "libgo"} + cmd := exec.Command(args[0], args[1:]...) + cmd.Env = gopathEnv + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) + } + + args = []string{"go", "build", "-buildmode=c-shared", + "-installsuffix", "testcshared", + "-o", libgoname, + filepath.Join("src", "libgo", "libgo.go")} + cmd = exec.Command(args[0], args[1:]...) + cmd.Env = gopathEnv + out, err = cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("command failed: %v\n%v\n%s\n", args, err, out) + } + + if GOOS == "android" { + args = []string{"adb", "push", libgoname, fmt.Sprintf("%s/%s", androiddir, libgoname)} + cmd = exec.Command(args[0], args[1:]...) + out, err = cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("adb command failed: %v\n%s\n", err, out) + } + } + + return nil +} + +var ( + headersOnce sync.Once + headersErr error +) + +func createHeadersOnce(t *testing.T) { + headersOnce.Do(func() { + headersErr = createHeaders() + }) + if headersErr != nil { + t.Fatal(headersErr) + } +} + +func cleanupHeaders() { + os.Remove("libgo.h") +} + +func cleanupAndroid() { + if GOOS != "android" { + return + } + cmd := exec.Command("adb", "shell", "rm", "-rf", androiddir) + out, err := cmd.CombinedOutput() + if err != nil { + log.Fatalf("cleanupAndroid failed: %v\n%s\n", err, out) + } +} + +// test0: exported symbols in shared lib are accessible. +func TestExportedSymbols(t *testing.T) { + t.Parallel() + + cmd := "testp0" + bin := cmdToRun(cmd) + + createHeadersOnce(t) + + runCC(t, "-I", installdir, "-o", cmd, "main0.c", libgoname) + adbPush(t, cmd) + + defer os.Remove(bin) + + out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin) + if strings.TrimSpace(out) != "PASS" { + t.Error(out) + } +} + +// test1: shared library can be dynamically loaded and exported symbols are accessible. +func TestExportedSymbolsWithDynamicLoad(t *testing.T) { + t.Parallel() + + if GOOS == "windows" { + t.Logf("Skipping on %s", GOOS) + return + } + + cmd := "testp1" + bin := cmdToRun(cmd) + + createHeadersOnce(t) + + runCC(t, "-o", cmd, "main1.c", "-ldl") + adbPush(t, cmd) + + defer os.Remove(bin) + + out := runExe(t, nil, bin, "./"+libgoname) + if strings.TrimSpace(out) != "PASS" { + t.Error(out) + } +} + +// test2: tests libgo2 which does not export any functions. +func TestUnexportedSymbols(t *testing.T) { + t.Parallel() + + if GOOS == "windows" { + t.Logf("Skipping on %s", GOOS) + return + } + + cmd := "testp2" + bin := cmdToRun(cmd) + libname := "libgo2." + libSuffix + + run(t, + gopathEnv, + "go", "build", + "-buildmode=c-shared", + "-installsuffix", "testcshared", + "-o", libname, "libgo2", + ) + adbPush(t, libname) + + linkFlags := "-Wl,--no-as-needed" + if GOOS == "darwin" { + linkFlags = "" + } + + runCC(t, "-o", cmd, "main2.c", linkFlags, libname) + adbPush(t, cmd) + + defer os.Remove(libname) + defer os.Remove(bin) + + out := runExe(t, append(gopathEnv, "LD_LIBRARY_PATH=."), bin) + + if strings.TrimSpace(out) != "PASS" { + t.Error(out) + } +} + +// test3: tests main.main is exported on android. +func TestMainExportedOnAndroid(t *testing.T) { + t.Parallel() + + switch GOOS { + case "android": + break + default: + t.Logf("Skipping on %s", GOOS) + return + } + + cmd := "testp3" + bin := cmdToRun(cmd) + + createHeadersOnce(t) + + runCC(t, "-o", cmd, "main3.c", "-ldl") + adbPush(t, cmd) + + defer os.Remove(bin) + + out := runExe(t, nil, bin, "./"+libgoname) + if strings.TrimSpace(out) != "PASS" { + t.Error(out) + } +} + +func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) { + libname := pkgname + "." + libSuffix + run(t, + gopathEnv, + "go", "build", + "-buildmode=c-shared", + "-installsuffix", "testcshared", + "-o", libname, pkgname, + ) + adbPush(t, libname) + runCC(t, "-pthread", "-o", cmd, cfile, "-ldl") + adbPush(t, cmd) + + bin := cmdToRun(cmd) + + defer os.Remove(libname) + defer os.Remove(bin) + defer os.Remove(pkgname + ".h") + + out := runExe(t, nil, bin, "./"+libname) + if strings.TrimSpace(out) != "PASS" { + t.Error(run(t, nil, bin, libname, "verbose")) + } +} + +// test4: test signal handlers +func TestSignalHandlers(t *testing.T) { + t.Parallel() + if GOOS == "windows" { + t.Logf("Skipping on %s", GOOS) + return + } + testSignalHandlers(t, "libgo4", "main4.c", "testp4") +} + +// test5: test signal handlers with os/signal.Notify +func TestSignalHandlersWithNotify(t *testing.T) { + t.Parallel() + if GOOS == "windows" { + t.Logf("Skipping on %s", GOOS) + return + } + testSignalHandlers(t, "libgo5", "main5.c", "testp5") +} + +func TestPIE(t *testing.T) { + t.Parallel() + + switch GOOS { + case "linux", "android": + break + default: + t.Logf("Skipping on %s", GOOS) + return + } + + createHeadersOnce(t) + + f, err := elf.Open(libgoname) + if err != nil { + t.Fatalf("elf.Open failed: %v", err) + } + defer f.Close() + + ds := f.SectionByType(elf.SHT_DYNAMIC) + if ds == nil { + t.Fatalf("no SHT_DYNAMIC section") + } + d, err := ds.Data() + if err != nil { + t.Fatalf("can't read SHT_DYNAMIC contents: %v", err) + } + for len(d) > 0 { + var tag elf.DynTag + switch f.Class { + case elf.ELFCLASS32: + tag = elf.DynTag(f.ByteOrder.Uint32(d[:4])) + d = d[8:] + case elf.ELFCLASS64: + tag = elf.DynTag(f.ByteOrder.Uint64(d[:8])) + d = d[16:] + } + if tag == elf.DT_TEXTREL { + t.Fatalf("%s has DT_TEXTREL flag", libgoname) + } + } +} diff --git a/libgo/misc/cgo/testcshared/test.bash b/libgo/misc/cgo/testcshared/test.bash deleted file mode 100644 index 315a0d40367..00000000000 --- a/libgo/misc/cgo/testcshared/test.bash +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2015 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# For testing Android, this script requires adb to push and run compiled -# binaries on a target device. - -set -e - -if [ ! -f src/libgo/libgo.go ]; then - cwd=$(pwd) - echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2 - exit 1 -fi - -goos=$(go env GOOS) -goarch=$(go env GOARCH) -goroot=$(go env GOROOT) -if [ ! -d "$goroot" ]; then - echo 'misc/cgo/testcshared/test.bash cannot find GOROOT' 1>&2 - echo '$GOROOT:' "$GOROOT" 1>&2 - echo 'go env GOROOT:' "$goroot" 1>&2 - exit 1 -fi - -# Directory where cgo headers and outputs will be installed. -# The installation directory format varies depending on the platform. -installdir=pkg/${goos}_${goarch}_testcshared_shared -if [ "${goos}" = "darwin" ]; then - installdir=pkg/${goos}_${goarch}_testcshared -fi - -# Temporary directory on the android device. -androidpath=/data/local/tmp/testcshared-$$ - -function cleanup() { - rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext - rm -f libgo.h libgo4.h libgo5.h - rm -f testp testp2 testp3 testp4 testp5 - rm -rf pkg "${goroot}/${installdir}" - - if [ "$goos" = "android" ]; then - adb shell rm -rf "$androidpath" - fi -} -trap cleanup EXIT - -if [ "$goos" = "android" ]; then - adb shell mkdir -p "$androidpath" -fi - -function run() { - case "$goos" in - "android") - local args=$@ - output=$(adb shell "cd ${androidpath}; $@") - output=$(echo $output|tr -d '\r') - case $output in - *PASS) echo "PASS";; - *) echo "$output";; - esac - ;; - *) - echo $(env $@) - ;; - esac -} - -function binpush() { - bin=${1} - if [ "$goos" = "android" ]; then - adb push "$bin" "${androidpath}/${bin}" 2>/dev/null - fi -} - -rm -rf pkg - -suffix="-installsuffix testcshared" - -libext="so" -if [ "$goos" = "darwin" ]; then - libext="dylib" -fi - -# Create the header files. -GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo - -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go -binpush libgo.$libext - -if [ "$goos" = "linux" ] || [ "$goos" = "android" ] ; then - if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then - echo "libgo.$libext has TEXTREL set" - exit 1 - fi -fi - -GOGCCFLAGS=$(go env GOGCCFLAGS) -if [ "$goos" = "android" ]; then - GOGCCFLAGS="${GOGCCFLAGS} -pie -fuse-ld=gold" -fi - -status=0 - -# test0: exported symbols in shared lib are accessible. -# TODO(iant): using _shared here shouldn't really be necessary. -$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext -binpush testp - -output=$(run LD_LIBRARY_PATH=. ./testp) -if [ "$output" != "PASS" ]; then - echo "FAIL test0 got ${output}" - status=1 -fi - -# test1: shared library can be dynamically loaded and exported symbols are accessible. -$(go env CC) ${GOGCCFLAGS} -o testp main1.c -ldl -binpush testp -output=$(run ./testp ./libgo.$libext) -if [ "$output" != "PASS" ]; then - echo "FAIL test1 got ${output}" - status=1 -fi - -# test2: tests libgo2 which does not export any functions. -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2 -binpush libgo2.$libext -linkflags="-Wl,--no-as-needed" -if [ "$goos" = "darwin" ]; then - linkflags="" -fi -$(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext -binpush testp2 -output=$(run LD_LIBRARY_PATH=. ./testp2) -if [ "$output" != "PASS" ]; then - echo "FAIL test2 got ${output}" - status=1 -fi - -# test3: tests main.main is exported on android. -if [ "$goos" = "android" ]; then - $(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl - binpush testp3 - output=$(run ./testp ./libgo.so) - if [ "$output" != "PASS" ]; then - echo "FAIL test3 got ${output}" - status=1 - fi -fi - -# test4: tests signal handlers -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4 -binpush libgo4.$libext -$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl -binpush testp4 -output=$(run ./testp4 ./libgo4.$libext 2>&1) -if test "$output" != "PASS"; then - echo "FAIL test4 got ${output}" - if test "$goos" != "android"; then - echo "re-running test4 in verbose mode" - ./testp4 ./libgo4.$libext verbose - fi - status=1 -fi - -# test5: tests signal handlers with os/signal.Notify -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5 -binpush libgo5.$libext -$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl -binpush testp5 -output=$(run ./testp5 ./libgo5.$libext 2>&1) -if test "$output" != "PASS"; then - echo "FAIL test5 got ${output}" - if test "$goos" != "android"; then - echo "re-running test5 in verbose mode" - ./testp5 ./libgo5.$libext verbose - fi - status=1 -fi - -if test "$libext" = "dylib"; then - # make sure dylibs are well-formed - if ! otool -l libgo*.dylib >/dev/null; then - status=1 - fi -fi - -if test $status = 0; then - echo "ok" -fi - -exit $status diff --git a/libgo/misc/cgo/testplugin/src/host/host.go b/libgo/misc/cgo/testplugin/src/host/host.go index 898f44efa15..0ca17da3def 100644 --- a/libgo/misc/cgo/testplugin/src/host/host.go +++ b/libgo/misc/cgo/testplugin/src/host/host.go @@ -126,14 +126,24 @@ func main() { log.Fatalf(`plugin1.F()=%d, want 17`, gotf) } - // plugin2 has no exported symbols, only an init function. - if _, err := plugin.Open("plugin2.so"); err != nil { + p2, err := plugin.Open("plugin2.so") + if err != nil { log.Fatalf("plugin.Open failed: %v", err) } + // Check that plugin2's init function was called, and + // that it modifies the same global variable as the host. if got, want := common.X, 2; got != want { log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want) } + _, err = plugin.Open("plugin2-dup.so") + if err == nil { + log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open should have failed`) + } + if s := err.Error(); !strings.Contains(s, "already loaded") { + log.Fatal(`plugin.Open("plugin2.so"): error does not mention "already loaded"`) + } + _, err = plugin.Open("plugin-mismatch.so") if err == nil { log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`) @@ -142,6 +152,24 @@ func main() { log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s) } + _, err = plugin.Open("plugin2-dup.so") + if err == nil { + log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open after bad plugin should have failed`) + } + _, err = plugin.Open("plugin2.so") + if err != nil { + log.Fatalf(`plugin.Open("plugin2.so"): second open with same name failed: %v`, err) + } + + // Test that unexported types with the same names in + // different plugins do not interfere with each other. + // + // See Issue #21386. + UnexportedNameReuse, _ := p.Lookup("UnexportedNameReuse") + UnexportedNameReuse.(func())() + UnexportedNameReuse, _ = p2.Lookup("UnexportedNameReuse") + UnexportedNameReuse.(func())() + testUnnamed() fmt.Println("PASS") diff --git a/libgo/misc/cgo/testplugin/src/issue18584/main.go b/libgo/misc/cgo/testplugin/src/issue18584/main.go new file mode 100644 index 00000000000..c280fd46203 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue18584/main.go @@ -0,0 +1,23 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "plugin" + +func main() { + p, err := plugin.Open("plugin.so") + if err != nil { + panic(err) + } + + sym, err := p.Lookup("G") + if err != nil { + panic(err) + } + g := sym.(func() bool) + if !g() { + panic("expected types to match, Issue #18584") + } +} diff --git a/libgo/misc/cgo/testplugin/src/issue18584/plugin.go b/libgo/misc/cgo/testplugin/src/issue18584/plugin.go new file mode 100644 index 00000000000..be0868d3752 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue18584/plugin.go @@ -0,0 +1,19 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "reflect" + +type C struct { +} + +func F(c *C) *C { + return nil +} + +func G() bool { + var c *C + return reflect.TypeOf(F).Out(0) == reflect.TypeOf(c) +} diff --git a/libgo/misc/cgo/testplugin/src/issue19418/main.go b/libgo/misc/cgo/testplugin/src/issue19418/main.go new file mode 100644 index 00000000000..2ec9f9aaaa2 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue19418/main.go @@ -0,0 +1,29 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "os" + "plugin" +) + +func main() { + p, err := plugin.Open("plugin.so") + if err != nil { + panic(err) + } + + val, err := p.Lookup("Val") + if err != nil { + panic(err) + } + got := *val.(*string) + const want = "linkstr" + if got != want { + fmt.Fprintf(os.Stderr, "issue19418 value is %q, want %q\n", got, want) + os.Exit(2) + } +} diff --git a/libgo/go/internal/cpu/cpu_ppc64.go b/libgo/misc/cgo/testplugin/src/issue19418/plugin.go similarity index 80% rename from libgo/go/internal/cpu/cpu_ppc64.go rename to libgo/misc/cgo/testplugin/src/issue19418/plugin.go index 5b151508479..fe93b161431 100644 --- a/libgo/go/internal/cpu/cpu_ppc64.go +++ b/libgo/misc/cgo/testplugin/src/issue19418/plugin.go @@ -2,6 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package cpu +package main -const CacheLineSize = 128 +var Val = "val-unset" diff --git a/libgo/misc/cgo/testplugin/src/issue19529/plugin.go b/libgo/misc/cgo/testplugin/src/issue19529/plugin.go new file mode 100644 index 00000000000..ad2df6cc7c7 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue19529/plugin.go @@ -0,0 +1,15 @@ +package main + +import ( + "reflect" +) + +type Foo struct { + Bar string `json:"Bar@baz,omitempty"` +} + +func F() { + println(reflect.TypeOf(Foo{}).Field(0).Tag) +} + +func main() {} diff --git a/libgo/misc/cgo/testplugin/src/issue22175/main.go b/libgo/misc/cgo/testplugin/src/issue22175/main.go new file mode 100644 index 00000000000..9be9bab9dc3 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue22175/main.go @@ -0,0 +1,28 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "os" + "plugin" +) + +func main() { + p2, err := plugin.Open("issue22175_plugin1.so") + if err != nil { + panic(err) + } + f, err := p2.Lookup("F") + if err != nil { + panic(err) + } + got := f.(func() int)() + const want = 971 + if got != want { + fmt.Fprintf(os.Stderr, "issue22175: F()=%d, want %d", got, want) + os.Exit(1) + } +} diff --git a/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go b/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go new file mode 100644 index 00000000000..5ae6cb631e7 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue22175/plugin1.go @@ -0,0 +1,21 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "plugin" + +func F() int { + p2, err := plugin.Open("issue22175_plugin2.so") + if err != nil { + panic(err) + } + g, err := p2.Lookup("G") + if err != nil { + panic(err) + } + return g.(func() int)() +} + +func main() {} diff --git a/libgo/go/internal/cpu/cpu_ppc64le.go b/libgo/misc/cgo/testplugin/src/issue22175/plugin2.go similarity index 73% rename from libgo/go/internal/cpu/cpu_ppc64le.go rename to libgo/misc/cgo/testplugin/src/issue22175/plugin2.go index 5b151508479..f387a192e67 100644 --- a/libgo/go/internal/cpu/cpu_ppc64le.go +++ b/libgo/misc/cgo/testplugin/src/issue22175/plugin2.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. -package cpu +package main -const CacheLineSize = 128 +func G() int { return 971 } + +func main() {} diff --git a/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go b/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go new file mode 100644 index 00000000000..6cb186e1003 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue22295.pkg/main.go @@ -0,0 +1,28 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "log" + "plugin" +) + +func main() { + p, err := plugin.Open("issue.22295.so") + if err != nil { + log.Fatal(err) + } + f, err := p.Lookup("F") + if err != nil { + log.Fatal(err) + } + const want = 2503 + got := f.(func() int)() + if got != want { + log.Fatalf("got %d, want %d", got, want) + } +} diff --git a/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go b/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go new file mode 100644 index 00000000000..46b08a405bc --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue22295.pkg/plugin.go @@ -0,0 +1,16 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +var f *int + +func init() { + f = new(int) + *f = 2503 +} + +func F() int { return *f } + +func main() {} diff --git a/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go index edcef2c77e9..0a9fa2f2c1f 100644 --- a/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go +++ b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go @@ -7,7 +7,10 @@ package main // // No C code required. import "C" -import "common" +import ( + "common" + "reflect" +) func F() int { _ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190. @@ -33,6 +36,21 @@ func init() { call(g) } +type sameNameReusedInPlugins struct { + X string +} + +type sameNameHolder struct { + F *sameNameReusedInPlugins +} + +func UnexportedNameReuse() { + h := sameNameHolder{} + v := reflect.ValueOf(&h).Elem().Field(0) + newval := reflect.New(v.Type().Elem()) + v.Set(newval) +} + func main() { panic("plugin1.main called") } diff --git a/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go index 9c507fc3658..a67f2de27a7 100644 --- a/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go +++ b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go @@ -13,6 +13,7 @@ import "C" import ( "common" + "reflect" "strings" ) @@ -22,6 +23,21 @@ func init() { common.X = 2 } +type sameNameReusedInPlugins struct { + X string +} + +type sameNameHolder struct { + F *sameNameReusedInPlugins +} + +func UnexportedNameReuse() { + h := sameNameHolder{} + v := reflect.ValueOf(&h).Elem().Field(0) + newval := reflect.New(v.Type().Elem()) + v.Set(newval) +} + func main() { panic("plugin1.main called") } diff --git a/libgo/misc/cgo/testplugin/test.bash b/libgo/misc/cgo/testplugin/test.bash index 69df5bd2bfa..18e3803bf42 100644 --- a/libgo/misc/cgo/testplugin/test.bash +++ b/libgo/misc/cgo/testplugin/test.bash @@ -15,38 +15,73 @@ goos=$(go env GOOS) goarch=$(go env GOARCH) function cleanup() { - rm -f plugin*.so unnamed*.so iface*.so - rm -rf host pkg sub iface issue18676 issue19534 + rm -f plugin*.so unnamed*.so iface*.so issue* + rm -rf host pkg sub iface } trap cleanup EXIT rm -rf pkg sub mkdir sub -GOPATH=$(pwd) go build -buildmode=plugin plugin1 -GOPATH=$(pwd) go build -buildmode=plugin plugin2 -GOPATH=$(pwd)/altpath go build -buildmode=plugin plugin-mismatch -GOPATH=$(pwd) go build -buildmode=plugin -o=sub/plugin1.so sub/plugin1 -GOPATH=$(pwd) go build -buildmode=plugin unnamed1.go -GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go -GOPATH=$(pwd) go build host +GOPATH=$(pwd) go build -i -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin1 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin2 +cp plugin2.so plugin2-dup.so +GOPATH=$(pwd)/altpath go build -gcflags "$GO_GCFLAGS" -buildmode=plugin plugin-mismatch +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=sub/plugin1.so sub/plugin1 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed1.so unnamed1/main.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed2.so unnamed2/main.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" host LD_LIBRARY_PATH=$(pwd) ./host # Test that types and itabs get properly uniqified. -GOPATH=$(pwd) go build -buildmode=plugin iface_a -GOPATH=$(pwd) go build -buildmode=plugin iface_b -GOPATH=$(pwd) go build iface +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin iface_a +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin iface_b +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" iface LD_LIBRARY_PATH=$(pwd) ./iface +function _timeout() ( + set -e + $2 & + p=$! + (sleep $1; kill $p 2>/dev/null) & + p2=$! + wait $p 2>/dev/null + kill -0 $p2 2>/dev/null +) + # Test for issue 18676 - make sure we don't add the same itab twice. # The buggy code hangs forever, so use a timeout to check for that. -GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go -GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go -timeout 10s ./issue18676 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue18676/plugin.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue18676 src/issue18676/main.go +_timeout 10s ./issue18676 # Test for issue 19534 - that we can load a plugin built in a path with non-alpha # characters -GOPATH=$(pwd) go build -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go -GOPATH=$(pwd) go build -o issue19534 src/issue19534/main.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue19534 src/issue19534/main.go ./issue19534 + +# Test for issue 18584 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue18584/plugin.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue18584 src/issue18584/main.go +./issue18584 + +# Test for issue 19418 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin "-ldflags=-X main.Val=linkstr" -o plugin.so src/issue19418/plugin.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue19418 src/issue19418/main.go +./issue19418 + +# Test for issue 19529 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o plugin.so src/issue19529/plugin.go + +# Test for issue 22175 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue22175_plugin1.so src/issue22175/plugin1.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue22175_plugin2.so src/issue22175/plugin2.go +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.go +./issue22175 + +# Test for issue 22295 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go +./issue22295 diff --git a/libgo/misc/cgo/testplugin/unnamed1.go b/libgo/misc/cgo/testplugin/unnamed1/main.go similarity index 100% rename from libgo/misc/cgo/testplugin/unnamed1.go rename to libgo/misc/cgo/testplugin/unnamed1/main.go diff --git a/libgo/misc/cgo/testplugin/unnamed2.go b/libgo/misc/cgo/testplugin/unnamed2/main.go similarity index 100% rename from libgo/misc/cgo/testplugin/unnamed2.go rename to libgo/misc/cgo/testplugin/unnamed2/main.go diff --git a/libgo/misc/cgo/testsanitizers/cc_test.go b/libgo/misc/cgo/testsanitizers/cc_test.go new file mode 100644 index 00000000000..cacb0d93df7 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/cc_test.go @@ -0,0 +1,441 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// sanitizers_test checks the use of Go with sanitizers like msan, asan, etc. +// See https://github.com/google/sanitizers. +package sanitizers_test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "sync" + "syscall" + "testing" + "unicode" +) + +var overcommit struct { + sync.Once + value int + err error +} + +// requireOvercommit skips t if the kernel does not allow overcommit. +func requireOvercommit(t *testing.T) { + t.Helper() + + overcommit.Once.Do(func() { + var out []byte + out, overcommit.err = ioutil.ReadFile("/proc/sys/vm/overcommit_memory") + if overcommit.err != nil { + return + } + overcommit.value, overcommit.err = strconv.Atoi(string(bytes.TrimSpace(out))) + }) + + if overcommit.err != nil { + t.Skipf("couldn't determine vm.overcommit_memory (%v); assuming no overcommit", overcommit.err) + } + if overcommit.value == 2 { + t.Skip("vm.overcommit_memory=2") + } +} + +var env struct { + sync.Once + m map[string]string + err error +} + +// goEnv returns the output of $(go env) as a map. +func goEnv(key string) (string, error) { + env.Once.Do(func() { + var out []byte + out, env.err = exec.Command("go", "env", "-json").Output() + if env.err != nil { + return + } + + env.m = make(map[string]string) + env.err = json.Unmarshal(out, &env.m) + }) + if env.err != nil { + return "", env.err + } + + v, ok := env.m[key] + if !ok { + return "", fmt.Errorf("`go env`: no entry for %v", key) + } + return v, nil +} + +// replaceEnv sets the key environment variable to value in cmd. +func replaceEnv(cmd *exec.Cmd, key, value string) { + if cmd.Env == nil { + cmd.Env = os.Environ() + } + cmd.Env = append(cmd.Env, key+"="+value) +} + +// mustRun executes t and fails cmd with a well-formatted message if it fails. +func mustRun(t *testing.T, cmd *exec.Cmd) { + t.Helper() + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out) + } +} + +// cc returns a cmd that executes `$(go env CC) $(go env GOGCCFLAGS) $args`. +func cc(args ...string) (*exec.Cmd, error) { + CC, err := goEnv("CC") + if err != nil { + return nil, err + } + + GOGCCFLAGS, err := goEnv("GOGCCFLAGS") + if err != nil { + return nil, err + } + + // Split GOGCCFLAGS, respecting quoting. + // + // TODO(bcmills): This code also appears in + // misc/cgo/testcarchive/carchive_test.go, and perhaps ought to go in + // src/cmd/dist/test.go as well. Figure out where to put it so that it can be + // shared. + var flags []string + quote := '\000' + start := 0 + lastSpace := true + backslash := false + for i, c := range GOGCCFLAGS { + if quote == '\000' && unicode.IsSpace(c) { + if !lastSpace { + flags = append(flags, GOGCCFLAGS[start:i]) + lastSpace = true + } + } else { + if lastSpace { + start = i + lastSpace = false + } + if quote == '\000' && !backslash && (c == '"' || c == '\'') { + quote = c + backslash = false + } else if !backslash && quote == c { + quote = '\000' + } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' { + backslash = true + } else { + backslash = false + } + } + } + if !lastSpace { + flags = append(flags, GOGCCFLAGS[start:]) + } + + cmd := exec.Command(CC, flags...) + cmd.Args = append(cmd.Args, args...) + return cmd, nil +} + +type version struct { + name string + major, minor int +} + +var compiler struct { + sync.Once + version + err error +} + +// compilerVersion detects the version of $(go env CC). +// +// It returns a non-nil error if the compiler matches a known version schema but +// the version could not be parsed, or if $(go env CC) could not be determined. +func compilerVersion() (version, error) { + compiler.Once.Do(func() { + compiler.err = func() error { + compiler.name = "unknown" + + cmd, err := cc("--version") + if err != nil { + return err + } + out, err := cmd.Output() + if err != nil { + // Compiler does not support "--version" flag: not Clang or GCC. + return nil + } + + var match [][]byte + if bytes.HasPrefix(out, []byte("gcc")) { + compiler.name = "gcc" + + cmd, err := cc("-dumpversion") + if err != nil { + return err + } + out, err := cmd.Output() + if err != nil { + // gcc, but does not support gcc's "-dumpversion" flag?! + return err + } + gccRE := regexp.MustCompile(`(\d+)\.(\d+)`) + match = gccRE.FindSubmatch(out) + } else { + clangRE := regexp.MustCompile(`clang version (\d+)\.(\d+)`) + if match = clangRE.FindSubmatch(out); len(match) > 0 { + compiler.name = "clang" + } + } + + if len(match) < 3 { + return nil // "unknown" + } + if compiler.major, err = strconv.Atoi(string(match[1])); err != nil { + return err + } + if compiler.minor, err = strconv.Atoi(string(match[2])); err != nil { + return err + } + return nil + }() + }) + return compiler.version, compiler.err +} + +type compilerCheck struct { + once sync.Once + err error + skip bool // If true, skip with err instead of failing with it. +} + +type config struct { + sanitizer string + + cFlags, ldFlags, goFlags []string + + sanitizerCheck, runtimeCheck compilerCheck +} + +var configs struct { + sync.Mutex + m map[string]*config +} + +// configure returns the configuration for the given sanitizer. +func configure(sanitizer string) *config { + configs.Lock() + defer configs.Unlock() + if c, ok := configs.m[sanitizer]; ok { + return c + } + + c := &config{ + sanitizer: sanitizer, + cFlags: []string{"-fsanitize=" + sanitizer}, + ldFlags: []string{"-fsanitize=" + sanitizer}, + } + + if testing.Verbose() { + c.goFlags = append(c.goFlags, "-x") + } + + switch sanitizer { + case "memory": + c.goFlags = append(c.goFlags, "-msan") + + case "thread": + c.goFlags = append(c.goFlags, "--installsuffix=tsan") + compiler, _ := compilerVersion() + if compiler.name == "gcc" { + c.cFlags = append(c.cFlags, "-fPIC") + c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan") + } + + default: + panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer)) + } + + if configs.m == nil { + configs.m = make(map[string]*config) + } + configs.m[sanitizer] = c + return c +} + +// goCmd returns a Cmd that executes "go $subcommand $args" with appropriate +// additional flags and environment. +func (c *config) goCmd(subcommand string, args ...string) *exec.Cmd { + cmd := exec.Command("go", subcommand) + cmd.Args = append(cmd.Args, c.goFlags...) + cmd.Args = append(cmd.Args, args...) + replaceEnv(cmd, "CGO_CFLAGS", strings.Join(c.cFlags, " ")) + replaceEnv(cmd, "CGO_LDFLAGS", strings.Join(c.ldFlags, " ")) + return cmd +} + +// skipIfCSanitizerBroken skips t if the C compiler does not produce working +// binaries as configured. +func (c *config) skipIfCSanitizerBroken(t *testing.T) { + check := &c.sanitizerCheck + check.once.Do(func() { + check.skip, check.err = c.checkCSanitizer() + }) + if check.err != nil { + t.Helper() + if check.skip { + t.Skip(check.err) + } + t.Fatal(check.err) + } +} + +var cMain = []byte(` +int main() { + return 0; +} +`) + +func (c *config) checkCSanitizer() (skip bool, err error) { + dir, err := ioutil.TempDir("", c.sanitizer) + if err != nil { + return false, fmt.Errorf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + src := filepath.Join(dir, "return0.c") + if err := ioutil.WriteFile(src, cMain, 0600); err != nil { + return false, fmt.Errorf("failed to write C source file: %v", err) + } + + dst := filepath.Join(dir, "return0") + cmd, err := cc(c.cFlags...) + if err != nil { + return false, err + } + cmd.Args = append(cmd.Args, c.ldFlags...) + cmd.Args = append(cmd.Args, "-o", dst, src) + out, err := cmd.CombinedOutput() + if err != nil { + if bytes.Contains(out, []byte("-fsanitize")) && + (bytes.Contains(out, []byte("unrecognized")) || + bytes.Contains(out, []byte("unsupported"))) { + return true, errors.New(string(out)) + } + return true, fmt.Errorf("%#q failed: %v\n%s", strings.Join(cmd.Args, " "), err, out) + } + + if out, err := exec.Command(dst).CombinedOutput(); err != nil { + if os.IsNotExist(err) { + return true, fmt.Errorf("%#q failed to produce executable: %v", strings.Join(cmd.Args, " "), err) + } + snippet := bytes.SplitN(out, []byte{'\n'}, 2)[0] + return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet) + } + + return false, nil +} + +// skipIfRuntimeIncompatible skips t if the Go runtime is suspected not to work +// with cgo as configured. +func (c *config) skipIfRuntimeIncompatible(t *testing.T) { + check := &c.runtimeCheck + check.once.Do(func() { + check.skip, check.err = c.checkRuntime() + }) + if check.err != nil { + t.Helper() + if check.skip { + t.Skip(check.err) + } + t.Fatal(check.err) + } +} + +func (c *config) checkRuntime() (skip bool, err error) { + if c.sanitizer != "thread" { + return false, nil + } + + // libcgo.h sets CGO_TSAN if it detects TSAN support in the C compiler. + // Dump the preprocessor defines to check that that works. + // (Sometimes it doesn't: see https://golang.org/issue/15983.) + cmd, err := cc(c.cFlags...) + if err != nil { + return false, err + } + cmd.Args = append(cmd.Args, "-dM", "-E", "../../../src/runtime/cgo/libcgo.h") + out, err := cmd.CombinedOutput() + if err != nil { + return false, fmt.Errorf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out) + } + if !bytes.Contains(out, []byte("#define CGO_TSAN")) { + return true, fmt.Errorf("%#q did not define CGO_TSAN") + } + return false, nil +} + +// srcPath returns the path to the given file relative to this test's source tree. +func srcPath(path string) string { + return filepath.Join("src", path) +} + +// A tempDir manages a temporary directory within a test. +type tempDir struct { + base string +} + +func (d *tempDir) RemoveAll(t *testing.T) { + t.Helper() + if d.base == "" { + return + } + if err := os.RemoveAll(d.base); err != nil { + t.Fatal("Failed to remove temp dir: %v", err) + } +} + +func (d *tempDir) Join(name string) string { + return filepath.Join(d.base, name) +} + +func newTempDir(t *testing.T) *tempDir { + t.Helper() + dir, err := ioutil.TempDir("", filepath.Dir(t.Name())) + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + return &tempDir{base: dir} +} + +// hangProneCmd returns an exec.Cmd for a command that is likely to hang. +// +// If one of these tests hangs, the caller is likely to kill the test process +// using SIGINT, which will be sent to all of the processes in the test's group. +// Unfortunately, TSAN in particular is prone to dropping signals, so the SIGINT +// may terminate the test binary but leave the subprocess running. hangProneCmd +// configures subprocess to receive SIGKILL instead to ensure that it won't +// leak. +func hangProneCmd(name string, arg ...string) *exec.Cmd { + cmd := exec.Command(name, arg...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + } + return cmd +} diff --git a/libgo/misc/cgo/testsanitizers/cshared_test.go b/libgo/misc/cgo/testsanitizers/cshared_test.go new file mode 100644 index 00000000000..56063ea6201 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/cshared_test.go @@ -0,0 +1,74 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sanitizers_test + +import ( + "fmt" + "io/ioutil" + "strings" + "testing" +) + +func TestShared(t *testing.T) { + t.Parallel() + requireOvercommit(t) + + GOOS, err := goEnv("GOOS") + if err != nil { + t.Fatal(err) + } + libExt := "so" + if GOOS == "darwin" { + libExt = "dylib" + } + + cases := []struct { + src string + sanitizer string + }{ + { + src: "msan_shared.go", + sanitizer: "memory", + }, + { + src: "tsan_shared.go", + sanitizer: "thread", + }, + } + + for _, tc := range cases { + tc := tc + name := strings.TrimSuffix(tc.src, ".go") + t.Run(name, func(t *testing.T) { + t.Parallel() + config := configure(tc.sanitizer) + config.skipIfCSanitizerBroken(t) + + dir := newTempDir(t) + defer dir.RemoveAll(t) + + lib := dir.Join(fmt.Sprintf("lib%s.%s", name, libExt)) + mustRun(t, config.goCmd("build", "-buildmode=c-shared", "-o", lib, srcPath(tc.src))) + + cSrc := dir.Join("main.c") + if err := ioutil.WriteFile(cSrc, cMain, 0600); err != nil { + t.Fatalf("failed to write C source file: %v", err) + } + + dstBin := dir.Join(name) + cmd, err := cc(config.cFlags...) + if err != nil { + t.Fatal(err) + } + cmd.Args = append(cmd.Args, config.ldFlags...) + cmd.Args = append(cmd.Args, "-o", dstBin, cSrc, lib) + mustRun(t, cmd) + + cmd = hangProneCmd(dstBin) + replaceEnv(cmd, "LD_LIBRARY_PATH", ".") + mustRun(t, cmd) + }) + } +} diff --git a/libgo/misc/cgo/testsanitizers/msan_test.go b/libgo/misc/cgo/testsanitizers/msan_test.go new file mode 100644 index 00000000000..af5afa9ee48 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan_test.go @@ -0,0 +1,55 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sanitizers_test + +import ( + "strings" + "testing" +) + +func TestMSAN(t *testing.T) { + t.Parallel() + requireOvercommit(t) + config := configure("memory") + config.skipIfCSanitizerBroken(t) + + mustRun(t, config.goCmd("build", "std")) + + cases := []struct { + src string + wantErr bool + }{ + {src: "msan.go"}, + {src: "msan2.go"}, + {src: "msan2_cmsan.go"}, + {src: "msan3.go"}, + {src: "msan4.go"}, + {src: "msan5.go"}, + {src: "msan_fail.go", wantErr: true}, + } + for _, tc := range cases { + tc := tc + name := strings.TrimSuffix(tc.src, ".go") + t.Run(name, func(t *testing.T) { + t.Parallel() + + dir := newTempDir(t) + defer dir.RemoveAll(t) + + outPath := dir.Join(name) + mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src))) + + cmd := hangProneCmd(outPath) + if tc.wantErr { + out, err := cmd.CombinedOutput() + if err != nil { + return + } + t.Fatalf("%#q exited without error; want MSAN failure\n%s", strings.Join(cmd.Args, " "), out) + } + mustRun(t, cmd) + }) + } +} diff --git a/libgo/misc/cgo/testsanitizers/msan.go b/libgo/misc/cgo/testsanitizers/src/msan.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan.go rename to libgo/misc/cgo/testsanitizers/src/msan.go diff --git a/libgo/misc/cgo/testsanitizers/msan2.go b/libgo/misc/cgo/testsanitizers/src/msan2.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan2.go rename to libgo/misc/cgo/testsanitizers/src/msan2.go diff --git a/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go b/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go new file mode 100644 index 00000000000..8fdaea90c97 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/src/msan2_cmsan.go @@ -0,0 +1,38 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +#cgo LDFLAGS: -fsanitize=memory +#cgo CPPFLAGS: -fsanitize=memory + +#include +#include +#include + +void f(int32_t *p, int n) { + int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n); + memcpy(p, q, n * sizeof(*p)); + free(q); +} + +void g(int32_t *p, int n) { + if (p[4] != 1) { + abort(); + } +} +*/ +import "C" + +import ( + "unsafe" +) + +func main() { + a := make([]int32, 10) + C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) + a[4] = 1 + C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) +} diff --git a/libgo/misc/cgo/testsanitizers/msan3.go b/libgo/misc/cgo/testsanitizers/src/msan3.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan3.go rename to libgo/misc/cgo/testsanitizers/src/msan3.go diff --git a/libgo/misc/cgo/testsanitizers/msan4.go b/libgo/misc/cgo/testsanitizers/src/msan4.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan4.go rename to libgo/misc/cgo/testsanitizers/src/msan4.go diff --git a/libgo/misc/cgo/testsanitizers/msan5.go b/libgo/misc/cgo/testsanitizers/src/msan5.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan5.go rename to libgo/misc/cgo/testsanitizers/src/msan5.go diff --git a/libgo/misc/cgo/testsanitizers/msan_fail.go b/libgo/misc/cgo/testsanitizers/src/msan_fail.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan_fail.go rename to libgo/misc/cgo/testsanitizers/src/msan_fail.go diff --git a/libgo/misc/cgo/testsanitizers/msan_shared.go b/libgo/misc/cgo/testsanitizers/src/msan_shared.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/msan_shared.go rename to libgo/misc/cgo/testsanitizers/src/msan_shared.go diff --git a/libgo/misc/cgo/testsanitizers/tsan.go b/libgo/misc/cgo/testsanitizers/src/tsan.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan.go rename to libgo/misc/cgo/testsanitizers/src/tsan.go diff --git a/libgo/misc/cgo/testsanitizers/tsan10.go b/libgo/misc/cgo/testsanitizers/src/tsan10.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan10.go rename to libgo/misc/cgo/testsanitizers/src/tsan10.go diff --git a/libgo/misc/cgo/testsanitizers/tsan11.go b/libgo/misc/cgo/testsanitizers/src/tsan11.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan11.go rename to libgo/misc/cgo/testsanitizers/src/tsan11.go diff --git a/libgo/misc/cgo/testsanitizers/tsan12.go b/libgo/misc/cgo/testsanitizers/src/tsan12.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan12.go rename to libgo/misc/cgo/testsanitizers/src/tsan12.go diff --git a/libgo/misc/cgo/testsanitizers/tsan2.go b/libgo/misc/cgo/testsanitizers/src/tsan2.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan2.go rename to libgo/misc/cgo/testsanitizers/src/tsan2.go diff --git a/libgo/misc/cgo/testsanitizers/tsan3.go b/libgo/misc/cgo/testsanitizers/src/tsan3.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan3.go rename to libgo/misc/cgo/testsanitizers/src/tsan3.go diff --git a/libgo/misc/cgo/testsanitizers/tsan4.go b/libgo/misc/cgo/testsanitizers/src/tsan4.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan4.go rename to libgo/misc/cgo/testsanitizers/src/tsan4.go diff --git a/libgo/misc/cgo/testsanitizers/tsan5.go b/libgo/misc/cgo/testsanitizers/src/tsan5.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan5.go rename to libgo/misc/cgo/testsanitizers/src/tsan5.go diff --git a/libgo/misc/cgo/testsanitizers/tsan6.go b/libgo/misc/cgo/testsanitizers/src/tsan6.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan6.go rename to libgo/misc/cgo/testsanitizers/src/tsan6.go diff --git a/libgo/misc/cgo/testsanitizers/tsan7.go b/libgo/misc/cgo/testsanitizers/src/tsan7.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan7.go rename to libgo/misc/cgo/testsanitizers/src/tsan7.go diff --git a/libgo/misc/cgo/testsanitizers/tsan8.go b/libgo/misc/cgo/testsanitizers/src/tsan8.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan8.go rename to libgo/misc/cgo/testsanitizers/src/tsan8.go diff --git a/libgo/misc/cgo/testsanitizers/tsan9.go b/libgo/misc/cgo/testsanitizers/src/tsan9.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan9.go rename to libgo/misc/cgo/testsanitizers/src/tsan9.go diff --git a/libgo/misc/cgo/testsanitizers/tsan_shared.go b/libgo/misc/cgo/testsanitizers/src/tsan_shared.go similarity index 100% rename from libgo/misc/cgo/testsanitizers/tsan_shared.go rename to libgo/misc/cgo/testsanitizers/src/tsan_shared.go diff --git a/libgo/misc/cgo/testsanitizers/test.bash b/libgo/misc/cgo/testsanitizers/test.bash deleted file mode 100644 index 9f80af6c507..00000000000 --- a/libgo/misc/cgo/testsanitizers/test.bash +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2015 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# This directory is intended to test the use of Go with sanitizers -# like msan, asan, etc. See https://github.com/google/sanitizers . - -set -e - -# The sanitizers were originally developed with clang, so prefer it. -CC=cc -if test -x "$(type -p clang)"; then - CC=clang -fi -export CC - -if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then - echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2 - exit 0 -fi - -msan=yes - -TMPDIR=${TMPDIR:-/tmp} -echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c -if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then - echo "skipping msan tests: $CC -fsanitize=memory not supported" - msan=no -elif ! test -x ${TMPDIR}/testsanitizers$$; then - echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable" - msan=no -elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then - echo "skipping msan tests: $CC -fsanitize-memory generates broken executable" - msan=no -fi -rm -f ${TMPDIR}/testsanitizers$$.* - -tsan=yes - -# The memory and thread sanitizers in versions of clang before 3.6 -# don't work with Go. -if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then - ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/') - major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') - minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/') - if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then - echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)" - msan=no - tsan=no - fi - - # Clang before 3.8 does not work with Linux at or after 4.1. - # golang.org/issue/12898. - if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then - if test "$(uname)" = Linux; then - linuxver=$(uname -r) - linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/') - linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/') - if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then - echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)" - msan=no - tsan=no - fi - fi - fi -fi - -status=0 - -testmsanshared() { - goos=$(go env GOOS) - suffix="-installsuffix testsanitizers" - libext="so" - if [ "$goos" = "darwin" ]; then - libext="dylib" - fi - go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go - - echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c - $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext - - if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then - echo "FAIL: msan_shared" - status=1 - fi - rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext} -} - -if test "$msan" = "yes"; then - if ! go build -msan std; then - echo "FAIL: build -msan std" - status=1 - fi - - if ! go run -msan msan.go; then - echo "FAIL: msan" - status=1 - fi - - if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then - echo "FAIL: msan2 with -fsanitize=memory" - status=1 - fi - - if ! go run -msan -a msan2.go; then - echo "FAIL: msan2" - status=1 - fi - - if ! go run -msan msan3.go; then - echo "FAIL: msan3" - status=1 - fi - - if ! go run -msan msan4.go; then - echo "FAIL: msan4" - status=1 - fi - - if ! go run -msan msan5.go; then - echo "FAIL: msan5" - status=1 - fi - - if go run -msan msan_fail.go 2>/dev/null; then - echo "FAIL: msan_fail" - status=1 - fi - - testmsanshared -fi - -testtsanshared() { - goos=$(go env GOOS) - suffix="-installsuffix tsan" - libext="so" - if [ "$goos" = "darwin" ]; then - libext="dylib" - fi - go build -buildmode=c-shared $suffix -o ${TMPDIR}/libtsanshared.$libext tsan_shared.go - - echo 'int main() { return 0; }' > ${TMPDIR}/testtsanshared.c - $CC $(go env GOGCCFLAGS) -fsanitize=thread -o ${TMPDIR}/testtsanshared ${TMPDIR}/testtsanshared.c ${TMPDIR}/libtsanshared.$libext - - if ! LD_LIBRARY_PATH=. ${TMPDIR}/testtsanshared; then - echo "FAIL: tsan_shared" - status=1 - fi - rm -f ${TMPDIR}/{testtsanshared,testtsanshared.c,libtsanshared.$libext} -} - -if test "$tsan" = "yes"; then - echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c - ok=yes - if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then - ok=no - fi - if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then - echo "skipping tsan tests: -fsanitize=thread not supported" - tsan=no - elif test "$ok" != "yes"; then - cat ${TMPDIR}/testsanitizers$$.err - echo "skipping tsan tests: -fsanitizer=thread build failed" - tsan=no - elif ! ${TMPDIR}/testsanitizers$$ 2>&1; then - echo "skipping tsan tests: running tsan program failed" - tsan=no - fi - rm -f ${TMPDIR}/testsanitizers$$* -fi - -# Run a TSAN test. -# $1 test name -# $2 environment variables -# $3 go run args -testtsan() { - err=${TMPDIR}/tsanerr$$.out - if ! env $2 go run $3 $1 2>$err; then - cat $err - echo "FAIL: $1" - status=1 - elif grep -i warning $err >/dev/null 2>&1; then - cat $err - echo "FAIL: $1" - status=1 - fi - rm -f $err -} - -if test "$tsan" = "yes"; then - testtsan tsan.go - testtsan tsan2.go - testtsan tsan3.go - testtsan tsan4.go - testtsan tsan8.go - testtsan tsan9.go - - # These tests are only reliable using clang or GCC version 7 or later. - # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use. - ok=false - clang=false - if ${CC} --version | grep clang >/dev/null 2>&1; then - ok=true - clang=true - else - ver=$($CC -dumpversion) - major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') - if test "$major" -lt 7; then - echo "skipping remaining TSAN tests: GCC version $major (older than 7)" - else - ok=true - fi - fi - - if test "$ok" = "true"; then - # These tests require rebuilding os/user with -fsanitize=thread. - testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - - # The remaining tests reportedly hang when built with GCC; issue #21196. - if test "$clang" = "true"; then - testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" - fi - - testtsanshared - fi -fi - -exit $status diff --git a/libgo/misc/cgo/testsanitizers/tsan_test.go b/libgo/misc/cgo/testsanitizers/tsan_test.go new file mode 100644 index 00000000000..ec4e0033fb4 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan_test.go @@ -0,0 +1,56 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sanitizers_test + +import ( + "strings" + "testing" +) + +func TestTSAN(t *testing.T) { + t.Parallel() + requireOvercommit(t) + config := configure("thread") + config.skipIfCSanitizerBroken(t) + + mustRun(t, config.goCmd("build", "std")) + + cases := []struct { + src string + needsRuntime bool + }{ + {src: "tsan.go"}, + {src: "tsan2.go"}, + {src: "tsan3.go"}, + {src: "tsan4.go"}, + {src: "tsan5.go", needsRuntime: true}, + {src: "tsan6.go", needsRuntime: true}, + {src: "tsan7.go", needsRuntime: true}, + {src: "tsan8.go"}, + {src: "tsan9.go"}, + {src: "tsan10.go", needsRuntime: true}, + {src: "tsan11.go", needsRuntime: true}, + {src: "tsan12.go", needsRuntime: true}, + } + for _, tc := range cases { + tc := tc + name := strings.TrimSuffix(tc.src, ".go") + t.Run(name, func(t *testing.T) { + t.Parallel() + + dir := newTempDir(t) + defer dir.RemoveAll(t) + + outPath := dir.Join(name) + mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src))) + + cmd := hangProneCmd(outPath) + if tc.needsRuntime { + config.skipIfRuntimeIncompatible(t) + } + mustRun(t, cmd) + }) + } +} diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go index 9e682a2fb59..f1e8f0605b6 100644 --- a/libgo/misc/cgo/testshared/shared_test.go +++ b/libgo/misc/cgo/testshared/shared_test.go @@ -10,6 +10,7 @@ import ( "debug/elf" "encoding/binary" "errors" + "flag" "fmt" "go/build" "io" @@ -46,7 +47,7 @@ func run(t *testing.T, msg string, args ...string) { func goCmd(t *testing.T, args ...string) { newargs := []string{args[0], "-installsuffix=" + suffix} if testing.Verbose() { - newargs = append(newargs, "-v") + newargs = append(newargs, "-x") } newargs = append(newargs, args[1:]...) c := exec.Command("go", newargs...) @@ -57,6 +58,7 @@ func goCmd(t *testing.T, args ...string) { c.Stdout = os.Stdout c.Stderr = os.Stderr err = c.Run() + output = []byte("(output above)") } else { output, err = c.CombinedOutput() } @@ -161,6 +163,8 @@ func testMain(m *testing.M) (int, error) { } func TestMain(m *testing.M) { + flag.Parse() + // Some of the tests install binaries into a custom GOPATH. // That won't work if GOBIN is set. os.Unsetenv("GOBIN") @@ -461,13 +465,13 @@ func TestGopathShlib(t *testing.T) { // that is not mapped into memory. func testPkgListNote(t *testing.T, f *elf.File, note *note) { if note.section.Flags != 0 { - t.Errorf("package list section has flags %v", note.section.Flags) + t.Errorf("package list section has flags %v, want 0", note.section.Flags) } if isOffsetLoaded(f, note.section.Offset) { t.Errorf("package list section contained in PT_LOAD segment") } if note.desc != "depBase\n" { - t.Errorf("incorrect package list %q", note.desc) + t.Errorf("incorrect package list %q, want %q", note.desc, "depBase\n") } } @@ -476,7 +480,7 @@ func testPkgListNote(t *testing.T, f *elf.File, note *note) { // bytes into it. func testABIHashNote(t *testing.T, f *elf.File, note *note) { if note.section.Flags != elf.SHF_ALLOC { - t.Errorf("abi hash section has flags %v", note.section.Flags) + t.Errorf("abi hash section has flags %v, want SHF_ALLOC", note.section.Flags) } if !isOffsetLoaded(f, note.section.Offset) { t.Errorf("abihash section not contained in PT_LOAD segment") @@ -497,13 +501,13 @@ func testABIHashNote(t *testing.T, f *elf.File, note *note) { return } if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL { - t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info)) + t.Errorf("%s has incorrect binding %v, want STB_LOCAL", hashbytes.Name, elf.ST_BIND(hashbytes.Info)) } if f.Sections[hashbytes.Section] != note.section { - t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name) + t.Errorf("%s has incorrect section %v, want %s", hashbytes.Name, f.Sections[hashbytes.Section].Name, note.section.Name) } if hashbytes.Value-note.section.Addr != 16 { - t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr) + t.Errorf("%s has incorrect offset into section %d, want 16", hashbytes.Name, hashbytes.Value-note.section.Addr) } } @@ -511,14 +515,14 @@ func testABIHashNote(t *testing.T, f *elf.File, note *note) { // was linked against in an unmapped section. func testDepsNote(t *testing.T, f *elf.File, note *note) { if note.section.Flags != 0 { - t.Errorf("package list section has flags %v", note.section.Flags) + t.Errorf("package list section has flags %v, want 0", note.section.Flags) } if isOffsetLoaded(f, note.section.Offset) { t.Errorf("package list section contained in PT_LOAD segment") } // libdepBase.so just links against the lib containing the runtime. if note.desc != soname { - t.Errorf("incorrect dependency list %q", note.desc) + t.Errorf("incorrect dependency list %q, want %q", note.desc, soname) } } @@ -556,7 +560,7 @@ func TestNotes(t *testing.T) { abiHashNoteFound = true case 3: // ELF_NOTE_GODEPS_TAG if depsNoteFound { - t.Error("multiple abi hash notes") + t.Error("multiple depedency list notes") } testDepsNote(t, f, note) depsNoteFound = true @@ -594,6 +598,7 @@ func TestThreeGopathShlibs(t *testing.T) { // If gccgo is not available or not new enough call t.Skip. Otherwise, // return a build.Context that is set up for gccgo. func prepGccgo(t *testing.T) build.Context { + t.Skip("golang.org/issue/22472") gccgoName := os.Getenv("GCCGO") if gccgoName == "" { gccgoName = "gccgo" @@ -643,6 +648,8 @@ func TestGoPathShlibGccgo(t *testing.T) { // library with gccgo, another GOPATH package that depends on the first and an // executable that links the second library. func TestTwoGopathShlibsGccgo(t *testing.T) { + t.Skip("golang.org/issue/22224") + gccgoContext := prepGccgo(t) libgoRE := regexp.MustCompile("libgo.so.[0-9]+") @@ -696,18 +703,55 @@ func resetFileStamps() { reset(gorootInstallDir) } -// touch makes path newer than the "old" time stamp used by resetFileStamps. -func touch(path string) { +// touch changes path and returns a function that changes it back. +// It also sets the time of the file, so that we can see if it is rewritten. +func touch(t *testing.T, path string) (cleanup func()) { + data, err := ioutil.ReadFile(path) + if err != nil { + t.Fatal(err) + } + old := make([]byte, len(data)) + copy(old, data) + if bytes.HasPrefix(data, []byte("!\n")) { + // Change last digit of build ID. + // (Content ID in the new content-based build IDs.) + const marker = `build id "` + i := bytes.Index(data, []byte(marker)) + if i < 0 { + t.Fatal("cannot find build id in archive") + } + j := bytes.IndexByte(data[i+len(marker):], '"') + if j < 0 { + t.Fatal("cannot find build id in archive") + } + i += len(marker) + j - 1 + if data[i] == 'a' { + data[i] = 'b' + } else { + data[i] = 'a' + } + } else { + // assume it's a text file + data = append(data, '\n') + } + if err := ioutil.WriteFile(path, data, 0666); err != nil { + t.Fatal(err) + } if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil { - log.Fatalf("os.Chtimes failed: %v", err) + t.Fatal(err) + } + return func() { + if err := ioutil.WriteFile(path, old, 0666); err != nil { + t.Fatal(err) + } } } // isNew returns if the path is newer than the time stamp used by touch. -func isNew(path string) bool { +func isNew(t *testing.T, path string) bool { fi, err := os.Stat(path) if err != nil { - log.Fatalf("os.Stat failed: %v", err) + t.Fatal(err) } return fi.ModTime().After(stampTime) } @@ -715,14 +759,16 @@ func isNew(path string) bool { // Fail unless path has been rebuilt (i.e. is newer than the time stamp used by // isNew) func AssertRebuilt(t *testing.T, msg, path string) { - if !isNew(path) { + t.Helper() + if !isNew(t, path) { t.Errorf("%s was not rebuilt (%s)", msg, path) } } // Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew) func AssertNotRebuilt(t *testing.T, msg, path string) { - if isNew(path) { + t.Helper() + if isNew(t, path) { t.Errorf("%s was rebuilt (%s)", msg, path) } } @@ -732,41 +778,55 @@ func TestRebuilding(t *testing.T) { goCmd(t, "install", "-linkshared", "exe") // If the source is newer than both the .a file and the .so, both are rebuilt. - resetFileStamps() - touch("src/depBase/dep.go") - goCmd(t, "install", "-linkshared", "exe") - AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a")) - AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.so")) + t.Run("newsource", func(t *testing.T) { + resetFileStamps() + cleanup := touch(t, "src/depBase/dep.go") + defer func() { + cleanup() + goCmd(t, "install", "-linkshared", "exe") + }() + goCmd(t, "install", "-linkshared", "exe") + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a")) + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.so")) + }) // If the .a file is newer than the .so, the .so is rebuilt (but not the .a) - resetFileStamps() - touch(filepath.Join(gopathInstallDir, "depBase.a")) - goCmd(t, "install", "-linkshared", "exe") - AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a")) - AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so")) + t.Run("newarchive", func(t *testing.T) { + resetFileStamps() + goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "depBase") + AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a")) + cleanup := touch(t, filepath.Join(gopathInstallDir, "depBase.a")) + defer func() { + cleanup() + goCmd(t, "install", "-v", "-linkshared", "exe") + }() + goCmd(t, "install", "-v", "-linkshared", "exe") + AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a")) + AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so")) + }) } -func appendFile(path, content string) { +func appendFile(t *testing.T, path, content string) { f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660) if err != nil { - log.Fatalf("os.OpenFile failed: %v", err) + t.Fatalf("os.OpenFile failed: %v", err) } defer func() { err := f.Close() if err != nil { - log.Fatalf("f.Close failed: %v", err) + t.Fatalf("f.Close failed: %v", err) } }() _, err = f.WriteString(content) if err != nil { - log.Fatalf("f.WriteString failed: %v", err) + t.Fatalf("f.WriteString failed: %v", err) } } -func writeFile(path, content string) { +func writeFile(t *testing.T, path, content string) { err := ioutil.WriteFile(path, []byte(content), 0644) if err != nil { - log.Fatalf("ioutil.WriteFile failed: %v", err) + t.Fatalf("ioutil.WriteFile failed: %v", err) } } @@ -780,7 +840,7 @@ func TestABIChecking(t *testing.T) { // some senses but suffices for the narrow definition of ABI compatibility the // toolchain uses today. resetFileStamps() - appendFile("src/depBase/dep.go", "func ABIBreak() {}\n") + appendFile(t, "src/depBase/dep.go", "func ABIBreak() {}\n") goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") c := exec.Command("./bin/exe") output, err := c.CombinedOutput() @@ -811,7 +871,7 @@ func TestABIChecking(t *testing.T) { // function) and rebuild libdepBase.so, exe still works, even if new function // is in a file by itself. resetFileStamps() - writeFile("src/depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n") + writeFile(t, "src/depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n") goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") run(t, "after non-ABI breaking change", "./bin/exe") } @@ -838,3 +898,12 @@ func TestInterface(t *testing.T) { goCmd(t, "install", "-linkshared", "iface") run(t, "running type/itab uniqueness tester", "./bin/iface") } + +// Access a global variable from a library. +func TestGlobal(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "globallib") + goCmd(t, "install", "-linkshared", "global") + run(t, "global executable", "./bin/global") + AssertIsLinkedTo(t, "./bin/global", soname) + AssertHasRPath(t, "./bin/global", gorootInstallDir) +} diff --git a/libgo/misc/cgo/testshared/src/depBase/dep.go b/libgo/misc/cgo/testshared/src/depBase/dep.go index 9f86710db01..569c210aa14 100644 --- a/libgo/misc/cgo/testshared/src/depBase/dep.go +++ b/libgo/misc/cgo/testshared/src/depBase/dep.go @@ -22,7 +22,7 @@ type Dep struct { func (d *Dep) Method() int { // This code below causes various go.itab.* symbols to be generated in // the shared library. Similar code in ../exe/exe.go results in - // exercising https://github.com/golang/go/issues/17594 + // exercising https://golang.org/issues/17594 reflect.TypeOf(os.Stdout).Elem() return 10 } diff --git a/libgo/misc/cgo/testshared/src/exe/exe.go b/libgo/misc/cgo/testshared/src/exe/exe.go index 84302a811f0..bd864d88ad8 100644 --- a/libgo/misc/cgo/testshared/src/exe/exe.go +++ b/libgo/misc/cgo/testshared/src/exe/exe.go @@ -25,7 +25,7 @@ func main() { defer depBase.ImplementedInAsm() // This code below causes various go.itab.* symbols to be generated in // the executable. Similar code in ../depBase/dep.go results in - // exercising https://github.com/golang/go/issues/17594 + // exercising https://golang.org/issues/17594 reflect.TypeOf(os.Stdout).Elem() runtime.GC() depBase.V = depBase.F() + 1 diff --git a/libgo/misc/cgo/testshared/src/global/main.go b/libgo/misc/cgo/testshared/src/global/main.go new file mode 100644 index 00000000000..94e7f247dee --- /dev/null +++ b/libgo/misc/cgo/testshared/src/global/main.go @@ -0,0 +1,71 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "globallib" +) + +//go:noinline +func testLoop() { + for i, s := range globallib.Data { + if s != int64(i) { + panic("testLoop: mismatch") + } + } +} + +//go:noinline +func ptrData() *[1<<20 + 10]int64 { + return &globallib.Data +} + +//go:noinline +func testMediumOffset() { + for i, s := range globallib.Data[1<<16-2:] { + if s != int64(i)+1<<16-2 { + panic("testMediumOffset: index mismatch") + } + } + + x := globallib.Data[1<<16-1] + if x != 1<<16-1 { + panic("testMediumOffset: direct mismatch") + } + + y := &globallib.Data[1<<16-3] + if y != &ptrData()[1<<16-3] { + panic("testMediumOffset: address mismatch") + } +} + +//go:noinline +func testLargeOffset() { + for i, s := range globallib.Data[1<<20:] { + if s != int64(i)+1<<20 { + panic("testLargeOffset: index mismatch") + } + } + + x := globallib.Data[1<<20+1] + if x != 1<<20+1 { + panic("testLargeOffset: direct mismatch") + } + + y := &globallib.Data[1<<20+2] + if y != &ptrData()[1<<20+2] { + panic("testLargeOffset: address mismatch") + } +} + +func main() { + testLoop() + + // SSA rules commonly merge offsets into addresses. These + // tests access global data in different ways to try + // and exercise different SSA rules. + testMediumOffset() + testLargeOffset() +} diff --git a/libgo/misc/cgo/testshared/src/globallib/global.go b/libgo/misc/cgo/testshared/src/globallib/global.go new file mode 100644 index 00000000000..b4372a2e9e2 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/globallib/global.go @@ -0,0 +1,17 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package globallib + +// Data is large enough to that offsets into it do not fit into +// 16-bit or 20-bit immediates. Ideally we'd also try and overrun +// 32-bit immediates, but that requires the test machine to have +// too much memory. +var Data [1<<20 + 10]int64 + +func init() { + for i := range Data { + Data[i] = int64(i) + } +} diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c index 09def91b1e8..9f376c7f4aa 100644 --- a/libgo/runtime/go-callers.c +++ b/libgo/runtime/go-callers.c @@ -127,8 +127,12 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno, p = filename; if (__builtin_strcmp (p, "/proc.c") == 0) { - if (__builtin_strcmp (function, "kickoff") == 0 - || __builtin_strcmp (function, "runtime.mstart") == 0 + if (__builtin_strcmp (function, "runtime_mstart") == 0) + return 1; + } + else if (__builtin_strcmp (p, "/proc.go") == 0) + { + if (__builtin_strcmp (function, "runtime.kickoff") == 0 || __builtin_strcmp (function, "runtime.main") == 0) return 1; } @@ -184,6 +188,21 @@ runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks) backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback, &data); runtime_xadd (&runtime_in_callers, -1); + + /* For some reason GCC sometimes loses the name of a thunk function + at the top of the stack. If we are skipping thunks, skip that + one too. */ + if (!keep_thunks + && data.index > 2 + && locbuf[data.index - 2].function.len == 0 + && locbuf[data.index - 1].function.str != NULL + && __builtin_strcmp ((const char *) locbuf[data.index - 1].function.str, + "runtime.kickoff") == 0) + { + locbuf[data.index - 2] = locbuf[data.index - 1]; + --data.index; + } + return data.index; } diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index d6e42e6d8b5..6d2adb8f791 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -32,6 +32,8 @@ extern void *__splitstack_makecontext(size_t, void *context[10], size_t *); extern void * __splitstack_resetcontext(void *context[10], size_t *); +extern void __splitstack_releasecontext(void *context[10]); + extern void *__splitstack_find(void *, void *, size_t *, void **, void **, void **); @@ -269,6 +271,9 @@ runtime_newosproc(M *mp) runtime_printf("pthread_create failed: %d\n", ret); runtime_throw("pthread_create"); } + + if(pthread_attr_destroy(&attr) != 0) + runtime_throw("pthread_attr_destroy"); } // Switch context to a different goroutine. This is like longjmp. @@ -377,10 +382,12 @@ extern void kickoff(void) __asm__(GOSYM_PREFIX "runtime.kickoff"); extern void minit(void) __asm__(GOSYM_PREFIX "runtime.minit"); -extern void mstart1(void) +extern void mstart1(int32) __asm__(GOSYM_PREFIX "runtime.mstart1"); extern void stopm(void) __asm__(GOSYM_PREFIX "runtime.stopm"); +extern void mexit(bool) + __asm__(GOSYM_PREFIX "runtime.mexit"); extern void handoffp(P*) __asm__(GOSYM_PREFIX "runtime.handoffp"); extern void wakep(void) @@ -519,6 +526,11 @@ runtime_mstart(void *arg) *(int*)0x21 = 0x21; } + if(mp->exiting) { + mexit(true); + return nil; + } + // Initial call to getcontext--starting thread. #ifdef USING_SPLIT_STACK @@ -528,7 +540,7 @@ runtime_mstart(void *arg) } #endif - mstart1(); + mstart1(0); // mstart1 does not return, but we need a return statement // here to avoid a compiler warning. @@ -751,6 +763,30 @@ runtime_malg(bool allocatestack, bool signalstack, byte** ret_stack, uintptr* re return newg; } +void stackfree(G*) + __asm__(GOSYM_PREFIX "runtime.stackfree"); + +// stackfree frees the stack of a g. +void +stackfree(G* gp) +{ +#if USING_SPLIT_STACK + __splitstack_releasecontext((void*)(&gp->stackcontext[0])); +#else + // If gcstacksize is 0, the stack is allocated by libc and will be + // released when the thread exits. Otherwise, in 64-bit mode it was + // allocated using sysAlloc and in 32-bit mode it was allocated + // using garbage collected memory. + if (gp->gcstacksize != 0) { + if (sizeof(void*) == 8) { + runtime_sysFree(gp->gcinitialsp, gp->gcstacksize, &getMemstats()->stacks_sys); + } + gp->gcinitialsp = nil; + gp->gcstacksize = 0; + } +#endif +} + void resetNewG(G*, void **, uintptr*) __asm__(GOSYM_PREFIX "runtime.resetNewG"); diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 39b5ef883bd..4124e9dc0a9 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -265,11 +265,12 @@ void* runtime_mallocgc(uintptr, const Type*, bool) __asm__ (GOSYM_PREFIX "runtime.mallocgc"); void* runtime_sysAlloc(uintptr, uint64*) __asm__ (GOSYM_PREFIX "runtime.sysAlloc"); +void runtime_sysFree(void*, uintptr, uint64*) + __asm__ (GOSYM_PREFIX "runtime.sysFree"); void runtime_mprofinit(void); #define runtime_getcallersp(p) __builtin_frame_address(0) void runtime_mcall(FuncVal*) __asm__ (GOSYM_PREFIX "runtime.mcall"); -uint32 runtime_fastrand(void) __asm__ (GOSYM_PREFIX "runtime.fastrand"); int32 runtime_timediv(int64, int32, int32*) __asm__ (GOSYM_PREFIX "runtime.timediv"); int32 runtime_round2(int32 x); // round x up to a power of 2. diff --git a/libgo/runtime/runtime_c.c b/libgo/runtime/runtime_c.c index 9a6672d602e..88f1adfb91b 100644 --- a/libgo/runtime/runtime_c.c +++ b/libgo/runtime/runtime_c.c @@ -33,21 +33,6 @@ runtime_atoi(const byte *p, intgo len) return n; } -uint32 -runtime_fastrand(void) -{ - M *m; - uint32 x; - - m = runtime_m(); - x = m->fastrand; - x += x; - if(x & 0x80000000L) - x ^= 0x88888eefUL; - m->fastrand = x; - return x; -} - int64 runtime_cputicks(void) { diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index 83f78d4d9b9..2b6e472d6c2 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -510,7 +510,7 @@ localname() { ppc64*) text="[TD]" ;; esac - symtogo='sed -e s/_test/XXXtest/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/' + symtogo='sed -e s/_test\([^A-Za-z0-9]\)/XXXtest\1/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/' # test functions are named TestFoo # the grep -v eliminates methods and other special names -- 2.30.2