[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch

Semi-regular merge from tip into dev.ssa.

Change-Id: I1627d7c7e6892cd4f1f5da5f3e07389ff1d677ce
This commit is contained in:
Keith Randall 2016-01-07 10:00:16 -08:00
commit b386c34ef9
700 changed files with 23857 additions and 22716 deletions

View file

@ -48,6 +48,7 @@ Alexandre Normand <alexandre.normand@gmail.com>
Alexei Sholik <alcosholik@gmail.com>
Alexey Borzenkov <snaury@gmail.com>
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Aliaksandr Valialkin <valyala@gmail.com>
Alif Rachmawadi <subosito@gmail.com>
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
@ -200,6 +201,7 @@ Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com>
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
Eden Li <eden.li@gmail.com>
Edward Muller <edwardam@interlix.com>
Egon Elbre <egonelbre@gmail.com>
Ehren Kret <ehren.kret@gmail.com>
Eivind Uggedal <eivind@uggedal.com>
@ -267,6 +269,7 @@ Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
Hiroshi Ioka <hirochachacha@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com>
Hsin-Ho Yeh <yhh92u@gmail.com>
Hu Keping <hukeping@huawei.com>
@ -313,6 +316,7 @@ Jihyun Yu <yjh0502@gmail.com>
Jim McGrath <jimmc2@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
Jingcheng Zhang <diogin@gmail.com>
Jingguo Yao <yaojingguo@gmail.com>
Jiong Du <londevil@gmail.com>
Joakim Sernbrant <serbaut@gmail.com>
Joe Harrison <joehazzers@gmail.com>
@ -328,6 +332,7 @@ John Jenkins <twodopeshaggy@gmail.com>
John Potocny <johnp@vividcortex.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Gold <jgold.bg@gmail.com>
Jonathan Mark <jhmark@xenops.com>
Jonathan Rudenberg <jonathan@titanous.com>

View file

@ -76,6 +76,7 @@ Alexei Sholik <alcosholik@gmail.com>
Alexey Borzenkov <snaury@gmail.com>
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Alexis Imperial-Legrand <ail@google.com>
Aliaksandr Valialkin <valyala@gmail.com>
Alif Rachmawadi <subosito@gmail.com>
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
@ -116,6 +117,7 @@ Anthony Starks <ajstarks@gmail.com>
Apisak Darakananda <pongad@gmail.com>
Aram Hăvărneanu <aram@mgk.ro>
Areski Belaid <areski@gmail.com>
Arkadi Pyuro <arkadi@google.com>
Arnaud Ysmal <arnaud.ysmal@gmail.com>
Arne Hormann <arnehormann@gmail.com>
Arnout Engelen <arnout@bzzt.net>
@ -135,6 +137,7 @@ Ben Fried <ben.fried@gmail.com>
Ben Lynn <benlynn@gmail.com>
Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us>
Benjamin Prosnitz <bprosnitz@google.com>
Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de>
@ -178,6 +181,7 @@ Cezar Sá Espinola <cezarsa@gmail.com>
ChaiShushan <chaishushan@gmail.com>
Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com>
Charles Weill <weill@google.com>
Chris Broadfoot <cbro@golang.org>
Chris Dollin <ehog.hedge@gmail.com>
Chris Farmiloe <chrisfarms@gmail.com>
@ -232,6 +236,7 @@ Dave Day <djd@golang.org>
Dave Grijalva <dgrijalva@ngmoco.com>
David Anderson <danderson@google.com>
David Barnett <dbarnett@google.com>
David Benjamin <davidben@google.com>
David Bürgin <676c7473@gmail.com>
David Calavera <david.calavera@gmail.com>
David Chase <drchase@google.com>
@ -277,6 +282,7 @@ Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com>
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
Eden Li <eden.li@gmail.com>
Edward Muller <edwardam@interlix.com>
Egon Elbre <egonelbre@gmail.com>
Ehren Kret <ehren.kret@gmail.com>
Eivind Uggedal <eivind@uggedal.com>
@ -359,6 +365,7 @@ Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
Hiroshi Ioka <hirochachacha@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com>
Hossein Sheikh Attar <hattar@google.com>
Hsin-Ho Yeh <yhh92u@gmail.com>
@ -379,6 +386,7 @@ Jacob Baskin <jbaskin@google.com>
Jacob H. Haven <jacob@cloudflare.com>
Jae Kwon <jae@tendermint.com>
Jakob Borg <jakob@nym.se>
Jakub Čajka <jcajka@redhat.com>
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
James Aguilar <jaguilar@google.com>
James David Chalfant <james.chalfant@gmail.com>
@ -422,6 +430,7 @@ Jim Cote <jfcote87@gmail.com>
Jim McGrath <jimmc2@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
Jingcheng Zhang <diogin@gmail.com>
Jingguo Yao <yaojingguo@gmail.com>
Jiong Du <londevil@gmail.com>
Joakim Sernbrant <serbaut@gmail.com>
Joe Harrison <joehazzers@gmail.com>
@ -444,6 +453,7 @@ John Potocny <johnp@vividcortex.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Allie <jonallie@google.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Feinberg <feinberg@google.com>
Jonathan Gold <jgold.bg@gmail.com>
Jonathan Hseu <jhseu@google.com>
@ -756,6 +766,7 @@ Sebastien Binet <seb.binet@gmail.com>
Sébastien Paolacci <sebastien.paolacci@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru>
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
Sergey Arseev <sergey.arseev@intel.com>
Sergio Luis O. B. Correia <sergio@correia.cc>
Seth Hoenig <seth.a.hoenig@gmail.com>
Shane Hansen <shanemhansen@gmail.com>

View file

@ -1,6 +1,6 @@
Files in this directory are data for Go's API checker ("go tool api", in src/cmd/api).
Each file is a list of of API features, one per line.
Each file is a list of API features, one per line.
go1.txt (and similarly named files) are frozen once a version has been
shipped. Each file adds new lines but does not remove any.

View file

@ -1983,13 +1983,13 @@ pkg log/syslog (openbsd-amd64-cgo), const LOG_SYSLOG = 40
pkg log/syslog (openbsd-amd64-cgo), const LOG_USER = 8
pkg log/syslog (openbsd-amd64-cgo), const LOG_UUCP = 64
pkg log/syslog (openbsd-amd64-cgo), const LOG_WARNING = 4
pkg math, const E = 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln10 = 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln2 = 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000
pkg math, const Log10E = 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279
pkg math, const Log2E = 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009
pkg math, const MaxFloat32 = 340282346638528859811704183484516925440
pkg math, const MaxFloat64 = 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const E = 2.71828 // 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln10 = 2.30259 // 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln2 = 0.693147 // 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000
pkg math, const Log10E = 0.434294 // 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279
pkg math, const Log2E = 1.4427 // 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009
pkg math, const MaxFloat32 = 3.40282e+38 // 340282346638528859811704183484516925440
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const MaxInt16 = 32767
pkg math, const MaxInt32 = 2147483647
pkg math, const MaxInt64 = 9223372036854775807
@ -2002,14 +2002,14 @@ pkg math, const MinInt16 = -32768
pkg math, const MinInt32 = -2147483648
pkg math, const MinInt64 = -9223372036854775808
pkg math, const MinInt8 = -128
pkg math, const Phi = 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000
pkg math, const Pi = 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat32 = 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat64 = 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const Sqrt2 = 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtE = 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPhi = 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPi = 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000
pkg math, const Phi = 1.61803 // 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000
pkg math, const Pi = 3.14159 // 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat32 = 1.4013e-45 // 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat64 = 4.94066e-324 // 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const Sqrt2 = 1.41421 // 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtE = 1.64872 // 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPhi = 1.27202 // 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPi = 1.77245 // 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000
pkg math/big, const MaxBase = 36
pkg math/big, method (*Int) MarshalJSON() ([]uint8, error)
pkg math/big, method (*Int) SetUint64(uint64) *Int

268
api/go1.6.txt Normal file
View file

@ -0,0 +1,268 @@
pkg archive/zip, method (*ReadCloser) RegisterDecompressor(uint16, Decompressor)
pkg archive/zip, method (*Reader) RegisterDecompressor(uint16, Decompressor)
pkg archive/zip, method (*Writer) RegisterCompressor(uint16, Compressor)
pkg bufio, method (*Scanner) Buffer([]uint8, int)
pkg bufio, var ErrFinalToken error
pkg crypto/tls, const TLS_RSA_WITH_AES_128_GCM_SHA256 = 156
pkg crypto/tls, const TLS_RSA_WITH_AES_128_GCM_SHA256 uint16
pkg crypto/tls, const TLS_RSA_WITH_AES_256_GCM_SHA384 = 157
pkg crypto/tls, const TLS_RSA_WITH_AES_256_GCM_SHA384 uint16
pkg crypto/tls, method (RecordHeaderError) Error() string
pkg crypto/tls, type RecordHeaderError struct
pkg crypto/tls, type RecordHeaderError struct, Msg string
pkg crypto/tls, type RecordHeaderError struct, RecordHeader [5]uint8
pkg crypto/x509, method (InsecureAlgorithmError) Error() string
pkg crypto/x509, method (SignatureAlgorithm) String() string
pkg crypto/x509, type InsecureAlgorithmError int
pkg database/sql, method (*DB) SetConnMaxLifetime(time.Duration)
pkg debug/dwarf, const ClassUnknown = 0
pkg debug/dwarf, const ClassUnknown Class
pkg debug/elf, const COMPRESS_HIOS = 1879048191
pkg debug/elf, const COMPRESS_HIOS CompressionType
pkg debug/elf, const COMPRESS_HIPROC = 2147483647
pkg debug/elf, const COMPRESS_HIPROC CompressionType
pkg debug/elf, const COMPRESS_LOOS = 1610612736
pkg debug/elf, const COMPRESS_LOOS CompressionType
pkg debug/elf, const COMPRESS_LOPROC = 1879048192
pkg debug/elf, const COMPRESS_LOPROC CompressionType
pkg debug/elf, const COMPRESS_ZLIB = 1
pkg debug/elf, const COMPRESS_ZLIB CompressionType
pkg debug/elf, const R_MIPS_16 = 1
pkg debug/elf, const R_MIPS_16 R_MIPS
pkg debug/elf, const R_MIPS_26 = 4
pkg debug/elf, const R_MIPS_26 R_MIPS
pkg debug/elf, const R_MIPS_32 = 2
pkg debug/elf, const R_MIPS_32 R_MIPS
pkg debug/elf, const R_MIPS_64 = 18
pkg debug/elf, const R_MIPS_64 R_MIPS
pkg debug/elf, const R_MIPS_ADD_IMMEDIATE = 34
pkg debug/elf, const R_MIPS_ADD_IMMEDIATE R_MIPS
pkg debug/elf, const R_MIPS_CALL16 = 11
pkg debug/elf, const R_MIPS_CALL16 R_MIPS
pkg debug/elf, const R_MIPS_CALL_HI16 = 30
pkg debug/elf, const R_MIPS_CALL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_CALL_LO16 = 31
pkg debug/elf, const R_MIPS_CALL_LO16 R_MIPS
pkg debug/elf, const R_MIPS_DELETE = 27
pkg debug/elf, const R_MIPS_DELETE R_MIPS
pkg debug/elf, const R_MIPS_GOT16 = 9
pkg debug/elf, const R_MIPS_GOT16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_DISP = 19
pkg debug/elf, const R_MIPS_GOT_DISP R_MIPS
pkg debug/elf, const R_MIPS_GOT_HI16 = 22
pkg debug/elf, const R_MIPS_GOT_HI16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_LO16 = 23
pkg debug/elf, const R_MIPS_GOT_LO16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_OFST = 21
pkg debug/elf, const R_MIPS_GOT_OFST R_MIPS
pkg debug/elf, const R_MIPS_GOT_PAGE = 20
pkg debug/elf, const R_MIPS_GOT_PAGE R_MIPS
pkg debug/elf, const R_MIPS_GPREL16 = 7
pkg debug/elf, const R_MIPS_GPREL16 R_MIPS
pkg debug/elf, const R_MIPS_GPREL32 = 12
pkg debug/elf, const R_MIPS_GPREL32 R_MIPS
pkg debug/elf, const R_MIPS_HI16 = 5
pkg debug/elf, const R_MIPS_HI16 R_MIPS
pkg debug/elf, const R_MIPS_HIGHER = 28
pkg debug/elf, const R_MIPS_HIGHER R_MIPS
pkg debug/elf, const R_MIPS_HIGHEST = 29
pkg debug/elf, const R_MIPS_HIGHEST R_MIPS
pkg debug/elf, const R_MIPS_INSERT_A = 25
pkg debug/elf, const R_MIPS_INSERT_A R_MIPS
pkg debug/elf, const R_MIPS_INSERT_B = 26
pkg debug/elf, const R_MIPS_INSERT_B R_MIPS
pkg debug/elf, const R_MIPS_JALR = 37
pkg debug/elf, const R_MIPS_JALR R_MIPS
pkg debug/elf, const R_MIPS_LITERAL = 8
pkg debug/elf, const R_MIPS_LITERAL R_MIPS
pkg debug/elf, const R_MIPS_LO16 = 6
pkg debug/elf, const R_MIPS_LO16 R_MIPS
pkg debug/elf, const R_MIPS_NONE = 0
pkg debug/elf, const R_MIPS_NONE R_MIPS
pkg debug/elf, const R_MIPS_PC16 = 10
pkg debug/elf, const R_MIPS_PC16 R_MIPS
pkg debug/elf, const R_MIPS_PJUMP = 35
pkg debug/elf, const R_MIPS_PJUMP R_MIPS
pkg debug/elf, const R_MIPS_REL16 = 33
pkg debug/elf, const R_MIPS_REL16 R_MIPS
pkg debug/elf, const R_MIPS_REL32 = 3
pkg debug/elf, const R_MIPS_REL32 R_MIPS
pkg debug/elf, const R_MIPS_RELGOT = 36
pkg debug/elf, const R_MIPS_RELGOT R_MIPS
pkg debug/elf, const R_MIPS_SCN_DISP = 32
pkg debug/elf, const R_MIPS_SCN_DISP R_MIPS
pkg debug/elf, const R_MIPS_SHIFT5 = 16
pkg debug/elf, const R_MIPS_SHIFT5 R_MIPS
pkg debug/elf, const R_MIPS_SHIFT6 = 17
pkg debug/elf, const R_MIPS_SHIFT6 R_MIPS
pkg debug/elf, const R_MIPS_SUB = 24
pkg debug/elf, const R_MIPS_SUB R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPMOD32 = 38
pkg debug/elf, const R_MIPS_TLS_DTPMOD32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPMOD64 = 40
pkg debug/elf, const R_MIPS_TLS_DTPMOD64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL32 = 39
pkg debug/elf, const R_MIPS_TLS_DTPREL32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL64 = 41
pkg debug/elf, const R_MIPS_TLS_DTPREL64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL_HI16 = 44
pkg debug/elf, const R_MIPS_TLS_DTPREL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL_LO16 = 45
pkg debug/elf, const R_MIPS_TLS_DTPREL_LO16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_GD = 42
pkg debug/elf, const R_MIPS_TLS_GD R_MIPS
pkg debug/elf, const R_MIPS_TLS_GOTTPREL = 46
pkg debug/elf, const R_MIPS_TLS_GOTTPREL R_MIPS
pkg debug/elf, const R_MIPS_TLS_LDM = 43
pkg debug/elf, const R_MIPS_TLS_LDM R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL32 = 47
pkg debug/elf, const R_MIPS_TLS_TPREL32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL64 = 48
pkg debug/elf, const R_MIPS_TLS_TPREL64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL_HI16 = 49
pkg debug/elf, const R_MIPS_TLS_TPREL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL_LO16 = 50
pkg debug/elf, const R_MIPS_TLS_TPREL_LO16 R_MIPS
pkg debug/elf, const SHF_COMPRESSED = 2048
pkg debug/elf, const SHF_COMPRESSED SectionFlag
pkg debug/elf, method (CompressionType) GoString() string
pkg debug/elf, method (CompressionType) String() string
pkg debug/elf, method (R_MIPS) GoString() string
pkg debug/elf, method (R_MIPS) String() string
pkg debug/elf, type Chdr32 struct
pkg debug/elf, type Chdr32 struct, Addralign uint32
pkg debug/elf, type Chdr32 struct, Size uint32
pkg debug/elf, type Chdr32 struct, Type uint32
pkg debug/elf, type Chdr64 struct
pkg debug/elf, type Chdr64 struct, Addralign uint64
pkg debug/elf, type Chdr64 struct, Size uint64
pkg debug/elf, type Chdr64 struct, Type uint32
pkg debug/elf, type CompressionType int
pkg debug/elf, type R_MIPS int
pkg debug/elf, type SectionHeader struct, FileSize uint64
pkg encoding/asn1, const ClassApplication = 1
pkg encoding/asn1, const ClassApplication ideal-int
pkg encoding/asn1, const ClassContextSpecific = 2
pkg encoding/asn1, const ClassContextSpecific ideal-int
pkg encoding/asn1, const ClassPrivate = 3
pkg encoding/asn1, const ClassPrivate ideal-int
pkg encoding/asn1, const ClassUniversal = 0
pkg encoding/asn1, const ClassUniversal ideal-int
pkg encoding/asn1, const TagBitString = 3
pkg encoding/asn1, const TagBitString ideal-int
pkg encoding/asn1, const TagBoolean = 1
pkg encoding/asn1, const TagBoolean ideal-int
pkg encoding/asn1, const TagEnum = 10
pkg encoding/asn1, const TagEnum ideal-int
pkg encoding/asn1, const TagGeneralString = 27
pkg encoding/asn1, const TagGeneralString ideal-int
pkg encoding/asn1, const TagGeneralizedTime = 24
pkg encoding/asn1, const TagGeneralizedTime ideal-int
pkg encoding/asn1, const TagIA5String = 22
pkg encoding/asn1, const TagIA5String ideal-int
pkg encoding/asn1, const TagInteger = 2
pkg encoding/asn1, const TagInteger ideal-int
pkg encoding/asn1, const TagOID = 6
pkg encoding/asn1, const TagOID ideal-int
pkg encoding/asn1, const TagOctetString = 4
pkg encoding/asn1, const TagOctetString ideal-int
pkg encoding/asn1, const TagPrintableString = 19
pkg encoding/asn1, const TagPrintableString ideal-int
pkg encoding/asn1, const TagSequence = 16
pkg encoding/asn1, const TagSequence ideal-int
pkg encoding/asn1, const TagSet = 17
pkg encoding/asn1, const TagSet ideal-int
pkg encoding/asn1, const TagT61String = 20
pkg encoding/asn1, const TagT61String ideal-int
pkg encoding/asn1, const TagUTCTime = 23
pkg encoding/asn1, const TagUTCTime ideal-int
pkg encoding/asn1, const TagUTF8String = 12
pkg encoding/asn1, const TagUTF8String ideal-int
pkg go/build, const AllowVendor = 8
pkg go/build, const AllowVendor ImportMode
pkg go/build, type Package struct, InvalidGoFiles []string
pkg go/constant, func ToComplex(Value) Value
pkg go/constant, func ToFloat(Value) Value
pkg go/constant, func ToInt(Value) Value
pkg go/constant, type Value interface, ExactString() string
pkg html/template, func IsTrue(interface{}) (bool, bool)
pkg html/template, method (*Template) DefinedTemplates() string
pkg image, func NewNYCbCrA(Rectangle, YCbCrSubsampleRatio) *NYCbCrA
pkg image, method (*NYCbCrA) AOffset(int, int) int
pkg image, method (*NYCbCrA) At(int, int) color.Color
pkg image, method (*NYCbCrA) Bounds() Rectangle
pkg image, method (*NYCbCrA) COffset(int, int) int
pkg image, method (*NYCbCrA) ColorModel() color.Model
pkg image, method (*NYCbCrA) NYCbCrAAt(int, int) color.NYCbCrA
pkg image, method (*NYCbCrA) Opaque() bool
pkg image, method (*NYCbCrA) SubImage(Rectangle) Image
pkg image, method (*NYCbCrA) YCbCrAt(int, int) color.YCbCr
pkg image, method (*NYCbCrA) YOffset(int, int) int
pkg image, type NYCbCrA struct
pkg image, type NYCbCrA struct, A []uint8
pkg image, type NYCbCrA struct, AStride int
pkg image, type NYCbCrA struct, embedded YCbCr
pkg image/color, method (NYCbCrA) RGBA() (uint32, uint32, uint32, uint32)
pkg image/color, type NYCbCrA struct
pkg image/color, type NYCbCrA struct, A uint8
pkg image/color, type NYCbCrA struct, embedded YCbCr
pkg image/color, var NYCbCrAModel Model
pkg math/big, method (*Float) MarshalText() ([]uint8, error)
pkg math/big, method (*Float) UnmarshalText([]uint8) error
pkg math/big, method (*Int) Append([]uint8, int) []uint8
pkg math/big, method (*Int) Text(int) string
pkg math/rand, func Read([]uint8) (int, error)
pkg math/rand, method (*Rand) Read([]uint8) (int, error)
pkg net, type DNSError struct, IsTemporary bool
pkg net, type Dialer struct, Cancel <-chan struct
pkg net/http, const MethodConnect = "CONNECT"
pkg net/http, const MethodConnect ideal-string
pkg net/http, const MethodDelete = "DELETE"
pkg net/http, const MethodDelete ideal-string
pkg net/http, const MethodGet = "GET"
pkg net/http, const MethodGet ideal-string
pkg net/http, const MethodHead = "HEAD"
pkg net/http, const MethodHead ideal-string
pkg net/http, const MethodOptions = "OPTIONS"
pkg net/http, const MethodOptions ideal-string
pkg net/http, const MethodPatch = "PATCH"
pkg net/http, const MethodPatch ideal-string
pkg net/http, const MethodPost = "POST"
pkg net/http, const MethodPost ideal-string
pkg net/http, const MethodPut = "PUT"
pkg net/http, const MethodPut ideal-string
pkg net/http, const MethodTrace = "TRACE"
pkg net/http, const MethodTrace ideal-string
pkg net/http, const StatusNetworkAuthenticationRequired = 511
pkg net/http, const StatusNetworkAuthenticationRequired ideal-int
pkg net/http, const StatusPreconditionRequired = 428
pkg net/http, const StatusPreconditionRequired ideal-int
pkg net/http, const StatusRequestHeaderFieldsTooLarge = 431
pkg net/http, const StatusRequestHeaderFieldsTooLarge ideal-int
pkg net/http, const StatusTooManyRequests = 429
pkg net/http, const StatusTooManyRequests ideal-int
pkg net/http, type Transport struct, ExpectContinueTimeout time.Duration
pkg net/http, type Transport struct, TLSNextProto map[string]func(string, *tls.Conn) RoundTripper
pkg net/http, var ErrSkipAltProtocol error
pkg net/http/httptest, method (*ResponseRecorder) WriteString(string) (int, error)
pkg net/http/httputil, type BufferPool interface { Get, Put }
pkg net/http/httputil, type BufferPool interface, Get() []uint8
pkg net/http/httputil, type BufferPool interface, Put([]uint8)
pkg net/http/httputil, type ReverseProxy struct, BufferPool BufferPool
pkg net/url, method (*Error) Temporary() bool
pkg net/url, method (*Error) Timeout() bool
pkg net/url, method (InvalidHostError) Error() string
pkg net/url, type InvalidHostError string
pkg os/exec, type ExitError struct, Stderr []uint8
pkg regexp, method (*Regexp) Copy() *Regexp
pkg runtime/debug, func SetTraceback(string)
pkg strconv, func AppendQuoteRuneToGraphic([]uint8, int32) []uint8
pkg strconv, func AppendQuoteToGraphic([]uint8, string) []uint8
pkg strconv, func IsGraphic(int32) bool
pkg strconv, func QuoteRuneToGraphic(int32) string
pkg strconv, func QuoteToGraphic(string) string
pkg text/template, func IsTrue(interface{}) (bool, bool)
pkg text/template, method (ExecError) Error() string
pkg text/template, type ExecError struct
pkg text/template, type ExecError struct, Err error
pkg text/template, type ExecError struct, Name string

View file

@ -1,160 +0,0 @@
pkg bufio, method (*Scanner) Buffer([]uint8, int)
pkg bufio, var ErrFinalToken error
pkg debug/dwarf, const ClassUnknown = 0
pkg debug/dwarf, const ClassUnknown Class
pkg debug/elf, const R_MIPS_16 = 1
pkg debug/elf, const R_MIPS_16 R_MIPS
pkg debug/elf, const R_MIPS_26 = 4
pkg debug/elf, const R_MIPS_26 R_MIPS
pkg debug/elf, const R_MIPS_32 = 2
pkg debug/elf, const R_MIPS_32 R_MIPS
pkg debug/elf, const R_MIPS_64 = 18
pkg debug/elf, const R_MIPS_64 R_MIPS
pkg debug/elf, const R_MIPS_ADD_IMMEDIATE = 34
pkg debug/elf, const R_MIPS_ADD_IMMEDIATE R_MIPS
pkg debug/elf, const R_MIPS_CALL16 = 11
pkg debug/elf, const R_MIPS_CALL16 R_MIPS
pkg debug/elf, const R_MIPS_CALL_HI16 = 30
pkg debug/elf, const R_MIPS_CALL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_CALL_LO16 = 31
pkg debug/elf, const R_MIPS_CALL_LO16 R_MIPS
pkg debug/elf, const R_MIPS_DELETE = 27
pkg debug/elf, const R_MIPS_DELETE R_MIPS
pkg debug/elf, const R_MIPS_GOT16 = 9
pkg debug/elf, const R_MIPS_GOT16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_DISP = 19
pkg debug/elf, const R_MIPS_GOT_DISP R_MIPS
pkg debug/elf, const R_MIPS_GOT_HI16 = 22
pkg debug/elf, const R_MIPS_GOT_HI16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_LO16 = 23
pkg debug/elf, const R_MIPS_GOT_LO16 R_MIPS
pkg debug/elf, const R_MIPS_GOT_OFST = 21
pkg debug/elf, const R_MIPS_GOT_OFST R_MIPS
pkg debug/elf, const R_MIPS_GOT_PAGE = 20
pkg debug/elf, const R_MIPS_GOT_PAGE R_MIPS
pkg debug/elf, const R_MIPS_GPREL16 = 7
pkg debug/elf, const R_MIPS_GPREL16 R_MIPS
pkg debug/elf, const R_MIPS_GPREL32 = 12
pkg debug/elf, const R_MIPS_GPREL32 R_MIPS
pkg debug/elf, const R_MIPS_HI16 = 5
pkg debug/elf, const R_MIPS_HI16 R_MIPS
pkg debug/elf, const R_MIPS_HIGHER = 28
pkg debug/elf, const R_MIPS_HIGHER R_MIPS
pkg debug/elf, const R_MIPS_HIGHEST = 29
pkg debug/elf, const R_MIPS_HIGHEST R_MIPS
pkg debug/elf, const R_MIPS_INSERT_A = 25
pkg debug/elf, const R_MIPS_INSERT_A R_MIPS
pkg debug/elf, const R_MIPS_INSERT_B = 26
pkg debug/elf, const R_MIPS_INSERT_B R_MIPS
pkg debug/elf, const R_MIPS_JALR = 37
pkg debug/elf, const R_MIPS_JALR R_MIPS
pkg debug/elf, const R_MIPS_LITERAL = 8
pkg debug/elf, const R_MIPS_LITERAL R_MIPS
pkg debug/elf, const R_MIPS_LO16 = 6
pkg debug/elf, const R_MIPS_LO16 R_MIPS
pkg debug/elf, const R_MIPS_NONE = 0
pkg debug/elf, const R_MIPS_NONE R_MIPS
pkg debug/elf, const R_MIPS_PC16 = 10
pkg debug/elf, const R_MIPS_PC16 R_MIPS
pkg debug/elf, const R_MIPS_PJUMP = 35
pkg debug/elf, const R_MIPS_PJUMP R_MIPS
pkg debug/elf, const R_MIPS_REL16 = 33
pkg debug/elf, const R_MIPS_REL16 R_MIPS
pkg debug/elf, const R_MIPS_REL32 = 3
pkg debug/elf, const R_MIPS_REL32 R_MIPS
pkg debug/elf, const R_MIPS_RELGOT = 36
pkg debug/elf, const R_MIPS_RELGOT R_MIPS
pkg debug/elf, const R_MIPS_SCN_DISP = 32
pkg debug/elf, const R_MIPS_SCN_DISP R_MIPS
pkg debug/elf, const R_MIPS_SHIFT5 = 16
pkg debug/elf, const R_MIPS_SHIFT5 R_MIPS
pkg debug/elf, const R_MIPS_SHIFT6 = 17
pkg debug/elf, const R_MIPS_SHIFT6 R_MIPS
pkg debug/elf, const R_MIPS_SUB = 24
pkg debug/elf, const R_MIPS_SUB R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPMOD32 = 38
pkg debug/elf, const R_MIPS_TLS_DTPMOD32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPMOD64 = 40
pkg debug/elf, const R_MIPS_TLS_DTPMOD64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL32 = 39
pkg debug/elf, const R_MIPS_TLS_DTPREL32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL64 = 41
pkg debug/elf, const R_MIPS_TLS_DTPREL64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL_HI16 = 44
pkg debug/elf, const R_MIPS_TLS_DTPREL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_DTPREL_LO16 = 45
pkg debug/elf, const R_MIPS_TLS_DTPREL_LO16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_GD = 42
pkg debug/elf, const R_MIPS_TLS_GD R_MIPS
pkg debug/elf, const R_MIPS_TLS_GOTTPREL = 46
pkg debug/elf, const R_MIPS_TLS_GOTTPREL R_MIPS
pkg debug/elf, const R_MIPS_TLS_LDM = 43
pkg debug/elf, const R_MIPS_TLS_LDM R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL32 = 47
pkg debug/elf, const R_MIPS_TLS_TPREL32 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL64 = 48
pkg debug/elf, const R_MIPS_TLS_TPREL64 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL_HI16 = 49
pkg debug/elf, const R_MIPS_TLS_TPREL_HI16 R_MIPS
pkg debug/elf, const R_MIPS_TLS_TPREL_LO16 = 50
pkg debug/elf, const R_MIPS_TLS_TPREL_LO16 R_MIPS
pkg debug/elf, method (R_MIPS) GoString() string
pkg debug/elf, method (R_MIPS) String() string
pkg debug/elf, type R_MIPS int
pkg html/template, func IsTrue(interface{}) (bool, bool)
pkg image, func NewNYCbCrA(Rectangle, YCbCrSubsampleRatio) *NYCbCrA
pkg image, method (*NYCbCrA) AOffset(int, int) int
pkg image, method (*NYCbCrA) At(int, int) color.Color
pkg image, method (*NYCbCrA) Bounds() Rectangle
pkg image, method (*NYCbCrA) COffset(int, int) int
pkg image, method (*NYCbCrA) ColorModel() color.Model
pkg image, method (*NYCbCrA) NYCbCrAAt(int, int) color.NYCbCrA
pkg image, method (*NYCbCrA) Opaque() bool
pkg image, method (*NYCbCrA) SubImage(Rectangle) Image
pkg image, method (*NYCbCrA) YCbCrAt(int, int) color.YCbCr
pkg image, method (*NYCbCrA) YOffset(int, int) int
pkg image, type NYCbCrA struct
pkg image, type NYCbCrA struct, A []uint8
pkg image, type NYCbCrA struct, AStride int
pkg image, type NYCbCrA struct, embedded YCbCr
pkg image/color, method (NYCbCrA) RGBA() (uint32, uint32, uint32, uint32)
pkg image/color, type NYCbCrA struct
pkg image/color, type NYCbCrA struct, A uint8
pkg image/color, type NYCbCrA struct, embedded YCbCr
pkg image/color, var NYCbCrAModel Model
pkg math/big, method (*Float) MarshalText() ([]uint8, error)
pkg math/big, method (*Float) UnmarshalText([]uint8) error
pkg math/big, method (*Int) Append([]uint8, int) []uint8
pkg math/big, method (*Int) Text(int) string
pkg math/rand, func Read([]uint8) (int, error)
pkg math/rand, method (*Rand) Read([]uint8) (int, error)
pkg net, type DNSError struct, IsTemporary bool
pkg net/http, const StatusNetworkAuthenticationRequired = 511
pkg net/http, const StatusNetworkAuthenticationRequired ideal-int
pkg net/http, const StatusPreconditionRequired = 428
pkg net/http, const StatusPreconditionRequired ideal-int
pkg net/http, const StatusRequestHeaderFieldsTooLarge = 431
pkg net/http, const StatusRequestHeaderFieldsTooLarge ideal-int
pkg net/http, const StatusTooManyRequests = 429
pkg net/http, const StatusTooManyRequests ideal-int
pkg net/http, type Transport struct, ExpectContinueTimeout time.Duration
pkg net/http, type Transport struct, TLSNextProto map[string]func(string, *tls.Conn) RoundTripper
pkg net/http, var ErrSkipAltProtocol error
pkg net/http/httptest, method (*ResponseRecorder) WriteString(string) (int, error)
pkg net/http/httputil, type BufferPool interface { Get, Put }
pkg net/http/httputil, type BufferPool interface, Get() []uint8
pkg net/http/httputil, type BufferPool interface, Put([]uint8)
pkg net/http/httputil, type ReverseProxy struct, BufferPool BufferPool
pkg net/url, method (*Error) Temporary() bool
pkg net/url, method (*Error) Timeout() bool
pkg os/exec, type ExitError struct, Stderr []uint8
pkg strconv, func AppendQuoteRuneToGraphic([]uint8, int32) []uint8
pkg strconv, func AppendQuoteToGraphic([]uint8, string) []uint8
pkg strconv, func IsGraphic(int32) bool
pkg strconv, func QuoteRuneToGraphic(int32) string
pkg strconv, func QuoteToGraphic(string) string
pkg text/template, func IsTrue(interface{}) (bool, bool)
pkg text/template, method (ExecError) Error() string
pkg text/template, type ExecError struct
pkg text/template, type ExecError struct, Err error
pkg text/template, type ExecError struct, Name string

View file

@ -176,7 +176,7 @@ This form is used to name global functions and data.
Adding <code>&lt;&gt;</code> to the name, as in <span style="white-space: nowrap"><code>foo&lt;&gt;(SB)</code></span>, makes the name
visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
Adding an offset to the name refers to that offset from the symbol's address, so
<code>a+4(SB)</code> is four bytes past the start of <code>foo</code>.
<code>foo+4(SB)</code> is four bytes past the start of <code>foo</code>.
</p>
<p>

273
doc/conduct.html Normal file
View file

@ -0,0 +1,273 @@
<!--{
"Title": "Go Community Code of Conduct",
"Path": "/conduct",
"Template": true
}-->
<style>
ul {
max-width: 800px;
}
ul ul {
margin: 0 0 5px;
}
</style>
<h2 id="about">About the Code of Conduct</h2>
<h3 id="why">Why have a Code of Conduct?</h3>
<p>
Online communities include people from many different backgrounds.
The Go contributors are committed to providing a friendly, safe and welcoming
environment for all, regardless of age, disability, gender, nationality, race,
religion, sexuality, or similar personal characteristic.
</p>
<p>
The first goal of the Code of Conduct is to specify a baseline standard
of behavior so that people with different social values and communication
styles can talk about Go effectively, productively, and respectfully.
</p>
<p>
The second goal is to provide a mechanism for resolving conflicts in the
community when they arise.
</p>
<p>
The third goal of the Code of Conduct is to make our community welcoming to
people from different backgrounds.
Diversity is critical to the project; for Go to be successful, it needs
contributors and users from all backgrounds.
(See <a href="https://blog.golang.org/open-source">Go, Open Source, Community</a>.)
</p>
<p>
With that said, a healthy community must allow for disagreement and debate.
The Code of Conduct is not a mechanism for people to silence others with whom
they disagree.
</p>
<h3 id="spaces">Where does the Code of Conduct apply?</h3>
<p>
If you participate in or contribute to the Go ecosystem in any way,
you are encouraged to follow the Code of Conduct while doing so.
</p>
<p>
Explicit enforcement of the Code of Conduct applies to the
official forums operated by the Go project (“Go spaces”):
</p>
<ul>
<li>The official <a href="https://github.com/golang/">GitHub projects</a>
and <a href="https://go-review.googlesource.com/">code reviews</a>.
<li>The <a href="https://groups.google.com/group/golang-nuts">golang-nuts</a> and
<a href="https://groups.google.com/group/golang-dev">golang-dev</a> mailing lists.
<li>The #go-nuts IRC channel on Freenode.
<li>The <a href="https://reddit.com/r/golang">/r/golang subreddit</a>.
</ul>
<p>
Other Go groups (such as conferences, meetups, and other unofficial forums) are
encouraged to adopt this Code of Conduct. Those groups must provide their own
moderators and/or working group (see below).
</p>
<h2 id="values">Gopher values</h2>
<p>
These are the values to which people in the Go community (“Gophers”) should aspire.
</p>
<ul>
<li>Be friendly and welcoming
<li>Be patient
<ul>
<li>Remember that people have varying communication styles and that not
everyone is using their native language.
(Meaning and tone can be lost in translation.)
</ul>
<li>Be thoughtful
<ul>
<li>Productive communication requires effort.
Think about how your words will be interpreted.
<li>Remember that sometimes it is best to refrain entirely from commenting.
</ul>
<li>Be respectful
<ul>
<li>In particular, respect differences of opinion.
</ul>
<li>Be charitable
<ul>
<li>Interpret the arguments of others in good faith, do not seek to disagree.
<li>When we do disagree, try to understand why.
</ul>
<li>Avoid destructive behavior:
<ul>
<li>Derailing: stay on topic; if you want to talk about something else,
start a new conversation.
<li>Unconstructive criticism: don't merely decry the current state of affairs;
offer—or at least solicit—suggestions as to how things may be improved.
<li>Snarking (pithy, unproductive, sniping comments)
<li>Discussing potentially offensive or sensitive issues;
this all too often leads to unnecessary conflict.
<li>Microaggressions: brief and commonplace verbal, behavioral and
environmental indignities that communicate hostile, derogatory or negative
slights and insults to a person or group.
</ul>
</ul>
<p>
People are complicated.
You should expect to be misunderstood and to misunderstand others;
when this inevitably occurs, resist the urge to be defensive or assign blame.
Try not to take offense where no offense was intended.
Give people the benefit of the doubt.
Even if the intent was to provoke, do not rise to it.
It is the responsibility of <i>all parties</i> to de-escalate conflict when it arises.
</p>
<h2 id="unwelcome_behavior">Unwelcome behavior</h2>
<p>
These actions are explicitly forbidden in Go spaces:
</p>
<ul>
<li>Insulting, demeaning, hateful, or threatening remarks.
<li>Discrimination based on age, disability, gender, nationality, race,
religion, sexuality, or similar personal characteristic.
<li>Bullying or systematic harassment.
<li>Unwelcome sexual advances.
<li>Incitement to any of these.
</ul>
<h2 id="moderation">Moderation</h2>
<p>
The Go spaces are not free speech venues; they are for discussion about Go.
These spaces have moderators.
The goal of the moderators is to facilitate civil discussion about Go.
</p>
<p>
When using the official Go spaces you should act in the spirit of the “Gopher
values”.
If you conduct yourself in a way that is explicitly forbidden by the CoC,
you will be warned and asked to stop.
If you do not stop, you will be removed from our community spaces temporarily.
Repeated, willful breaches of the CoC will result in a permanent ban.
</p>
<p>
Moderators are held to a higher standard than other community members.
If a moderator creates an inappropriate situation, they should expect less
leeway than others, and should expect to be removed from their position if they
cannot adhere to the CoC.
</p>
<p>
Complaints about moderator actions must be handled using the reporting process
below.
</p>
<h2 id="reporting">Reporting issues</h2>
<p>
The Code of Conduct Working Group is a group of people that represent the Go
community. They are responsible for handling conduct-related issues.
Their purpose is to de-escalate conflicts and try to resolve issues to the
satisfaction of all parties. They are:
</p>
<ul>
<li>Aditya Mukerjee &lt;dev@chimeracoder.net&gt;
<li>Andrew Gerrand &lt;adg@golang.org&gt;
<li>Dave Cheney &lt;dave@cheney.net&gt;
<li>Jason Buberel &lt;jbuberel@google.com&gt;
<li>Peggy Li &lt;peggyli.224@gmail.com&gt;
<li>Sarah Adams &lt;sadams.codes@gmail.com&gt;
<li>Steve Francia &lt;steve.francia@gmail.com&gt;
<li>Verónica López &lt;gveronicalg@gmail.com&gt;
</ul>
<p>
If you encounter a conduct-related issue, you should report it to the
Working Group using the process described below.
<b>Do not</b> post about the issue publicly or try to rally sentiment against a
particular individual or group.
</p>
<ul>
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a> or
<a href="https://golang.org/s/conduct-report">submit an anonymous report</a>.
<ul>
<li>Your message will reach the Working Group.
<li>Reports are confidential within the Working Group.
<li>Should you choose to remain anonymous then the Working Group cannot
notify you of the outcome of your report.
<li>You may contact a member of the group directly if you do not feel
comfortable contacting the group as a whole. That member will then raise
the issue with the Working Group as a whole, preserving the privacy of the
reporter (if desired).
<li>If your report concerns a member of the Working Group they will be recused
from Working Group discussions of the report.
<li>The Working Group will strive to handle reports with discretion and
sensitivity, to protect the privacy of the involved parties,
and to avoid conflicts of interest.
</ul>
<li>You should receive a response within 48 hours (likely sooner).
(Should you choose to contact a single Working Group member,
it may take longer to receive a response.)
<li>The Working Group will meet to review the incident and determine what happened.
<ul>
<li>With the permission of person reporting the incident, the Working Group
may reach out to other community members for more context.
</ul>
<li>The Working Group will reach a decision as to how to act. These may include:
<ul>
<li>Nothing.
<li>A request for a private or public apology.
<li>A private or public warning.
<li>An imposed vacation (for instance, asking someone to abstain for a week
from a mailing list or IRC).
<li>A permanent or temporary ban from some or all Go spaces.
</ul>
<li>The Working Group will reach out to the original reporter to let them know
the decision.
<li>Appeals to the decision may be made to the Working Group,
or to any of its members directly.
</ul>
<p>
<b>Note that the goal of the Code of Conduct and the Working Group is to resolve
conflicts in the most harmonious way possible.</b>
We hope that in most cases issues may be resolved through polite discussion and
mutual agreement.
Bannings and other forceful measures are to be employed only as a last resort.
</p>
<p>
Changes to the Code of Conduct (including to the members of the Working Group)
should be proposed using the
<a href="https://golang.org/s/proposal-process">change proposal process</a>.
</p>
<h2 id="summary">Summary</h2>
<ul>
<li>Treat everyone with respect and kindness.
<li>Be thoughtful in how you communicate.
<li>Dont be destructive or inflammatory.
<li>If you encounter an issue, please mail <a href="mailto:conduct@golang.org">conduct@golang.org</a>.
</ul>
<h3 id="acknowledgements">Acknowledgements</h3>
<p>
Parts of this document were derived from the Code of Conduct documents of the
Django, FreeBSD, and Rust projects.
</p>

View file

@ -91,10 +91,16 @@ We pride ourselves on being meticulous; no issue is too small.
<p>
Security-related issues should be reported to
<a href="mailto:security@golang.org">security@golang.org</a>.
<a href="mailto:security@golang.org">security@golang.org</a>.<br>
See the <a href="/security">security policy</a> for more details.
</p>
<p>
Community-related issues should be reported to
<a href="mailto:conduct@golang.org">conduct@golang.org</a>.<br>
See the <a href="/conduct">Code of Conduct</a> for more details.
</p>
<h3><a href="/doc/contribute.html">Contributing code</a></h3>
<p>

View file

@ -81,7 +81,7 @@ discussed below, helps manage the code review process through a Google-hosted
system called <a href="https://code.google.com/p/gerrit/">Gerrit</a>.
</p>
<h3>Set up authentication for code review</h3>
<h3 id="auth">Set up authentication for code review</h3>
<p>
Gerrit uses Google Accounts for authentication. If you don't have
@ -120,7 +120,7 @@ Your secret authentication token is now in a <code>.gitcookie</code> file
and Git is configured to use this file.
</p>
<h3>Register with Gerrit</h3>
<h3 id="gerrit">Register with Gerrit</h3>
<p>
Now that you have your authentication token,
@ -132,7 +132,7 @@ to Google Accounts. Sign in using the same Google Account you used above.
That is all that is required.
</p>
<h3>Contributor License Agreement</h3>
<h3 id="cla">Contributor License Agreement</h3>
<p>Gerrit serves as the gatekeeper and uses your e-mail address as the key.
To send your first change to the Go project from a given address,
@ -167,7 +167,14 @@ you can create one by clicking "New Contributor Agreement" and following the ste
This rigmarole only needs to be done for your first submission for each email address.
</p>
<h3>Install the git-codereview command</h3>
<p>
If the copyright holder for the code you are submitting changes—for example,
if you start contributing code on behalf of a new company—please send email
to let us know, so that we can make sure an appropriate agreement is completed
and update the <code>AUTHORS</code> file.
</p>
<h3 id="git-codereview">Install the git-codereview command</h3>
<p>
Now install the <code>git-codereview</code> command by running,
@ -201,7 +208,7 @@ if you intend to use plain Git for daily work, install the hooks in a new Git
checkout by running <code>git-codereview</code> <code>hooks</code>.
</p>
<h3>Set up git aliases</h3>
<h3 id="git-config">Set up git aliases</h3>
<p>
The <code>git-codereview</code> command can be run directly from the shell
@ -243,7 +250,7 @@ To install them, copy this text into your Git configuration file
sync = codereview sync
</pre>
<h3>Understanding the git-codereview command</h3>
<h3 id="help">Understanding the git-codereview command</h3>
<p>After installing the <code>git-codereview</code> command, you can run</p>
@ -256,7 +263,7 @@ to learn more about its commands.
You can also read the <a href="https://godoc.org/golang.org/x/review/git-codereview">command documentation</a>.
</p>
<h3>Switch to the master branch</h3>
<h3 id="master">Switch to the master branch</h3>
<p>
Most Go installations use a release branch, but new changes should
@ -276,7 +283,7 @@ $ git sync
<code>git</code> <code>pull</code> <code>-r</code>.)
</p>
<h3>Make a change</h3>
<h3 id="change">Make a change</h3>
<p>
The entire checked-out tree is writable.
@ -405,7 +412,7 @@ Do not edit or delete it.
runs <code>git</code> <code>commit</code> <code>--amend</code>.)
</p>
<h3>Mail the change for review</h3>
<h3 id="mail">Mail the change for review</h3>
<p>
Once the change is ready, mail it out for review:
@ -455,7 +462,7 @@ remote: New Changes:
remote: https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
</pre>
<h3>Reviewing code</h3>
<h3 id="review">Reviewing code</h3>
<p>
Running <code>git</code> <code>mail</code> will send an email to you and the
@ -467,7 +474,7 @@ You must reply through the web interface.
(Unlike with the old Rietveld review system, replying by mail has no effect.)
</p>
<h3>Revise and upload</h3>
<h3 id="revise">Revise and upload</h3>
<p>
You must respond to review comments through the web interface.
@ -494,7 +501,7 @@ You can see a list of your pending changes by running <code>git</code>
<code>change</code> <code><i>&lt;branch&gt;</i></code>.
</p>
<h3>Synchronize your client</h3>
<h3 id="sync">Synchronize your client</h3>
<p>
While you were working, others might have submitted changes to the repository.
@ -612,7 +619,7 @@ Then run <code>git</code> <code>rebase</code> <code>--continue</code> to
restore the change commit.
</p>
<h3>Reviewing code by others</h3>
<h3 id="download">Reviewing code by others</h3>
<p>
You can import a change proposed by someone else into your local Git repository.
@ -629,7 +636,7 @@ $ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 &amp;&amp;
To revert, change back to the branch you were working in.
</p>
<h3>Submit the change after the review</h3>
<h3 id="submit">Submit the change after the review</h3>
<p>
After the code has been <code>LGTM</code>'ed, an approver may
@ -648,7 +655,7 @@ the commit hashes in the repository will be changed by
the submit operation.
</p>
<h3>More information</h3>
<h3 id="more">More information</h3>
<p>
In addition to the information here, the Go community maintains a <a href="https://golang.org/wiki/CodeReview">CodeReview</a> wiki page.
@ -674,7 +681,7 @@ These files will be periodically updated based on the commit logs.
<p>Code that you contribute should use the standard copyright header:</p>
<pre>
// Copyright 2015 The Go Authors. All rights reserved.
// 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.
</pre>

View file

@ -124,7 +124,7 @@ href="/src/runtime/runtime-gdb.py">src/runtime/runtime-gdb.py</a> in
the Go source distribution. It depends on some special magic types
(<code>hash&lt;T,U&gt;</code>) and variables (<code>runtime.m</code> and
<code>runtime.g</code>) that the linker
(<a href="/src/cmd/ld/dwarf.c">src/cmd/ld/dwarf.c</a>) ensures are described in
(<a href="/src/cmd/link/internal/ld/dwarf.go">src/cmd/link/internal/ld/dwarf.go</a>) ensures are described in
the DWARF code.
</p>

View file

@ -12,6 +12,24 @@ git pull
git checkout <i>release-branch</i>
</pre>
<h2 id="policy">Release Policy</h2>
<p>
Each major Go release obsoletes and ends support for the previous one.
For example, if Go 1.5 has been released, then it is the current release
and Go 1.4 and earlier are no longer supported.
We fix critical problems in the current release as needed by issuing minor revisions
(for example, Go 1.5.1, Go 1.5.2, and so on).
</p>
<p>
As a special case, we issue minor revisions for critical security problems
in both the current release and the previous release.
For example, if Go 1.5 is the current release then we will issue minor revisions
to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
See the <a href="/security">security policy</a> for more details.
</p>
<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
<p>
@ -29,6 +47,14 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.1">Go
1.5.1 milestone</a> on our issue tracker for details.
</p>
<p>
go1.5.2 (released 2015/12/02) includes bug fixes to the compiler, linker, and
the <code>mime/multipart</code>, <code>net</code>, and <code>runtime</code>
packages.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.2">Go
1.5.2 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.4">go1.4 (released 2014/12/10)</h2>
<p>

894
doc/go1.6.html Normal file
View file

@ -0,0 +1,894 @@
<!--{
"Title": "Go 1.6 Release Notes DRAFT",
"Path": "/doc/go1.6",
"Template": true
}-->
<!--
Edit .,s;^PKG:([a-z][A-Za-z0-9_/]+);<a href="/pkg/\1/"><code>\1</code></a>;g
Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',]|$);<a href="/pkg/\1/#\2\3"><code>\3</code></a>\4;g
-->
<style>
ul li { margin: 0.5em 0; }
</style>
<p>
<i>NOTE: This is a DRAFT of the Go 1.6 release notes, prepared for the Go 1.6 beta.
Go 1.6 has NOT yet been released.
By our regular schedule, it is expected some time in February 2016.
</i>
</p>
<h2 id="introduction">Introduction to Go 1.6</h2>
<p>
The latest Go release, version 1.6, arrives six months after 1.5.
Most of its changes are in the implementation of the language, runtime, and libraries.
There are no changes to the language specification.
As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
We expect almost all Go programs to continue to compile and run as before.
</p>
<p>
The release adds new ports to <a href="#ports">Linux on 64-bit MIPS and Android on 32-bit x86</a>;
defined and enforced <a href="#cgo">rules for sharing Go pointers with C</a>;
transparent, automatic <a href="#http2">support for HTTP/2</a>;
and a new mechanism for <a href="#template">template reuse</a>.
</p>
<h2 id="language">Changes to the language</h2>
<p>
There are no language changes in this release.
</p>
<h2 id="ports">Ports</h2>
<p>
Go 1.6 adds experimental ports to
Linux on 64-bit MIPS (<code>linux/mips64</code> and <code>linux/mips64le</code>).
These ports support <code>cgo</code> but only with internal linking.
</p>
<p>
Go 1.6 also adds an experimental port to Android on 32-bit x86 (<code>android/386</code>).
</p>
<p>
On FreeBSD, Go 1.6 defaults to using <code>clang</code>, not <code>gcc</code>, as the external C compiler.
</p>
<p>
On Linux on little-endian 64-bit PowerPC (<code>linux/ppc64le</code>),
Go 1.6 now supports <code>cgo</code> with external linking and
is roughly feature complete.
</p>
<p>
On NaCl, Go 1.5 required SDK version pepper-41.
Go 1.6 adds support for later SDK versions.
</p>
<pre>
TODO: CX no longer available on 386 assembly? (https://golang.org/cl/16386)
</pre>
<h2 id="tools">Tools</h2>
<h3 id="cgo">Cgo</h3>
<p>
There is one major change to <a href="/cmd/cgo/"><code>cgo</code></a>, along with one minor change.
</p>
<p>
The major change is the definition of rules for sharing Go pointers with C code,
to ensure that such C code can coexist with Go's garbage collector.
Briefly, Go and C may share memory allocated by Go
when a pointer to that memory is passed to C as part of a <code>cgo</code> call,
provided that the memory itself contains no pointers to Go-allocated memory,
and provided that C does not retain the pointer after the call returns.
These rules are checked by the runtime during program execution:
if the runtime detects a violation, it prints a diagnosis and crashes the program.
The checks can be disabled by setting the environment variable
<code>GODEBUG=cgocheck=0</code>, but note that the vast majority of
code identified by the checks is subtly incompatible with garbage collection
in one way or another.
Disabling the checks will typically only lead to more mysterious failure modes.
Fixing the code in question should be strongly preferred
over turning off the checks.
See the <a href="/cmd/cgo/#hdr-Passing_pointers"><code>cgo</code> documentation</a> for more details.
</p>
<p>
The minor change is
the addition of explicit <code>C.complexfloat</code> and <code>C.complexdouble</code> types,
separate from Go's <code>complex64</code> and <code>complex128</code>.
Matching the other numeric types, C's complex types and Go's complex type are
no longer interchangeable.
</p>
<h3 id="compiler">Compiler Toolchain</h3>
<p>
The compiler toolchain is mostly unchanged.
Internally, the most significant change is that the parser is now hand-written
instead of generated from <a href="/cmd/yacc/">yacc</a>.
</p>
<p>
The compiler, linker, and <code>go</code> command have new flag <code>-msan</code>,
analogous to <code>-race</code> and only available on linux/amd64,
that enables interoperation with the <a href="http://clang.llvm.org/docs/MemorySanitizer.html">Clang MemorySanitizer</a>.
Such interoperation useful mainly for testing a program containing suspect C or C++ code.
</p>
<p>
The linker has a new option <code>-libgcc</code> to set the expected location
of the C compiler support library when linking <a href="/cmd/cgo/"><code>cgo</code></a> code.
The option is only consulted when using <code>-linkmode=internal</code>,
and it may be set to <code>none</code> to disable the use of a support library.
</p>
<p>
The implementation of <a href="/doc/go1.5#link">build modes started in Go 1.5</a> has been expanded to more systems.
This release adds support for the <code>c-shared</code> mode on <code>android/386</code>, <code>android/amd64</code>,
<code>android/arm64</code>, <code>linux/386</code>, and <code>linux/arm64</code>;
for the <code>shared</code> mode on <code>linux/386</code>, <code>linux/arm</code>, <code>linux/amd64</code>, and <code>linux/ppc64le</code>;
and for the new <code>pie</code> mode (generating position-independent executables) on
<code>android/386</code>, <code>android/amd64</code>, <code>android/arm</code>, <code>android/arm64</code>, <code>linux/386</code>,
<code>linux/amd64</code>, <code>linux/arm</code>, <code>linux/arm64</code>, and <code>linux/ppc64le</code>.
See the <a href="https://golang.org/s/execmodes">design document</a> for details.
</p>
<p>
As a reminder, the linker's <code>-X</code> flag changed in Go 1.5.
In Go 1.4 and earlier, it took two arguments, as in
</p>
<pre>
-X importpath.name value
</pre>
<p>
Go 1.5 added an alternative syntax using a single argument
that is itself a <code>name=value</code> pair:
</p>
<pre>
-X importpath.name=value
</pre>
<p>
In Go 1.5 the old syntax was still accepted, after printing a warning
suggesting use of the new syntax instead.
Go 1.6 continues to accept the old syntax and print the warning.
Go 1.7 will remove support for the old syntax.
</p>
<h3 id="gccgo">Gccgo</h3>
<p>
The release schedules for the GCC and Go projects do not coincide.
GCC release 5 contains the Go 1.4 version of gccgo.
The next release, GCC 6, will have the Go 1.5 version of gccgo.
Due to release scheduling, it is likely that
Go 1.6 will not be in a GCC release until GCC 7.
</p>
<h3 id="go_command">Go command</h3>
<p>
The <a href="/cmd/go"><code>go</code></a> command's basic operation
is unchanged, but there are a number of changes worth noting.
</p>
<p>
Go 1.5 introduced experimental support for vendoring,
enabled by setting the <code>GO15VENDOREXPERIMENT</code> environment variable to <code>1</code>.
Go 1.6 keeps the vendoring support, no longer considered experimental,
and enables it by default.
It can be disabled explicitly by setting
the <code>GO15VENDOREXPERIMENT</code> environment variable to <code>0</code>.
Go 1.7 will remove support for the environment variable.
</p>
<p>
The most likely problem caused by enabling vendoring by default happens
in source trees containing an existing directory named <code>vendor</code> that
does not expect to be interpreted according to new vendoring semantics.
In this case, the simplest fix is to rename the directory to anything other
than <code>vendor</code> and update any affected import paths.
</p>
<p>
For details about vendoring,
see the documentation for the <a href="/cmd/go/#hdr-Vendor_Directories"><code>go</code> command</a>
and the <a href="https://golang.org/s/go15vendor">design document</a>.
</p>
<p>
There is a new build flag, <code>-msan</code>,
that compiles Go with support for the LLVM memory sanitizer.
This is intended mainly for use when linking against C or C++ code
that is being checked with the memory sanitizer.
</p>
<h3 id="doc_command">Go doc command</h3>
<p>
Go 1.5 introduced the
<a href="/cmd/go/#hdr-Show_documentation_for_package_or_symbol"><code>go doc</code></a> command,
which allows references to packages using only the package name, as in
<code>go</code> <code>doc</code> <code>http</code>.
In the event of ambiguity, the Go 1.5 behavior was to use the package
with the lexicographically earliest import path.
In Go 1.6, ambiguity is resolved by preferring import paths with
fewer elements, breaking ties using lexicographic comparison.
An important effect of this change is that original copies of packages
are now preferred over vendored copies.
Successful searches also tend to run faster.
</p>
<h3 id="vet_command">Go vet command</h3>
<p>
The <a href="/cmd/vet"><code>go vet</code></a> command now diagnoses
passing function or method values as arguments to <code>Printf</code>,
such as when passing <code>f</code> where <code>f()</code> was intended.
</p>
<h2 id="performance">Performance</h2>
<p>
As always, the changes are so general and varied that precise statements
about performance are difficult to make.
Some programs may run faster, some slower.
On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.6
than they did in Go 1.5.
The garbage collector's pauses are even lower than in Go 1.5,
although the effect is likely only noticeable for programs using
a large amount of memory.
</p>
<p>
There have been significant optimizations bringing more than 10% improvements
to implementations of the
<a href="/pkg/compress/bzip2/"><code>compress/bzip2</code></a>,
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>,
<a href="/pkg/crypto/aes/"><code>crypto/aes</code></a>,
<a href="/pkg/crypto/elliptic/"><code>crypto/elliptic</code></a>,
<a href="/pkg/crypto/ecdsa/"><code>crypto/ecdsa</code></a>, and
<a href="/pkg/sort/"><code>sort</code></a> packages.
</p>
<h2 id="library">Core library</h2>
<h3 id="http2">HTTP/2</h3>
<p>
Go 1.6 adds transparent support in the
<a href="/pkg/net/http/"><code>net/http</code></a> package
for the new <a href="https://http2.github.io/">HTTP/2 protocol</a>.
Go clients and servers will automatically use HTTP/2 as appropriate when using HTTPS.
There is no exported API specific to details of the HTTP/2 protocol handling,
just as there is no exported API specific to HTTP/1.1.
</p>
<p>
Programs that must disable HTTP/2 can do so by setting
<a href="/pkg/net/http/#Transport"><code>Transport.TLSNextProto</code></a> (for clients)
or
<a href="/pkg/net/http/#Server"><code>Server.TLSNextProto</code></a> (for servers)
to a non-nil, empty map.
</p>
<p>
Programs that must adjust HTTP/2 protocol-specific details can import and use
<a href="https://golang.org/x/net/http2"><code>golang.org/x/net/http2</code></a>,
in particular its
<a href="https://godoc.org/golang.org/x/net/http2/#ConfigureServer">ConfigureServer</a>
and
<a href="https://godoc.org/golang.org/x/net/http2/#ConfigureTransport">ConfigureTransport</a>
functions.
</p>
<h3 id="runtime">Runtime</h3>
<p>
The runtime has added lightweight, best-effort detection of concurrent misuse of maps.
As always, if one goroutine is writing to a map, no other goroutine should be
reading or writing the map concurrently.
If the runtime detects this condition, it prints a diagnosis and crashes the program.
The best way to find out more about the problem is to run the program
under the
<a href="https://blog.golang.org/race-detector">race detector</a>,
which will more reliably identify the race
and give more detail.
</p>
<p>
For program-ending panics, the runtime now by default
prints only the stack of the running goroutine,
not all existing goroutines.
Usually only the current goroutine is relevant to a panic,
so omitting the others significantly reduces irrelevant output
in a crash message.
To see the stacks from all goroutines in crash messages, set the environment variable
<code>GOTRACEBACK</code> to <code>all</code>
or call
<a href="/pkg/runtime/debug/#SetTraceback"><code>debug.SetTraceback</code></a>
before the crash, and rerun the program.
See the <a href="/pkg/runtime/#hdr-Environment_Variables">runtime documentation</a> for details.
</p>
<p>
<em>Updating</em>:
Uncaught panics intended to dump the state of the entire program,
such as when a timeout is detected or when explicitly handling a received signal,
should now call <code>debug.SetTraceback("all")</code> before panicking.
Searching for uses of
<a href="/pkg/os/signal/#Notify"><code>signal.Notify</code></a> may help identify such code.
</p>
<p>
On Windows, Go programs in Go 1.5 and earlier forced
the global Windows timer resolution to 1ms at startup
by calling <code>timeBeginPeriod(1)</code>.
Go no longer needs this for good scheduler performance,
and changing the global timer resolution caused problems on some systems,
so the call has been removed.
</p>
<h3 id="reflect">Reflect</h3>
<p>
The
<a href="/pkg/reflect/"><code>reflect</code></a> package has
<a href="https://golang.org/issue/12367">resolved a long-standing incompatibility</a>
between the gc and gccgo toolchains
regarding embedded unexported struct types containing exported fields.
Code that walks data structures using reflection, especially to implement
serialization in the spirit
of the
<a href="/pkg/encoding/json/"><code>encoding/json</code></a> and
<a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> packages,
may need to be updated.
</p>
<p>
The problem arises when using reflection to walk through
an embedded unexported struct-typed field
into an exported field of that struct.
In this case, <code>reflect</code> had incorrectly reported
the embedded field as exported, by returning an empty <code>Field.PkgPath</code>.
Now it correctly reports the field as unexported
but ignores that fact when evaluating access to exported fields
contained within the struct.
</p>
<p>
<em>Updating</em>:
Typically, code that previously walked over structs and used
</p>
<pre>
f.PkgPath != ""
</pre>
<p>
to exclude inaccessible fields
should now use
</p>
<pre>
f.PkgPath != "" &amp;&amp; !f.Anonymous
</pre>
<p>
For example, see the changes to the implementations of
<a href="https://go-review.googlesource.com/#/c/14011/2/src/encoding/json/encode.go"><code>encoding/json</code></a> and
<a href="https://go-review.googlesource.com/#/c/14012/2/src/encoding/xml/typeinfo.go"><code>encoding/xml</code></a>.
</p>
<h3 id="sort">Sorting</h3>
<p>
In the
<a href="/pkg/sort/"><code>sort</code></a>
package,
the implementation of
<a href="/pkg/sort/#Sort"><code>Sort</code></a>
has been rewritten to make about 10% fewer calls to the
<a href="/pkg/sort/#Interface"><code>Interface</code></a>'s
<code>Less</code> and <code>Swap</code>
methods, with a corresponding overall time savings.
The new algorithm does choose a different ordering than before
for values that compare equal (those pairs for which <code>Less(i,</code> <code>j)</code> and <code>Less(j,</code> <code>i)</code> are false).
</p>
<p>
<em>Updating</em>:
The definition of <code>Sort</code> makes no guarantee about the final order of equal values,
but the new behavior may still break programs that expect a specific order.
Such programs should either refine their <code>Less</code> implementations
to report the desired order
or should switch to
<a href="/pkg/sort/#Stable"><code>Stable</code></a>,
which preserves the original input order
of equal values.
</p>
<h3 id="template">Templates</h3>
<p>
In the
<a href="/pkg/text/template/">text/template</a> package,
there are two significant new features to make writing templates easier.
</p>
<p>
First, it is now possible to <a href="/pkg/text/template/#hdr-Text_and_spaces">trim spaces around template actions</a>,
which can make template definitions more readable.
A minus sign at the beginning of an action says to trim space before the action,
and a minus sign at the end of an action says to trim space after the action.
For example, the template
</p>
<pre>
{{"{{"}}23 -}}
&lt;
{{"{{"}}- 45}}
</pre>
<p>
formats as <code>23&lt;45</code>.
</p>
<p>
Second, the new <a href="/pkg/text/template/#hdr-Actions"><code>{{"{{"}}block}}</code> action</a>,
combined with allowing redefinition of named templates,
provides a simple way to define pieces of a template that
can be replaced in different instantiations.
For example, the template
</p>
<pre>
&lt;title&gt;{{"{{"}}block "title"}}Page Title{{"{{"}}end}}&lt;/title&gt;
&lt;body&gt;
&lt;h1&gt;{{"{{"}}template "title"}}&lt;/h1&gt;
{{"{{"}}block "page"}}Main text{{"{{"}}end}}
</pre>
<p>
defines the basic formatting of a web page. A program can then
overlay that template with new definitions for the <code>"title"</code>
and <code>"page"</code> blocks to reuse the formatting for another page.
</p>
<h3 id="minor_library_changes">Minor changes to the library</h3>
<ul>
<li>
In the <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package, the
<a href="/pkg/archive/zip/#Reader"><code>Reader</code></a> type now has a
<a href="/pkg/archive/zip/#Reader.RegisterDecompressor"><code>RegisterDecompressor</code></a> method,
and the
<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> type now has a
<a href="/pkg/archive/zip/#Writer.RegisterCompressor"><code>RegisterCompressor</code></a> method,
enabling control over compression options for individual zip files.
These take precedence over the pre-existing global
<a href="/pkg/archive/zip/#RegisterDecompressor"><code>RegisterDecompressor</code></a> and
<a href="/pkg/archive/zip/#RegisterCompressor"><code>RegisterCompressor</code></a> functions.
</li>
<li>
The <a href="/pkg/bufio/"><code>bufio</code></a> package's
<a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> type now has a
<a href="/pkg/bufio/#Scanner.Buffer"><code>Buffer</code></a> method,
to specify an initial buffer and maximum buffer size to use during scanning.
This makes it possible, when needed, to scan tokens larger than
<code>MaxScanTokenSize</code>.
Also for the <code>Scanner</code>, the package now defines the
<a href="/pkg/bufio/#ErrFinalToken"><code>ErrFinalToken</code></a> error value, for use by
<a href="/pkg/bufio/#SplitFunc">split functions</a> to abort processing or to return a final empty token.
</li>
<li>
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a> package
has deprecated its
<a href="/pkg/compress/flate/#ReadError"><code>ReadError</code></a> and
<a href="/pkg/compress/flate/#WriteError"><code>WriteError</code></a> error implementations.
In Go 1.5 they were only rarely returned when an error was encountered;
now they are never returned, although they remain defined for compatibility.
</li>
<li>
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>,
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>, and
<a href="/pkg/compress/zlib/"><code>compress/zlib</code></a> packages
now report
<a href="/pkg/io/#ErrUnexpectedEOF"><code>io.ErrUnexpectedEOF</code></a> for truncated input streams, instead of
<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
</li>
<li>
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
has a variety of minor changes.
It now allows
<a href="/pkg/crypto/tls/#Listen"><code>Listen</code></a>
to succeed when the
<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>
has a nil <code>Certificates</code>, as long as the <code>GetCertificate</code> callback is set,
it adds support for RSA with AES-GCM cipher suites,
and
it adds a
<a href="/pkg/crypto/tls/#RecordHeaderError"><code>RecordHeaderError</code></a>
to allow clients (in particular, the <a href="/pkg/net/http/"><code>net/http</code></a> package)
to report a better error when attempting a TLS connection to a non-TLS server.
</li>
<li>
The <a href="/pkg/crypto/x509/"><code>crypto/x509</code></a> package
now permits certificates to contain negative serial numbers
(technically an error, but unfortunately common in practice),
and it defines a new
<a href="/pkg/crypto/x509/#InsecureAlgorithmError"><code>InsecureAlgorithmError</code></a>
to give a better error message when rejecting a certificate
signed with an insecure algorithm like MD5.
</li>
<li>
The <a href="/pkg/debug/dwarf"><code>debug/dwarf</code></a> and
<a href="/pkg/debug/elf/"><code>debug/elf</code></a> packages
together add support for compressed DWARF sections.
User code needs no updating: the sections are decompressed automatically when read.
</li>
<li>
The <a href="/pkg/debug/elf/"><code>debug/elf</code></a> package
adds support for general compressed ELF sections.
User code needs no updating: the sections are decompressed automatically when read.
However, compressed
<a href="/pkg/debug/elf/#Section"><code>Section</code></a>'s do not support random access:
they have a nil <code>ReaderAt</code> field.
</li>
<li>
The <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package
now exports
<a href="/pkg/encoding/asn1/#pkg-constants">tag and class constants</a>
useful for advanced parsing of ASN.1 structures.
</li>
<li>
Also in the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package,
<a href="/pkg/encoding/asn1/#Unmarshal"><code>Unmarshal</code></a> now rejects various non-standard integer and length encodings.
</li>
<li>
The <a href="/pkg/encoding/json/"><code>encoding/json</code></a> package
now checks the syntax of a
<a href="/pkg/encoding/json/#Number"><code>Number</code></a>
before marshaling it, requiring that it conforms to the JSON specification for numeric values.
As in previous releases, the zero <code>Number</code> (an empty string) is marshaled as a literal 0 (zero).
</li>
<li>
The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package's
<a href="/pkg/encoding/xml/#Marshal"><code>Marshal</code></a>
function now supports a <code>cdata</code> attribute, such as <code>chardata</code>
but encoding its argument in one or more <code>&lt;![CDATA[ ... ]]&gt;</code> tags.
</li>
<li>
Also in the <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package,
<a href="/pkg/encoding/xml/#Decoder"><code>Decoder</code></a>'s
<a href="/pkg/encoding/xml/#Decoder.Token"><code>Token</code></a> method
now reports an error when encountering EOF before seeing all open tags closed,
consistent with its general requirement that tags in the input be properly matched.
To avoid that requirement, use
<a href="/pkg/encoding/xml/#Decoder.RawToken"><code>RawToken</code></a>.
</li>
<li>
The <a href="/pkg/fmt/"><code>fmt</code></a> package now allows
any integer type as an argument to
<a href="/pkg/fmt/#Printf"><code>Printf</code></a>'s <code>*</code> width and precision specification.
In previous releases, the argument to <code>*</code> was required to have type <code>int</code>.
</li>
<li>
Also in the <a href="/pkg/fmt/"><code>fmt</code></a> package,
<a href="/pkg/fmt/#Scanf"><code>Scanf</code></a> can now scan hexadecimal strings using %X, as an alias for %x.
Both formats accept any mix of upper- and lower-case hexadecimal.
<a href="golang.org/x/13585">TODO: Keep?</a>
</li>
<li>
The <a href="/pkg/image/"><code>image</code></a>
and
The <a href="/pkg/image/color/"><code>image/color</code></a> packages
add
<a href="/pkg/image/#NYCbCrA"><code>NYCbCrA</code></a>
and
<a href="/pkg/color/#NYCbCrA"><code>NYCbCrA</code></a>
types, to support Y'CbCr images with non-premultiplied alpha.
</li>
<li>
The <a href="/pkg/io/"><code>io</code></a> package's
<a href="/pkg/io/#MultiWriter"><code>MultiWriter</code></a>
implementation now implements a <code>WriteString</code> method,
for use by
<a href="/pkg/io/#WriteString"><code>WriteString</code></a>.
</li>
<li>
In the <a href="/pkg/math/big/"><code>math/big</code></a> package,
<a href="/pkg/math/big/#Int"><code>Int</code></a> adds
<a href="/pkg/math/big/#Int.Append"><code>Append</code></a>
and
<a href="/pkg/math/big/#Int.Text"><code>Text</code></a>
methods to give more control over printing.
</li>
<li>
Also in the <a href="/pkg/math/big/"><code>math/big</code></a> package,
<a href="/pkg/math/big/#Float"><code>Float</code></a> now implements
<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a> and
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>,
allowing it to be serialized in a natural form by the
<a href="/pkg/encoding/json/"><code>encoding/json</code></a> and
<a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> packages.
</li>
<li>
Also in the <a href="/pkg/math/big/"><code>math/big</code></a> package,
<a href="/pkg/math/big/#Float"><code>Float</code></a>'s
<a href="/pkg/math/big/#Float.Append"><code>Append</code></a> method now supports the special precision argument -1.
As in
<a href="/pkg/strconv/#ParseFloat"><code>strconv.ParseFloat</code></a>,
precision -1 means to use the smallest number of digits necessary such that
<a href="/pkg/math/big/#Float.Parse"><code>Parse</code></a>
reading the result into a <code>Float</code> of the same precision
will yield the original value.
</li>
<li>
The <a href="/pkg/math/rand/"><code>math/rand</code></a> package
adds a
<a href="/pkg/math/rand/#Read"><code>Read</code></a>
function, and likewise
<a href="/pkg/math/rand/#Rand"><code>Rand</code></a> adds a
<a href="/pkg/math/rand/#Rand.Read"><code>Read</code></a> method.
These make it easier to generate pseudorandom test data.
Note that, like the rest of the package,
these should not be used in cryptographic settings;
for such purposes, use the <a href="/pkg/crypto/rand/"><code>crypto/rand</code></a> package instead.
</li>
<li>
The <a href="/pkg/net/"><code>net</code></a> package's
<a href="/pkg/net/#ParseMAC"><code>ParseMAC</code></a> function now accepts 20-byte IP-over-InfiniBand (IPoIB) link-layer addresses.
</li>
<li>
Also in the <a href="/pkg/net/"><code>net</code></a> package,
there have been a few changes to DNS lookups.
First, the
<a href="/pkg/net/#DNSError"><code>DNSError</code></a> error implementation now implements
<a href="/pkg/net/#Error"><code>Error</code></a>,
and in particular its new
<a href="/pkg/net/#DNSError.IsTemporary"><code>IsTemporary</code></a>
method returns true for DNS server errors.
Second, DNS lookup functions such as
<a href="/pkg/net/#LookupAddr"><code>LookupAddr</code></a>
now return rooted domain names (with a trailing dot)
on Plan 9 and Windows, to match the behavior of Go on Unix systems.
TODO: Third, lookups satisfied from /etc/hosts now add a trailing dot as well,
so that looking up 127.0.0.1 typically now returns &ldquo;localhost.&rdquo; not &ldquo;localhost&rdquo;.
This is arguably a mistake but is not yet fixed. See https://golang.org/issue/13564.
</li>
<li>
The <a href="/pkg/net/http/"><code>net/http</code></a> package has
a number of minor additions beyond the HTTP/2 support already discussed.
First, the
<a href="/pkg/http/#FileServer"><code>FileServer</code></a> now sorts its generated directory listings by file name.
Second, the
<a href="/pkg/http/#Client"><code>Client</code></a> now allows user code to set the
<code>Expect:</code> <code>100-continue</code> header (see
<a href="/pkg/http/#Transport"><code>Transport.ExpectContinueTimeout</code></a>).
Third, there are
<a href="/pkg/net/http/#pkg-constants">four new error codes</a> from RFC 6585:
<code>StatusPreconditionRequired</code> (428),
<code>StatusTooManyRequests</code> (429),
<code>StatusRequestHeaderFieldsTooLarge</code> (431),
and
<code>StatusNetworkAuthenticationRequired</code> (511).
Fourth, the implementation and documentation of
<a href="/pkg/http/#CloseNotifier"><code>CloseNotifier</code></a>
has been substantially changed.
The <a href="/pkg/http/#Hijacker"><code>Hijacker</code></a>
interface now works correctly on connections that have previously
been used with <code>CloseNotifier</code>.
The documentation now describes when <code>CloseNotifier</code>
is expected to work.
</li>
<li>
Also in the <a href="/pkg/net/http/"><code>net/http</code></a> package,
there are a few changes related to the handling of a
<a href="/pkg/http/#Request"><code>Request</code></a> data structure with its <code>Method</code> field set to the empty string.
An empty <code>Method</code> field has always been documented as an alias for <code>"GET"</code>
and it remains so.
However, Go 1.6 fixes a few routines that did not treat an empty
<code>Method</code> the same as an explicit <code>"GET"</code>.
Most notably, in previous releases
<a href="/pkg/http/#Client"><code>Client</code></a> followed redirects only with
<code>Method</code> set explicitly to <code>"GET"</code>;
in Go 1.6 <code>Client</code> also follows redirects for the empty <code>Method</code>.
Finally,
<a href="/pkg/http/#NewRequest"><code>NewRequest</code></a> accepts a <code>method</code> argument that has not been
documented as allowed to be empty.
In past releases, passing an empty <code>method</code> argument resulted
in a <code>Request</code> with an empty <code>Method</code> field.
In Go 1.6, the resulting <code>Request</code> always has an initialized
<code>Method</code> field: if its argument is an empty string, <code>NewRequest</code>
sets the <code>Method</code> field in the returned <code>Request</code> to <code>"GET"</code>.
</li>
<li>
The <a href="/pkg/net/http/httptest/"><code>net/http/httptest</code></a> package's
<a href="/pkg/net/http/httptest/#ResponseRecorder"><code>ResponseRecorder</code></a> now initializes a default Content-Type header
using the same content-sniffing algorithm as in
<a href="/pkg/net/http/#Server"><code>http.Server</code></a>.
</li>
<li>
The <a href="/pkg/net/url/"><code>net/url</code></a> package's
<a href="/pkg/net/url/#Parse"><code>Parse</code></a> is now stricter and more spec-compliant regarding the parsing
of host names.
For example, spaces in the host name are no longer accepted.
</li>
<li>
Also in the <a href="/pkg/net/url/"><code>net/url</code></a> package,
the <a href="/pkg/net/url/#Error"><code>Error</code></a> type now implements
<a href="/pkg/net/#Error"><code>net.Error</code></a>.
</li>
<li>
The <a href="/pkg/os/"><code>os</code></a> package's
<a href="/pkg/os/#IsExist"><code>IsExist</code></a>,
<a href="/pkg/os/#IsNotExist"><code>IsNotExist</code></a>,
and
<a href="/pkg/os/#IsPermission"><code>IsPermission</code></a>
now return correct results when inquiring about an
<a href="/pkg/os/#SyscallError"><code>SyscallError</code></a>.
</li>
<li>
On Unix-like systems, when a write
to <a href="/pkg/os/#pkg-variables"><code>os.Stdout</code>
or <code>os.Stderr</code></a> (more precisely, an <code>os.File</code>
opened for file descriptor 1 or 2) fails due to a broken pipe error,
the program will raise a <code>SIGPIPE</code> signal.
By default this will cause the program to exit; this may be changed by
calling the
<a href="/pkg/os/signal"><code>os/signal</code></a>
<a href="/pkg/os/signal/#Notify"><code>Notify</code></a> function
for <code>syscall.SIGPIPE</code>.
A write to a broken pipe on a file descriptor other 1 or 2 will simply
return <code>syscall.EPIPE</code> (possibly wrapped in
<a href="/pkg/os#PathError"><code>os.PathError</code></a>
and/or <a href="/pkg/os#SyscallError"><code>os.SyscallError</code></a>)
to the caller.
The old behavior of raising an uncatchable <code>SIGPIPE</code> signal
after 10 consecutive writes to a broken pipe no longer occurs.
</li>
<li>
In the <a href="/pkg/os/exec/"><code>os/exec</code></a> package,
<a href="/pkg/os/exec/#Cmd"><code>Cmd</code></a>'s
<a href="/pkg/os/exec/#Cmd.Output"><code>Output</code></a> method continues to return an
<a href="/pkg/os/exec/#ExitError"><code>ExitError</code></a> when a command exits with an unsuccessful status.
If standard error would otherwise have been discarded,
the returned <code>ExitError</code> now holds a prefix
(currently 32 kB) of the failed command's standard error output,
for debugging or for inclusion in error messages.
The <code>ExitError</code>'s
<a href="/pkg/os/exec/#ExitError.String"><code>String</code></a>
method does not show the captured standard error;
programs must retrieve it from the data structure
separately.
</li>
<li>
On Windows, the <a href="/pkg/path/filepath/"><code>path/filepath</code></a> package's
<a href="/pkg/path/filepath/#Join"><code>Join</code></a> function now correctly handles the case when the base is a relative drive path.
For example, <code>Join(`c:`,</code> <code>`a`)</code> now
returns <code>`c:a`</code> instead of <code>`c:\a`</code> as in past releases.
This may affect code that expects the incorrect result.
</li>
<li>
In the <a href="/pkg/regexp/"><code>regexp</code></a> package,
the
<a href="/pkg/regexp/#Regexp"><code>Regexp</code></a> type has always been safe for use by
concurrent goroutines.
It uses a <a href="/pkg/sync/#Mutex"><code>sync.Mutex</code></a> to protect
a cache of scratch spaces used during regular expression searches.
Some high-concurrency servers using the same <code>Regexp</code> from many goroutines
have seen degraded performance due to contention on that mutex.
To help such servers, <code>Regexp</code> now has a
<a href="/pkg/regexp/#Regexp.Copy"><code>Copy</code></a> method,
which makes a copy of a <code>Regexp</code> that shares most of the structure
of the original but has its own scratch space cache.
Two goroutines can use different copies of a <code>Regexp</code>
without mutex contention.
A copy does have additional space overhead, so <code>Copy</code>
should only be used when contention has been observed.
</li>
<li>
The <a href="/pkg/strconv/"><code>strconv</code></a> package adds
<a href="/pkg/strconv/#IsGraphic"><code>IsGraphic</code></a>,
<a href="/pkg/strconv/#QuoteToGraphic"><code>QuoteToGraphic</code></a>,
<a href="/pkg/strconv/#QuoteRuneToGraphic"><code>QuoteRuneToGraphic</code></a>,
<a href="/pkg/strconv/#AppendQuoteToGraphic"><code>AppendQuoteToGraphic</code></a>,
and
<a href="/pkg/strconv/#AppendQuoteRuneToGraphic"><code>AppendQuoteRuneToGraphic</code></a>,
analogous to
<a href="/pkg/strconv/#IsPrint"><code>IsPrint</code></a>,
<a href="/pkg/strconv/#QuoteToPrint"><code>QuoteToPrint</code></a>,
and so on.
The <code>Print</code> family escapes all space characters except ASCII space (U+0020).
In contrast, the <code>Graphic</code> family does not escape any Unicode space characters (category Zs).
</li>
<li>
In the <a href="/pkg/testing/"><code>testing</code></a> package,
when a test calls
<a href="/pkg/testing/#T.Parallel">t.Parallel</a>,
that test is paused until all non-parallel tests complete, and then
that test continues execution with all other parallel tests.
Go 1.6 changes the time reported for such a test:
previously the time counted only the parallel execution,
but now it also counts the time from the start of testing
until the call to <code>t.Parallel</code>.
</li>
<li>
The <a href="/pkg/text/template/"><code>text/template</code></a> package
contains two minor changes, in addition to the <a href="#template">major changes</a>
described above.
First, it adds a new
<a href="/pkg/text/template/#ExecError"><code>ExecError</code></a> type
returned for any error during
<a href="/pkg/text/template/#Template.Execute"><code>Execute</code></a>
that does not originate in a <code>Write</code> to the underlying writer.
Callers can distinguish template usage errors from I/O errors by checking for
<code>ExecError</code>.
Second, the
<a href="/pkg/text/template/#Template.Funcs"><code>Funcs</code></a> method
now checks that the names used as keys in the
<a href="/pkg/text/template/#FuncMap"><code>FuncMap</code></a>
are identifiers that can appear in a template function invocation.
If not, <code>Funcs</code> panics.
</li>
<li>
The <a href="/pkg/time/"><code>time</code></a> package's
<a href="/pkg/time/#Parse"><code>Parse</code></a> function has always rejected any day of month larger than 31,
such as January 32.
In Go 1.6, <code>Parse</code> now also rejects February 29 in non-leap years,
February 30, February 31, April 31, June 31, September 31, and November 31.
</li>
</ul>

View file

@ -1,39 +0,0 @@
Tools:
cmd/dist: use clang on FreeBSD (https://golang.org/cl/16635)
cmd/go: vendoring enabled by default (https://golang.org/cl/13967/)
cmd/go: flags for tests must precede package name if present; also makes it easier to pass flags to test binaries (https://golang.org/cl/14826)
cmd/go: add -msan option (https://golang.org/cl/16169)
cmd/go: use shallow clones for new git checkouts (https://golang.org/cl/16360)
cmd/compile: add -msan option (https://golang.org/cl/16160)
cmd/link: add -msan option (https://golang.org/cl/16161)
Ports:
Add new experimental ports for linux/mips64 and linux/mips64le: no cgo, external linking or disasm yet (https://golang.org/cl/14460 and others)
NaCl is no longer restricted to pepper_41 (https://golang.org/cl/13958/)
Reflect change:
cmd/compile/internal/gc: make embedded unexported structs RO (https://golang.org/cl/14085)
encoding/json: check for exported fields in embedded structs (https://golang.org/cl/14011)
encoding/xml: check for exported fields in embedded structs (https://golang.org/cl/14012)
reflect: adjust access to unexported embedded structs (https://golang.org/cl/14010)
API additions and behavior changes:
bufio: add Scanner.Buffer (https://golang.org/cl/14599/)
bufio: add ErrFinalToken as a sentinel value for Scan's split functions (https://golang.org/cl/14924)
crypto/aes: dedicated asm version of AES-GCM (https://golang.org/cl/10484)
fmt: allow any integer type as an argument to the * operator (https://golang.org/cl/14491/)
image: add NYCbCrA types (https://golang.org/cl/15671)
math/rand: add Read (https://golang.org/cl/14522)
net/http: HTTP/2.0 support (many CLs)
net/url: make *url.Error implement net.Error (https://golang.org/cl/15672)
runtime: only one goroutine in traceback (https://golang.org/cl/16512) maybe
strconv: QuoteToGraphic (https://golang.org/cl/14184/)
text/template: ExecError (https://golang.org/cl/13957/)
text/template: trimming spaces (https://golang.org/cl/14391/)
text/template: Funcs check names (https://golang.org/cl/14562/)
text/template: IsTrue (https://golang.org/cl/14562/)
text/template: blocks and permit redefinition (https://golang.org/cl/14005)
time: allow one and two-digit days of the month during Parse (https://golang.org/cl/14123/)

View file

@ -860,6 +860,36 @@ value to hold the error and a type switch to discriminate cases. The
syntax tree example is also doable, although not as elegantly.
</p>
<h3 id="covariant_types">
Why does Go not have covariant result types?</h3>
<p>
Covariant result types would mean that an interface like
<pre>
type Copyable interface {
Copy() interface{}
}
</pre>
would be satisfied by the method
<pre>
func (v Value) Copy() Value
</pre>
because <code>Value</code> implements the empty interface.
In Go method types must match exactly, so <code>Value</code> does not
implement <code>Copyable</code>.
Go separates the notion of what a
type does&mdash;its methods&mdash;from the type's implementation.
If two methods return different types, they are not doing the same thing.
Programmers who want covariant result types are often trying to
express a type hierarchy through interfaces.
In Go it's more natural to have a clean separation between interface
and implementation.
</p>
<h2 id="values">Values</h2>
<h3 id="conversions">

View file

@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of October 20, 2015",
"Subtitle": "Version of January 5, 2016",
"Path": "/ref/spec"
}-->
@ -101,15 +101,14 @@ The following terms are used to denote specific Unicode character classes:
newline = /* the Unicode code point U+000A */ .
unicode_char = /* an arbitrary Unicode code point except newline */ .
unicode_letter = /* a Unicode code point classified as "Letter" */ .
unicode_digit = /* a Unicode code point classified as "Decimal Digit" */ .
unicode_digit = /* a Unicode code point classified as "Number, decimal digit" */ .
</pre>
<p>
In <a href="http://www.unicode.org/versions/Unicode6.3.0/">The Unicode Standard 6.3</a>,
Section 4.5 "General Category"
defines a set of character categories. Go treats
those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters,
and those in category Nd as Unicode digits.
In <a href="http://www.unicode.org/versions/Unicode8.0.0/">The Unicode Standard 8.0</a>,
Section 4.5 "General Category" defines a set of character categories.
Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo
as Unicode letters, and those in the Number category Nd as Unicode digits.
</p>
<h3 id="Letters_and_digits">Letters and digits</h3>
@ -1051,12 +1050,18 @@ but are otherwise ignored.
</p>
<pre>
// A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct {
microsec uint64 "field 1"
serverIP6 uint64 "field 2"
process string "field 3"
x, y float64 "" // an empty tag string is like an absent tag
name string "any string is permitted as a tag"
_ [4]byte "ceci n'est pas un champ de structure"
}
// A struct corresponding to a TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers;
// they follow the convention outlined by the reflect package.
struct {
microsec uint64 `protobuf:"1"`
serverIP6 uint64 `protobuf:"2"`
}
</pre>
@ -1108,7 +1113,7 @@ one unnamed result it may be written as an unparenthesized type.
</p>
<p>
The final parameter in a function signature may have
The final incoming parameter in a function signature may have
a type prefixed with <code>...</code>.
A function with such a parameter is called <i>variadic</i> and
may be invoked with zero or more arguments for that parameter.
@ -1789,26 +1794,27 @@ It can be used to construct a set of related constants:
</p>
<pre>
const ( // iota is reset to 0
const ( // iota is reset to 0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 &lt;&lt; iota // a == 1 (iota has been reset)
const ( // iota is reset to 0
a = 1 &lt;&lt; iota // a == 1
b = 1 &lt;&lt; iota // b == 2
c = 1 &lt;&lt; iota // c == 4
c = 3 // c == 3 (iota is not used but still incremented)
d = 1 &lt;&lt; iota // d == 8
)
const (
const ( // iota is reset to 0
u = iota * 42 // u == 0 (untyped integer constant)
v float64 = iota * 42 // v == 42.0 (float64 constant)
w = iota * 42 // w == 84 (untyped integer constant)
)
const x = iota // x == 0 (iota has been reset)
const y = iota // y == 0 (iota has been reset)
const x = iota // x == 0 (iota has been reset)
const y = iota // y == 0 (iota has been reset)
</pre>
<p>
@ -2083,7 +2089,7 @@ Receiver = Parameters .
<p>
The receiver is specified via an extra parameter section preceding the method
name. That parameter section must declare a single parameter, the receiver.
name. That parameter section must declare a single non-variadic parameter, the receiver.
Its type must be of the form <code>T</code> or <code>*T</code> (possibly using
parentheses) where <code>T</code> is a type name. The type denoted by <code>T</code> is called
the receiver <i>base type</i>; it must not be a pointer or interface type and
@ -5323,7 +5329,7 @@ the "for" statement's block but the <code>goto</code> is not.
<p>
A "fallthrough" statement transfers control to the first statement of the
next case clause in a <a href="#Expression_switches">expression "switch" statement</a>.
next case clause in an <a href="#Expression_switches">expression "switch" statement</a>.
It may be used only as the final non-empty statement in such a clause.
</p>

View file

@ -48,3 +48,9 @@ Each month in places around the world, groups of Go programmers ("gophers")
meet to talk about Go. Find a chapter near you.
</p>
<h3 id="conduct"><a href="/conduct">Code of Conduct</a></h3>
<p>
Guidelines for participating in Go community spaces
and a reporting process for handling issues.
</p>

View file

@ -93,6 +93,17 @@ The full set of supported combinations is listed in the discussion of
<a href="#environment">environment variables</a> below.
</p>
<p>
See the main installation page for the <a href="/doc/install#requirements">overall system requirements</a>.
The following additional constraints apply to systems that can be built only from source:
</p>
<ul>
<li>For Linux on PowerPC 64-bit, the minimum supported kernel version is 2.6.37, meaning that
Go does not support CentOS 6 on these systems.
</li>
</ul>
</div>
<h2 id="go14">Install Go compiler binaries</h2>
@ -139,7 +150,7 @@ and used as <code>GOROOT_BOOTSTRAP</code> to bootstrap a local build.
</p>
<p>
To use gccgo, you need to arrange for <code>$GOROOT_BOOSTRAP/bin/go</code> to be
To use gccgo, you need to arrange for <code>$GOROOT_BOOTSTRAP/bin/go</code> to be
the go tool that comes as part of gccgo 5. For example on Ubuntu Vivid:
</p>
@ -173,7 +184,7 @@ Then clone the repository and check out the latest release tag:</p>
<pre>
$ git clone https://go.googlesource.com/go
$ cd go
$ git checkout go1.5.1
$ git checkout go1.5.2
</pre>
<h2 id="head">(Optional) Switch to the master branch</h2>
@ -352,7 +363,7 @@ New releases are announced on the
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
mailing list.
Each announcement mentions the latest release tag, for instance,
<code>go1.5.1</code>.
<code>go1.5.2</code>.
</p>
<p>

View file

@ -48,7 +48,7 @@ If your OS or architecture is not on the list, you may be able to
</tr>
<tr><td colspan="3"><hr></td></tr>
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; install from source for ARM</td></tr>
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported</td></tr>
<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup></td></tr>
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>&#8224;</sup>. No need for cygwin or msys.</td></tr>
</table>
@ -220,19 +220,29 @@ and building a simple program, as follows.
<p>
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
<code>$HOME/work</code> for example, and set the <code>GOPATH</code> environment
<code class="testUnix">$HOME/work</code>
<code class="testWindows" style="display: none">%HOME%\work</code>
for example, and set the <code>GOPATH</code> environment
variable to point to that location.
</p>
<pre>
<pre class="testUnix">
$ <b>export GOPATH=$HOME/work</b>
</pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>set GOPATH=%HOME%\work</b>
</pre>
<p>
<span class="testUnix">
You should put the above command in your shell startup script
(<code>$HOME/.profile</code> for example) or, if you use Windows,
follow the <a href="#windows_env">instructions above</a> to set the
(<code>$HOME/.profile</code> for example).
</span>
<span class="testWindows">
On Windows, follow the <a href="#windows_env">instructions above</a> to set the
<code>GOPATH</code> environment variable on your system.
</span>
</p>
<p>
@ -256,21 +266,30 @@ func main() {
Then compile it with the <code>go</code> tool:
</p>
<pre>
<pre class="testUnix">
$ <b>go install github.com/user/hello</b>
</pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>go install github.com/user/hello</b>
</pre>
<p>
The above command will put an executable command named <code>hello</code>
The command above will put an executable command named <code>hello</code>
(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
Execute the command to see the greeting:
</p>
<pre>
<pre class="testUnix">
$ <b>$GOPATH/bin/hello</b>
hello, world
</pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>%GOPATH%\bin\hello</b>
hello, world
</pre>
<p>
If you see the "hello, world" message then your Go installation is working.
</p>

View file

@ -1,5 +1,5 @@
// Concurrent computation of pi.
// See http://goo.gl/ZuTZM.
// See https://goo.gl/la6Kli.
//
// This demonstrates Go's ability to handle
// large numbers of concurrent processes.

View file

@ -0,0 +1,14 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// issue 13129: used to output error about C.unsignedshort with CC=clang
package main
import "C"
func main() {
var x C.ushort
x = int(0) // ERROR HERE
}

View file

@ -0,0 +1,12 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// #include <stdio.h>
import "C"
func main() {
_ = C.fopen() // ERROR HERE
}

View file

@ -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.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
)
}

View file

@ -125,7 +125,6 @@ var ptrTests = []ptrTest{
fail: true,
},
/*
TODO(khr): reenable when write barriers are fixed.
{
// Storing a Go pointer into C memory should fail.
name: "barrier",
@ -211,6 +210,24 @@ var ptrTests = []ptrTest{
fail: true,
expensive: true,
},
{
// Exported functions may not return Go pointers.
name: "export1",
c: `extern unsigned char *GoFn();`,
support: `//export GoFn
func GoFn() *byte { return new(byte) }`,
body: `C.GoFn()`,
fail: true,
},
{
// Returning a C pointer is fine.
name: "exportok",
c: `#include <stdlib.h>
extern unsigned char *GoFn();`,
support: `//export GoFn
func GoFn() *byte { return (*byte)(C.malloc(1)) }`,
body: `C.GoFn()`,
},
*/
}

View file

@ -11,6 +11,12 @@ check() {
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 $file >errs 2>&1; then
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
exit 1
@ -19,11 +25,13 @@ check() {
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
exit 1
fi
if ! fgrep $file:$line: errs >/dev/null 2>&1; then
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error on line $line but saw:
cat 1>&2 errs
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 to contain \"$error\" but saw:
cat 1>&2 errs
exit 1
fi
done
}
check err1.go
@ -33,6 +41,9 @@ 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
if ! go run ptr.go; then
exit 1

View file

@ -1,42 +1,9 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of "The Computer Language Benchmarks Game" nor the
name of "The Computer Language Shootout Benchmarks" nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* The Computer Language Benchmarks Game
* http://shootout.alioth.debian.org/
*
* contributed by The Go Authors.
* based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
* modified by Michael Mellor)
*/
package main
import (

View file

@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +build test_run
// Run the game of life in C using Go for parallelization.

View file

@ -4,16 +4,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +build test_run
// Pass numbers along a chain of threads.
package main
import (
"../stdio"
"runtime"
"strconv"
"../stdio"
)
const N = 10

View file

@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +build test_run
// Compute Fibonacci numbers with two goroutines
// that pass integers back and forth. No actual
@ -14,9 +14,10 @@
package main
import (
"../stdio"
"runtime"
"strconv"
"../stdio"
)
func fibber(c, out chan int64, i int64) {

View file

@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// +build test_run
package main

View file

@ -12,6 +12,7 @@ void callPanic(void);
int callGoReturnVal(void);
int returnAfterGrow(void);
int returnAfterGrowFromGo(void);
void callGoWithString(void);
*/
import "C"
@ -178,7 +179,6 @@ func testCallbackCallers(t *testing.T) {
pc := make([]uintptr, 100)
n := 0
name := []string{
"test.goCallback",
"runtime.call16",
"runtime.cgocallbackg1",
"runtime.cgocallbackg",
@ -193,10 +193,10 @@ func testCallbackCallers(t *testing.T) {
"runtime.goexit",
}
if unsafe.Sizeof((*byte)(nil)) == 8 {
name[1] = "runtime.call32"
name[0] = "runtime.call32"
}
nestedCall(func() {
n = runtime.Callers(2, pc)
n = runtime.Callers(4, pc)
})
if n != len(name) {
t.Errorf("expected %d frames, got %d", len(name), n)
@ -277,6 +277,22 @@ func goReturnVal() (r C.int) {
return
}
// Test that C can pass in a Go string from a string constant.
func testCallGoWithString(t *testing.T) {
C.callGoWithString()
want := "string passed from C to Go"
if stringFromGo != want {
t.Errorf("string passed through C is %s, want %s", stringFromGo, want)
}
}
var stringFromGo string
//export goWithString
func goWithString(s string) {
stringFromGo = s
}
func testCallbackStack(t *testing.T) {
// Make cgo call and callback with different amount of stack stack available.
// We do not do any explicit checks, just ensure that it does not crash.

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "_cgo_export.h"
@ -80,3 +81,10 @@ returnAfterGrowFromGo(void)
return goReturnVal();
}
void
callGoWithString(void)
{
extern void goWithString(GoString);
const char *str = "string passed from C to Go";
goWithString((GoString){str, strlen(str)});
}

View file

@ -68,5 +68,6 @@ func Test10303(t *testing.T) { test10303(t, 10) }
func Test11925(t *testing.T) { test11925(t) }
func Test12030(t *testing.T) { test12030(t) }
func TestGCC68255(t *testing.T) { testGCC68255(t) }
func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View file

@ -0,0 +1,11 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
package cgotest
import "testing"
func TestSigaltstack(t *testing.T) { testSigaltstack(t) }

View file

@ -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.
package cgotest
import "C"
var _ C.complexfloat
var _ C.complexdouble

View file

@ -14,6 +14,11 @@ void scatter() {
printf("scatter = %p\n", p);
}
// Adding this explicit extern declaration makes this a test for
// https://gcc.gnu.org/PR68072 aka https://golang.org/issue/13344 .
// It used to cause a cgo error when building with GCC 6.
extern int hola;
// this example is in issue 3253
int hola = 0;
int testHola() { return hola; }

10
misc/cgo/test/issue4029.c Normal file
View file

@ -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 !windows
void call4029(void *arg) {
void (*fn)(void) = arg;
fn();
}

View file

@ -9,32 +9,35 @@ package cgotest
/*
#include <dlfcn.h>
#cgo linux LDFLAGS: -ldl
extern void call4029(void *arg);
*/
import "C"
import (
"fmt"
"testing"
)
var callbacks int
//export IMPIsOpaque
func IMPIsOpaque() {
fmt.Println("isOpaque")
callbacks++
}
//export IMPInitWithFrame
func IMPInitWithFrame() {
fmt.Println("IInitWithFrame")
callbacks++
}
//export IMPDrawRect
func IMPDrawRect() {
fmt.Println("drawRect:")
callbacks++
}
//export IMPWindowResize
func IMPWindowResize() {
fmt.Println("windowDidResize:")
callbacks++
}
func test4029(t *testing.T) {
@ -42,6 +45,9 @@ func test4029(t *testing.T) {
loadThySelf(t, "IMPDrawRect")
loadThySelf(t, "IMPInitWithFrame")
loadThySelf(t, "IMPIsOpaque")
if callbacks != 4 {
t.Errorf("got %d callbacks, expected 4", callbacks)
}
}
func loadThySelf(t *testing.T, symbol string) {
@ -58,4 +64,5 @@ func loadThySelf(t *testing.T, symbol string) {
return
}
t.Log(symbol, symbol_address)
C.call4029(symbol_address)
}

View file

@ -22,14 +22,14 @@ func test8694(t *testing.T) {
t.Skip("test8694 is disabled on ARM because 5l cannot handle thumb library.")
}
// Really just testing that this compiles, but check answer anyway.
x := complex64(2 + 3i)
x := C.complexfloat(2 + 3i)
x2 := x * x
cx2 := C.complexFloatSquared(x)
if cx2 != x2 {
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2)
}
y := complex128(2 + 3i)
y := C.complexdouble(2 + 3i)
y2 := y * y
cy2 := C.complexDoubleSquared(y)
if cy2 != y2 {

View file

@ -0,0 +1,71 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
// Test that the Go runtime still works if C code changes the signal stack.
package cgotest
/*
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static stack_t oss;
static char signalStack[SIGSTKSZ];
static void changeSignalStack() {
stack_t ss;
memset(&ss, 0, sizeof ss);
ss.ss_sp = signalStack;
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
if (sigaltstack(&ss, &oss) < 0) {
perror("sigaltstack");
abort();
}
}
static void restoreSignalStack() {
#if defined(__x86_64__) && defined(__APPLE__)
// The Darwin C library enforces a minimum that the kernel does not.
// This is OK since we allocated this much space in mpreinit,
// it was just removed from the buffer by stackalloc.
oss.ss_size = MINSIGSTKSZ;
#endif
if (sigaltstack(&oss, NULL) < 0) {
perror("sigaltstack restore");
abort();
}
}
static int zero() {
return 0;
}
*/
import "C"
import (
"runtime"
"testing"
)
func testSigaltstack(t *testing.T) {
switch {
case runtime.GOOS == "solaris", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"):
t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
C.changeSignalStack()
defer C.restoreSignalStack()
defer func() {
if recover() == nil {
t.Error("did not see expected panic")
}
}()
v := 1 / int(C.zero())
t.Errorf("unexpected success of division by zero == %d", v)
}

View file

@ -0,0 +1,185 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test installing a signal handler before the Go code starts.
// This is a lot like misc/cgo/testcshared/main4.c.
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include "libgo2.h"
static void die(const char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static volatile sig_atomic_t sigioSeen;
// Use up some stack space.
static void recur(int i, char *p) {
char a[1024];
*p = '\0';
if (i > 0) {
recur(i - 1, a);
}
}
// Signal handler that uses up more stack space than a goroutine will have.
static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
char a[1024];
recur(4, a);
sigioSeen = 1;
}
static jmp_buf jmp;
static char* nullPointer;
// Signal handler for SIGSEGV on a C thread.
static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
sigset_t mask;
int i;
if (sigemptyset(&mask) < 0) {
die("sigemptyset");
}
if (sigaddset(&mask, SIGSEGV) < 0) {
die("sigaddset");
}
i = sigprocmask(SIG_UNBLOCK, &mask, NULL);
if (i != 0) {
fprintf(stderr, "sigprocmask: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
// Don't try this at home.
longjmp(jmp, signo);
// We should never get here.
abort();
}
// Set up the signal handlers in a high priority constructor,
// so that they are installed before the Go code starts.
static void init(void) __attribute__ ((constructor (200)));
static void init() {
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = ioHandler;
if (sigemptyset(&sa.sa_mask) < 0) {
die("sigemptyset");
}
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGIO, &sa, NULL) < 0) {
die("sigaction");
}
sa.sa_sigaction = segvHandler;
if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) {
die("sigaction");
}
}
int main(int argc, char** argv) {
int verbose;
sigset_t mask;
int i;
verbose = argc > 1;
setvbuf(stdout, NULL, _IONBF, 0);
// Call setsid so that we can use kill(0, SIGIO) below.
// Don't check the return value so that this works both from
// a job control shell and from a shell script.
setsid();
if (verbose) {
printf("calling RunGoroutines\n");
}
RunGoroutines();
// Block SIGIO in this thread to make it more likely that it
// will be delivered to a goroutine.
if (verbose) {
printf("calling pthread_sigmask\n");
}
if (sigemptyset(&mask) < 0) {
die("sigemptyset");
}
if (sigaddset(&mask, SIGIO) < 0) {
die("sigaddset");
}
i = pthread_sigmask(SIG_BLOCK, &mask, NULL);
if (i != 0) {
fprintf(stderr, "pthread_sigmask: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling kill\n");
}
if (kill(0, SIGIO) < 0) {
die("kill");
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
if (verbose) {
printf("calling setjmp\n");
}
// Test that a SIGSEGV on this thread is delivered to us.
if (setjmp(jmp) == 0) {
if (verbose) {
printf("triggering SIGSEGV\n");
}
*nullPointer = '\0';
fprintf(stderr, "continued after address error\n");
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling TestSEGV\n");
}
TestSEGV();
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,153 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test os/signal.Notify and os/signal.Reset.
// This is a lot like misc/cgo/testcshared/main5.c.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include "libgo3.h"
static void die(const char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static volatile sig_atomic_t sigioSeen;
static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
sigioSeen = 1;
}
int main(int argc, char** argv) {
int verbose;
struct sigaction sa;
int i;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
if (verbose) {
printf("calling sigaction\n");
}
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = ioHandler;
if (sigemptyset(&sa.sa_mask) < 0) {
die("sigemptyset");
}
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGIO, &sa, NULL) < 0) {
die("sigaction");
}
// At this point there should not be a Go signal handler
// installed for SIGIO.
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
sigioSeen = 0;
// Tell the Go code to catch SIGIO.
if (verbose) {
printf("calling CatchSIGIO\n");
}
CatchSIGIO();
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("calling SawSIGIO\n");
}
if (!SawSIGIO()) {
fprintf(stderr, "Go handler did not see SIGIO\n");
exit(EXIT_FAILURE);
}
if (sigioSeen != 0) {
fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
exit(EXIT_FAILURE);
}
// Tell the Go code to stop catching SIGIO.
if (verbose) {
printf("calling ResetSIGIO\n");
}
ResetSIGIO();
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("calling SawSIGIO\n");
}
if (SawSIGIO()) {
fprintf(stderr, "Go handler saw SIGIO after Reset\n");
exit(EXIT_FAILURE);
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,194 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test a C thread that calls sigaltstack and then calls Go code.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <pthread.h>
#include "libgo4.h"
static void die(const char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static int ok = 1;
static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
}
// Set up the SIGIO signal handler in a high priority constructor, so
// that it is installed before the Go code starts.
static void init(void) __attribute__ ((constructor (200)));
static void init() {
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = ioHandler;
if (sigemptyset(&sa.sa_mask) < 0) {
die("sigemptyset");
}
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGIO, &sa, NULL) < 0) {
die("sigaction");
}
}
// Test raising SIGIO on a C thread with an alternate signal stack
// when there is a Go signal handler for SIGIO.
static void* thread1(void* arg) {
pthread_t* ptid = (pthread_t*)(arg);
stack_t ss;
int i;
stack_t nss;
// Set up an alternate signal stack for this thread.
memset(&ss, 0, sizeof ss);
ss.ss_sp = malloc(SIGSTKSZ);
if (ss.ss_sp == NULL) {
die("malloc");
}
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
if (sigaltstack(&ss, NULL) < 0) {
die("sigaltstack");
}
// Send ourselves a SIGIO. This will be caught by the Go
// signal handler which should forward to the C signal
// handler.
i = pthread_kill(*ptid, SIGIO);
if (i != 0) {
fprintf(stderr, "pthread_kill: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
// Wait until the signal has been delivered.
i = 0;
while (SIGIOCount() == 0) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
// We should still be on the same signal stack.
if (sigaltstack(NULL, &nss) < 0) {
die("sigaltstack check");
}
if ((nss.ss_flags & SS_DISABLE) != 0) {
fprintf(stderr, "sigaltstack disabled on return from Go\n");
ok = 0;
} else if (nss.ss_sp != ss.ss_sp) {
fprintf(stderr, "sigalstack changed on return from Go\n");
ok = 0;
}
return NULL;
}
// Test calling a Go function to raise SIGIO on a C thread with an
// alternate signal stack when there is a Go signal handler for SIGIO.
static void* thread2(void* arg) {
pthread_t* ptid = (pthread_t*)(arg);
stack_t ss;
int i;
int oldcount;
stack_t nss;
// Set up an alternate signal stack for this thread.
memset(&ss, 0, sizeof ss);
ss.ss_sp = malloc(SIGSTKSZ);
if (ss.ss_sp == NULL) {
die("malloc");
}
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
if (sigaltstack(&ss, NULL) < 0) {
die("sigaltstack");
}
oldcount = SIGIOCount();
// Call a Go function that will call a C function to send us a
// SIGIO.
GoRaiseSIGIO(ptid);
// Wait until the signal has been delivered.
i = 0;
while (SIGIOCount() == oldcount) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
// We should still be on the same signal stack.
if (sigaltstack(NULL, &nss) < 0) {
die("sigaltstack check");
}
if ((nss.ss_flags & SS_DISABLE) != 0) {
fprintf(stderr, "sigaltstack disabled on return from Go\n");
ok = 0;
} else if (nss.ss_sp != ss.ss_sp) {
fprintf(stderr, "sigalstack changed on return from Go\n");
ok = 0;
}
return NULL;
}
int main(int argc, char **argv) {
pthread_t tid;
int i;
// Tell the Go library to start looking for SIGIO.
GoCatchSIGIO();
i = pthread_create(&tid, NULL, thread1, (void*)(&tid));
if (i != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
i = pthread_join(tid, NULL);
if (i != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
i = pthread_create(&tid, NULL, thread2, (void*)(&tid));
if (i != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
i = pthread_join(tid, NULL);
if (i != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
if (!ok) {
exit(EXIT_FAILURE);
}
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,45 @@
// 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 (
"fmt"
"os"
"runtime"
)
// RunGoroutines starts some goroutines that don't do anything.
// The idea is to get some threads going, so that a signal will be delivered
// to a thread started by Go.
//export RunGoroutines
func RunGoroutines() {
for i := 0; i < 4; i++ {
go func() {
runtime.LockOSThread()
select {}
}()
}
}
var P *byte
// TestSEGV makes sure that an invalid address turns into a run-time Go panic.
//export TestSEGV
func TestSEGV() {
defer func() {
if recover() == nil {
fmt.Fprintln(os.Stderr, "no panic from segv")
os.Exit(1)
}
}()
*P = 0
fmt.Fprintln(os.Stderr, "continued after segv")
os.Exit(1)
}
func main() {
}

View file

@ -0,0 +1,44 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "C"
import (
"os"
"os/signal"
"syscall"
"time"
)
// The channel used to read SIGIO signals.
var sigioChan chan os.Signal
// CatchSIGIO starts catching SIGIO signals.
//export CatchSIGIO
func CatchSIGIO() {
sigioChan = make(chan os.Signal, 1)
signal.Notify(sigioChan, syscall.SIGIO)
}
// ResetSIGIO stops catching SIGIO signals.
//export ResetSIGIO
func ResetSIGIO() {
signal.Reset(syscall.SIGIO)
}
// SawSIGIO returns whether we saw a SIGIO within a brief pause.
//export SawSIGIO
func SawSIGIO() C.int {
select {
case <-sigioChan:
return 1
case <-time.After(100 * time.Millisecond):
return 0
}
}
func main() {
}

View file

@ -0,0 +1,52 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
/*
#include <signal.h>
#include <pthread.h>
// Raise SIGIO.
static void CRaiseSIGIO(pthread_t* p) {
pthread_kill(*p, SIGIO);
}
*/
import "C"
import (
"os"
"os/signal"
"sync/atomic"
"syscall"
)
var sigioCount int32
// Catch SIGIO.
//export GoCatchSIGIO
func GoCatchSIGIO() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGIO)
go func() {
for range c {
atomic.AddInt32(&sigioCount, 1)
}
}()
}
// Raise SIGIO.
//export GoRaiseSIGIO
func GoRaiseSIGIO(p *C.pthread_t) {
C.CRaiseSIGIO(p)
}
// Return the number of SIGIO signals seen.
//export SIGIOCount
func SIGIOCount() C.int {
return C.int(atomic.LoadInt32(&sigioCount))
}
func main() {
}

View file

@ -23,11 +23,16 @@ fi
rm -rf libgo.a libgo.h testp pkg
status=0
# Installing first will create the header files we want.
GOPATH=$(pwd) go install -buildmode=c-archive libgo
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c pkg/$(go env GOOS)_$(go env GOARCH)/libgo.a
$bin arg1 arg2
if ! $bin arg1 arg2; then
echo "FAIL test1a"
status=1
fi
rm -f libgo.a libgo.h testp
# Test building libgo other than installing it.
@ -35,10 +40,49 @@ rm -f libgo.a libgo.h testp
GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
$bin arg1 arg2
if ! $bin arg1 arg2; then
echo "FAIL test1b"
status=1
fi
rm -f libgo.a libgo.h testp
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
$bin arg1 arg2
if ! $bin arg1 arg2; then
echo "FAIL test1c"
status=1
fi
rm -rf libgo.a libgo.h testp pkg
case "$(go env GOOS)/$(go env GOARCH)" in
"darwin/arm" | "darwin/arm64")
echo "Skipping test2; see https://golang.org/issue/13701"
;;
*)
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo2.a libgo2
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main2.c libgo2.a
if ! $bin; then
echo "FAIL test2"
status=1
fi
rm -rf libgo2.a libgo2.h testp pkg
;;
esac
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo3.a libgo3
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main3.c libgo3.a
if ! $bin; then
echo "FAIL test3"
status=1
fi
rm -rf libgo3.a libgo3.h testp pkg
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo4.a libgo4
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main4.c libgo4.a
if ! $bin; then
echo "FAIL test4"
status=1
fi
rm -rf libgo4.a libgo4.h testp pkg
exit $status

View file

@ -9,7 +9,7 @@
#include <time.h>
#include <unistd.h>
#define fd (10)
#define fd (100)
// Tests libgo2.so, which does not export any functions.
// Read a string from the file descriptor and print it.

View file

@ -0,0 +1,214 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that a signal handler that uses up stack space does not crash
// if the signal is delivered to a thread running a goroutine.
// This is a lot like misc/cgo/testcarchive/main2.c.
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include <dlfcn.h>
static void die(const char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static volatile sig_atomic_t sigioSeen;
// Use up some stack space.
static void recur(int i, char *p) {
char a[1024];
*p = '\0';
if (i > 0) {
recur(i - 1, a);
}
}
// Signal handler that uses up more stack space than a goroutine will have.
static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
char a[1024];
recur(4, a);
sigioSeen = 1;
}
static jmp_buf jmp;
static char* nullPointer;
// Signal handler for SIGSEGV on a C thread.
static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
sigset_t mask;
int i;
if (sigemptyset(&mask) < 0) {
die("sigemptyset");
}
if (sigaddset(&mask, SIGSEGV) < 0) {
die("sigaddset");
}
i = sigprocmask(SIG_UNBLOCK, &mask, NULL);
if (i != 0) {
fprintf(stderr, "sigprocmask: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
// Don't try this at home.
longjmp(jmp, signo);
// We should never get here.
abort();
}
int main(int argc, char** argv) {
int verbose;
struct sigaction sa;
void* handle;
void (*fn)(void);
sigset_t mask;
int i;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
// Call setsid so that we can use kill(0, SIGIO) below.
// Don't check the return value so that this works both from
// a job control shell and from a shell script.
setsid();
if (verbose) {
printf("calling sigaction\n");
}
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = ioHandler;
if (sigemptyset(&sa.sa_mask) < 0) {
die("sigemptyset");
}
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGIO, &sa, NULL) < 0) {
die("sigaction");
}
sa.sa_sigaction = segvHandler;
if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) {
die("sigaction");
}
if (verbose) {
printf("calling dlopen\n");
}
handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
if (handle == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling dlsym\n");
}
// Start some goroutines.
fn = (void(*)(void))dlsym(handle, "RunGoroutines");
if (fn == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling RunGoroutines\n");
}
fn();
// Block SIGIO in this thread to make it more likely that it
// will be delivered to a goroutine.
if (verbose) {
printf("calling pthread_sigmask\n");
}
if (sigemptyset(&mask) < 0) {
die("sigemptyset");
}
if (sigaddset(&mask, SIGIO) < 0) {
die("sigaddset");
}
i = pthread_sigmask(SIG_BLOCK, &mask, NULL);
if (i != 0) {
fprintf(stderr, "pthread_sigmask: %s\n", strerror(i));
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling kill\n");
}
if (kill(0, SIGIO) < 0) {
die("kill");
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
if (verbose) {
printf("calling setjmp\n");
}
// Test that a SIGSEGV on this thread is delivered to us.
if (setjmp(jmp) == 0) {
if (verbose) {
printf("triggering SIGSEGV\n");
}
*nullPointer = '\0';
fprintf(stderr, "continued after address error\n");
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling dlsym\n");
}
// Make sure that a SIGSEGV in Go causes a run-time panic.
fn = (void (*)(void))dlsym(handle, "TestSEGV");
if (fn == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling TestSEGV\n");
}
fn();
printf("PASS\n");
return 0;
}

View file

@ -0,0 +1,197 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that a signal handler works in non-Go code when using
// os/signal.Notify.
// This is a lot like misc/cgo/testcarchive/main3.c.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <dlfcn.h>
static void die(const char* msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static volatile sig_atomic_t sigioSeen;
static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
sigioSeen = 1;
}
int main(int argc, char** argv) {
int verbose;
struct sigaction sa;
void* handle;
void (*fn1)(void);
int (*sawSIGIO)(void);
int i;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
if (verbose) {
printf("calling sigaction\n");
}
memset(&sa, 0, sizeof sa);
sa.sa_sigaction = ioHandler;
if (sigemptyset(&sa.sa_mask) < 0) {
die("sigemptyset");
}
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGIO, &sa, NULL) < 0) {
die("sigaction");
}
if (verbose) {
printf("calling dlopen\n");
}
handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
if (handle == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
// At this point there should not be a Go signal handler
// installed for SIGIO.
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
sigioSeen = 0;
// Tell the Go code to catch SIGIO.
if (verbose) {
printf("calling dlsym\n");
}
fn1 = (void(*)(void))dlsym(handle, "CatchSIGIO");
if (fn1 == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling CatchSIGIO\n");
}
fn1();
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("calling dlsym\n");
}
// Check that the Go code saw SIGIO.
sawSIGIO = (int (*)(void))dlsym(handle, "SawSIGIO");
if (sawSIGIO == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling SawSIGIO\n");
}
if (!sawSIGIO()) {
fprintf(stderr, "Go handler did not see SIGIO\n");
exit(EXIT_FAILURE);
}
if (sigioSeen != 0) {
fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
exit(EXIT_FAILURE);
}
// Tell the Go code to stop catching SIGIO.
if (verbose) {
printf("calling dlsym\n");
}
fn1 = (void(*)(void))dlsym(handle, "ResetSIGIO");
if (fn1 == NULL) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
if (verbose) {
printf("calling ResetSIGIO\n");
}
fn1();
if (verbose) {
printf("raising SIGIO\n");
}
if (raise(SIGIO) < 0) {
die("raise");
}
if (verbose) {
printf("calling SawSIGIO\n");
}
if (sawSIGIO()) {
fprintf(stderr, "Go handler saw SIGIO after Reset\n");
exit(EXIT_FAILURE);
}
if (verbose) {
printf("waiting for sigioSeen\n");
}
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 100000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
printf("PASS\n");
return 0;
}

View file

@ -21,7 +21,7 @@ import (
// that the C code can also use.
const (
fd = 10
fd = 100
)
func init() {

View file

@ -0,0 +1,45 @@
// 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 (
"fmt"
"os"
"runtime"
)
// RunGoroutines starts some goroutines that don't do anything.
// The idea is to get some threads going, so that a signal will be delivered
// to a thread started by Go.
//export RunGoroutines
func RunGoroutines() {
for i := 0; i < 4; i++ {
go func() {
runtime.LockOSThread()
select {}
}()
}
}
var P *byte
// TestSEGV makes sure that an invalid address turns into a run-time Go panic.
//export TestSEGV
func TestSEGV() {
defer func() {
if recover() == nil {
fmt.Fprintln(os.Stderr, "no panic from segv")
os.Exit(1)
}
}()
*P = 0
fmt.Fprintln(os.Stderr, "continued after segv")
os.Exit(1)
}
func main() {
}

View file

@ -0,0 +1,44 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "C"
import (
"os"
"os/signal"
"syscall"
"time"
)
// The channel used to read SIGIO signals.
var sigioChan chan os.Signal
// CatchSIGIO starts catching SIGIO signals.
//export CatchSIGIO
func CatchSIGIO() {
sigioChan = make(chan os.Signal, 1)
signal.Notify(sigioChan, syscall.SIGIO)
}
// ResetSIGIO stops catching SIGIO signals.
//export ResetSIGIO
func ResetSIGIO() {
signal.Reset(syscall.SIGIO)
}
// SawSIGIO returns whether we saw a SIGIO within a brief pause.
//export SawSIGIO
func SawSIGIO() C.int {
select {
case <-sigioChan:
return 1
case <-time.After(100 * time.Millisecond):
return 0
}
}
func main() {
}

View file

@ -16,6 +16,13 @@ fi
goos=$(go env GOOS)
goarch=$(go env GOARCH)
goroot=$(go env GOROOT)
if [ ! -d "$goroot" ]; then
echo 'misc/cgo/testcshared/test.bash cannnot 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.
@ -28,12 +35,13 @@ fi
androidpath=/data/local/tmp/testcshared-$$
function cleanup() {
rm -rf libgo.$libext libgo2.$libext libgo.h testp testp2 testp3 pkg
rm -rf $(go env GOROOT)/${installdir}
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
adb shell rm -rf "$androidpath"
fi
}
trap cleanup EXIT
@ -93,6 +101,8 @@ if [ "$goos" == "android" ]; then
GOGCCFLAGS="${GOGCCFLAGS} -pie"
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
@ -101,7 +111,7 @@ binpush testp
output=$(run LD_LIBRARY_PATH=. ./testp)
if [ "$output" != "PASS" ]; then
echo "FAIL test0 got ${output}"
exit 1
status=1
fi
# test1: shared library can be dynamically loaded and exported symbols are accessible.
@ -110,7 +120,7 @@ binpush testp
output=$(run ./testp ./libgo.$libext)
if [ "$output" != "PASS" ]; then
echo "FAIL test1 got ${output}"
exit 1
status=1
fi
# test2: tests libgo2 which does not export any functions.
@ -125,7 +135,7 @@ binpush testp2
output=$(run LD_LIBRARY_PATH=. ./testp2)
if [ "$output" != "PASS" ]; then
echo "FAIL test2 got ${output}"
exit 1
status=1
fi
# test3: tests main.main is exported on android.
@ -135,7 +145,42 @@ if [ "$goos" == "android" ]; then
output=$(run ./testp ./libgo.so)
if [ "$output" != "PASS" ]; then
echo "FAIL test3 got ${output}"
exit 1
status=1
fi
fi
echo "ok"
# 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 $status = 0; then
echo "ok"
fi
exit $status

View file

@ -5,13 +5,14 @@
package main
/*
extern int *GoFn(void);
extern int *GoFn(int *);
// Yes, you can have definitions if you use //export, as long as they are weak.
int f(void) __attribute__ ((weak));
int f() {
int *p = GoFn();
int i;
int *p = GoFn(&i);
if (*p != 12345)
return 0;
return 1;
@ -20,9 +21,9 @@ int f() {
import "C"
//export GoFn
func GoFn() *C.int {
i := C.int(12345)
return &i
func GoFn(p *C.int) *C.int {
*p = C.int(12345)
return p
}
func main() {

View file

@ -29,10 +29,24 @@ if $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 test; clang version $major.$minor older than 3.6"
if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
echo "skipping msan test; clang version $major.$minor (older than 3.6)"
exit 0
fi
# Clang before 3.8 does not work with Linux at or after 4.1.
# golang.org/issue/12898.
if test "$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 test; clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
exit 0
fi
fi
fi
fi
status=0
@ -47,7 +61,12 @@ if ! go run -msan msan.go; then
status=1
fi
if ! go run -msan msan2.go; then
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

View file

@ -285,23 +285,23 @@ func readNotes(f *elf.File) ([]*note, error) {
if err == io.EOF {
break
}
return nil, fmt.Errorf("read namesize failed:", err)
return nil, fmt.Errorf("read namesize failed: %v", err)
}
err = binary.Read(r, f.ByteOrder, &descsize)
if err != nil {
return nil, fmt.Errorf("read descsize failed:", err)
return nil, fmt.Errorf("read descsize failed: %v", err)
}
err = binary.Read(r, f.ByteOrder, &tag)
if err != nil {
return nil, fmt.Errorf("read type failed:", err)
return nil, fmt.Errorf("read type failed: %v", err)
}
name, err := readwithpad(r, namesize)
if err != nil {
return nil, fmt.Errorf("read name failed:", err)
return nil, fmt.Errorf("read name failed: %v", err)
}
desc, err := readwithpad(r, descsize)
if err != nil {
return nil, fmt.Errorf("read desc failed:", err)
return nil, fmt.Errorf("read desc failed: %v", err)
}
notes = append(notes, &note{name: string(name), tag: tag, desc: string(desc), section: sect})
}

View file

@ -7,9 +7,14 @@ package main
import "fmt"
/*
#cgo CFLAGS: -pthread
#cgo LDFLAGS: -pthread
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
int *p;
static void sigsegv() {
@ -18,16 +23,65 @@ static void sigsegv() {
exit(2);
}
static void sighandler(int signum) {
static void segvhandler(int signum) {
if (signum == SIGSEGV) {
exit(0); // success
}
}
static volatile sig_atomic_t sigioSeen;
// Use up some stack space.
static void recur(int i, char *p) {
char a[1024];
*p = '\0';
if (i > 0) {
recur(i - 1, a);
}
}
static void iohandler(int signum) {
char a[1024];
recur(4, a);
sigioSeen = 1;
}
static void* sigioThread(void* arg __attribute__ ((unused))) {
raise(SIGIO);
}
static void sigioOnThread() {
pthread_t tid;
int i;
pthread_create(&tid, NULL, sigioThread, NULL);
pthread_join(tid, NULL);
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
if (sched_yield() < 0) {
perror("sched_yield");
}
i++;
if (i > 10000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
}
}
static void __attribute__ ((constructor)) sigsetup(void) {
struct sigaction act;
act.sa_handler = &sighandler;
sigaction(SIGSEGV, &act, 0);
memset(&act, 0, sizeof act);
act.sa_handler = segvhandler;
sigaction(SIGSEGV, &act, NULL);
act.sa_handler = iohandler;
sigaction(SIGIO, &act, NULL);
}
*/
import "C"

View file

@ -327,3 +327,14 @@ func toASCII(s string) string {
}
return buf.String()
}
// isHeaderOnlyType checks if the given type flag is of the type that has no
// data section even if a size is specified.
func isHeaderOnlyType(flag byte) bool {
switch flag {
case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
return true
default:
return false
}
}

View file

@ -26,7 +26,7 @@ func Example() {
}{
{"readme.txt", "This archive contains some text files."},
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling licence."},
{"todo.txt", "Get animal handling license."},
}
for _, file := range files {
hdr := &tar.Header{
@ -76,5 +76,5 @@ func Example() {
// Geoffrey
// Gonzo
// Contents of todo.txt:
// Get animal handling licence.
// Get animal handling license.
}

View file

@ -37,6 +37,10 @@ type Reader struct {
hdrBuff [blockSize]byte // buffer to use in readHeader
}
type parser struct {
err error // Last error seen
}
// A numBytesReader is an io.Reader with a numBytes method, returning the number
// of bytes remaining in the underlying encoded data.
type numBytesReader interface {
@ -113,78 +117,82 @@ func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
//
// io.EOF is returned at the end of the input.
func (tr *Reader) Next() (*Header, error) {
var hdr *Header
if tr.err == nil {
tr.skipUnread()
}
if tr.err != nil {
return hdr, tr.err
return nil, tr.err
}
hdr = tr.readHeader()
if hdr == nil {
return hdr, tr.err
}
// Check for PAX/GNU header.
switch hdr.Typeflag {
case TypeXHeader:
// PAX extended header
headers, err := parsePAX(tr)
if err != nil {
return nil, err
}
// We actually read the whole file,
// but this skips alignment padding
tr.skipUnread()
var hdr *Header
var extHdrs map[string]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".
loop:
for {
tr.err = tr.skipUnread()
if tr.err != nil {
return nil, tr.err
}
hdr = tr.readHeader()
if hdr == nil {
if tr.err != nil {
return nil, tr.err
}
mergePAX(hdr, headers)
// Check for a PAX format sparse file
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
if err != nil {
tr.err = err
return nil, err
}
if sp != nil {
// Current file is a PAX format GNU sparse file.
// Set the current file reader to a sparse file reader.
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
// Check for PAX/GNU special headers and files.
switch hdr.Typeflag {
case TypeXHeader:
extHdrs, tr.err = parsePAX(tr)
if tr.err != nil {
return nil, tr.err
}
continue loop // This is a meta header affecting the next header
case TypeGNULongName, TypeGNULongLink:
var realname []byte
realname, tr.err = ioutil.ReadAll(tr)
if tr.err != nil {
return nil, tr.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)
case TypeGNULongLink:
extHdrs[paxLinkpath] = p.parseString(realname)
}
if p.err != nil {
tr.err = p.err
return nil, tr.err
}
continue loop // This is a meta header affecting the next header
default:
mergePAX(hdr, extHdrs)
// Check for a PAX format sparse file
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
if err != nil {
tr.err = err
return nil, err
}
if sp != nil {
// Current file is a PAX format GNU sparse file.
// Set the current file reader to a sparse file reader.
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
if tr.err != nil {
return nil, tr.err
}
}
break loop // This is a file, so stop
}
return hdr, nil
case TypeGNULongName:
// We have a GNU long name header. Its contents are the real file name.
realname, err := ioutil.ReadAll(tr)
if err != nil {
return nil, err
}
hdr, tr.err = tr.Next()
if tr.err != nil {
return nil, tr.err
}
hdr.Name = cString(realname)
return hdr, nil
case TypeGNULongLink:
// We have a GNU long link header.
realname, err := ioutil.ReadAll(tr)
if err != nil {
return nil, err
}
hdr, tr.err = tr.Next()
if tr.err != nil {
return nil, tr.err
}
hdr.Linkname = cString(realname)
return hdr, nil
}
return hdr, tr.err
return hdr, nil
}
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
@ -355,6 +363,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
if err != nil {
return nil, err
}
sbuf := string(buf)
// For GNU PAX sparse format 0.0 support.
// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
@ -363,35 +372,17 @@ func parsePAX(r io.Reader) (map[string]string, error) {
headers := make(map[string]string)
// Each record is constructed as
// "%d %s=%s\n", length, keyword, value
for len(buf) > 0 {
// or the header was empty to start with.
var sp int
// The size field ends at the first space.
sp = bytes.IndexByte(buf, ' ')
if sp == -1 {
for len(sbuf) > 0 {
key, value, residual, err := parsePAXRecord(sbuf)
if err != nil {
return nil, ErrHeader
}
// Parse the first token as a decimal integer.
n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
if err != nil || n < 5 || int64(len(buf)) < n {
return nil, ErrHeader
}
// Extract everything between the decimal and the n -1 on the
// beginning to eat the ' ', -1 on the end to skip the newline.
var record []byte
record, buf = buf[sp+1:n-1], buf[n:]
// The first equals is guaranteed to mark the end of the key.
// Everything else is value.
eq := bytes.IndexByte(record, '=')
if eq == -1 {
return nil, ErrHeader
}
key, value := record[:eq], record[eq+1:]
sbuf = residual
keyStr := string(key)
if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
sparseMap.Write(value)
sparseMap.WriteString(value)
sparseMap.Write([]byte{','})
} else {
// Normal key. Set the value in the headers map.
@ -406,9 +397,42 @@ func parsePAX(r io.Reader) (map[string]string, error) {
return headers, nil
}
// cString parses bytes as a NUL-terminated C-style string.
// 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, ' ')
if sp == -1 {
return "", "", s, ErrHeader
}
// Parse the first token as a decimal integer.
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
if perr != nil || n < 5 || int64(len(s)) < n {
return "", "", s, ErrHeader
}
// Extract everything between the space and the final newline.
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
if nl != "\n" {
return "", "", s, ErrHeader
}
// The first equals separates the key from the value.
eq := strings.IndexByte(rec, '=')
if eq == -1 {
return "", "", s, ErrHeader
}
return rec[:eq], rec[eq+1:], rem, nil
}
// 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 cString(b []byte) string {
func (*parser) parseString(b []byte) string {
n := 0
for n < len(b) && b[n] != 0 {
n++
@ -416,19 +440,51 @@ func cString(b []byte) string {
return string(b[0:n])
}
func (tr *Reader) octal(b []byte) int64 {
// Check for binary format first.
// parseNumeric parses the input as being encoded in either base-256 or octal.
// This function may return negative numbers.
// If parsing fails or an integer overflow occurs, err will be set.
func (p *parser) parseNumeric(b []byte) int64 {
// Check for base-256 (binary) format first.
// If the first bit is set, then all following bits constitute a two's
// complement encoded number in big-endian byte order.
if len(b) > 0 && b[0]&0x80 != 0 {
var x int64
for i, c := range b {
if i == 0 {
c &= 0x7f // ignore signal bit in first byte
}
x = x<<8 | int64(c)
// Handling negative numbers relies on the following identity:
// -a-1 == ^a
//
// If the number is negative, we use an inversion mask to invert the
// data bytes and treat the value as an unsigned number.
var inv byte // 0x00 if positive or zero, 0xff if negative
if b[0]&0x40 != 0 {
inv = 0xff
}
return x
var x uint64
for i, c := range b {
c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
if i == 0 {
c &= 0x7f // Ignore signal bit in first byte
}
if (x >> 56) > 0 {
p.err = ErrHeader // Integer overflow
return 0
}
x = x<<8 | uint64(c)
}
if (x >> 63) > 0 {
p.err = ErrHeader // Integer overflow
return 0
}
if inv == 0xff {
return ^int64(x)
}
return int64(x)
}
// Normal case is base-8 (octal) format.
return p.parseOctal(b)
}
func (p *parser) parseOctal(b []byte) int64 {
// Because unused fields are filled with NULs, we need
// to skip leading NULs. Fields may also be padded with
// spaces or NULs.
@ -439,9 +495,9 @@ func (tr *Reader) octal(b []byte) int64 {
if len(b) == 0 {
return 0
}
x, err := strconv.ParseUint(cString(b), 8, 64)
if err != nil {
tr.err = err
x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
if perr != nil {
p.err = ErrHeader
}
return int64(x)
}
@ -492,9 +548,10 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
return false
}
given := tr.octal(header[148:156])
var p parser
given := p.parseOctal(header[148:156])
unsigned, signed := checksum(header)
return given == unsigned || given == signed
return p.err == nil && (given == unsigned || given == signed)
}
// readHeader reads the next block header and assumes that the underlying reader
@ -531,22 +588,19 @@ func (tr *Reader) readHeader() *Header {
}
// Unpack
var p parser
hdr := new(Header)
s := slicer(header)
hdr.Name = cString(s.next(100))
hdr.Mode = tr.octal(s.next(8))
hdr.Uid = int(tr.octal(s.next(8)))
hdr.Gid = int(tr.octal(s.next(8)))
hdr.Size = tr.octal(s.next(12))
if hdr.Size < 0 {
tr.err = ErrHeader
return nil
}
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
hdr.Name = p.parseString(s.next(100))
hdr.Mode = p.parseNumeric(s.next(8))
hdr.Uid = int(p.parseNumeric(s.next(8)))
hdr.Gid = int(p.parseNumeric(s.next(8)))
hdr.Size = p.parseNumeric(s.next(12))
hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
s.next(8) // chksum
hdr.Typeflag = s.next(1)[0]
hdr.Linkname = cString(s.next(100))
hdr.Linkname = p.parseString(s.next(100))
// The remainder of the header depends on the value of magic.
// The original (v7) version of tar had no explicit magic field,
@ -566,45 +620,54 @@ func (tr *Reader) readHeader() *Header {
switch format {
case "posix", "gnu", "star":
hdr.Uname = cString(s.next(32))
hdr.Gname = cString(s.next(32))
hdr.Uname = p.parseString(s.next(32))
hdr.Gname = p.parseString(s.next(32))
devmajor := s.next(8)
devminor := s.next(8)
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
hdr.Devmajor = tr.octal(devmajor)
hdr.Devminor = tr.octal(devminor)
hdr.Devmajor = p.parseNumeric(devmajor)
hdr.Devminor = p.parseNumeric(devminor)
}
var prefix string
switch format {
case "posix", "gnu":
prefix = cString(s.next(155))
prefix = p.parseString(s.next(155))
case "star":
prefix = cString(s.next(131))
hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
prefix = p.parseString(s.next(131))
hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name
}
}
if tr.err != nil {
if p.err != nil {
tr.err = p.err
return nil
}
nb := hdr.Size
if isHeaderOnlyType(hdr.Typeflag) {
nb = 0
}
if nb < 0 {
tr.err = ErrHeader
return nil
}
// Maximum value of hdr.Size is 64 GB (12 octal digits),
// so there's no risk of int64 overflowing.
nb := int64(hdr.Size)
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
// Set the current file reader.
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
tr.curr = &regFileReader{r: tr.r, nb: nb}
// Check for old GNU sparse format entry.
if hdr.Typeflag == TypeGNUSparse {
// Get the real size of the file.
hdr.Size = tr.octal(header[483:495])
hdr.Size = p.parseNumeric(header[483:495])
if p.err != nil {
tr.err = p.err
return nil
}
// Read the sparse map.
sp := tr.readOldGNUSparseMap(header)
@ -626,6 +689,7 @@ func (tr *Reader) readHeader() *Header {
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
// then one or more extension headers are used to store the rest of the sparse map.
func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
var p parser
isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
spCap := oldGNUSparseMainHeaderNumEntries
if isExtended {
@ -636,10 +700,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
// Read the four entries from the main tar header
for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
offset := tr.octal(s.next(oldGNUSparseOffsetSize))
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
if tr.err != nil {
tr.err = ErrHeader
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
if p.err != nil {
tr.err = p.err
return nil
}
if offset == 0 && numBytes == 0 {
@ -657,10 +721,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
s = slicer(sparseHeader)
for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
offset := tr.octal(s.next(oldGNUSparseOffsetSize))
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
if tr.err != nil {
tr.err = ErrHeader
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
if p.err != nil {
tr.err = p.err
return nil
}
if offset == 0 && numBytes == 0 {
@ -672,85 +736,77 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
return sp
}
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
// The sparse map is stored just before the file data and padded out to the nearest block boundary.
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
// 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
// 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) {
buf := make([]byte, 2*blockSize)
sparseHeader := buf[:blockSize]
var cntNewline int64
var buf bytes.Buffer
var blk = make([]byte, blockSize)
// readDecimal is a helper function to read a decimal integer from the sparse map
// while making sure to read from the file in blocks of size blockSize
readDecimal := func() (int64, error) {
// Look for newline
nl := bytes.IndexByte(sparseHeader, '\n')
if nl == -1 {
if len(sparseHeader) >= blockSize {
// This is an error
return 0, ErrHeader
// feedTokens copies data in numBlock chunks 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
}
return err
}
oldLen := len(sparseHeader)
newLen := oldLen + blockSize
if cap(sparseHeader) < newLen {
// There's more header, but we need to make room for the next block
copy(buf, sparseHeader)
sparseHeader = buf[:newLen]
} else {
// There's more header, and we can just reslice
sparseHeader = sparseHeader[:newLen]
buf.Write(blk)
for _, c := range blk {
if c == '\n' {
cntNewline++
}
}
// Now that sparseHeader is large enough, read next block
if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
return 0, err
}
// Look for a newline in the new data
nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
if nl == -1 {
// This is an error
return 0, ErrHeader
}
nl += oldLen // We want the position from the beginning
}
// Now that we've found a newline, read a number
n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
if err != nil {
return 0, ErrHeader
}
// Update sparseHeader to consume this number
sparseHeader = sparseHeader[nl+1:]
return n, nil
return nil
}
// Read the first block
if _, err := io.ReadFull(r, sparseHeader); err != nil {
// nextToken gets the next token delimited by a newline. This assumes that
// at least one newline exists in the buffer.
var nextToken = func() string {
cntNewline--
tok, _ := buf.ReadString('\n')
return tok[:len(tok)-1] // Cut off newline
}
// Parse for the number of entries.
// Use integer overflow resistant math to check this.
if err := feedTokens(1); err != nil {
return nil, err
}
// The first line contains the number of entries
numEntries, err := readDecimal()
if err != nil {
return nil, err
numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
return nil, ErrHeader
}
// Read all the entries
// Parse for all member entries.
// numEntries is trusted after this since a potential attacker must have
// committed resources proportional to what this library used.
if err := feedTokens(2 * numEntries); err != nil {
return nil, err
}
sp := make([]sparseEntry, 0, numEntries)
for i := int64(0); i < numEntries; i++ {
// Read the offset
offset, err := readDecimal()
offset, err := strconv.ParseInt(nextToken(), 10, 64)
if err != nil {
return nil, err
return nil, ErrHeader
}
// Read numBytes
numBytes, err := readDecimal()
numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
if err != nil {
return nil, err
return nil, ErrHeader
}
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
}
return sp, nil
}
@ -801,6 +857,10 @@ func (tr *Reader) numBytes() int64 {
// 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.
//
// 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) (n int, err error) {
if tr.err != nil {
return 0, tr.err

View file

@ -288,6 +288,30 @@ var untarTests = []*untarTest{
},
},
},
{
// Matches the behavior of GNU, BSD, and STAR tar utilities.
file: "testdata/gnu-multi-hdrs.tar",
headers: []*Header{
{
Name: "GNU2/GNU2/long-path-name",
Linkname: "GNU4/GNU4/long-linkpath-name",
ModTime: time.Unix(0, 0),
Typeflag: '2',
},
},
},
{
// Matches the behavior of GNU and BSD tar utilities.
file: "testdata/pax-multi-hdrs.tar",
headers: []*Header{
{
Name: "bar",
Linkname: "PAX4/PAX4/long-linkpath-name",
ModTime: time.Unix(0, 0),
Typeflag: '2',
},
},
},
{
file: "testdata/neg-size.tar",
err: ErrHeader,
@ -298,17 +322,11 @@ var untarTests = []*untarTest{
},
{
file: "testdata/issue11169.tar",
// TODO(dsnet): Currently the library does not detect that this file is
// malformed. Instead it incorrectly believes that file just ends.
// At least the library doesn't crash anymore.
// err: ErrHeader,
err: ErrHeader,
},
{
file: "testdata/issue12435.tar",
// TODO(dsnet): Currently the library does not detect that this file is
// malformed. Instead, it incorrectly believes that file just ends.
// At least the library doesn't crash anymore.
// err: ErrHeader,
err: ErrHeader,
},
}
@ -727,35 +745,82 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
}
func TestReadGNUSparseMap1x0(t *testing.T) {
// This test uses lots of holes so the sparse header takes up more than two blocks
numEntries := 100
expected := make([]sparseEntry, 0, numEntries)
sparseMap := new(bytes.Buffer)
fmt.Fprintf(sparseMap, "%d\n", numEntries)
for i := 0; i < numEntries; i++ {
offset := int64(2048 * i)
numBytes := int64(1024)
expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
var sp = []sparseEntry{{1, 2}, {3, 4}}
for i := 0; i < 98; i++ {
sp = append(sp, sparseEntry{54321, 12345})
}
// Make the header the smallest multiple of blockSize that fits the sparseMap
headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
bufLen := blockSize * headerBlocks
buf := make([]byte, bufLen)
copy(buf, sparseMap.Bytes())
var 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,
}}
// Get an reader to read the sparse map
r := bytes.NewReader(buf)
// Read the sparse map
sp, err := readGNUSparseMap1x0(r)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(sp, expected) {
t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
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)
}
}
}
@ -901,3 +966,160 @@ func TestReadTruncation(t *testing.T) {
}
}
}
// TestReadHeaderOnly tests that Reader does not attempt to read special
// header-only files.
func TestReadHeaderOnly(t *testing.T) {
f, err := os.Open("testdata/hdr-only.tar")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
defer f.Close()
var hdrs []*Header
tr := NewReader(f)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
t.Errorf("Next(): got %v, want %v", err, nil)
continue
}
hdrs = append(hdrs, hdr)
// If a special flag, we should read nothing.
cnt, _ := io.ReadFull(tr, []byte{0})
if cnt > 0 && hdr.Typeflag != TypeReg {
t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
}
}
// File is crafted with 16 entries. The later 8 are identical to the first
// 8 except that the size is set.
if len(hdrs) != 16 {
t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
}
for i := 0; i < 8; i++ {
var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
hdr1.Size, hdr2.Size = 0, 0
if !reflect.DeepEqual(*hdr1, *hdr2) {
t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
}
}
}
func TestParsePAXRecord(t *testing.T) {
var medName = strings.Repeat("CD", 50)
var longName = strings.Repeat("AB", 100)
var vectors = []struct {
input string
residual string
outputKey string
outputVal string
ok bool
}{
{"6 k=v\n\n", "\n", "k", "v", true},
{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
{"110 path=" + medName + "\n", "", "path", medName, true},
{"9 foo=ba\n", "", "foo", "ba", true},
{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
{"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},
{"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},
{"6 k=1 ", "6 k=1 ", "", "", false},
{"632 k=1\n", "632 k=1\n", "", "", false},
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
}
for _, v := range vectors {
key, val, res, err := parsePAXRecord(v.input)
ok := (err == nil)
if v.ok != ok {
if v.ok {
t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
} else {
t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
}
}
if ok && (key != v.outputKey || val != v.outputVal) {
t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
v.input, key, val, v.outputKey, v.outputVal)
}
if res != v.residual {
t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
v.input, res, v.residual)
}
}
}
func TestParseNumeric(t *testing.T) {
var vectors = []struct {
input string
output int64
ok bool
}{
// Test base-256 (binary) encoded values.
{"", 0, true},
{"\x80", 0, true},
{"\x80\x00", 0, true},
{"\x80\x00\x00", 0, true},
{"\xbf", (1 << 6) - 1, true},
{"\xbf\xff", (1 << 14) - 1, true},
{"\xbf\xff\xff", (1 << 22) - 1, true},
{"\xff", -1, true},
{"\xff\xff", -1, true},
{"\xff\xff\xff", -1, true},
{"\xc0", -1 * (1 << 6), true},
{"\xc0\x00", -1 * (1 << 14), true},
{"\xc0\x00\x00", -1 * (1 << 22), true},
{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
// Test base-8 (octal) encoded values.
{"0000000\x00", 0, true},
{" \x0000000\x00", 0, true},
{" \x0000003\x00", 3, true},
{"00000000227\x00", 0227, true},
{"032033\x00 ", 032033, true},
{"320330\x00 ", 0320330, true},
{"0000660\x00 ", 0660, true},
{"\x00 0000660\x00 ", 0660, true},
{"0123456789abcdef", 0, false},
{"0123456789\x00abcdef", 0, false},
{"01234567\x0089abcdef", 342391, true},
{"0123\x7e\x5f\x264123", 0, false},
}
for _, v := range vectors {
var p parser
num := p.parseNumeric([]byte(v.input))
ok := (p.err == nil)
if v.ok != ok {
if v.ok {
t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
} else {
t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
}
}
if ok && num != v.output {
t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
}
}
}

Binary file not shown.

BIN
src/archive/tar/testdata/hdr-only.tar vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -42,6 +42,10 @@ type Writer struct {
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
}
type formatter struct {
err error // Last error seen
}
// NewWriter creates a new Writer writing to w.
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
@ -68,17 +72,9 @@ func (tw *Writer) Flush() error {
}
// Write s into b, terminating it with a NUL if there is room.
// If the value is too long for the field and allowPax is true add a paxheader record instead
func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
needsPaxHeader := allowPax && len(s) > len(b) || !isASCII(s)
if needsPaxHeader {
paxHeaders[paxKeyword] = s
return
}
func (f *formatter) formatString(b []byte, s string) {
if len(s) > len(b) {
if tw.err == nil {
tw.err = ErrFieldTooLong
}
f.err = ErrFieldTooLong
return
}
ascii := toASCII(s)
@ -89,40 +85,40 @@ func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string,
}
// Encode x as an octal ASCII string and write it into b with leading zeros.
func (tw *Writer) octal(b []byte, x int64) {
func (f *formatter) formatOctal(b []byte, x int64) {
s := strconv.FormatInt(x, 8)
// leading zeros, but leave room for a NUL.
for len(s)+1 < len(b) {
s = "0" + s
}
tw.cString(b, s, false, paxNone, nil)
f.formatString(b, s)
}
// Write x into b, either as octal or as binary (GNUtar/star extension).
// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead
func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
// Try octal first.
s := strconv.FormatInt(x, 8)
if len(s) < len(b) {
tw.octal(b, x)
// fitsInBase256 reports whether x can be encoded into n bytes using base-256
// encoding. Unlike octal encoding, base-256 encoding does not require that the
// string ends with a NUL character. Thus, all n bytes are available for output.
//
// If operating in binary mode, this assumes strict GNU binary mode; which means
// 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
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
}
// Write x into b, as binary (GNUtar/star extension).
func (f *formatter) formatNumeric(b []byte, x int64) {
if fitsInBase256(len(b), x) {
for i := len(b) - 1; i >= 0; i-- {
b[i] = byte(x)
x >>= 8
}
b[0] |= 0x80 // Highest bit indicates binary format
return
}
// If it is too long for octal, and pax is preferred, use a pax header
if allowPax && tw.preferPax {
tw.octal(b, 0)
s := strconv.FormatInt(x, 10)
paxHeaders[paxKeyword] = s
return
}
// Too big: use binary (big-endian).
tw.usedBinary = true
for i := len(b) - 1; x > 0 && i >= 0; i-- {
b[i] = byte(x)
x >>= 8
}
b[0] |= 0x80 // highest bit indicates binary format
f.formatOctal(b, 0) // Last resort, just write zero
f.err = ErrFieldTooLong
}
var (
@ -161,6 +157,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
// subsecond time resolution, but for now let's just capture
// too long fields or non ascii characters
var f formatter
var header []byte
// We need to select which scratch buffer to use carefully,
@ -175,10 +172,40 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
copy(header, zeroBlock)
s := slicer(header)
// Wrappers around formatter that automatically sets paxHeaders if the
// argument extends beyond the capacity of the input byte slice.
var formatString = func(b []byte, s string, paxKeyword string) {
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
if needsPaxHeader {
paxHeaders[paxKeyword] = s
return
}
f.formatString(b, s)
}
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
}
// 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
}
tw.usedBinary = true
f.formatNumeric(b, x)
}
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
pathHeaderBytes := s.next(fileNameSize)
tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders)
formatString(pathHeaderBytes, hdr.Name, paxPath)
// Handle out of range ModTime carefully.
var modTime int64
@ -186,25 +213,25 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
modTime = hdr.ModTime.Unix()
}
tw.octal(s.next(8), hdr.Mode) // 100:108
tw.numeric(s.next(8), int64(hdr.Uid), true, paxUid, paxHeaders) // 108:116
tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124
tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders) // 124:136
tw.numeric(s.next(12), modTime, false, paxNone, nil) // 136:148 --- consider using pax for finer granularity
s.next(8) // chksum (148:156)
s.next(1)[0] = hdr.Typeflag // 156:157
f.formatOctal(s.next(8), hdr.Mode) // 100:108
formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity
s.next(8) // chksum (148:156)
s.next(1)[0] = hdr.Typeflag // 156:157
tw.cString(s.next(100), hdr.Linkname, true, paxLinkpath, paxHeaders)
formatString(s.next(100), hdr.Linkname, paxLinkpath)
copy(s.next(8), []byte("ustar\x0000")) // 257:265
tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297
tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329
tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil) // 329:337
tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil) // 337:345
copy(s.next(8), []byte("ustar\x0000")) // 257:265
formatString(s.next(32), hdr.Uname, paxUname) // 265:297
formatString(s.next(32), hdr.Gname, paxGname) // 297:329
formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
prefixHeaderBytes := s.next(155)
tw.cString(prefixHeaderBytes, "", false, paxNone, nil) // 345:500 prefix
formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
@ -220,19 +247,20 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
delete(paxHeaders, paxPath)
// Update the path fields
tw.cString(pathHeaderBytes, suffix, false, paxNone, nil)
tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
formatString(pathHeaderBytes, suffix, paxNone)
formatString(prefixHeaderBytes, prefix, paxNone)
}
}
// The chksum field is terminated by a NUL and a space.
// This is different from the other octal fields.
chksum, _ := checksum(header)
tw.octal(header[148:155], chksum)
f.formatOctal(header[148:155], chksum) // Never fails
header[155] = ' '
if tw.err != nil {
// problem with header; probably integer too big for a field.
// Check if there were any formatting errors.
if f.err != nil {
tw.err = f.err
return tw.err
}
@ -310,7 +338,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
sort.Strings(keys)
for _, k := range keys {
fmt.Fprint(&buf, paxHeader(k+"="+paxHeaders[k]))
fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
}
ext.Size = int64(len(buf.Bytes()))
@ -326,17 +354,18 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
return nil
}
// paxHeader formats a single pax record, prefixing it with the appropriate length
func paxHeader(msg string) string {
const padding = 2 // Extra padding for space and newline
size := len(msg) + padding
// formatPAXRecord formats a single PAX record, prefixing it with the
// appropriate length.
func formatPAXRecord(k, v string) string {
const padding = 3 // Extra padding for ' ', '=', and '\n'
size := len(k) + len(v) + padding
size += len(strconv.Itoa(size))
record := fmt.Sprintf("%d %s\n", size, msg)
record := fmt.Sprintf("%d %s=%s\n", size, k, v)
// Final adjustment if adding size field increased the record size.
if len(record) != size {
// Final adjustment if adding size increased
// the number of digits in size
size = len(record)
record = fmt.Sprintf("%d %s\n", size, msg)
record = fmt.Sprintf("%d %s=%s\n", size, k, v)
}
return record
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
"math"
"os"
"reflect"
"sort"
@ -486,24 +487,6 @@ func TestPaxHeadersSorted(t *testing.T) {
}
}
func TestPAXHeader(t *testing.T) {
medName := strings.Repeat("CD", 50)
longName := strings.Repeat("AB", 100)
paxTests := [][2]string{
{paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
{"a=b", "6 a=b\n"}, // Single digit length
{"a=names", "11 a=names\n"}, // Test case involving carries
{paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
{paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
for _, test := range paxTests {
key, expected := test[0], test[1]
if result := paxHeader(key); result != expected {
t.Fatalf("paxHeader: got %s, expected %s", result, expected)
}
}
}
func TestUSTARLongName(t *testing.T) {
// Create an archive with a path that failed to split with USTAR extension in previous versions.
fileinfo, err := os.Stat("testdata/small.txt")
@ -625,3 +608,115 @@ func TestSplitUSTARPath(t *testing.T) {
}
}
}
func TestFormatPAXRecord(t *testing.T) {
var medName = strings.Repeat("CD", 50)
var longName = strings.Repeat("AB", 100)
var vectors = []struct {
inputKey string
inputVal string
output string
}{
{"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"},
}
for _, v := range vectors {
output := formatPAXRecord(v.inputKey, v.inputVal)
if output != v.output {
t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
v.inputKey, v.inputVal, output, v.output)
}
}
}
func TestFitsInBase256(t *testing.T) {
var vectors = []struct {
input int64
width int
ok bool
}{
{+1, 8, true},
{0, 8, true},
{-1, 8, true},
{1 << 56, 8, false},
{(1 << 56) - 1, 8, true},
{-1 << 56, 8, true},
{(-1 << 56) - 1, 8, false},
{121654, 8, true},
{-9849849, 8, true},
{math.MaxInt64, 9, true},
{0, 9, true},
{math.MinInt64, 9, true},
{math.MaxInt64, 12, true},
{0, 12, true},
{math.MinInt64, 12, true},
}
for _, v := range vectors {
ok := fitsInBase256(v.width, v.input)
if ok != v.ok {
t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
}
}
}
func TestFormatNumeric(t *testing.T) {
var vectors = []struct {
input int64
output string
ok bool
}{
// Test base-256 (binary) encoded values.
{-1, "\xff", true},
{-1, "\xff\xff", true},
{-1, "\xff\xff\xff", true},
{(1 << 0), "0", false},
{(1 << 8) - 1, "\x80\xff", true},
{(1 << 8), "0\x00", false},
{(1 << 16) - 1, "\x80\xff\xff", true},
{(1 << 16), "00\x00", false},
{-1 * (1 << 0), "\xff", true},
{-1*(1<<0) - 1, "0", false},
{-1 * (1 << 8), "\xff\x00", true},
{-1*(1<<8) - 1, "0\x00", false},
{-1 * (1 << 16), "\xff\x00\x00", true},
{-1*(1<<16) - 1, "00\x00", false},
{537795476381659745, "0000000\x00", false},
{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
{-615126028225187231, "0000000\x00", false},
{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
{math.MaxInt64, "0000000\x00", false},
{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
{math.MinInt64, "0000000\x00", false},
{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
}
for _, v := range vectors {
var f formatter
output := make([]byte, len(v.output))
f.formatNumeric(output, v.input)
ok := (f.err == nil)
if ok != v.ok {
if v.ok {
t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
} else {
t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
}
}
if string(output) != v.output {
t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
}
}
}

View file

@ -7,6 +7,7 @@ package zip_test
import (
"archive/zip"
"bytes"
"compress/flate"
"fmt"
"io"
"log"
@ -73,3 +74,31 @@ func ExampleReader() {
// Contents of README:
// This is the source code repository for the Go programming language.
}
func ExampleWriter_RegisterCompressor() {
// Override the default Deflate compressor with a higher compression
// level.
// Create a buffer to write our archive to.
buf := new(bytes.Buffer)
// Create a new zip archive.
w := zip.NewWriter(buf)
var fw *flate.Writer
// Register the deflator.
w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
var err error
if fw == nil {
// Creating a flate compressor for every file is
// expensive, create one and reuse it.
fw, err = flate.NewWriter(out, flate.BestCompression)
} else {
fw.Reset(out)
}
return fw, err
})
// Proceed to add files to w.
}

View file

@ -22,9 +22,10 @@ var (
)
type Reader struct {
r io.ReaderAt
File []*File
Comment string
r io.ReaderAt
File []*File
Comment string
decompressors map[uint16]Decompressor
}
type ReadCloser struct {
@ -34,6 +35,7 @@ type ReadCloser struct {
type File struct {
FileHeader
zip *Reader
zipr io.ReaderAt
zipsize int64
headerOffset int64
@ -95,7 +97,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
// a bad one, and then only report a ErrFormat or UnexpectedEOF if
// the file count modulo 65536 is incorrect.
for {
f := &File{zipr: r, zipsize: size}
f := &File{zip: z, zipr: r, zipsize: size}
err = readDirectoryHeader(f, buf)
if err == ErrFormat || err == io.ErrUnexpectedEOF {
break
@ -113,6 +115,26 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
return nil
}
// RegisterDecompressor registers or overrides a custom decompressor for a
// specific method ID. If a decompressor for a given method is not found,
// Reader will default to looking up the decompressor at the package level.
//
// Must not be called concurrently with Open on any Files in the Reader.
func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
if z.decompressors == nil {
z.decompressors = make(map[uint16]Decompressor)
}
z.decompressors[method] = dcomp
}
func (z *Reader) decompressor(method uint16) Decompressor {
dcomp := z.decompressors[method]
if dcomp == nil {
dcomp = decompressor(method)
}
return dcomp
}
// Close closes the Zip file, rendering it unusable for I/O.
func (rc *ReadCloser) Close() error {
return rc.f.Close()
@ -140,7 +162,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
}
size := int64(f.CompressedSize64)
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
dcomp := decompressor(f.Method)
dcomp := f.zip.decompressor(f.Method)
if dcomp == nil {
err = ErrAlgorithm
return
@ -261,39 +283,59 @@ func readDirectoryHeader(f *File, r io.Reader) error {
f.Extra = d[filenameLen : filenameLen+extraLen]
f.Comment = string(d[filenameLen+extraLen:])
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) {
return ErrFormat
break
}
if tag == zip64ExtraId {
// update directory values from the zip64 extra block
// 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 len(eb) >= 8 {
if needUSize {
needUSize = false
if len(eb) < 8 {
return ErrFormat
}
f.UncompressedSize64 = eb.uint64()
}
if len(eb) >= 8 {
if needCSize {
needCSize = false
if len(eb) < 8 {
return ErrFormat
}
f.CompressedSize64 = eb.uint64()
}
if len(eb) >= 8 {
if needHeaderOffset {
needHeaderOffset = false
if len(eb) < 8 {
return ErrFormat
}
f.headerOffset = int64(eb.uint64())
}
break
}
b = b[size:]
}
// Should have consumed the whole header.
// But popular zip & JAR creation tools are broken and
// may pad extra zeros at the end, so accept those
// too. See golang.org/issue/8186.
for _, v := range b {
if v != 0 {
return ErrFormat
}
}
}
if needUSize || needCSize || needHeaderOffset {
return ErrFormat
}
return nil
}

View file

@ -235,7 +235,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) {
// isZip64 reports whether the file size exceeds the 32 bit limit
func (fh *FileHeader) isZip64() bool {
return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
return fh.CompressedSize64 >= uint32max || fh.UncompressedSize64 >= uint32max
}
func msdosModeToFileMode(m uint32) (mode os.FileMode) {

View file

@ -14,14 +14,14 @@ import (
)
// TODO(adg): support zip file comments
// TODO(adg): support specifying deflate level
// Writer implements a zip file writer.
type Writer struct {
cw *countWriter
dir []*header
last *fileWriter
closed bool
cw *countWriter
dir []*header
last *fileWriter
closed bool
compressors map[uint16]Compressor
}
type header struct {
@ -78,7 +78,7 @@ func (w *Writer) Close() error {
b.uint16(h.ModifiedTime)
b.uint16(h.ModifiedDate)
b.uint32(h.CRC32)
if h.isZip64() || h.offset > uint32max {
if h.isZip64() || h.offset >= uint32max {
// the file needs a zip64 header. store maxint in both
// 32 bit size fields (and offset later) to signal that the
// zip64 extra header should be used.
@ -220,7 +220,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
compCount: &countWriter{w: w.cw},
crc32: crc32.NewIEEE(),
}
comp := compressor(fh.Method)
comp := w.compressor(fh.Method)
if comp == nil {
return nil, ErrAlgorithm
}
@ -270,6 +270,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
return err
}
// RegisterCompressor registers or overrides a custom compressor for a specific
// method ID. If a compressor for a given method is not found, Writer will
// default to looking up the compressor at the package level.
func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
if w.compressors == nil {
w.compressors = make(map[uint16]Compressor)
}
w.compressors[method] = comp
}
func (w *Writer) compressor(method uint16) Compressor {
comp := w.compressors[method]
if comp == nil {
comp = compressor(method)
}
return comp
}
type fileWriter struct {
*header
zipw io.Writer

View file

@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
"hash"
"internal/testenv"
"io"
"io/ioutil"
"sort"
@ -19,6 +20,9 @@ import (
)
func TestOver65kFiles(t *testing.T) {
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
buf := new(bytes.Buffer)
w := NewWriter(buf)
const nFiles = (1 << 16) + 42
@ -233,10 +237,24 @@ func TestZip64(t *testing.T) {
testZip64DirectoryRecordLength(buf, t)
}
func TestZip64EdgeCase(t *testing.T) {
if testing.Short() {
t.Skip("slow test; skipping")
}
// Test a zip file with uncompressed size 0xFFFFFFFF.
// That's the magic marker for a 64-bit file, so even though
// it fits in a 32-bit field we must use the 64-bit field.
// Go 1.5 and earlier got this wrong,
// writing an invalid zip file.
const size = 1<<32 - 1 - int64(len("END\n")) // before the "END\n" part
buf := testZip64(t, size)
testZip64DirectoryRecordLength(buf, t)
}
func testZip64(t testing.TB, size int64) *rleBuffer {
const chunkSize = 1024
chunks := int(size / chunkSize)
// write 2^32 bytes plus "END\n" to a zip file
// write size bytes plus "END\n" to a zip file
buf := new(rleBuffer)
w := NewWriter(buf)
f, err := w.CreateHeader(&FileHeader{
@ -257,6 +275,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
t.Fatal("write chunk:", err)
}
}
if frag := int(size % chunkSize); frag > 0 {
_, err := f.Write(chunk[:frag])
if err != nil {
t.Fatal("write chunk:", err)
}
}
end := []byte("END\n")
_, err = f.Write(end)
if err != nil {
@ -283,6 +307,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
t.Fatal("read:", err)
}
}
if frag := int(size % chunkSize); frag > 0 {
_, err := io.ReadFull(rc, chunk[:frag])
if err != nil {
t.Fatal("read:", err)
}
}
gotEnd, err := ioutil.ReadAll(rc)
if err != nil {
t.Fatal("read end:", err)
@ -294,14 +324,14 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
if err != nil {
t.Fatal("closing:", err)
}
if size == 1<<32 {
if size+int64(len("END\n")) >= 1<<32-1 {
if got, want := f0.UncompressedSize, uint32(uint32max); got != want {
t.Errorf("UncompressedSize %d, want %d", got, want)
t.Errorf("UncompressedSize %#x, want %#x", got, want)
}
}
if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
t.Errorf("UncompressedSize64 %d, want %d", got, want)
t.Errorf("UncompressedSize64 %#x, want %#x", got, want)
}
return buf
@ -373,9 +403,14 @@ func testValidHeader(h *FileHeader, t *testing.T) {
}
b := buf.Bytes()
if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != nil {
zf, err := NewReader(bytes.NewReader(b), int64(len(b)))
if err != nil {
t.Fatalf("got %v, expected nil", err)
}
zh := zf.File[0].FileHeader
if zh.Name != h.Name || zh.Method != h.Method || zh.UncompressedSize64 != uint64(len("hi")) {
t.Fatalf("got %q/%d/%d expected %q/%d/%d", zh.Name, zh.Method, zh.UncompressedSize64, h.Name, h.Method, len("hi"))
}
}
// Issue 4302.
@ -388,20 +423,29 @@ func TestHeaderInvalidTagAndSize(t *testing.T) {
h := FileHeader{
Name: filename,
Method: Deflate,
Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len
Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len, but Extra is best-effort parsing
}
h.SetModTime(ts)
testInvalidHeader(&h, t)
testValidHeader(&h, t)
}
func TestHeaderTooShort(t *testing.T) {
h := FileHeader{
Name: "foo.txt",
Method: Deflate,
Extra: []byte{zip64ExtraId}, // missing size
Extra: []byte{zip64ExtraId}, // missing size and second half of tag, but Extra is best-effort parsing
}
testInvalidHeader(&h, t)
testValidHeader(&h, t)
}
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
}
testValidHeader(&h, t)
}
// Issue 4393. It is valid to have an extra data header

View file

@ -179,7 +179,7 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
// Read reads data into p.
// It returns the number of bytes read into p.
// It calls Read at most once on the underlying Reader,
// The bytes are taken from at most one Read on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (b *Reader) Read(p []byte) (n int, err error) {

View file

@ -36,10 +36,11 @@ const (
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large")
// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
// 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,
// only until the next call to a method like Read, Write, Reset, or Truncate).
// The slice aliases the buffer content at least until the next buffer modification,
// so immediate changes to the slice will affect the result of future reads.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
// String returns the contents of the unread portion of the buffer
@ -60,7 +61,8 @@ func (b *Buffer) Len() int { return len(b.buf) - b.off }
// total space allocated for the buffer's data.
func (b *Buffer) Cap() int { return cap(b.buf) }
// Truncate discards all but the first n unread bytes from the buffer.
// Truncate discards all but the first n unread bytes from the buffer
// but continues to use the same allocated storage.
// It panics if n is negative or greater than the length of the buffer.
func (b *Buffer) Truncate(n int) {
b.lastRead = opInvalid
@ -74,8 +76,9 @@ func (b *Buffer) Truncate(n int) {
b.buf = b.buf[0 : b.off+n]
}
// Reset resets the buffer so it has no content.
// b.Reset() is the same as b.Truncate(0).
// Reset resets the buffer to be empty,
// but it retains the underlying storage for use by future writes.
// Reset is the same as Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }
// grow grows the buffer to guarantee space for n more bytes.

View file

@ -680,7 +680,14 @@ func (w *Walker) emitObj(obj types.Object) {
switch obj := obj.(type) {
case *types.Const:
w.emitf("const %s %s", obj.Name(), w.typeString(obj.Type()))
w.emitf("const %s = %s", obj.Name(), obj.Val())
x := obj.Val()
short := x.String()
exact := x.ExactString()
if short == exact {
w.emitf("const %s = %s", obj.Name(), short)
} else {
w.emitf("const %s = %s // %s", obj.Name(), short, exact)
}
case *types.Var:
w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type()))
case *types.TypeName:

View file

@ -26,7 +26,7 @@ func main() {
}
out, err := exec.Command("go", "tool", "api",
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5"),
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"),
"-next", file("next"),
"-except", file("except")).CombinedOutput()
if err != nil {

View file

@ -10,7 +10,7 @@ pkg p1, const ConstChase2 = 11
pkg p1, const ConstChase2 ideal-int
pkg p1, const ConversionConst = 5
pkg p1, const ConversionConst MyInt
pkg p1, const FloatConst = 3/2
pkg p1, const FloatConst = 1.5 // 3/2
pkg p1, const FloatConst ideal-float
pkg p1, const StrConst = "foo"
pkg p1, const StrConst ideal-string

48
src/cmd/asm/doc.go Normal file
View file

@ -0,0 +1,48 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Asm, typically invoked as ``go tool asm'', assembles the source file into an object
file named for the basename of the argument source file with a .o suffix. The
object file can then be combined with other objects into a package archive.
Command Line
Usage:
go tool asm [flags] file
The specified file must be a Go assembly file.
The same assembler is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.
Flags:
-D value
predefined symbol with optional simple value -D=identifer=value;
can be set multiple times
-I value
include directory; can be set multiple times
-S print assembly and machine code
-debug
dump instructions as they are parsed
-dynlink
support references to Go symbols defined in other shared libraries
-o string
output file; default foo.o for /a/b/c/foo.s
-shared
generate code that can be linked into a shared library
-trimpath string
remove prefix from recorded source file paths
Input language:
The assembler uses mostly the same syntax for all architectures,
the main variation having to do with addressing modes. Input is
run through a simplified C preprocessor that implements #include,
#define, #ifdef/endif, but not #if or ##.
For more information, see https://golang.org/doc/asm.
*/
package main

View file

@ -87,7 +87,7 @@ func Set(GOARCH string) *Arch {
}
func jumpX86(word string) bool {
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP")
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN"
}
func archX86(linkArch *obj.LinkArch) *Arch {

View file

@ -36,6 +36,9 @@ func init() {
type MultiFlag []string
func (m *MultiFlag) String() string {
if len(*m) == 0 {
return ""
}
return fmt.Sprint(*m)
}

View file

@ -117,7 +117,8 @@ The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double.
C.ulonglong (unsigned long long), C.float, C.double,
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.
@ -238,7 +239,7 @@ the type of the pointer.
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 into Go memory, even
this property: it must not store any Go pointers in Go memory, even
temporarily. When passing a pointer to a field in a struct, the Go
memory in question is the memory occupied by the field, not the entire
struct. When passing a pointer to an element in an array or slice,
@ -247,25 +248,29 @@ array of the slice.
C code may not keep a copy of a Go pointer after the call returns.
If Go code passes a Go pointer to a C function, the C function must
return. There is no specific time limit, but a C function that simply
blocks holding a Go pointer while other goroutines are running may
eventually cause the program to run out of memory and fail (because
the garbage collector may not be able to make progress).
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 into memory pointed to by a C pointer. A Go
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.
These rules are partially enforced by cgo by default. It is possible
to defeat this enforcement by using the unsafe package, 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.
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
the Go pointer when the C function returns.
These rules are checked dynamically at runtime. The checking is
controlled by the cgocheck setting of the GODEBUG environment
variable. The default setting is GODEBUG=cgocheck=1, which implements
reasonably cheap dynamic checks. These checks may be disabled
entirely using GODEBUG=cgocheck=0. Complete checking of pointer
handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
It is possible to defeat this enforcement by using the unsafe package,
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.
Using cgo directly

View file

@ -38,8 +38,8 @@ var nameToC = map[string]string{
"ulong": "unsigned long",
"longlong": "long long",
"ulonglong": "unsigned long long",
"complexfloat": "float complex",
"complexdouble": "double complex",
"complexfloat": "float _Complex",
"complexdouble": "double _Complex",
}
// cname returns the C name to use for C.s.
@ -491,6 +491,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
name, _ := e.Val(dwarf.AttrName).(string)
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
if name == "" || typOff == 0 {
if e.Val(dwarf.AttrSpecification) != nil {
// Since we are reading all the DWARF,
// assume we will see the variable elsewhere.
break
}
fatalf("malformed DWARF TagVariable entry")
}
if !strings.HasPrefix(name, "__cgo__") {
@ -593,6 +598,12 @@ func (p *Package) rewriteCalls(f *File) {
// each pointer argument x with _cgoCheckPointer(x).(T).
func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
for i, param := range name.FuncType.Params {
if len(call.Args) <= i {
// Avoid a crash; this will be caught when the
// generated file is compiled.
return
}
// An untyped nil does not need a pointer check, and
// when _cgoCheckPointer returns the untyped nil the
// type assertion we are going to insert will fail.
@ -606,12 +617,6 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
continue
}
if len(call.Args) <= i {
// Avoid a crash; this will be caught when the
// generated file is compiled.
return
}
c := &ast.CallExpr{
Fun: ast.NewIdent("_cgoCheckPointer"),
Args: []ast.Expr{
@ -675,6 +680,7 @@ func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
// hasPointer is used by needsPointerCheck. If top is true it returns
// whether t is or contains a pointer that might point to a pointer.
// If top is false it returns whether t is or contains a pointer.
// f may be nil.
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
switch t := t.(type) {
case *ast.ArrayType:
@ -738,6 +744,10 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
// pointer.
return true
}
if f == nil {
// Conservative approach: assume pointer.
return true
}
name := f.Name[t.Sel.Name]
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
return p.hasPointer(f, name.Type.Go, top)
@ -768,7 +778,7 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
// This is the address of something that is not an
// index expression. We only need to examine the
// single value to which it points.
// TODO: what is true is shadowed?
// TODO: what if true is shadowed?
return append(args, ast.NewIdent("true"))
}
if !p.hasSideEffects(f, index.X) {
@ -1304,12 +1314,12 @@ var dwarfToName = map[string]string{
"long unsigned int": "ulong",
"unsigned int": "uint",
"short unsigned int": "ushort",
"unsigned short": "ushort", // Used by Clang; issue 13129.
"short int": "short",
"long long int": "longlong",
"long long unsigned int": "ulonglong",
"signed char": "schar",
"float complex": "complexfloat",
"double complex": "complexdouble",
"unsigned char": "uchar",
}
const signedDelta = 64
@ -1679,7 +1689,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
switch dtype.(type) {
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
s := dtype.Common().Name
if s != "" {
if ss, ok := dwarfToName[s]; ok {

View file

@ -103,6 +103,7 @@ func (p *Package) writeDefs() {
}
if *gccgo {
fmt.Fprint(fgo2, gccgoGoProlog)
fmt.Fprint(fc, p.cPrologGccgo())
} else {
fmt.Fprint(fgo2, goProlog)
@ -811,12 +812,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by gc.
goname := exp.Func.Name.Name
// Build the wrapper function compiled by cmd/compile.
goname := "_cgoexpwrap" + cPrefix + "_"
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
goname += fn.Recv.List[0].Names[0].Name + "_"
}
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
goname += exp.Func.Name.Name
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
@ -829,44 +831,75 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
// Calling a function with a receiver from C requires
// a Go wrapper function.
// This code uses printer.Fprint, not conf.Fprint,
// because we don't want //line comments in the middle
// of the function types.
fmt.Fprintf(fgo2, "\n")
fmt.Fprintf(fgo2, "func %s(", goname)
comma := false
if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname)
conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgo2, ", p%d ", i)
conf.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
fmt.Fprint(fgo2, " (")
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
conf.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
fmt.Fprint(fgo2, " {\n")
fmt.Fprint(fgo2, "\t")
if gccResult != "void" {
fmt.Fprint(fgo2, "return ")
}
fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
forFieldList(fntype.Params,
fmt.Fprintf(fgo2, "recv ")
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
comma = true
}
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
if comma {
fmt.Fprintf(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d ", i)
printer.Fprint(fgo2, fset, atype)
comma = true
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
fmt.Fprint(fgo2, " (")
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d", i)
fmt.Fprintf(fgo2, "r%d ", i)
printer.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")\n")
fmt.Fprint(fgo2, "}\n")
fmt.Fprint(fgo2, ")")
}
fmt.Fprint(fgo2, " {\n")
if gccResult == "void" {
fmt.Fprint(fgo2, "\t")
} else {
// Verify that any results don't contain any
// Go pointers.
addedDefer := false
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
if !p.hasPointer(nil, atype, false) {
return
}
if !addedDefer {
fmt.Fprint(fgo2, "\tdefer func() {\n")
addedDefer = true
}
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
})
if addedDefer {
fmt.Fprint(fgo2, "\t}()\n")
}
fmt.Fprint(fgo2, "\treturn ")
}
if fn.Recv != nil {
fmt.Fprintf(fgo2, "recv.")
}
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d", i)
})
fmt.Fprint(fgo2, ")\n")
fmt.Fprint(fgo2, "}\n")
}
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
@ -1251,6 +1284,15 @@ func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
//go:linkname _cgoCheckResult runtime.cgoCheckResult
func _cgoCheckResult(interface{})
`
const gccgoGoProlog = `
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
func _cgoCheckResult(interface{})
`
const goStringDef = `
@ -1305,7 +1347,8 @@ var builtinDefs = map[string]string{
}
func (p *Package) cPrologGccgo() string {
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
}
const cPrologGccgo = `
@ -1360,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
runtime_throw("runtime: C malloc failed");
return p;
}
struct __go_type_descriptor;
typedef struct __go_empty_interface {
const struct __go_type_descriptor *__type_descriptor;
void *__object;
} Eface;
extern Eface runtimeCgoCheckPointer(Eface, Slice)
__asm__("runtime.cgoCheckPointer")
__attribute__((weak));
extern Eface localCgoCheckPointer(Eface, Slice)
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
Eface localCgoCheckPointer(Eface ptr, Slice args) {
if(runtimeCgoCheckPointer) {
return runtimeCgoCheckPointer(ptr, args);
}
return ptr;
}
extern void runtimeCgoCheckResult(Eface)
__asm__("runtime.cgoCheckResult")
__attribute__((weak));
extern void localCgoCheckResult(Eface)
__asm__("GCCGOSYMBOLPREF._cgoCheckResult");
void localCgoCheckResult(Eface val) {
if(runtimeCgoCheckResult) {
runtimeCgoCheckResult(val);
}
}
`
func (p *Package) gccExportHeaderProlog() string {
@ -1385,8 +1461,8 @@ typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef __complex float GoComplex64;
typedef __complex double GoComplex128;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
@ -1394,7 +1470,7 @@ typedef __complex double GoComplex128;
*/
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
typedef struct { char *p; GoInt n; } GoString;
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;

View file

@ -365,24 +365,25 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
gc.Cgenr(nl, &n1, res)
var n2 gc.Node
gc.Cgenr(nr, &n2, nil)
var ax gc.Node
gc.Nodreg(&ax, t, x86.REG_AX)
var ax, oldax, dx, olddx gc.Node
savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT64])
savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT64])
gmove(&n1, &ax)
gins(a, &n2, nil)
gc.Regfree(&n2)
gc.Regfree(&n1)
var dx gc.Node
if t.Width == 1 {
// byte multiply behaves differently.
gc.Nodreg(&ax, t, x86.REG_AH)
gc.Nodreg(&dx, t, x86.REG_DX)
gmove(&ax, &dx)
var byteAH, byteDX gc.Node
gc.Nodreg(&byteAH, t, x86.REG_AH)
gc.Nodreg(&byteDX, t, x86.REG_DX)
gmove(&byteAH, &byteDX)
}
gc.Nodreg(&dx, t, x86.REG_DX)
gmove(&dx, res)
restx(&ax, &oldax)
restx(&dx, &olddx)
}
/*

View file

@ -1365,7 +1365,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
case obj.APCDATA,
obj.AFUNCDATA,
obj.AVARDEF,
obj.AVARKILL:
obj.AVARKILL,
obj.AUSEFIELD:
return 0
}
}

View file

@ -710,7 +710,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
obj.APCDATA,
obj.AFUNCDATA,
obj.AVARDEF,
obj.AVARKILL:
obj.AVARKILL,
obj.AUSEFIELD:
return 0
}
}

View file

@ -20,7 +20,7 @@
package big
// A decimal represents an unsigned floating-point number in decimal representation.
// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= 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.
@ -29,6 +29,14 @@ type decimal struct {
exp int // exponent
}
// at returns the i'th mantissa digit, starting with the most significant digit at 0.
func (d *decimal) at(i int) byte {
if 0 <= i && i < len(d.mant) {
return d.mant[i]
}
return '0'
}
// Maximum shift amount that can be done in one pass without overflow.
// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
const maxShift = _W - 4
@ -72,7 +80,7 @@ func (x *decimal) init(m nat, shift int) {
}
// Convert mantissa into decimal representation.
s := m.decimalString() // TODO(gri) avoid string conversion here
s := m.utoa(10)
n := len(s)
x.exp = n
// Trim trailing zeros; instead the exponent is tracking
@ -92,12 +100,6 @@ func (x *decimal) init(m nat, shift int) {
}
}
// Possibly optimization: The current implementation of nat.string takes
// a charset argument. When a right shift is needed, we could provide
// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
// single +'0' pass at the end).
// shr implements x >> s, for s <= maxShift.
func shr(x *decimal, s uint) {
// Division by 1<<s using shift-and-subtract algorithm.

View file

@ -104,3 +104,13 @@ func TestDecimalRounding(t *testing.T) {
}
}
}
func BenchmarkDecimalConversion(b *testing.B) {
for i := 0; i < b.N; i++ {
for shift := -100; shift <= +100; shift++ {
var d decimal
d.init(natOne, shift)
d.String()
}
}
}

View file

@ -124,7 +124,7 @@ const (
// rounding error is described by the Float's Accuracy.
type RoundingMode byte
// The following rounding modes are supported.
// These constants define supported rounding modes.
const (
ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
ToNearestAway // == IEEE 754-2008 roundTiesToAway
@ -298,7 +298,7 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) {
// not require 0.5 <= |mant| < 1.0. Specifically:
//
// mant := new(Float)
// new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true
// new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0
//
// Special cases are:
//
@ -1123,7 +1123,7 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) {
// Rat returns the rational number corresponding to x;
// or nil if x is an infinity.
// The result is Exact is x is not an Inf.
// The result is Exact if x is not an Inf.
// If a non-nil *Rat argument z is provided, Rat stores
// the result in z instead of allocating a new Rat.
func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {

View file

@ -72,37 +72,46 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
// ebase**exp. Finally, mantissa normalization (shift left) requires
// a correcting multiplication by 2**(-shiftcount). Multiplications
// are commutative, so we can apply them in any order as long as there
// is no loss of precision. We only have powers of 2 and 10; keep
// track via separate exponents exp2 and exp10.
// is no loss of precision. We only have powers of 2 and 10, and
// we split powers of 10 into the product of the same powers of
// 2 and 5. This reduces the size of the multiplication factor
// needed for base-10 exponents.
// normalize mantissa and get initial binary exponent
var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
// normalize mantissa and determine initial exponent contributions
exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
exp5 := int64(0)
// determine binary or decimal exponent contribution of decimal point
var exp10 int64
if fcount < 0 {
// The mantissa has a "decimal" point ddd.dddd; and
// -fcount is the number of digits to the right of '.'.
// Adjust relevant exponent accodingly.
d := int64(fcount)
switch b {
case 16:
fcount *= 4 // hexadecimal digits are 4 bits each
fallthrough
case 10:
exp5 = d
fallthrough // 10**e == 5**e * 2**e
case 2:
exp2 += int64(fcount)
default: // b == 10
exp10 = int64(fcount)
exp2 += d
case 16:
exp2 += d * 4 // hexadecimal digits are 4 bits each
default:
panic("unexpected mantissa base")
}
// we don't need fcount anymore
// fcount consumed - not needed anymore
}
// take actual exponent into account
if ebase == 2 {
switch ebase {
case 10:
exp5 += exp
fallthrough
case 2:
exp2 += exp
} else { // ebase == 10
exp10 += exp
default:
panic("unexpected exponent base")
}
// we don't need exp anymore
// exp consumed - not needed anymore
// apply 2**exp2
if MinExp <= exp2 && exp2 <= MaxExp {
@ -115,49 +124,76 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
return
}
if exp10 == 0 {
// no decimal exponent to consider
if exp5 == 0 {
// no decimal exponent contribution
z.round(0)
return
}
// exp10 != 0
// exp5 != 0
// apply 10**exp10
// apply 5**exp5
p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
if exp10 < 0 {
z.Quo(z, p.pow10(-exp10))
if exp5 < 0 {
z.Quo(z, p.pow5(uint64(-exp5)))
} else {
z.Mul(z, p.pow10(exp10))
z.Mul(z, p.pow5(uint64(exp5)))
}
return
}
// These powers of 10 can be represented exactly as a float64.
var pow10tab = [...]float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
// These powers of 5 fit into a uint64.
//
// for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
// fmt.Println(q)
// }
//
var pow5tab = [...]uint64{
1,
5,
25,
125,
625,
3125,
15625,
78125,
390625,
1953125,
9765625,
48828125,
244140625,
1220703125,
6103515625,
30517578125,
152587890625,
762939453125,
3814697265625,
19073486328125,
95367431640625,
476837158203125,
2384185791015625,
11920928955078125,
59604644775390625,
298023223876953125,
1490116119384765625,
7450580596923828125,
}
// pow10 sets z to 10**n and returns z.
// pow5 sets z to 5**n and returns z.
// n must not be negative.
func (z *Float) pow10(n int64) *Float {
if n < 0 {
panic("pow10 called with negative argument")
}
const m = int64(len(pow10tab) - 1)
func (z *Float) pow5(n uint64) *Float {
const m = uint64(len(pow5tab) - 1)
if n <= m {
return z.SetFloat64(pow10tab[n])
return z.SetUint64(pow5tab[n])
}
// n > m
z.SetFloat64(pow10tab[m])
z.SetUint64(pow5tab[m])
n -= m
// use more bits for f than for z
// TODO(gri) what is the right number?
f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
for n > 0 {
if n&1 != 0 {

View file

@ -139,6 +139,8 @@ func TestFloatSetFloat64String(t *testing.T) {
}
}
func fdiv(a, b float64) float64 { return a / b }
const (
below1e23 = 99999999999999974834176
above1e23 = 100000000000000008388608
@ -187,11 +189,11 @@ func TestFloat64Text(t *testing.T) {
{1, 'e', 5, "1.00000e+00"},
{1, 'f', 5, "1.00000"},
{1, 'g', 5, "1"},
// {1, 'g', -1, "1"},
// {20, 'g', -1, "20"},
// {1234567.8, 'g', -1, "1.2345678e+06"},
// {200000, 'g', -1, "200000"},
// {2000000, 'g', -1, "2e+06"},
{1, 'g', -1, "1"},
{20, 'g', -1, "20"},
{1234567.8, 'g', -1, "1.2345678e+06"},
{200000, 'g', -1, "200000"},
{2000000, 'g', -1, "2e+06"},
// g conversion and zero suppression
{400, 'g', 2, "4e+02"},
@ -207,22 +209,22 @@ func TestFloat64Text(t *testing.T) {
{0, 'e', 5, "0.00000e+00"},
{0, 'f', 5, "0.00000"},
{0, 'g', 5, "0"},
// {0, 'g', -1, "0"},
{0, 'g', -1, "0"},
{-1, 'e', 5, "-1.00000e+00"},
{-1, 'f', 5, "-1.00000"},
{-1, 'g', 5, "-1"},
// {-1, 'g', -1, "-1"},
{-1, 'g', -1, "-1"},
{12, 'e', 5, "1.20000e+01"},
{12, 'f', 5, "12.00000"},
{12, 'g', 5, "12"},
// {12, 'g', -1, "12"},
{12, 'g', -1, "12"},
{123456700, 'e', 5, "1.23457e+08"},
{123456700, 'f', 5, "123456700.00000"},
{123456700, 'g', 5, "1.2346e+08"},
// {123456700, 'g', -1, "1.234567e+08"},
{123456700, 'g', -1, "1.234567e+08"},
{1.2345e6, 'e', 5, "1.23450e+06"},
{1.2345e6, 'f', 5, "1234500.00000"},
@ -232,36 +234,38 @@ func TestFloat64Text(t *testing.T) {
{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
{1e23, 'g', 17, "9.9999999999999992e+22"},
// {1e23, 'e', -1, "1e+23"},
// {1e23, 'f', -1, "100000000000000000000000"},
// {1e23, 'g', -1, "1e+23"},
{1e23, 'e', -1, "1e+23"},
{1e23, 'f', -1, "100000000000000000000000"},
{1e23, 'g', -1, "1e+23"},
{below1e23, 'e', 17, "9.99999999999999748e+22"},
{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
{below1e23, 'g', 17, "9.9999999999999975e+22"},
// {below1e23, 'e', -1, "9.999999999999997e+22"},
// {below1e23, 'f', -1, "99999999999999970000000"},
// {below1e23, 'g', -1, "9.999999999999997e+22"},
{below1e23, 'e', -1, "9.999999999999997e+22"},
{below1e23, 'f', -1, "99999999999999970000000"},
{below1e23, 'g', -1, "9.999999999999997e+22"},
{above1e23, 'e', 17, "1.00000000000000008e+23"},
{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
// {above1e23, 'g', 17, "1.0000000000000001e+23"},
{above1e23, 'g', 17, "1.0000000000000001e+23"},
// {above1e23, 'e', -1, "1.0000000000000001e+23"},
// {above1e23, 'f', -1, "100000000000000010000000"},
// {above1e23, 'g', -1, "1.0000000000000001e+23"},
{above1e23, 'e', -1, "1.0000000000000001e+23"},
{above1e23, 'f', -1, "100000000000000010000000"},
{above1e23, 'g', -1, "1.0000000000000001e+23"},
// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
{5e-304 / 1e20, 'g', -1, "5e-324"},
{-5e-304 / 1e20, 'g', -1, "-5e-324"},
{fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic
{fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic
// {32, 'g', -1, "32"},
// {32, 'g', 0, "3e+01"},
{32, 'g', -1, "32"},
{32, 'g', 0, "3e+01"},
// {100, 'x', -1, "%x"},
{100, 'x', -1, "%x"},
// {math.NaN(), 'g', -1, "NaN"},
// {-math.NaN(), 'g', -1, "NaN"},
// {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
// {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
{math.Inf(0), 'g', -1, "+Inf"},
{math.Inf(-1), 'g', -1, "-Inf"},
{-math.Inf(0), 'g', -1, "-Inf"},
@ -279,18 +283,24 @@ func TestFloat64Text(t *testing.T) {
{1.5, 'f', 0, "2"},
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
{2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
{2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
// Issue 2625.
{383260575764816448, 'f', 0, "383260575764816448"},
// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
} {
f := new(Float).SetFloat64(test.x)
// The test cases are from the strconv package which tests float64 values.
// When formatting values with prec = -1 (shortest representation),
// the actually available mantissa precision matters.
// For denormalized values, that precision is < 53 (SetFloat64 default).
// Compute and set the actual precision explicitly.
f := new(Float).SetPrec(actualPrec(test.x)).SetFloat64(test.x)
got := f.Text(test.format, test.prec)
if got != test.want {
t.Errorf("%v: got %s; want %s", test, got, test.want)
continue
}
if test.format == 'b' && test.x == 0 {
@ -308,6 +318,15 @@ func TestFloat64Text(t *testing.T) {
}
}
// actualPrec returns the number of actually used mantissa bits.
func actualPrec(x float64) uint {
if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 {
// x is denormalized
return 64 - nlz64(bits&(1<<52-1))
}
return 53
}
func TestFloatText(t *testing.T) {
for _, test := range []struct {
x string
@ -367,10 +386,20 @@ func TestFloatText(t *testing.T) {
// make sure "stupid" exponents don't stall the machine
{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
{"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
{"1e646456993", 64, 'p', 0, "+Inf"},
{"1e1000000000", 64, 'p', 0, "+Inf"},
{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
{"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
{"1e-646456994", 64, 'p', 0, "0"},
{"1e-1000000000", 64, 'p', 0, "0"},
// minimum and maximum values
{"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"},
{"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"},
{"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"},
{"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"},
// TODO(gri) need tests for actual large Floats
{"0", 53, 'b', 0, "0"},
@ -438,9 +467,6 @@ func TestFloatFormat(t *testing.T) {
value interface{} // float32, float64, or string (== 512bit *Float)
want string
}{
// TODO(gri) uncomment the disabled 'g'/'G' formats
// below once (*Float).Text supports prec < 0
// from fmt/fmt_test.go
{"%+.3e", 0.0, "+0.000e+00"},
{"%+.3e", 1.0, "+1.000e+00"},
@ -471,9 +497,9 @@ func TestFloatFormat(t *testing.T) {
{"%f", 1234.5678e-8, "0.000012"},
{"%f", -7.0, "-7.000000"},
{"%f", -1e-9, "-0.000000"},
// {"%g", 1234.5678e3, "1.2345678e+06"},
// {"%g", float32(1234.5678e3), "1.2345678e+06"},
// {"%g", 1234.5678e-8, "1.2345678e-05"},
{"%g", 1234.5678e3, "1.2345678e+06"},
{"%g", float32(1234.5678e3), "1.2345678e+06"},
{"%g", 1234.5678e-8, "1.2345678e-05"},
{"%g", -7.0, "-7"},
{"%g", -1e-9, "-1e-09"},
{"%g", float32(-1e-9), "-1e-09"},
@ -482,9 +508,9 @@ func TestFloatFormat(t *testing.T) {
{"%E", 1234.5678e-8, "1.234568E-05"},
{"%E", -7.0, "-7.000000E+00"},
{"%E", -1e-9, "-1.000000E-09"},
// {"%G", 1234.5678e3, "1.2345678E+06"},
// {"%G", float32(1234.5678e3), "1.2345678E+06"},
// {"%G", 1234.5678e-8, "1.2345678E-05"},
{"%G", 1234.5678e3, "1.2345678E+06"},
{"%G", float32(1234.5678e3), "1.2345678E+06"},
{"%G", 1234.5678e-8, "1.2345678E-05"},
{"%G", -7.0, "-7"},
{"%G", -1e-9, "-1E-09"},
{"%G", float32(-1e-9), "-1E-09"},
@ -500,9 +526,9 @@ func TestFloatFormat(t *testing.T) {
{"%-20f", 1.23456789e3, "1234.567890 "},
{"%20.8f", 1.23456789e3, " 1234.56789000"},
{"%20.8f", 1.23456789e-3, " 0.00123457"},
// {"%g", 1.23456789e3, "1234.56789"},
// {"%g", 1.23456789e-3, "0.00123456789"},
// {"%g", 1.23456789e20, "1.23456789e+20"},
{"%g", 1.23456789e3, "1234.56789"},
{"%g", 1.23456789e-3, "0.00123456789"},
{"%g", 1.23456789e20, "1.23456789e+20"},
{"%20e", math.Inf(1), " +Inf"},
{"%-20f", math.Inf(-1), "-Inf "},
@ -541,7 +567,6 @@ func TestFloatFormat(t *testing.T) {
{"%v", -1e-9, "-1e-09"},
{"%v", float32(-1e-9), "-1e-09"},
{"%010v", 0.0, "0000000000"},
{"%010v", 0.0, "0000000000"},
// *Float cases
{"%.20f", "1e-20", "0.00000000000000000001"},
@ -571,3 +596,67 @@ func TestFloatFormat(t *testing.T) {
}
}
}
func BenchmarkParseFloatSmallExp(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, s := range []string{
"1e0",
"1e-1",
"1e-2",
"1e-3",
"1e-4",
"1e-5",
"1e-10",
"1e-20",
"1e-50",
"1e1",
"1e2",
"1e3",
"1e4",
"1e5",
"1e10",
"1e20",
"1e50",
} {
var x Float
_, _, err := x.Parse(s, 0)
if err != nil {
b.Fatalf("%s: %v", s, err)
}
}
}
}
func BenchmarkParseFloatLargeExp(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, s := range []string{
"1e0",
"1e-10",
"1e-20",
"1e-30",
"1e-40",
"1e-50",
"1e-100",
"1e-500",
"1e-1000",
"1e-5000",
"1e-10000",
"1e10",
"1e20",
"1e30",
"1e40",
"1e50",
"1e100",
"1e500",
"1e1000",
"1e5000",
"1e10000",
} {
var x Float
_, _, err := x.Parse(s, 0)
if err != nil {
b.Fatalf("%s: %v", s, err)
}
}
}
}

View file

@ -109,3 +109,33 @@ func ExampleFloat_Cmp() {
// +Inf 1.2 1
// +Inf +Inf 0
}
func ExampleRoundingMode() {
operands := []float64{2.6, 2.5, 2.1, -2.1, -2.5, -2.6}
fmt.Print(" x")
for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
fmt.Printf(" %s", mode)
}
fmt.Println()
for _, f64 := range operands {
fmt.Printf("%4g", f64)
for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
// sample operands above require 2 bits to represent mantissa
// set binary precision to 2 to round them to integer values
f := new(big.Float).SetPrec(2).SetMode(mode).SetFloat64(f64)
fmt.Printf(" %*g", len(mode.String()), f)
}
fmt.Println()
}
// Output:
// x ToNearestEven ToNearestAway ToZero AwayFromZero ToNegativeInf ToPositiveInf
// 2.6 3 3 2 3 2 3
// 2.5 2 3 2 3 2 3
// 2.1 2 2 2 3 2 3
// -2.1 -2 -2 -2 -3 -3 -2
// -2.5 -2 -3 -2 -3 -3 -2
// -2.6 -3 -3 -2 -3 -3 -2
}

View file

@ -9,9 +9,9 @@
package big
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// Text converts the floating-point number x to a string according
@ -37,16 +37,16 @@ import (
// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
// it is the number of digits after the decimal point. For 'g' and 'G' it is
// the total number of digits. A negative precision selects the smallest
// number of digits necessary to identify the value x uniquely.
// number of decimal digits necessary to identify the value x uniquely using
// x.Prec() mantissa bits.
// The prec value is ignored for the 'b' or 'p' format.
//
// BUG(gri) Float.Text does not accept negative precisions (issue #10991).
func (x *Float) Text(format byte, prec int) string {
const extra = 10 // TODO(gri) determine a good/better value here
return string(x.Append(make([]byte, 0, prec+extra), format, prec))
}
// String formats x like x.Text('g', 10).
// (String must be called explicitly, Float.Format does not support %s verb.)
func (x *Float) String() string {
return x.Text('g', 10)
}
@ -83,6 +83,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
// 1) convert Float to multiprecision decimal
var d decimal // == 0.0
if x.form == finite {
// x != 0
d.init(x.mant, int(x.exp)-x.mant.bitLen())
}
@ -90,9 +91,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
shortest := false
if prec < 0 {
shortest = true
panic("unimplemented")
// TODO(gri) complete this
// roundShortest(&d, f.mant, int(f.exp))
roundShortest(&d, x)
// Precision for shortest representation mode.
switch fmt {
case 'e', 'E':
@ -158,6 +157,80 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
return append(buf, '%', fmt)
}
func roundShortest(d *decimal, x *Float) {
// if the mantissa is zero, the number is zero - stop now
if len(d.mant) == 0 {
return
}
// Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
// (possibly exclusive) round to x for the given precision of x.
// Compute the lower and upper bound in decimal form and find the
// shortest decimal number d such that lower <= d <= upper.
// TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
// See if we can use it (in adjusted form) here as well.
// 1) Compute normalized mantissa mant and exponent exp for x such
// that the lsb of mant corresponds to 1/2 ulp for the precision of
// x (i.e., for mant we want x.prec + 1 bits).
mant := nat(nil).set(x.mant)
exp := int(x.exp) - mant.bitLen()
s := mant.bitLen() - int(x.prec+1)
switch {
case s < 0:
mant = mant.shl(mant, uint(-s))
case s > 0:
mant = mant.shr(mant, uint(+s))
}
exp += s
// x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
// 2) Compute lower bound by subtracting 1/2 ulp.
var lower decimal
var tmp nat
lower.init(tmp.sub(mant, natOne), exp)
// 3) Compute upper bound by adding 1/2 ulp.
var upper decimal
upper.init(tmp.add(mant, natOne), exp)
// The upper and lower bounds are possible outputs only if
// the original mantissa is even, so that ToNearestEven rounding
// would round to the original mantissa and not the neighbors.
inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
// Now we can figure out the minimum number of digits required.
// Walk along until d has distinguished itself from upper and lower.
for i, m := range d.mant {
l := lower.at(i)
u := upper.at(i)
// Okay to round down (truncate) if lower has a different digit
// or if lower is inclusive and is exactly the result of rounding
// down (i.e., and we have reached the final digit of lower).
okdown := l != m || inclusive && i+1 == len(lower.mant)
// Okay to round up if upper has a different digit and either upper
// is inclusive or upper is bigger than the result of rounding up.
okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
// If it's okay to do either, then round to the nearest one.
// If it's okay to do only one, do it.
switch {
case okdown && okup:
d.round(i + 1)
return
case okdown:
d.roundDown(i + 1)
return
case okup:
d.roundUp(i + 1)
return
}
}
}
// %e: d.ddddde±dd
func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
// first digit
@ -219,11 +292,7 @@ func fmtF(buf []byte, prec int, d decimal) []byte {
if prec > 0 {
buf = append(buf, '.')
for i := 0; i < prec; i++ {
ch := byte('0')
if j := d.exp + i; 0 <= j && j < len(d.mant) {
ch = d.mant[j]
}
buf = append(buf, ch)
buf = append(buf, d.at(d.exp+i))
}
}
@ -255,7 +324,7 @@ func (x *Float) fmtB(buf []byte) []byte {
m = nat(nil).shr(m, uint(w-x.prec))
}
buf = append(buf, m.decimalString()...)
buf = append(buf, m.utoa(10)...)
buf = append(buf, 'p')
e := int64(x.exp) - int64(x.prec)
if e >= 0 {
@ -289,7 +358,7 @@ func (x *Float) fmtP(buf []byte) []byte {
m = m[i:]
buf = append(buf, "0x."...)
buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
buf = append(buf, 'p')
if x.exp >= 0 {
buf = append(buf, '+')
@ -314,10 +383,6 @@ func min(x, y int) int {
// '+' and ' ' for sign control, '0' for space or zero padding,
// and '-' for left or right justification. See the fmt package
// for details.
//
// BUG(gri) A missing precision for the 'g' format, or a negative
// (via '*') precision is not yet supported. Instead the
// default precision (6) is used in that case (issue #10991).
func (x *Float) Format(s fmt.State, format rune) {
prec, hasPrec := s.Precision()
if !hasPrec {
@ -336,8 +401,7 @@ func (x *Float) Format(s fmt.State, format rune) {
fallthrough
case 'g', 'G':
if !hasPrec {
// TODO(gri) uncomment once (*Float).Text handles prec < 0
// prec = -1 // default precision for 'g', 'G'
prec = -1 // default precision for 'g', 'G'
}
default:
fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())

View file

@ -551,8 +551,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
}
// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
// If it returns true, x is prime with probability 1 - 1/4^n.
// If it returns false, x is not prime. n must be > 0.
// If x is prime, it returns true.
// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
//
// It is not suitable for judging primes that an adversary may have crafted
// to fool this test.
func (x *Int) ProbablyPrime(n int) bool {
if n <= 0 {
panic("non-positive n for ProbablyPrime")
@ -640,23 +643,23 @@ func Jacobi(x, y *Int) int {
}
}
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
// not an odd integer.
func (z *Int) ModSqrt(x, p *Int) *Int {
switch Jacobi(x, p) {
case -1:
return nil // x is not a square mod p
case 0:
return z.SetInt64(0) // sqrt(0) mod p = 0
case 1:
break
}
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
x = new(Int).Mod(x, p)
}
// modSqrt3Mod4 uses the identity
// (a^((p+1)/4))^2 mod p
// == u^(p+1) mod p
// == u^2 mod p
// 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
return z
}
// modSqrtTonelliShanks uses the Tonelli-Shanks algorithm to find the square
// root of a quadratic residue modulo any prime.
func (z *Int) modSqrtTonelliShanks(x, p *Int) *Int {
// Break p-1 into s*2^e such that s is odd.
var s Int
s.Sub(p, intOne)
@ -703,6 +706,31 @@ func (z *Int) ModSqrt(x, p *Int) *Int {
}
}
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
// not an odd integer.
func (z *Int) ModSqrt(x, p *Int) *Int {
switch Jacobi(x, p) {
case -1:
return nil // x is not a square mod p
case 0:
return z.SetInt64(0) // sqrt(0) mod p = 0
case 1:
break
}
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
x = new(Int).Mod(x, p)
}
// Check whether p is 3 mod 4, and if so, use the faster algorithm.
if len(p.abs) > 0 && p.abs[0]%4 == 3 {
return z.modSqrt3Mod4Prime(x, p)
}
// Otherwise, use Tonelli-Shanks.
return z.modSqrtTonelliShanks(x, p)
}
// Lsh sets z = x << n and returns z.
func (z *Int) Lsh(x *Int, n uint) *Int {
z.abs = z.abs.shl(x.abs, n)
@ -904,65 +932,3 @@ func (z *Int) Not(x *Int) *Int {
z.neg = true // z cannot be zero if x is positive
return z
}
// Gob codec version. Permits backward-compatible changes to the encoding.
const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
func (x *Int) GobEncode() ([]byte, error) {
if x == nil {
return nil, nil
}
buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
i := x.abs.bytes(buf) - 1 // i >= 0
b := intGobVersion << 1 // make space for sign bit
if x.neg {
b |= 1
}
buf[i] = b
return buf[i:], nil
}
// GobDecode implements the gob.GobDecoder interface.
func (z *Int) GobDecode(buf []byte) error {
if len(buf) == 0 {
// Other side sent a nil or default value.
*z = Int{}
return nil
}
b := buf[0]
if b>>1 != intGobVersion {
return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
}
z.neg = b&1 != 0
z.abs = z.abs.setBytes(buf[1:])
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (z *Int) MarshalJSON() ([]byte, error) {
// TODO(gri): get rid of the []byte/string conversions
return []byte(z.String()), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (z *Int) UnmarshalJSON(text []byte) error {
// TODO(gri): get rid of the []byte/string conversions
if _, ok := z.SetString(string(text), 0); !ok {
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
}
return nil
}
// MarshalText implements the encoding.TextMarshaler interface.
func (z *Int) MarshalText() (text []byte, err error) {
return []byte(z.String()), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (z *Int) UnmarshalText(text []byte) error {
if _, ok := z.SetString(string(text), 0); !ok {
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
}
return nil
}

View file

@ -6,10 +6,7 @@ package big
import (
"bytes"
"encoding/gob"
"encoding/hex"
"encoding/json"
"encoding/xml"
"fmt"
"math/rand"
"testing"
@ -1187,6 +1184,53 @@ func BenchmarkBitsetNegOrig(b *testing.B) {
}
}
// tri generates the trinomial 2**(n*2) - 2**n - 1, which is always 3 mod 4 and
// 7 mod 8, so that 2 is always a quadratic residue.
func tri(n uint) *Int {
x := NewInt(1)
x.Lsh(x, n)
x2 := new(Int).Lsh(x, n)
x2.Sub(x2, x)
x2.Sub(x2, intOne)
return x2
}
func BenchmarkModSqrt225_Tonelli(b *testing.B) {
p := tri(225)
x := NewInt(2)
for i := 0; i < b.N; i++ {
x.SetUint64(2)
x.modSqrtTonelliShanks(x, p)
}
}
func BenchmarkModSqrt224_3Mod4(b *testing.B) {
p := tri(225)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
x.SetUint64(2)
x.modSqrt3Mod4Prime(x, p)
}
}
func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
x.SetUint64(2)
x.modSqrtTonelliShanks(x, p)
}
}
func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
x.SetUint64(2)
x.modSqrt3Mod4Prime(x, p)
}
}
func TestBitwise(t *testing.T) {
x := new(Int)
y := new(Int)
@ -1408,138 +1452,6 @@ func TestJacobiPanic(t *testing.T) {
panic(failureMsg)
}
var encodingTests = []string{
"-539345864568634858364538753846587364875430589374589",
"-678645873",
"-100",
"-2",
"-1",
"0",
"1",
"2",
"10",
"42",
"1234567890",
"298472983472983471903246121093472394872319615612417471234712061",
}
func TestIntGobEncoding(t *testing.T) {
var medium bytes.Buffer
enc := gob.NewEncoder(&medium)
dec := gob.NewDecoder(&medium)
for _, test := range encodingTests {
medium.Reset() // empty buffer for each test case (in case of failures)
var tx Int
tx.SetString(test, 10)
if err := enc.Encode(&tx); err != nil {
t.Errorf("encoding of %s failed: %s", &tx, err)
}
var rx Int
if err := dec.Decode(&rx); err != nil {
t.Errorf("decoding of %s failed: %s", &tx, err)
}
if rx.Cmp(&tx) != 0 {
t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
// TODO: top-level nils.
func TestGobEncodingNilIntInSlice(t *testing.T) {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
dec := gob.NewDecoder(buf)
var in = make([]*Int, 1)
err := enc.Encode(&in)
if err != nil {
t.Errorf("gob encode failed: %q", err)
}
var out []*Int
err = dec.Decode(&out)
if err != nil {
t.Fatalf("gob decode failed: %q", err)
}
if len(out) != 1 {
t.Fatalf("wrong len; want 1 got %d", len(out))
}
var zero Int
if out[0].Cmp(&zero) != 0 {
t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
}
}
func TestIntJSONEncoding(t *testing.T) {
for _, test := range encodingTests {
var tx Int
tx.SetString(test, 10)
b, err := json.Marshal(&tx)
if err != nil {
t.Errorf("marshaling of %s failed: %s", &tx, err)
}
var rx Int
if err := json.Unmarshal(b, &rx); err != nil {
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
}
if rx.Cmp(&tx) != 0 {
t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
var intVals = []string{
"-141592653589793238462643383279502884197169399375105820974944592307816406286",
"-1415926535897932384626433832795028841971",
"-141592653589793",
"-1",
"0",
"1",
"141592653589793",
"1415926535897932384626433832795028841971",
"141592653589793238462643383279502884197169399375105820974944592307816406286",
}
func TestIntJSONEncodingTextMarshaller(t *testing.T) {
for _, num := range intVals {
var tx Int
tx.SetString(num, 0)
b, err := json.Marshal(&tx)
if err != nil {
t.Errorf("marshaling of %s failed: %s", &tx, err)
continue
}
var rx Int
if err := json.Unmarshal(b, &rx); err != nil {
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
continue
}
if rx.Cmp(&tx) != 0 {
t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
func TestIntXMLEncodingTextMarshaller(t *testing.T) {
for _, num := range intVals {
var tx Int
tx.SetString(num, 0)
b, err := xml.Marshal(&tx)
if err != nil {
t.Errorf("marshaling of %s failed: %s", &tx, err)
continue
}
var rx Int
if err := xml.Unmarshal(b, &rx); err != nil {
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
continue
}
if rx.Cmp(&tx) != 0 {
t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
func TestIssue2607(t *testing.T) {
// This code sequence used to hang.
n := NewInt(10)

View file

@ -12,30 +12,34 @@ import (
"io"
)
func (x *Int) String() string {
switch {
case x == nil:
// 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.
func (x *Int) Text(base int) string {
if x == nil {
return "<nil>"
case x.neg:
return "-" + x.abs.decimalString()
}
return x.abs.decimalString()
return string(x.abs.itoa(x.neg, base))
}
func charset(ch rune) string {
switch ch {
case 'b':
return lowercaseDigits[0:2]
case 'o':
return lowercaseDigits[0:8]
case 'd', 's', 'v':
return lowercaseDigits[0:10]
case 'x':
return lowercaseDigits[0:16]
case 'X':
return uppercaseDigits[0:16]
// Append appends the string representation of x, as generated by
// x.Text(base), to buf and returns the extended buffer.
func (x *Int) Append(buf []byte, base int) []byte {
if x == nil {
return append(buf, "<nil>"...)
}
return "" // unknown format
return append(buf, x.abs.itoa(x.neg, base)...)
}
func (x *Int) String() string {
return x.Text(10)
}
// write count copies of text to s
@ -60,15 +64,24 @@ func writeMultiple(s fmt.State, text string, count int) {
// right justification.
//
func (x *Int) Format(s fmt.State, ch rune) {
cs := charset(ch)
// special cases
switch {
case cs == "":
// determine base
var base int
switch ch {
case 'b':
base = 2
case 'o':
base = 8
case 'd', 's', 'v':
base = 10
case 'x', 'X':
base = 16
default:
// unknown format
fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
return
case x == nil:
}
if x == nil {
fmt.Fprint(s, "<nil>")
return
}
@ -97,8 +110,15 @@ func (x *Int) Format(s fmt.State, ch rune) {
}
}
// determine digits with base set by len(cs) and digit characters from cs
digits := x.abs.string(cs)
digits := x.abs.utoa(base)
if ch == 'X' {
// faster than bytes.ToUpper
for i, d := range digits {
if 'a' <= d && d <= 'z' {
digits[i] = 'A' + (d - 'a')
}
}
}
// number of characters for the three classes of number padding
var left int // space characters to left of digits for right justification ("%8d")
@ -111,7 +131,7 @@ func (x *Int) Format(s fmt.State, ch rune) {
switch {
case len(digits) < precision:
zeros = precision - len(digits) // count of zero padding
case digits == "0" && precision == 0:
case len(digits) == 1 && digits[0] == '0' && precision == 0:
return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
}
}
@ -137,7 +157,7 @@ func (x *Int) Format(s fmt.State, ch rune) {
writeMultiple(s, sign, 1)
writeMultiple(s, prefix, 1)
writeMultiple(s, "0", zeros)
writeMultiple(s, digits, 1)
s.Write(digits)
writeMultiple(s, " ", right)
}

View file

@ -17,19 +17,19 @@ var stringTests = []struct {
val int64
ok bool
}{
{in: "", ok: false},
{in: "a", ok: false},
{in: "z", ok: false},
{in: "+", ok: false},
{in: "-", ok: false},
{in: "0b", ok: false},
{in: "0x", ok: false},
{in: "2", base: 2, ok: false},
{in: "0b2", base: 0, ok: false},
{in: "08", ok: false},
{in: "8", base: 8, ok: false},
{in: "0xg", base: 0, ok: false},
{in: "g", base: 16, ok: false},
{in: ""},
{in: "a"},
{in: "z"},
{in: "+"},
{in: "-"},
{in: "0b"},
{in: "0x"},
{in: "2", base: 2},
{in: "0b2", base: 0},
{in: "08"},
{in: "8", base: 8},
{in: "0xg", base: 0},
{in: "g", base: 16},
{"0", "0", 0, 0, true},
{"0", "0", 10, 0, true},
{"0", "0", 16, 0, true},
@ -41,7 +41,7 @@ var stringTests = []struct {
{"-10", "-10", 16, -16, true},
{"+10", "10", 16, 16, true},
{"0x10", "16", 0, 16, true},
{in: "0x10", base: 16, ok: false},
{in: "0x10", base: 16},
{"-0x10", "-16", 0, -16, true},
{"+0x10", "16", 0, 16, true},
{"00", "0", 0, 0, true},
@ -58,6 +58,57 @@ var stringTests = []struct {
{"1001010111", "1001010111", 2, 0x257, true},
}
func TestIntText(t *testing.T) {
z := new(Int)
for _, test := range stringTests {
if !test.ok {
continue
}
_, ok := z.SetString(test.in, test.base)
if !ok {
t.Errorf("%v: failed to parse", test)
continue
}
base := test.base
if base == 0 {
base = 10
}
if got := z.Text(base); got != test.out {
t.Errorf("%v: got %s; want %s", test, got, test.out)
}
}
}
func TestAppendText(t *testing.T) {
z := new(Int)
var buf []byte
for _, test := range stringTests {
if !test.ok {
continue
}
_, ok := z.SetString(test.in, test.base)
if !ok {
t.Errorf("%v: failed to parse", test)
continue
}
base := test.base
if base == 0 {
base = 10
}
i := len(buf)
buf = z.Append(buf, base)
if got := string(buf[i:]); got != test.out {
t.Errorf("%v: got %s; want %s", test, got, test.out)
}
}
}
func format(base int) string {
switch base {
case 2:
@ -79,15 +130,13 @@ func TestGetString(t *testing.T) {
z.SetInt64(test.val)
if test.base == 10 {
s := z.String()
if s != test.out {
t.Errorf("#%da got %s; want %s", i, s, test.out)
if got := z.String(); got != test.out {
t.Errorf("#%da got %s; want %s", i, got, test.out)
}
}
s := fmt.Sprintf(format(test.base), z)
if s != test.out {
t.Errorf("#%db got %s; want %s", i, s, test.out)
if got := fmt.Sprintf(format(test.base), z); got != test.out {
t.Errorf("#%db got %s; want %s", i, got, test.out)
}
}
}

View file

@ -2,31 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package big implements multi-precision arithmetic (big numbers).
// The following numeric types are supported:
//
// Int signed integers
// Rat rational numbers
// Float floating-point numbers
//
// Methods are typically of the form:
//
// func (z *T) Unary(x *T) *T // z = op x
// func (z *T) Binary(x, y *T) *T // z = x op y
// func (x *T) M() T1 // v = x.M()
//
// with T one of Int, Rat, or Float. For unary and binary operations, the
// result is the receiver (usually named z in that case); if it is one of
// the operands x or y it may be overwritten (and its memory reused).
// To enable chaining of operations, the result is also returned. Methods
// returning a result other than *Int, *Rat, or *Float take an operand as
// the receiver (usually named x in that case).
//
package big
// This file implements unsigned multi-precision integers (natural
// numbers). They are the building blocks for the implementation
// of signed integers, rationals, and floating-point numbers.
// This file contains operations on unsigned multi-precision integers.
// These are the building blocks for the operations on signed integers
// and rationals.
package big
import "math/rand"
@ -216,23 +196,36 @@ func basicMul(z, x, y nat) {
}
}
// montgomery computes x*y*2^(-n*_W) mod m,
// assuming k = -1/m mod 2^_W.
// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
// assuming k = -1/m mod 2**_W.
// z is used for storing the result which is returned;
// z must not alias x, y or m.
// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
// https://eprint.iacr.org/2011/239.pdf
// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
var c1, c2 Word
// This code assumes x, y, m are all the same length, n.
// (required by addMulVVW and the for loop).
// It also assumes that x, y are already reduced mod m,
// or else the result will not be properly reduced.
if len(x) != n || len(y) != n || len(m) != n {
panic("math/big: mismatched montgomery number lengths")
}
var c1, c2, c3 Word
z = z.make(n)
z.clear()
for i := 0; i < n; i++ {
d := y[i]
c1 += addMulVVW(z, x, d)
c2 = addMulVVW(z, x, d)
t := z[0] * k
c2 = addMulVVW(z, m, t)
c3 = addMulVVW(z, m, t)
copy(z, z[1:])
z[n-1] = c1 + c2
if z[n-1] < c1 {
cx := c1 + c2
cy := cx + c3
z[n-1] = cy
if cx < c2 || cy < c3 {
c1 = 1
} else {
c1 = 0
@ -1082,7 +1075,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
x = rr
// Ideally the precomputations would be performed outside, and reused
// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On NewtonRaphson
// k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On NewtonRaphson
// Iteration for Multiplicative Inverses Modulo Prime Powers".
k0 := 2 - m[0]
t := m[0] - 1
@ -1092,7 +1085,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
}
k0 = -k0
// RR = 2ˆ(2*_W*len(m)) mod m
// RR = 2**(2*_W*len(m)) mod m
RR = RR.setWord(1)
zz = zz.shl(RR, uint(2*numWords*_W))
_, RR = RR.div(RR, zz, m)
@ -1141,9 +1134,12 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
return zz.norm()
}
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
// If it returns true, n is prime with probability 1 - 1/4^reps.
// If it returns false, n is not prime.
// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
// If x is prime, it returns true.
// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
//
// It is not suitable for judging primes that an adversary may have crafted
// to fool this test.
func (n nat) probablyPrime(reps int) bool {
if len(n) == 0 {
return false

View file

@ -158,7 +158,7 @@ var mulRangesN = []struct {
func TestMulRangeN(t *testing.T) {
for i, r := range mulRangesN {
prod := nat(nil).mulRange(r.a, r.b).decimalString()
prod := string(nat(nil).mulRange(r.a, r.b).utoa(10))
if prod != r.prod {
t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
}
@ -326,7 +326,7 @@ func TestTrailingZeroBits(t *testing.T) {
for i := uint(0); i <= 3*_W; i++ {
n := y.trailingZeroBits()
if n != i {
t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i)
}
y = y.shl(y, 1)
}
@ -341,25 +341,57 @@ var montgomeryTests = []struct {
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
0x0000000000000000,
"0xffffffffffffffffffffffffffffffffffffffffff",
"0xffffffffffffffffffffffffffffffffff",
1,
"0x1000000000000000000000000000000000000000000",
"0x10000000000000000000000000000000000",
},
{
"0x000000000ffffff5",
"0x000000000ffffff0",
"0x0000000010000001",
0xff0000000fffffff,
"0x000000000bfffff4",
"0x0000000003400001",
},
{
"0x0000000080000000",
"0x00000000ffffffff",
"0x0000000010000001",
0xff0000000fffffff,
"0x0000000088000000",
"0x0000000007800001",
"0x1000000000000001",
0xfffffffffffffff,
"0x0800000008000001",
"0x0800000008000001",
},
{
"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
"0x0000000080000000",
"0x0000000080000000",
"0xffffffff00000001",
0xfffffffeffffffff,
"0xbfffffff40000001",
"0xbfffffff40000001",
},
{
"0x0000000080000000",
"0x0000000080000000",
"0x00ffffff00000001",
0xfffffeffffffff,
"0xbfffff40000001",
"0xbfffff40000001",
},
{
"0x0000000080000000",
"0x0000000080000000",
"0x0000ffff00000001",
0xfffeffffffff,
"0xbfff40000001",
"0xbfff40000001",
},
{
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
0xdecc8f1249812adf,
"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
"0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
"0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
},
{
"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
@ -372,10 +404,27 @@ var montgomeryTests = []struct {
}
func TestMontgomery(t *testing.T) {
one := NewInt(1)
_B := new(Int).Lsh(one, _W)
for i, test := range montgomeryTests {
x := natFromString(test.x)
y := natFromString(test.y)
m := natFromString(test.m)
for len(x) < len(m) {
x = append(x, 0)
}
for len(y) < len(m) {
y = append(y, 0)
}
if x.cmp(m) > 0 {
_, r := nat(nil).div(nil, x, m)
t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16))
}
if y.cmp(m) > 0 {
_, r := nat(nil).div(nil, x, m)
t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16))
}
var out nat
if _W == 32 {
@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) {
out = natFromString(test.out64)
}
k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
// t.Logf("#%d: len=%d\n", i, len(m))
// check output in table
xi := &Int{abs: x}
yi := &Int{abs: y}
mi := &Int{abs: m}
p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi)
if out.cmp(p.abs.norm()) != 0 {
t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16))
}
// check k0 in table
k := new(Int).Mod(&Int{abs: m}, _B)
k = new(Int).Sub(_B, k)
k = new(Int).Mod(k, _B)
k0 := Word(new(Int).ModInverse(k, _B).Uint64())
if k0 != Word(test.k0) {
t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0)
}
// check montgomery with correct k0 produces correct output
z := nat(nil).montgomery(x, y, m, k0, len(m))
z = z.norm()
if z.cmp(out) != 0 {
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16))
}
}
}
@ -429,7 +498,7 @@ func TestExpNN(t *testing.T) {
z := nat(nil).expNN(x, y, m)
if z.cmp(out) != 0 {
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
t.Errorf("#%d got %s want %s", i, z.utoa(10), out.utoa(10))
}
}
}
@ -486,7 +555,7 @@ var fiboNums = []string{
func TestFibo(t *testing.T) {
for i, want := range fiboNums {
n := i * 10
got := fibo(n).decimalString()
got := string(fibo(n).utoa(10))
if got != want {
t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
}

Some files were not shown because too many files have changed in this diff Show more