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

View file

@ -76,6 +76,7 @@ Alexei Sholik <alcosholik@gmail.com>
Alexey Borzenkov <snaury@gmail.com> Alexey Borzenkov <snaury@gmail.com>
Alexey Palazhchenko <alexey.palazhchenko@gmail.com> Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Alexis Imperial-Legrand <ail@google.com> Alexis Imperial-Legrand <ail@google.com>
Aliaksandr Valialkin <valyala@gmail.com>
Alif Rachmawadi <subosito@gmail.com> Alif Rachmawadi <subosito@gmail.com>
Amir Mohammad Saied <amir@gluegadget.com> Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com> Amrut Joshi <amrut.joshi@gmail.com>
@ -116,6 +117,7 @@ Anthony Starks <ajstarks@gmail.com>
Apisak Darakananda <pongad@gmail.com> Apisak Darakananda <pongad@gmail.com>
Aram Hăvărneanu <aram@mgk.ro> Aram Hăvărneanu <aram@mgk.ro>
Areski Belaid <areski@gmail.com> Areski Belaid <areski@gmail.com>
Arkadi Pyuro <arkadi@google.com>
Arnaud Ysmal <arnaud.ysmal@gmail.com> Arnaud Ysmal <arnaud.ysmal@gmail.com>
Arne Hormann <arnehormann@gmail.com> Arne Hormann <arnehormann@gmail.com>
Arnout Engelen <arnout@bzzt.net> Arnout Engelen <arnout@bzzt.net>
@ -135,6 +137,7 @@ Ben Fried <ben.fried@gmail.com>
Ben Lynn <benlynn@gmail.com> Ben Lynn <benlynn@gmail.com>
Ben Olive <sionide21@gmail.com> Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us> Benjamin Black <b@b3k.us>
Benjamin Prosnitz <bprosnitz@google.com>
Benny Siegert <bsiegert@gmail.com> Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com> Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de> Berengar Lehr <Berengar.Lehr@gmx.de>
@ -178,6 +181,7 @@ Cezar Sá Espinola <cezarsa@gmail.com>
ChaiShushan <chaishushan@gmail.com> ChaiShushan <chaishushan@gmail.com>
Charles L. Dorian <cldorian@gmail.com> Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com> Charles Lee <zombie.fml@gmail.com>
Charles Weill <weill@google.com>
Chris Broadfoot <cbro@golang.org> Chris Broadfoot <cbro@golang.org>
Chris Dollin <ehog.hedge@gmail.com> Chris Dollin <ehog.hedge@gmail.com>
Chris Farmiloe <chrisfarms@gmail.com> Chris Farmiloe <chrisfarms@gmail.com>
@ -232,6 +236,7 @@ Dave Day <djd@golang.org>
Dave Grijalva <dgrijalva@ngmoco.com> Dave Grijalva <dgrijalva@ngmoco.com>
David Anderson <danderson@google.com> David Anderson <danderson@google.com>
David Barnett <dbarnett@google.com> David Barnett <dbarnett@google.com>
David Benjamin <davidben@google.com>
David Bürgin <676c7473@gmail.com> David Bürgin <676c7473@gmail.com>
David Calavera <david.calavera@gmail.com> David Calavera <david.calavera@gmail.com>
David Chase <drchase@google.com> David Chase <drchase@google.com>
@ -277,6 +282,7 @@ Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com> Dustin Shields-Cloues <dcloues@gmail.com>
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com> Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
Eden Li <eden.li@gmail.com> Eden Li <eden.li@gmail.com>
Edward Muller <edwardam@interlix.com>
Egon Elbre <egonelbre@gmail.com> Egon Elbre <egonelbre@gmail.com>
Ehren Kret <ehren.kret@gmail.com> Ehren Kret <ehren.kret@gmail.com>
Eivind Uggedal <eivind@uggedal.com> Eivind Uggedal <eivind@uggedal.com>
@ -359,6 +365,7 @@ Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org> Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com> Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com> Herbert Georg Fischer <herbert.fischer@gmail.com>
Hiroshi Ioka <hirochachacha@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com> Hong Ruiqi <hongruiqi@gmail.com>
Hossein Sheikh Attar <hattar@google.com> Hossein Sheikh Attar <hattar@google.com>
Hsin-Ho Yeh <yhh92u@gmail.com> Hsin-Ho Yeh <yhh92u@gmail.com>
@ -379,6 +386,7 @@ Jacob Baskin <jbaskin@google.com>
Jacob H. Haven <jacob@cloudflare.com> Jacob H. Haven <jacob@cloudflare.com>
Jae Kwon <jae@tendermint.com> Jae Kwon <jae@tendermint.com>
Jakob Borg <jakob@nym.se> Jakob Borg <jakob@nym.se>
Jakub Čajka <jcajka@redhat.com>
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com> Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
James Aguilar <jaguilar@google.com> James Aguilar <jaguilar@google.com>
James David Chalfant <james.chalfant@gmail.com> James David Chalfant <james.chalfant@gmail.com>
@ -422,6 +430,7 @@ Jim Cote <jfcote87@gmail.com>
Jim McGrath <jimmc2@gmail.com> Jim McGrath <jimmc2@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com> Jimmy Zelinskie <jimmyzelinskie@gmail.com>
Jingcheng Zhang <diogin@gmail.com> Jingcheng Zhang <diogin@gmail.com>
Jingguo Yao <yaojingguo@gmail.com>
Jiong Du <londevil@gmail.com> Jiong Du <londevil@gmail.com>
Joakim Sernbrant <serbaut@gmail.com> Joakim Sernbrant <serbaut@gmail.com>
Joe Harrison <joehazzers@gmail.com> Joe Harrison <joehazzers@gmail.com>
@ -444,6 +453,7 @@ John Potocny <johnp@vividcortex.com>
John Shahid <jvshahid@gmail.com> John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org> John Tuley <john@tuley.org>
Jonathan Allie <jonallie@google.com> Jonathan Allie <jonallie@google.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Feinberg <feinberg@google.com> Jonathan Feinberg <feinberg@google.com>
Jonathan Gold <jgold.bg@gmail.com> Jonathan Gold <jgold.bg@gmail.com>
Jonathan Hseu <jhseu@google.com> Jonathan Hseu <jhseu@google.com>
@ -756,6 +766,7 @@ Sebastien Binet <seb.binet@gmail.com>
Sébastien Paolacci <sebastien.paolacci@gmail.com> Sébastien Paolacci <sebastien.paolacci@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru> Sergei Skorobogatov <skorobo@rambler.ru>
Sergey 'SnakE' Gromov <snake.scaly@gmail.com> Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
Sergey Arseev <sergey.arseev@intel.com>
Sergio Luis O. B. Correia <sergio@correia.cc> Sergio Luis O. B. Correia <sergio@correia.cc>
Seth Hoenig <seth.a.hoenig@gmail.com> Seth Hoenig <seth.a.hoenig@gmail.com>
Shane Hansen <shanemhansen@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). 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 go1.txt (and similarly named files) are frozen once a version has been
shipped. Each file adds new lines but does not remove any. 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_USER = 8
pkg log/syslog (openbsd-amd64-cgo), const LOG_UUCP = 64 pkg log/syslog (openbsd-amd64-cgo), const LOG_UUCP = 64
pkg log/syslog (openbsd-amd64-cgo), const LOG_WARNING = 4 pkg log/syslog (openbsd-amd64-cgo), const LOG_WARNING = 4
pkg math, const E = 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000 pkg math, const E = 2.71828 // 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln10 = 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000 pkg math, const Ln10 = 2.30259 // 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000
pkg math, const Ln2 = 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000 pkg math, const Ln2 = 0.693147 // 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000
pkg math, const Log10E = 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279 pkg math, const Log10E = 0.434294 // 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279
pkg math, const Log2E = 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009 pkg math, const Log2E = 1.4427 // 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009
pkg math, const MaxFloat32 = 340282346638528859811704183484516925440 pkg math, const MaxFloat32 = 3.40282e+38 // 340282346638528859811704183484516925440
pkg math, const MaxFloat64 = 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const MaxInt16 = 32767 pkg math, const MaxInt16 = 32767
pkg math, const MaxInt32 = 2147483647 pkg math, const MaxInt32 = 2147483647
pkg math, const MaxInt64 = 9223372036854775807 pkg math, const MaxInt64 = 9223372036854775807
@ -2002,14 +2002,14 @@ pkg math, const MinInt16 = -32768
pkg math, const MinInt32 = -2147483648 pkg math, const MinInt32 = -2147483648
pkg math, const MinInt64 = -9223372036854775808 pkg math, const MinInt64 = -9223372036854775808
pkg math, const MinInt8 = -128 pkg math, const MinInt8 = -128
pkg math, const Phi = 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000 pkg math, const Phi = 1.61803 // 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000
pkg math, const Pi = 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000 pkg math, const Pi = 3.14159 // 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat32 = 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000 pkg math, const SmallestNonzeroFloat32 = 1.4013e-45 // 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const SmallestNonzeroFloat64 = 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 pkg math, const SmallestNonzeroFloat64 = 4.94066e-324 // 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
pkg math, const Sqrt2 = 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000 pkg math, const Sqrt2 = 1.41421 // 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtE = 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000 pkg math, const SqrtE = 1.64872 // 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPhi = 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000 pkg math, const SqrtPhi = 1.27202 // 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000
pkg math, const SqrtPi = 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000 pkg math, const SqrtPi = 1.77245 // 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000
pkg math/big, const MaxBase = 36 pkg math/big, const MaxBase = 36
pkg math/big, method (*Int) MarshalJSON() ([]uint8, error) pkg math/big, method (*Int) MarshalJSON() ([]uint8, error)
pkg math/big, method (*Int) SetUint64(uint64) *Int 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 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. 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 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>
<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> <p>
Security-related issues should be reported to 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. See the <a href="/security">security policy</a> for more details.
</p> </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> <h3><a href="/doc/contribute.html">Contributing code</a></h3>
<p> <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>. system called <a href="https://code.google.com/p/gerrit/">Gerrit</a>.
</p> </p>
<h3>Set up authentication for code review</h3> <h3 id="auth">Set up authentication for code review</h3>
<p> <p>
Gerrit uses Google Accounts for authentication. If you don't have 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. and Git is configured to use this file.
</p> </p>
<h3>Register with Gerrit</h3> <h3 id="gerrit">Register with Gerrit</h3>
<p> <p>
Now that you have your authentication token, 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. That is all that is required.
</p> </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. <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, 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. This rigmarole only needs to be done for your first submission for each email address.
</p> </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> <p>
Now install the <code>git-codereview</code> command by running, 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>. checkout by running <code>git-codereview</code> <code>hooks</code>.
</p> </p>
<h3>Set up git aliases</h3> <h3 id="git-config">Set up git aliases</h3>
<p> <p>
The <code>git-codereview</code> command can be run directly from the shell 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 sync = codereview sync
</pre> </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> <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>. You can also read the <a href="https://godoc.org/golang.org/x/review/git-codereview">command documentation</a>.
</p> </p>
<h3>Switch to the master branch</h3> <h3 id="master">Switch to the master branch</h3>
<p> <p>
Most Go installations use a release branch, but new changes should 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>.) <code>git</code> <code>pull</code> <code>-r</code>.)
</p> </p>
<h3>Make a change</h3> <h3 id="change">Make a change</h3>
<p> <p>
The entire checked-out tree is writable. 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>.) runs <code>git</code> <code>commit</code> <code>--amend</code>.)
</p> </p>
<h3>Mail the change for review</h3> <h3 id="mail">Mail the change for review</h3>
<p> <p>
Once the change is ready, mail it out for review: 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 remote: https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
</pre> </pre>
<h3>Reviewing code</h3> <h3 id="review">Reviewing code</h3>
<p> <p>
Running <code>git</code> <code>mail</code> will send an email to you and the 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.) (Unlike with the old Rietveld review system, replying by mail has no effect.)
</p> </p>
<h3>Revise and upload</h3> <h3 id="revise">Revise and upload</h3>
<p> <p>
You must respond to review comments through the web interface. 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>. <code>change</code> <code><i>&lt;branch&gt;</i></code>.
</p> </p>
<h3>Synchronize your client</h3> <h3 id="sync">Synchronize your client</h3>
<p> <p>
While you were working, others might have submitted changes to the repository. 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. restore the change commit.
</p> </p>
<h3>Reviewing code by others</h3> <h3 id="download">Reviewing code by others</h3>
<p> <p>
You can import a change proposed by someone else into your local Git repository. 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. To revert, change back to the branch you were working in.
</p> </p>
<h3>Submit the change after the review</h3> <h3 id="submit">Submit the change after the review</h3>
<p> <p>
After the code has been <code>LGTM</code>'ed, an approver may 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. the submit operation.
</p> </p>
<h3>More information</h3> <h3 id="more">More information</h3>
<p> <p>
In addition to the information here, the Go community maintains a <a href="https://golang.org/wiki/CodeReview">CodeReview</a> wiki page. 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> <p>Code that you contribute should use the standard copyright header:</p>
<pre> <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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
</pre> </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 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>hash&lt;T,U&gt;</code>) and variables (<code>runtime.m</code> and
<code>runtime.g</code>) that the linker <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. the DWARF code.
</p> </p>

View file

@ -12,6 +12,24 @@ git pull
git checkout <i>release-branch</i> git checkout <i>release-branch</i>
</pre> </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> <h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
<p> <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. 1.5.1 milestone</a> on our issue tracker for details.
</p> </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> <h2 id="go1.4">go1.4 (released 2014/12/10)</h2>
<p> <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. syntax tree example is also doable, although not as elegantly.
</p> </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> <h2 id="values">Values</h2>
<h3 id="conversions"> <h3 id="conversions">

View file

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of October 20, 2015", "Subtitle": "Version of January 5, 2016",
"Path": "/ref/spec" "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 */ . newline = /* the Unicode code point U+000A */ .
unicode_char = /* an arbitrary Unicode code point except newline */ . unicode_char = /* an arbitrary Unicode code point except newline */ .
unicode_letter = /* a Unicode code point classified as "Letter" */ . 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> </pre>
<p> <p>
In <a href="http://www.unicode.org/versions/Unicode6.3.0/">The Unicode Standard 6.3</a>, In <a href="http://www.unicode.org/versions/Unicode8.0.0/">The Unicode Standard 8.0</a>,
Section 4.5 "General Category" Section 4.5 "General Category" defines a set of character categories.
defines a set of character categories. Go treats Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo
those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters, as Unicode letters, and those in the Number category Nd as Unicode digits.
and those in category Nd as Unicode digits.
</p> </p>
<h3 id="Letters_and_digits">Letters and digits</h3> <h3 id="Letters_and_digits">Letters and digits</h3>
@ -1051,12 +1050,18 @@ but are otherwise ignored.
</p> </p>
<pre> <pre>
// A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct { struct {
microsec uint64 "field 1" x, y float64 "" // an empty tag string is like an absent tag
serverIP6 uint64 "field 2" name string "any string is permitted as a tag"
process string "field 3" _ [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> </pre>
@ -1108,7 +1113,7 @@ one unnamed result it may be written as an unparenthesized type.
</p> </p>
<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 type prefixed with <code>...</code>.
A function with such a parameter is called <i>variadic</i> and A function with such a parameter is called <i>variadic</i> and
may be invoked with zero or more arguments for that parameter. may be invoked with zero or more arguments for that parameter.
@ -1795,13 +1800,14 @@ const ( // iota is reset to 0
c2 = iota // c2 == 2 c2 = iota // c2 == 2
) )
const ( const ( // iota is reset to 0
a = 1 &lt;&lt; iota // a == 1 (iota has been reset) a = 1 &lt;&lt; iota // a == 1
b = 1 &lt;&lt; iota // b == 2 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) u = iota * 42 // u == 0 (untyped integer constant)
v float64 = iota * 42 // v == 42.0 (float64 constant) v float64 = iota * 42 // v == 42.0 (float64 constant)
w = iota * 42 // w == 84 (untyped integer constant) w = iota * 42 // w == 84 (untyped integer constant)
@ -2083,7 +2089,7 @@ Receiver = Parameters .
<p> <p>
The receiver is specified via an extra parameter section preceding the method 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 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 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 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> <p>
A "fallthrough" statement transfers control to the first statement of the 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. It may be used only as the final non-empty statement in such a clause.
</p> </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. meet to talk about Go. Find a chapter near you.
</p> </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. <a href="#environment">environment variables</a> below.
</p> </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> </div>
<h2 id="go14">Install Go compiler binaries</h2> <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>
<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: the go tool that comes as part of gccgo 5. For example on Ubuntu Vivid:
</p> </p>
@ -173,7 +184,7 @@ Then clone the repository and check out the latest release tag:</p>
<pre> <pre>
$ git clone https://go.googlesource.com/go $ git clone https://go.googlesource.com/go
$ cd go $ cd go
$ git checkout go1.5.1 $ git checkout go1.5.2
</pre> </pre>
<h2 id="head">(Optional) Switch to the master branch</h2> <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> <a href="//groups.google.com/group/golang-announce">golang-announce</a>
mailing list. mailing list.
Each announcement mentions the latest release tag, for instance, Each announcement mentions the latest release tag, for instance,
<code>go1.5.1</code>. <code>go1.5.2</code>.
</p> </p>
<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>
<tr><td colspan="3"><hr></td></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>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>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> <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> </table>
@ -220,19 +220,29 @@ and building a simple program, as follows.
<p> <p>
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>, 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. variable to point to that location.
</p> </p>
<pre> <pre class="testUnix">
$ <b>export GOPATH=$HOME/work</b> $ <b>export GOPATH=$HOME/work</b>
</pre> </pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>set GOPATH=%HOME%\work</b>
</pre>
<p> <p>
<span class="testUnix">
You should put the above command in your shell startup script You should put the above command in your shell startup script
(<code>$HOME/.profile</code> for example) or, if you use Windows, (<code>$HOME/.profile</code> for example).
follow the <a href="#windows_env">instructions above</a> to set the </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. <code>GOPATH</code> environment variable on your system.
</span>
</p> </p>
<p> <p>
@ -256,21 +266,30 @@ func main() {
Then compile it with the <code>go</code> tool: Then compile it with the <code>go</code> tool:
</p> </p>
<pre> <pre class="testUnix">
$ <b>go install github.com/user/hello</b> $ <b>go install github.com/user/hello</b>
</pre> </pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>go install github.com/user/hello</b>
</pre>
<p> <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. (or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
Execute the command to see the greeting: Execute the command to see the greeting:
</p> </p>
<pre> <pre class="testUnix">
$ <b>$GOPATH/bin/hello</b> $ <b>$GOPATH/bin/hello</b>
hello, world hello, world
</pre> </pre>
<pre class="testWindows" style="display: none">
C:\&gt; <b>%GOPATH%\bin\hello</b>
hello, world
</pre>
<p> <p>
If you see the "hello, world" message then your Go installation is working. If you see the "hello, world" message then your Go installation is working.
</p> </p>

View file

@ -1,5 +1,5 @@
// Concurrent computation of pi. // Concurrent computation of pi.
// See http://goo.gl/ZuTZM. // See https://goo.gl/la6Kli.
// //
// This demonstrates Go's ability to handle // This demonstrates Go's ability to handle
// large numbers of concurrent processes. // 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, fail: true,
}, },
/* /*
TODO(khr): reenable when write barriers are fixed.
{ {
// Storing a Go pointer into C memory should fail. // Storing a Go pointer into C memory should fail.
name: "barrier", name: "barrier",
@ -211,6 +210,24 @@ var ptrTests = []ptrTest{
fail: true, fail: true,
expensive: 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 echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file
exit 1 exit 1
fi fi
expect $file $file:$line:
}
expect() {
file=$1
shift
if go build $file >errs 2>&1; then if go build $file >errs 2>&1; then
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
exit 1 exit 1
@ -19,11 +25,13 @@ check() {
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
exit 1 exit 1
fi fi
if ! fgrep $file:$line: errs >/dev/null 2>&1; then for error; do
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error on line $line but saw: 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 cat 1>&2 errs
exit 1 exit 1
fi fi
done
} }
check err1.go check err1.go
@ -33,6 +41,9 @@ check issue7757.go
check issue8442.go check issue8442.go
check issue11097a.go check issue11097a.go
check issue11097b.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 if ! go run ptr.go; then
exit 1 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 // +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 package main
import ( import (

View file

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

View file

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

View file

@ -12,6 +12,7 @@ void callPanic(void);
int callGoReturnVal(void); int callGoReturnVal(void);
int returnAfterGrow(void); int returnAfterGrow(void);
int returnAfterGrowFromGo(void); int returnAfterGrowFromGo(void);
void callGoWithString(void);
*/ */
import "C" import "C"
@ -178,7 +179,6 @@ func testCallbackCallers(t *testing.T) {
pc := make([]uintptr, 100) pc := make([]uintptr, 100)
n := 0 n := 0
name := []string{ name := []string{
"test.goCallback",
"runtime.call16", "runtime.call16",
"runtime.cgocallbackg1", "runtime.cgocallbackg1",
"runtime.cgocallbackg", "runtime.cgocallbackg",
@ -193,10 +193,10 @@ func testCallbackCallers(t *testing.T) {
"runtime.goexit", "runtime.goexit",
} }
if unsafe.Sizeof((*byte)(nil)) == 8 { if unsafe.Sizeof((*byte)(nil)) == 8 {
name[1] = "runtime.call32" name[0] = "runtime.call32"
} }
nestedCall(func() { nestedCall(func() {
n = runtime.Callers(2, pc) n = runtime.Callers(4, pc)
}) })
if n != len(name) { if n != len(name) {
t.Errorf("expected %d frames, got %d", len(name), n) t.Errorf("expected %d frames, got %d", len(name), n)
@ -277,6 +277,22 @@ func goReturnVal() (r C.int) {
return 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) { func testCallbackStack(t *testing.T) {
// Make cgo call and callback with different amount of stack stack available. // 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. // 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "_cgo_export.h" #include "_cgo_export.h"
@ -80,3 +81,10 @@ returnAfterGrowFromGo(void)
return goReturnVal(); 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 Test11925(t *testing.T) { test11925(t) }
func Test12030(t *testing.T) { test12030(t) } func Test12030(t *testing.T) { test12030(t) }
func TestGCC68255(t *testing.T) { testGCC68255(t) } func TestGCC68255(t *testing.T) { testGCC68255(t) }
func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } 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); 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 // this example is in issue 3253
int hola = 0; int hola = 0;
int testHola() { return hola; } 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> #include <dlfcn.h>
#cgo linux LDFLAGS: -ldl #cgo linux LDFLAGS: -ldl
extern void call4029(void *arg);
*/ */
import "C" import "C"
import ( import (
"fmt"
"testing" "testing"
) )
var callbacks int
//export IMPIsOpaque //export IMPIsOpaque
func IMPIsOpaque() { func IMPIsOpaque() {
fmt.Println("isOpaque") callbacks++
} }
//export IMPInitWithFrame //export IMPInitWithFrame
func IMPInitWithFrame() { func IMPInitWithFrame() {
fmt.Println("IInitWithFrame") callbacks++
} }
//export IMPDrawRect //export IMPDrawRect
func IMPDrawRect() { func IMPDrawRect() {
fmt.Println("drawRect:") callbacks++
} }
//export IMPWindowResize //export IMPWindowResize
func IMPWindowResize() { func IMPWindowResize() {
fmt.Println("windowDidResize:") callbacks++
} }
func test4029(t *testing.T) { func test4029(t *testing.T) {
@ -42,6 +45,9 @@ func test4029(t *testing.T) {
loadThySelf(t, "IMPDrawRect") loadThySelf(t, "IMPDrawRect")
loadThySelf(t, "IMPInitWithFrame") loadThySelf(t, "IMPInitWithFrame")
loadThySelf(t, "IMPIsOpaque") loadThySelf(t, "IMPIsOpaque")
if callbacks != 4 {
t.Errorf("got %d callbacks, expected 4", callbacks)
}
} }
func loadThySelf(t *testing.T, symbol string) { func loadThySelf(t *testing.T, symbol string) {
@ -58,4 +64,5 @@ func loadThySelf(t *testing.T, symbol string) {
return return
} }
t.Log(symbol, symbol_address) 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.") t.Skip("test8694 is disabled on ARM because 5l cannot handle thumb library.")
} }
// Really just testing that this compiles, but check answer anyway. // Really just testing that this compiles, but check answer anyway.
x := complex64(2 + 3i) x := C.complexfloat(2 + 3i)
x2 := x * x x2 := x * x
cx2 := C.complexFloatSquared(x) cx2 := C.complexFloatSquared(x)
if cx2 != x2 { if cx2 != x2 {
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, 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 y2 := y * y
cy2 := C.complexDoubleSquared(y) cy2 := C.complexDoubleSquared(y)
if cy2 != y2 { 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 rm -rf libgo.a libgo.h testp pkg
status=0
# Installing first will create the header files we want. # Installing first will create the header files we want.
GOPATH=$(pwd) go install -buildmode=c-archive libgo 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 $(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 rm -f libgo.a libgo.h testp
# Test building libgo other than installing it. # 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 GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a $(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 rm -f libgo.a libgo.h testp
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a $(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 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 <time.h>
#include <unistd.h> #include <unistd.h>
#define fd (10) #define fd (100)
// Tests libgo2.so, which does not export any functions. // Tests libgo2.so, which does not export any functions.
// Read a string from the file descriptor and print it. // 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. // that the C code can also use.
const ( const (
fd = 10 fd = 100
) )
func init() { 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) goos=$(go env GOOS)
goarch=$(go env GOARCH) 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. # Directory where cgo headers and outputs will be installed.
# The installation directory format varies depending on the platform. # The installation directory format varies depending on the platform.
@ -28,12 +35,13 @@ fi
androidpath=/data/local/tmp/testcshared-$$ androidpath=/data/local/tmp/testcshared-$$
function cleanup() { function cleanup() {
rm -rf libgo.$libext libgo2.$libext libgo.h testp testp2 testp3 pkg rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext
rm -f libgo.h libgo4.h libgo5.h
rm -rf $(go env GOROOT)/${installdir} rm -f testp testp2 testp3 testp4 testp5
rm -rf pkg "${goroot}/${installdir}"
if [ "$goos" == "android" ]; then if [ "$goos" == "android" ]; then
adb shell rm -rf $androidpath adb shell rm -rf "$androidpath"
fi fi
} }
trap cleanup EXIT trap cleanup EXIT
@ -93,6 +101,8 @@ if [ "$goos" == "android" ]; then
GOGCCFLAGS="${GOGCCFLAGS} -pie" GOGCCFLAGS="${GOGCCFLAGS} -pie"
fi fi
status=0
# test0: exported symbols in shared lib are accessible. # test0: exported symbols in shared lib are accessible.
# TODO(iant): using _shared here shouldn't really be necessary. # TODO(iant): using _shared here shouldn't really be necessary.
$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c libgo.$libext $(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c libgo.$libext
@ -101,7 +111,7 @@ binpush testp
output=$(run LD_LIBRARY_PATH=. ./testp) output=$(run LD_LIBRARY_PATH=. ./testp)
if [ "$output" != "PASS" ]; then if [ "$output" != "PASS" ]; then
echo "FAIL test0 got ${output}" echo "FAIL test0 got ${output}"
exit 1 status=1
fi fi
# test1: shared library can be dynamically loaded and exported symbols are accessible. # test1: shared library can be dynamically loaded and exported symbols are accessible.
@ -110,7 +120,7 @@ binpush testp
output=$(run ./testp ./libgo.$libext) output=$(run ./testp ./libgo.$libext)
if [ "$output" != "PASS" ]; then if [ "$output" != "PASS" ]; then
echo "FAIL test1 got ${output}" echo "FAIL test1 got ${output}"
exit 1 status=1
fi fi
# test2: tests libgo2 which does not export any functions. # test2: tests libgo2 which does not export any functions.
@ -125,7 +135,7 @@ binpush testp2
output=$(run LD_LIBRARY_PATH=. ./testp2) output=$(run LD_LIBRARY_PATH=. ./testp2)
if [ "$output" != "PASS" ]; then if [ "$output" != "PASS" ]; then
echo "FAIL test2 got ${output}" echo "FAIL test2 got ${output}"
exit 1 status=1
fi fi
# test3: tests main.main is exported on android. # test3: tests main.main is exported on android.
@ -135,7 +145,42 @@ if [ "$goos" == "android" ]; then
output=$(run ./testp ./libgo.so) output=$(run ./testp ./libgo.so)
if [ "$output" != "PASS" ]; then if [ "$output" != "PASS" ]; then
echo "FAIL test3 got ${output}" echo "FAIL test3 got ${output}"
exit 1 status=1
fi fi
fi fi
# test4: tests signal handlers
GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4
binpush libgo4.$libext
$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl
binpush testp4
output=$(run ./testp4 ./libgo4.$libext 2>&1)
if test "$output" != "PASS"; then
echo "FAIL test4 got ${output}"
if test "$goos" != "android"; then
echo "re-running test4 in verbose mode"
./testp4 ./libgo4.$libext verbose
fi
status=1
fi
# test5: tests signal handlers with os/signal.Notify
GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5
binpush libgo5.$libext
$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl
binpush testp5
output=$(run ./testp5 ./libgo5.$libext 2>&1)
if test "$output" != "PASS"; then
echo "FAIL test5 got ${output}"
if test "$goos" != "android"; then
echo "re-running test5 in verbose mode"
./testp5 ./libgo5.$libext verbose
fi
status=1
fi
if test $status = 0; then
echo "ok" echo "ok"
fi
exit $status

View file

@ -5,13 +5,14 @@
package main 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. // Yes, you can have definitions if you use //export, as long as they are weak.
int f(void) __attribute__ ((weak)); int f(void) __attribute__ ((weak));
int f() { int f() {
int *p = GoFn(); int i;
int *p = GoFn(&i);
if (*p != 12345) if (*p != 12345)
return 0; return 0;
return 1; return 1;
@ -20,9 +21,9 @@ int f() {
import "C" import "C"
//export GoFn //export GoFn
func GoFn() *C.int { func GoFn(p *C.int) *C.int {
i := C.int(12345) *p = C.int(12345)
return &i return p
} }
func main() { 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/') ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
minor=$(echo $ver | sed -e 's/[0-9]*\.\([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 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" echo "skipping msan test; clang version $major.$minor (older than 3.6)"
exit 0 exit 0
fi 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 fi
status=0 status=0
@ -47,7 +61,12 @@ if ! go run -msan msan.go; then
status=1 status=1
fi 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" echo "FAIL: msan2"
status=1 status=1
fi fi

View file

@ -285,23 +285,23 @@ func readNotes(f *elf.File) ([]*note, error) {
if err == io.EOF { if err == io.EOF {
break 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) err = binary.Read(r, f.ByteOrder, &descsize)
if err != nil { 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) err = binary.Read(r, f.ByteOrder, &tag)
if err != nil { 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) name, err := readwithpad(r, namesize)
if err != nil { 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) desc, err := readwithpad(r, descsize)
if err != nil { 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}) notes = append(notes, &note{name: string(name), tag: tag, desc: string(desc), section: sect})
} }

View file

@ -7,9 +7,14 @@ package main
import "fmt" import "fmt"
/* /*
#cgo CFLAGS: -pthread
#cgo LDFLAGS: -pthread
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <pthread.h>
int *p; int *p;
static void sigsegv() { static void sigsegv() {
@ -18,16 +23,65 @@ static void sigsegv() {
exit(2); exit(2);
} }
static void sighandler(int signum) { static void segvhandler(int signum) {
if (signum == SIGSEGV) { if (signum == SIGSEGV) {
exit(0); // success 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) { static void __attribute__ ((constructor)) sigsetup(void) {
struct sigaction act; 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" import "C"

View file

@ -327,3 +327,14 @@ func toASCII(s string) string {
} }
return buf.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."}, {"readme.txt", "This archive contains some text files."},
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"}, {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling licence."}, {"todo.txt", "Get animal handling license."},
} }
for _, file := range files { for _, file := range files {
hdr := &tar.Header{ hdr := &tar.Header{
@ -76,5 +76,5 @@ func Example() {
// Geoffrey // Geoffrey
// Gonzo // Gonzo
// Contents of todo.txt: // 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 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 // A numBytesReader is an io.Reader with a numBytes method, returning the number
// of bytes remaining in the underlying encoded data. // of bytes remaining in the underlying encoded data.
type numBytesReader interface { type numBytesReader interface {
@ -113,39 +117,66 @@ func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
// //
// io.EOF is returned at the end of the input. // io.EOF is returned at the end of the input.
func (tr *Reader) Next() (*Header, error) { func (tr *Reader) Next() (*Header, error) {
var hdr *Header
if tr.err == nil {
tr.skipUnread()
}
if tr.err != nil { if tr.err != nil {
return hdr, tr.err return nil, tr.err
} }
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() hdr = tr.readHeader()
if hdr == nil { if tr.err != nil {
return hdr, tr.err return nil, tr.err
} }
// Check for PAX/GNU header.
// Check for PAX/GNU special headers and files.
switch hdr.Typeflag { switch hdr.Typeflag {
case TypeXHeader: case TypeXHeader:
// PAX extended header extHdrs, tr.err = parsePAX(tr)
headers, err := parsePAX(tr)
if err != nil {
return nil, err
}
// We actually read the whole file,
// but this skips alignment padding
tr.skipUnread()
if tr.err != nil { if tr.err != nil {
return nil, tr.err return nil, tr.err
} }
hdr = tr.readHeader() continue loop // This is a meta header affecting the next header
if hdr == nil { case TypeGNULongName, TypeGNULongLink:
var realname []byte
realname, tr.err = ioutil.ReadAll(tr)
if tr.err != nil {
return nil, tr.err return nil, tr.err
} }
mergePAX(hdr, headers)
// 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 // Check for a PAX format sparse file
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers) sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
if err != nil { if err != nil {
tr.err = err tr.err = err
return nil, err return nil, err
@ -158,33 +189,10 @@ func (tr *Reader) Next() (*Header, error) {
return nil, tr.err return nil, tr.err
} }
} }
break loop // This is a file, so stop
}
}
return hdr, nil 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
} }
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then // 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 { if err != nil {
return nil, err return nil, err
} }
sbuf := string(buf)
// For GNU PAX sparse format 0.0 support. // For GNU PAX sparse format 0.0 support.
// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers. // 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) headers := make(map[string]string)
// Each record is constructed as // Each record is constructed as
// "%d %s=%s\n", length, keyword, value // "%d %s=%s\n", length, keyword, value
for len(buf) > 0 { for len(sbuf) > 0 {
// or the header was empty to start with. key, value, residual, err := parsePAXRecord(sbuf)
var sp int if err != nil {
// The size field ends at the first space.
sp = bytes.IndexByte(buf, ' ')
if sp == -1 {
return nil, ErrHeader return nil, ErrHeader
} }
// Parse the first token as a decimal integer. sbuf = residual
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:]
keyStr := string(key) keyStr := string(key)
if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes { if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map. // 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{','}) sparseMap.Write([]byte{','})
} else { } else {
// Normal key. Set the value in the headers map. // 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 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. // 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 n := 0
for n < len(b) && b[n] != 0 { for n < len(b) && b[n] != 0 {
n++ n++
@ -416,19 +440,51 @@ func cString(b []byte) string {
return string(b[0:n]) return string(b[0:n])
} }
func (tr *Reader) octal(b []byte) int64 { // parseNumeric parses the input as being encoded in either base-256 or octal.
// Check for binary format first. // 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 { if len(b) > 0 && b[0]&0x80 != 0 {
var x int64 // Handling negative numbers relies on the following identity:
for i, c := range b { // -a-1 == ^a
if i == 0 { //
c &= 0x7f // ignore signal bit in first byte // If the number is negative, we use an inversion mask to invert the
} // data bytes and treat the value as an unsigned number.
x = x<<8 | int64(c) var inv byte // 0x00 if positive or zero, 0xff if negative
} if b[0]&0x40 != 0 {
return x inv = 0xff
} }
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 // Because unused fields are filled with NULs, we need
// to skip leading NULs. Fields may also be padded with // to skip leading NULs. Fields may also be padded with
// spaces or NULs. // spaces or NULs.
@ -439,9 +495,9 @@ func (tr *Reader) octal(b []byte) int64 {
if len(b) == 0 { if len(b) == 0 {
return 0 return 0
} }
x, err := strconv.ParseUint(cString(b), 8, 64) x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
if err != nil { if perr != nil {
tr.err = err p.err = ErrHeader
} }
return int64(x) return int64(x)
} }
@ -492,9 +548,10 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
return false return false
} }
given := tr.octal(header[148:156]) var p parser
given := p.parseOctal(header[148:156])
unsigned, signed := checksum(header) 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 // readHeader reads the next block header and assumes that the underlying reader
@ -531,22 +588,19 @@ func (tr *Reader) readHeader() *Header {
} }
// Unpack // Unpack
var p parser
hdr := new(Header) hdr := new(Header)
s := slicer(header) s := slicer(header)
hdr.Name = cString(s.next(100)) hdr.Name = p.parseString(s.next(100))
hdr.Mode = tr.octal(s.next(8)) hdr.Mode = p.parseNumeric(s.next(8))
hdr.Uid = int(tr.octal(s.next(8))) hdr.Uid = int(p.parseNumeric(s.next(8)))
hdr.Gid = int(tr.octal(s.next(8))) hdr.Gid = int(p.parseNumeric(s.next(8)))
hdr.Size = tr.octal(s.next(12)) hdr.Size = p.parseNumeric(s.next(12))
if hdr.Size < 0 { hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
tr.err = ErrHeader
return nil
}
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
s.next(8) // chksum s.next(8) // chksum
hdr.Typeflag = s.next(1)[0] 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 remainder of the header depends on the value of magic.
// The original (v7) version of tar had no explicit magic field, // The original (v7) version of tar had no explicit magic field,
@ -566,45 +620,54 @@ func (tr *Reader) readHeader() *Header {
switch format { switch format {
case "posix", "gnu", "star": case "posix", "gnu", "star":
hdr.Uname = cString(s.next(32)) hdr.Uname = p.parseString(s.next(32))
hdr.Gname = cString(s.next(32)) hdr.Gname = p.parseString(s.next(32))
devmajor := s.next(8) devmajor := s.next(8)
devminor := s.next(8) devminor := s.next(8)
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock { if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
hdr.Devmajor = tr.octal(devmajor) hdr.Devmajor = p.parseNumeric(devmajor)
hdr.Devminor = tr.octal(devminor) hdr.Devminor = p.parseNumeric(devminor)
} }
var prefix string var prefix string
switch format { switch format {
case "posix", "gnu": case "posix", "gnu":
prefix = cString(s.next(155)) prefix = p.parseString(s.next(155))
case "star": case "star":
prefix = cString(s.next(131)) prefix = p.parseString(s.next(131))
hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0) hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0) hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
} }
if len(prefix) > 0 { if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name 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 tr.err = ErrHeader
return nil 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. // Set the current file reader.
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
tr.curr = &regFileReader{r: tr.r, nb: nb} tr.curr = &regFileReader{r: tr.r, nb: nb}
// Check for old GNU sparse format entry. // Check for old GNU sparse format entry.
if hdr.Typeflag == TypeGNUSparse { if hdr.Typeflag == TypeGNUSparse {
// Get the real size of the file. // 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. // Read the sparse map.
sp := tr.readOldGNUSparseMap(header) 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, // 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. // then one or more extension headers are used to store the rest of the sparse map.
func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
var p parser
isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0 isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
spCap := oldGNUSparseMainHeaderNumEntries spCap := oldGNUSparseMainHeaderNumEntries
if isExtended { if isExtended {
@ -636,10 +700,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
// Read the four entries from the main tar header // Read the four entries from the main tar header
for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ { for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
offset := tr.octal(s.next(oldGNUSparseOffsetSize)) offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
if tr.err != nil { if p.err != nil {
tr.err = ErrHeader tr.err = p.err
return nil return nil
} }
if offset == 0 && numBytes == 0 { if offset == 0 && numBytes == 0 {
@ -657,10 +721,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0 isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
s = slicer(sparseHeader) s = slicer(sparseHeader)
for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ { for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
offset := tr.octal(s.next(oldGNUSparseOffsetSize)) offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
if tr.err != nil { if p.err != nil {
tr.err = ErrHeader tr.err = p.err
return nil return nil
} }
if offset == 0 && numBytes == 0 { if offset == 0 && numBytes == 0 {
@ -672,85 +736,77 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
return sp return sp
} }
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0. // readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
// The sparse map is stored just before the file data and padded out to the nearest block boundary. // 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) { func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
buf := make([]byte, 2*blockSize) var cntNewline int64
sparseHeader := buf[:blockSize] var buf bytes.Buffer
var blk = make([]byte, blockSize)
// readDecimal is a helper function to read a decimal integer from the sparse map // feedTokens copies data in numBlock chunks from r into buf until there are
// while making sure to read from the file in blocks of size blockSize // at least cnt newlines in buf. It will not read more blocks than needed.
readDecimal := func() (int64, error) { var feedTokens = func(cnt int64) error {
// Look for newline for cntNewline < cnt {
nl := bytes.IndexByte(sparseHeader, '\n') if _, err := io.ReadFull(r, blk); err != nil {
if nl == -1 { if err == io.EOF {
if len(sparseHeader) >= blockSize { err = io.ErrUnexpectedEOF
// This is an error
return 0, ErrHeader
} }
oldLen := len(sparseHeader) return err
newLen := oldLen + blockSize }
if cap(sparseHeader) < newLen { buf.Write(blk)
// There's more header, but we need to make room for the next block for _, c := range blk {
copy(buf, sparseHeader) if c == '\n' {
sparseHeader = buf[:newLen] cntNewline++
} else { }
// There's more header, and we can just reslice }
sparseHeader = sparseHeader[:newLen] }
return nil
} }
// Now that sparseHeader is large enough, read next block // nextToken gets the next token delimited by a newline. This assumes that
if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil { // at least one newline exists in the buffer.
return 0, err var nextToken = func() string {
cntNewline--
tok, _ := buf.ReadString('\n')
return tok[:len(tok)-1] // Cut off newline
} }
// Look for a newline in the new data // Parse for the number of entries.
nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n') // Use integer overflow resistant math to check this.
if nl == -1 { if err := feedTokens(1); err != nil {
// This is an error
return 0, ErrHeader
}
nl += oldLen // We want the position from the beginning
}
// Now that we've found a newline, read a number
n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
if err != nil {
return 0, ErrHeader
}
// Update sparseHeader to consume this number
sparseHeader = sparseHeader[nl+1:]
return n, nil
}
// Read the first block
if _, err := io.ReadFull(r, sparseHeader); err != nil {
return nil, err return nil, err
} }
numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
// The first line contains the number of entries if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
numEntries, err := readDecimal() return nil, ErrHeader
if err != nil {
return nil, err
} }
// 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) sp := make([]sparseEntry, 0, numEntries)
for i := int64(0); i < numEntries; i++ { for i := int64(0); i < numEntries; i++ {
// Read the offset offset, err := strconv.ParseInt(nextToken(), 10, 64)
offset, err := readDecimal()
if err != nil { if err != nil {
return nil, err return nil, ErrHeader
} }
// Read numBytes numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
numBytes, err := readDecimal()
if err != nil { if err != nil {
return nil, err return nil, ErrHeader
} }
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
} }
return sp, nil return sp, nil
} }
@ -801,6 +857,10 @@ func (tr *Reader) numBytes() int64 {
// Read reads from the current entry in the tar archive. // Read reads from the current entry in the tar archive.
// It returns 0, io.EOF when it reaches the end of that entry, // It returns 0, io.EOF when it reaches the end of that entry,
// until Next is called to advance to the next 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) { func (tr *Reader) Read(b []byte) (n int, err error) {
if tr.err != nil { if tr.err != nil {
return 0, tr.err 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", file: "testdata/neg-size.tar",
err: ErrHeader, err: ErrHeader,
@ -298,17 +322,11 @@ var untarTests = []*untarTest{
}, },
{ {
file: "testdata/issue11169.tar", file: "testdata/issue11169.tar",
// TODO(dsnet): Currently the library does not detect that this file is err: ErrHeader,
// malformed. Instead it incorrectly believes that file just ends.
// At least the library doesn't crash anymore.
// err: ErrHeader,
}, },
{ {
file: "testdata/issue12435.tar", file: "testdata/issue12435.tar",
// TODO(dsnet): Currently the library does not detect that this file is err: ErrHeader,
// malformed. Instead, it incorrectly believes that file just ends.
// At least the library doesn't crash anymore.
// err: ErrHeader,
}, },
} }
@ -727,35 +745,82 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
} }
func TestReadGNUSparseMap1x0(t *testing.T) { func TestReadGNUSparseMap1x0(t *testing.T) {
// This test uses lots of holes so the sparse header takes up more than two blocks var sp = []sparseEntry{{1, 2}, {3, 4}}
numEntries := 100 for i := 0; i < 98; i++ {
expected := make([]sparseEntry, 0, numEntries) sp = append(sp, sparseEntry{54321, 12345})
sparseMap := new(bytes.Buffer)
fmt.Fprintf(sparseMap, "%d\n", numEntries)
for i := 0; i < numEntries; i++ {
offset := int64(2048 * i)
numBytes := int64(1024)
expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
} }
// Make the header the smallest multiple of blockSize that fits the sparseMap var vectors = []struct {
headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize input string // Input data
bufLen := blockSize * headerBlocks sparseMap []sparseEntry // Expected sparse entries to be outputted
buf := make([]byte, bufLen) cnt int // Expected number of bytes read
copy(buf, sparseMap.Bytes()) 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 for i, v := range vectors {
r := bytes.NewReader(buf) r := strings.NewReader(v.input)
// Read the sparse map
sp, err := readGNUSparseMap1x0(r) sp, err := readGNUSparseMap1x0(r)
if err != nil { if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
t.Errorf("Unexpected error: %v", err) t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap)
}
if numBytes := len(v.input) - r.Len(); numBytes != v.cnt {
t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt)
}
if err != v.err {
t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
} }
if !reflect.DeepEqual(sp, expected) {
t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
} }
} }
@ -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 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. // NewWriter creates a new Writer writing to w.
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} } func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
@ -68,17 +72,9 @@ func (tw *Writer) Flush() error {
} }
// Write s into b, terminating it with a NUL if there is room. // 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 (f *formatter) formatString(b []byte, s string) {
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
}
if len(s) > len(b) { if len(s) > len(b) {
if tw.err == nil { f.err = ErrFieldTooLong
tw.err = ErrFieldTooLong
}
return return
} }
ascii := toASCII(s) 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. // 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) s := strconv.FormatInt(x, 8)
// leading zeros, but leave room for a NUL. // leading zeros, but leave room for a NUL.
for len(s)+1 < len(b) { for len(s)+1 < len(b) {
s = "0" + s 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). // fitsInBase256 reports whether x can be encoded into n bytes using base-256
// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead // encoding. Unlike octal encoding, base-256 encoding does not require that the
func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) { // string ends with a NUL character. Thus, all n bytes are available for output.
// Try octal first. //
s := strconv.FormatInt(x, 8) // If operating in binary mode, this assumes strict GNU binary mode; which means
if len(s) < len(b) { // that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
tw.octal(b, x) // equivalent to the sign bit in two's complement form.
return func fitsInBase256(n int, x int64) bool {
var binBits = uint(n-1) * 8
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
} }
// If it is too long for octal, and pax is preferred, use a pax header // Write x into b, as binary (GNUtar/star extension).
if allowPax && tw.preferPax { func (f *formatter) formatNumeric(b []byte, x int64) {
tw.octal(b, 0) if fitsInBase256(len(b), x) {
s := strconv.FormatInt(x, 10) for i := len(b) - 1; i >= 0; i-- {
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) b[i] = byte(x)
x >>= 8 x >>= 8
} }
b[0] |= 0x80 // highest bit indicates binary format b[0] |= 0x80 // Highest bit indicates binary format
return
}
f.formatOctal(b, 0) // Last resort, just write zero
f.err = ErrFieldTooLong
} }
var ( var (
@ -161,6 +157,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
// subsecond time resolution, but for now let's just capture // subsecond time resolution, but for now let's just capture
// too long fields or non ascii characters // too long fields or non ascii characters
var f formatter
var header []byte var header []byte
// We need to select which scratch buffer to use carefully, // 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) copy(header, zeroBlock)
s := slicer(header) 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 // 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) pathHeaderBytes := s.next(fileNameSize)
tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders) formatString(pathHeaderBytes, hdr.Name, paxPath)
// Handle out of range ModTime carefully. // Handle out of range ModTime carefully.
var modTime int64 var modTime int64
@ -186,25 +213,25 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
modTime = hdr.ModTime.Unix() modTime = hdr.ModTime.Unix()
} }
tw.octal(s.next(8), hdr.Mode) // 100:108 f.formatOctal(s.next(8), hdr.Mode) // 100:108
tw.numeric(s.next(8), int64(hdr.Uid), true, paxUid, paxHeaders) // 108:116 formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124 formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders) // 124:136 formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
tw.numeric(s.next(12), modTime, false, paxNone, nil) // 136:148 --- consider using pax for finer granularity formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity
s.next(8) // chksum (148:156) s.next(8) // chksum (148:156)
s.next(1)[0] = hdr.Typeflag // 156:157 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 copy(s.next(8), []byte("ustar\x0000")) // 257:265
tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297 formatString(s.next(32), hdr.Uname, paxUname) // 265:297
tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329 formatString(s.next(32), hdr.Gname, paxGname) // 297:329
tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil) // 329:337 formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil) // 337:345 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 // 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) 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. // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary { if tw.usedBinary {
@ -220,19 +247,20 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
delete(paxHeaders, paxPath) delete(paxHeaders, paxPath)
// Update the path fields // Update the path fields
tw.cString(pathHeaderBytes, suffix, false, paxNone, nil) formatString(pathHeaderBytes, suffix, paxNone)
tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil) formatString(prefixHeaderBytes, prefix, paxNone)
} }
} }
// The chksum field is terminated by a NUL and a space. // The chksum field is terminated by a NUL and a space.
// This is different from the other octal fields. // This is different from the other octal fields.
chksum, _ := checksum(header) chksum, _ := checksum(header)
tw.octal(header[148:155], chksum) f.formatOctal(header[148:155], chksum) // Never fails
header[155] = ' ' header[155] = ' '
if tw.err != nil { // Check if there were any formatting errors.
// problem with header; probably integer too big for a field. if f.err != nil {
tw.err = f.err
return tw.err return tw.err
} }
@ -310,7 +338,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
sort.Strings(keys) sort.Strings(keys)
for _, k := range 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())) ext.Size = int64(len(buf.Bytes()))
@ -326,17 +354,18 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
return nil return nil
} }
// paxHeader formats a single pax record, prefixing it with the appropriate length // formatPAXRecord formats a single PAX record, prefixing it with the
func paxHeader(msg string) string { // appropriate length.
const padding = 2 // Extra padding for space and newline func formatPAXRecord(k, v string) string {
size := len(msg) + padding const padding = 3 // Extra padding for ' ', '=', and '\n'
size := len(k) + len(v) + padding
size += len(strconv.Itoa(size)) 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 { if len(record) != size {
// Final adjustment if adding size increased
// the number of digits in size
size = len(record) size = len(record)
record = fmt.Sprintf("%d %s\n", size, msg) record = fmt.Sprintf("%d %s=%s\n", size, k, v)
} }
return record return record
} }

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"math"
"os" "os"
"reflect" "reflect"
"sort" "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) { func TestUSTARLongName(t *testing.T) {
// Create an archive with a path that failed to split with USTAR extension in previous versions. // Create an archive with a path that failed to split with USTAR extension in previous versions.
fileinfo, err := os.Stat("testdata/small.txt") 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 ( import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"compress/flate"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -73,3 +74,31 @@ func ExampleReader() {
// Contents of README: // Contents of README:
// This is the source code repository for the Go programming language. // 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

@ -25,6 +25,7 @@ type Reader struct {
r io.ReaderAt r io.ReaderAt
File []*File File []*File
Comment string Comment string
decompressors map[uint16]Decompressor
} }
type ReadCloser struct { type ReadCloser struct {
@ -34,6 +35,7 @@ type ReadCloser struct {
type File struct { type File struct {
FileHeader FileHeader
zip *Reader
zipr io.ReaderAt zipr io.ReaderAt
zipsize int64 zipsize int64
headerOffset 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 // a bad one, and then only report a ErrFormat or UnexpectedEOF if
// the file count modulo 65536 is incorrect. // the file count modulo 65536 is incorrect.
for { for {
f := &File{zipr: r, zipsize: size} f := &File{zip: z, zipr: r, zipsize: size}
err = readDirectoryHeader(f, buf) err = readDirectoryHeader(f, buf)
if err == ErrFormat || err == io.ErrUnexpectedEOF { if err == ErrFormat || err == io.ErrUnexpectedEOF {
break break
@ -113,6 +115,26 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
return nil 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. // Close closes the Zip file, rendering it unusable for I/O.
func (rc *ReadCloser) Close() error { func (rc *ReadCloser) Close() error {
return rc.f.Close() return rc.f.Close()
@ -140,7 +162,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
} }
size := int64(f.CompressedSize64) size := int64(f.CompressedSize64)
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size) r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
dcomp := decompressor(f.Method) dcomp := f.zip.decompressor(f.Method)
if dcomp == nil { if dcomp == nil {
err = ErrAlgorithm err = ErrAlgorithm
return return
@ -261,39 +283,59 @@ func readDirectoryHeader(f *File, r io.Reader) error {
f.Extra = d[filenameLen : filenameLen+extraLen] f.Extra = d[filenameLen : filenameLen+extraLen]
f.Comment = string(d[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 { 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) b := readBuf(f.Extra)
for len(b) >= 4 { // need at least tag and size for len(b) >= 4 { // need at least tag and size
tag := b.uint16() tag := b.uint16()
size := b.uint16() size := b.uint16()
if int(size) > len(b) { if int(size) > len(b) {
return ErrFormat break
} }
if tag == zip64ExtraId { 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]) eb := readBuf(b[:size])
if len(eb) >= 8 {
if needUSize {
needUSize = false
if len(eb) < 8 {
return ErrFormat
}
f.UncompressedSize64 = eb.uint64() f.UncompressedSize64 = eb.uint64()
} }
if len(eb) >= 8 { if needCSize {
needCSize = false
if len(eb) < 8 {
return ErrFormat
}
f.CompressedSize64 = eb.uint64() f.CompressedSize64 = eb.uint64()
} }
if len(eb) >= 8 { if needHeaderOffset {
needHeaderOffset = false
if len(eb) < 8 {
return ErrFormat
}
f.headerOffset = int64(eb.uint64()) f.headerOffset = int64(eb.uint64())
} }
break
} }
b = b[size:] 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 if needUSize || needCSize || needHeaderOffset {
// too. See golang.org/issue/8186.
for _, v := range b {
if v != 0 {
return ErrFormat return ErrFormat
} }
}
}
return nil 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 // isZip64 reports whether the file size exceeds the 32 bit limit
func (fh *FileHeader) isZip64() bool { 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) { func msdosModeToFileMode(m uint32) (mode os.FileMode) {

View file

@ -14,7 +14,6 @@ import (
) )
// TODO(adg): support zip file comments // TODO(adg): support zip file comments
// TODO(adg): support specifying deflate level
// Writer implements a zip file writer. // Writer implements a zip file writer.
type Writer struct { type Writer struct {
@ -22,6 +21,7 @@ type Writer struct {
dir []*header dir []*header
last *fileWriter last *fileWriter
closed bool closed bool
compressors map[uint16]Compressor
} }
type header struct { type header struct {
@ -78,7 +78,7 @@ func (w *Writer) Close() error {
b.uint16(h.ModifiedTime) b.uint16(h.ModifiedTime)
b.uint16(h.ModifiedDate) b.uint16(h.ModifiedDate)
b.uint32(h.CRC32) 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 // the file needs a zip64 header. store maxint in both
// 32 bit size fields (and offset later) to signal that the // 32 bit size fields (and offset later) to signal that the
// zip64 extra header should be used. // zip64 extra header should be used.
@ -220,7 +220,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
compCount: &countWriter{w: w.cw}, compCount: &countWriter{w: w.cw},
crc32: crc32.NewIEEE(), crc32: crc32.NewIEEE(),
} }
comp := compressor(fh.Method) comp := w.compressor(fh.Method)
if comp == nil { if comp == nil {
return nil, ErrAlgorithm return nil, ErrAlgorithm
} }
@ -270,6 +270,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
return err 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 { type fileWriter struct {
*header *header
zipw io.Writer zipw io.Writer

View file

@ -10,6 +10,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"hash" "hash"
"internal/testenv"
"io" "io"
"io/ioutil" "io/ioutil"
"sort" "sort"
@ -19,6 +20,9 @@ import (
) )
func TestOver65kFiles(t *testing.T) { func TestOver65kFiles(t *testing.T) {
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
w := NewWriter(buf) w := NewWriter(buf)
const nFiles = (1 << 16) + 42 const nFiles = (1 << 16) + 42
@ -233,10 +237,24 @@ func TestZip64(t *testing.T) {
testZip64DirectoryRecordLength(buf, 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 { func testZip64(t testing.TB, size int64) *rleBuffer {
const chunkSize = 1024 const chunkSize = 1024
chunks := int(size / chunkSize) 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) buf := new(rleBuffer)
w := NewWriter(buf) w := NewWriter(buf)
f, err := w.CreateHeader(&FileHeader{ f, err := w.CreateHeader(&FileHeader{
@ -257,6 +275,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
t.Fatal("write chunk:", err) 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") end := []byte("END\n")
_, err = f.Write(end) _, err = f.Write(end)
if err != nil { if err != nil {
@ -283,6 +307,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
t.Fatal("read:", err) 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) gotEnd, err := ioutil.ReadAll(rc)
if err != nil { if err != nil {
t.Fatal("read end:", err) t.Fatal("read end:", err)
@ -294,14 +324,14 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
if err != nil { if err != nil {
t.Fatal("closing:", err) 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 { 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 { 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 return buf
@ -373,9 +403,14 @@ func testValidHeader(h *FileHeader, t *testing.T) {
} }
b := buf.Bytes() 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) 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. // Issue 4302.
@ -388,20 +423,29 @@ func TestHeaderInvalidTagAndSize(t *testing.T) {
h := FileHeader{ h := FileHeader{
Name: filename, Name: filename,
Method: Deflate, 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) h.SetModTime(ts)
testInvalidHeader(&h, t) testValidHeader(&h, t)
} }
func TestHeaderTooShort(t *testing.T) { func TestHeaderTooShort(t *testing.T) {
h := FileHeader{ h := FileHeader{
Name: "foo.txt", Name: "foo.txt",
Method: Deflate, 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 // 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. // Read reads data into p.
// It returns the number of bytes read 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). // hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF. // At EOF, the count will be zero and err will be io.EOF.
func (b *Reader) Read(p []byte) (n int, err error) { 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. // ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large") var ErrTooLarge = errors.New("bytes.Buffer: too large")
// Bytes returns a slice of the contents of the unread portion of the buffer; // Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the // The slice is valid for use only until the next buffer modification (that is,
// returned slice, the contents of the buffer will change provided there // only until the next call to a method like Read, Write, Reset, or Truncate).
// are no intervening method calls on the Buffer. // 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:] } func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
// String returns the contents of the unread portion of the buffer // 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. // total space allocated for the buffer's data.
func (b *Buffer) Cap() int { return cap(b.buf) } 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. // It panics if n is negative or greater than the length of the buffer.
func (b *Buffer) Truncate(n int) { func (b *Buffer) Truncate(n int) {
b.lastRead = opInvalid b.lastRead = opInvalid
@ -74,8 +76,9 @@ func (b *Buffer) Truncate(n int) {
b.buf = b.buf[0 : b.off+n] b.buf = b.buf[0 : b.off+n]
} }
// Reset resets the buffer so it has no content. // Reset resets the buffer to be empty,
// b.Reset() is the same as b.Truncate(0). // 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) } func (b *Buffer) Reset() { b.Truncate(0) }
// grow grows the buffer to guarantee space for n more bytes. // 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) { switch obj := obj.(type) {
case *types.Const: case *types.Const:
w.emitf("const %s %s", obj.Name(), w.typeString(obj.Type())) 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: case *types.Var:
w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type())) w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type()))
case *types.TypeName: case *types.TypeName:

View file

@ -26,7 +26,7 @@ func main() {
} }
out, err := exec.Command("go", "tool", "api", 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"), "-next", file("next"),
"-except", file("except")).CombinedOutput() "-except", file("except")).CombinedOutput()
if err != nil { if err != nil {

View file

@ -10,7 +10,7 @@ pkg p1, const ConstChase2 = 11
pkg p1, const ConstChase2 ideal-int pkg p1, const ConstChase2 ideal-int
pkg p1, const ConversionConst = 5 pkg p1, const ConversionConst = 5
pkg p1, const ConversionConst MyInt 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 FloatConst ideal-float
pkg p1, const StrConst = "foo" pkg p1, const StrConst = "foo"
pkg p1, const StrConst ideal-string 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 { 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 { func archX86(linkArch *obj.LinkArch) *Arch {

View file

@ -36,6 +36,9 @@ func init() {
type MultiFlag []string type MultiFlag []string
func (m *MultiFlag) String() string { func (m *MultiFlag) String() string {
if len(*m) == 0 {
return ""
}
return fmt.Sprint(*m) 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.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long), 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 type void* is represented by Go's unsafe.Pointer.
The C types __int128_t and __uint128_t are represented by [16]byte. 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 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 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 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 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, 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. 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 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 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 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 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 must preserve the property that the Go memory to which it points does
not contain any Go pointers. not contain any Go pointers.
These rules are partially enforced by cgo by default. It is possible Go code may not store a Go pointer in C memory. C code may store Go
to defeat this enforcement by using the unsafe package, and of course pointers in C memory, subject to the rule above: it must stop storing
there is nothing stopping the C code from doing anything it likes. the Go pointer when the C function returns.
However, programs that break these rules are likely to fail in
unexpected and unpredictable ways. 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 Using cgo directly

View file

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

View file

@ -103,6 +103,7 @@ func (p *Package) writeDefs() {
} }
if *gccgo { if *gccgo {
fmt.Fprint(fgo2, gccgoGoProlog)
fmt.Fprint(fc, p.cPrologGccgo()) fmt.Fprint(fc, p.cPrologGccgo())
} else { } else {
fmt.Fprint(fgo2, goProlog) fmt.Fprint(fgo2, goProlog)
@ -811,12 +812,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
} }
fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by gc. // Build the wrapper function compiled by cmd/compile.
goname := exp.Func.Name.Name goname := "_cgoexpwrap" + cPrefix + "_"
if fn.Recv != nil { 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: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:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
@ -829,15 +831,25 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
// Calling a function with a receiver from C requires // This code uses printer.Fprint, not conf.Fprint,
// a Go wrapper function. // 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 { if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname) fmt.Fprintf(fgo2, "recv ")
conf.Fprint(fgo2, fset, fn.Recv.List[0].Type) printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
comma = true
}
forFieldList(fntype.Params, forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) { func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgo2, ", p%d ", i) if comma {
conf.Fprint(fgo2, fset, atype) fmt.Fprintf(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d ", i)
printer.Fprint(fgo2, fset, atype)
comma = true
}) })
fmt.Fprintf(fgo2, ")") fmt.Fprintf(fgo2, ")")
if gccResult != "void" { if gccResult != "void" {
@ -847,16 +859,38 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
if i > 0 { if i > 0 {
fmt.Fprint(fgo2, ", ") fmt.Fprint(fgo2, ", ")
} }
conf.Fprint(fgo2, fset, atype) fmt.Fprintf(fgo2, "r%d ", i)
printer.Fprint(fgo2, fset, atype)
}) })
fmt.Fprint(fgo2, ")") fmt.Fprint(fgo2, ")")
} }
fmt.Fprint(fgo2, " {\n") fmt.Fprint(fgo2, " {\n")
if gccResult == "void" {
fmt.Fprint(fgo2, "\t") fmt.Fprint(fgo2, "\t")
if gccResult != "void" { } else {
fmt.Fprint(fgo2, "return ") // 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
} }
fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name) 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, forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) { func(i int, aname string, atype ast.Expr) {
if i > 0 { if i > 0 {
@ -867,7 +901,6 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprint(fgo2, ")\n") fmt.Fprint(fgo2, ")\n")
fmt.Fprint(fgo2, "}\n") fmt.Fprint(fgo2, "}\n")
} }
}
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
} }
@ -1251,6 +1284,15 @@ func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer //go:linkname _cgoCheckPointer runtime.cgoCheckPointer
func _cgoCheckPointer(interface{}, ...interface{}) interface{} 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 = ` const goStringDef = `
@ -1305,7 +1347,8 @@ var builtinDefs = map[string]string{
} }
func (p *Package) cPrologGccgo() 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 = ` const cPrologGccgo = `
@ -1360,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
runtime_throw("runtime: C malloc failed"); runtime_throw("runtime: C malloc failed");
return p; 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 { func (p *Package) gccExportHeaderProlog() string {
@ -1385,8 +1461,8 @@ typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr; typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32; typedef float GoFloat32;
typedef double GoFloat64; typedef double GoFloat64;
typedef __complex float GoComplex64; typedef float _Complex GoComplex64;
typedef __complex double GoComplex128; typedef double _Complex GoComplex128;
/* /*
static assertion to make sure the file is being used on architecture 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 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 *GoMap;
typedef void *GoChan; typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface; 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) gc.Cgenr(nl, &n1, res)
var n2 gc.Node var n2 gc.Node
gc.Cgenr(nr, &n2, nil) gc.Cgenr(nr, &n2, nil)
var ax gc.Node var ax, oldax, dx, olddx gc.Node
gc.Nodreg(&ax, t, x86.REG_AX) 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) gmove(&n1, &ax)
gins(a, &n2, nil) gins(a, &n2, nil)
gc.Regfree(&n2) gc.Regfree(&n2)
gc.Regfree(&n1) gc.Regfree(&n1)
var dx gc.Node
if t.Width == 1 { if t.Width == 1 {
// byte multiply behaves differently. // byte multiply behaves differently.
gc.Nodreg(&ax, t, x86.REG_AH) var byteAH, byteDX gc.Node
gc.Nodreg(&byteAH, t, x86.REG_AH)
gc.Nodreg(&dx, t, x86.REG_DX) gc.Nodreg(&byteDX, t, x86.REG_DX)
gmove(&ax, &dx) gmove(&byteAH, &byteDX)
} }
gc.Nodreg(&dx, t, x86.REG_DX)
gmove(&dx, res) 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, case obj.APCDATA,
obj.AFUNCDATA, obj.AFUNCDATA,
obj.AVARDEF, obj.AVARDEF,
obj.AVARKILL: obj.AVARKILL,
obj.AUSEFIELD:
return 0 return 0
} }
} }

View file

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

View file

@ -20,7 +20,7 @@
package big package big
// A decimal represents an unsigned floating-point number in decimal representation. // 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 // with the most-significant mantissa digit at index 0. For the zero decimal, the
// mantissa length and exponent are 0. // mantissa length and exponent are 0.
// The zero value for decimal represents a ready-to-use 0.0. // The zero value for decimal represents a ready-to-use 0.0.
@ -29,6 +29,14 @@ type decimal struct {
exp int // exponent 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. // 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. // A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
const maxShift = _W - 4 const maxShift = _W - 4
@ -72,7 +80,7 @@ func (x *decimal) init(m nat, shift int) {
} }
// Convert mantissa into decimal representation. // Convert mantissa into decimal representation.
s := m.decimalString() // TODO(gri) avoid string conversion here s := m.utoa(10)
n := len(s) n := len(s)
x.exp = n x.exp = n
// Trim trailing zeros; instead the exponent is tracking // 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. // shr implements x >> s, for s <= maxShift.
func shr(x *decimal, s uint) { func shr(x *decimal, s uint) {
// Division by 1<<s using shift-and-subtract algorithm. // 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. // rounding error is described by the Float's Accuracy.
type RoundingMode byte type RoundingMode byte
// The following rounding modes are supported. // These constants define supported rounding modes.
const ( const (
ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
ToNearestAway // == IEEE 754-2008 roundTiesToAway 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: // not require 0.5 <= |mant| < 1.0. Specifically:
// //
// mant := new(Float) // 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: // Special cases are:
// //
@ -1123,7 +1123,7 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) {
// Rat returns the rational number corresponding to x; // Rat returns the rational number corresponding to x;
// or nil if x is an infinity. // 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 // If a non-nil *Rat argument z is provided, Rat stores
// the result in z instead of allocating a new Rat. // the result in z instead of allocating a new Rat.
func (x *Float) Rat(z *Rat) (*Rat, Accuracy) { 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 // ebase**exp. Finally, mantissa normalization (shift left) requires
// a correcting multiplication by 2**(-shiftcount). Multiplications // a correcting multiplication by 2**(-shiftcount). Multiplications
// are commutative, so we can apply them in any order as long as there // 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 // is no loss of precision. We only have powers of 2 and 10, and
// track via separate exponents exp2 and exp10. // 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 // normalize mantissa and determine initial exponent contributions
var exp2 = int64(len(z.mant))*_W - fnorm(z.mant) exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
exp5 := int64(0)
// determine binary or decimal exponent contribution of decimal point // determine binary or decimal exponent contribution of decimal point
var exp10 int64
if fcount < 0 { if fcount < 0 {
// The mantissa has a "decimal" point ddd.dddd; and // The mantissa has a "decimal" point ddd.dddd; and
// -fcount is the number of digits to the right of '.'. // -fcount is the number of digits to the right of '.'.
// Adjust relevant exponent accodingly. // Adjust relevant exponent accodingly.
d := int64(fcount)
switch b { switch b {
case 16: case 10:
fcount *= 4 // hexadecimal digits are 4 bits each exp5 = d
fallthrough fallthrough // 10**e == 5**e * 2**e
case 2: case 2:
exp2 += int64(fcount) exp2 += d
default: // b == 10 case 16:
exp10 = int64(fcount) 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 // take actual exponent into account
if ebase == 2 { switch ebase {
case 10:
exp5 += exp
fallthrough
case 2:
exp2 += exp exp2 += exp
} else { // ebase == 10 default:
exp10 += exp panic("unexpected exponent base")
} }
// we don't need exp anymore // exp consumed - not needed anymore
// apply 2**exp2 // apply 2**exp2
if MinExp <= exp2 && exp2 <= MaxExp { 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 return
} }
if exp10 == 0 { if exp5 == 0 {
// no decimal exponent to consider // no decimal exponent contribution
z.round(0) z.round(0)
return 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? p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
if exp10 < 0 { if exp5 < 0 {
z.Quo(z, p.pow10(-exp10)) z.Quo(z, p.pow5(uint64(-exp5)))
} else { } else {
z.Mul(z, p.pow10(exp10)) z.Mul(z, p.pow5(uint64(exp5)))
} }
return return
} }
// These powers of 10 can be represented exactly as a float64. // These powers of 5 fit into a uint64.
var pow10tab = [...]float64{ //
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, // for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, // 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. // n must not be negative.
func (z *Float) pow10(n int64) *Float { func (z *Float) pow5(n uint64) *Float {
if n < 0 { const m = uint64(len(pow5tab) - 1)
panic("pow10 called with negative argument")
}
const m = int64(len(pow10tab) - 1)
if n <= m { if n <= m {
return z.SetFloat64(pow10tab[n]) return z.SetUint64(pow5tab[n])
} }
// n > m // n > m
z.SetFloat64(pow10tab[m]) z.SetUint64(pow5tab[m])
n -= m n -= m
// use more bits for f than for z // use more bits for f than for z
// TODO(gri) what is the right number? // 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 { for n > 0 {
if n&1 != 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 ( const (
below1e23 = 99999999999999974834176 below1e23 = 99999999999999974834176
above1e23 = 100000000000000008388608 above1e23 = 100000000000000008388608
@ -187,11 +189,11 @@ func TestFloat64Text(t *testing.T) {
{1, 'e', 5, "1.00000e+00"}, {1, 'e', 5, "1.00000e+00"},
{1, 'f', 5, "1.00000"}, {1, 'f', 5, "1.00000"},
{1, 'g', 5, "1"}, {1, 'g', 5, "1"},
// {1, 'g', -1, "1"}, {1, 'g', -1, "1"},
// {20, 'g', -1, "20"}, {20, 'g', -1, "20"},
// {1234567.8, 'g', -1, "1.2345678e+06"}, {1234567.8, 'g', -1, "1.2345678e+06"},
// {200000, 'g', -1, "200000"}, {200000, 'g', -1, "200000"},
// {2000000, 'g', -1, "2e+06"}, {2000000, 'g', -1, "2e+06"},
// g conversion and zero suppression // g conversion and zero suppression
{400, 'g', 2, "4e+02"}, {400, 'g', 2, "4e+02"},
@ -207,22 +209,22 @@ func TestFloat64Text(t *testing.T) {
{0, 'e', 5, "0.00000e+00"}, {0, 'e', 5, "0.00000e+00"},
{0, 'f', 5, "0.00000"}, {0, 'f', 5, "0.00000"},
{0, 'g', 5, "0"}, {0, 'g', 5, "0"},
// {0, 'g', -1, "0"}, {0, 'g', -1, "0"},
{-1, 'e', 5, "-1.00000e+00"}, {-1, 'e', 5, "-1.00000e+00"},
{-1, 'f', 5, "-1.00000"}, {-1, 'f', 5, "-1.00000"},
{-1, 'g', 5, "-1"}, {-1, 'g', 5, "-1"},
// {-1, 'g', -1, "-1"}, {-1, 'g', -1, "-1"},
{12, 'e', 5, "1.20000e+01"}, {12, 'e', 5, "1.20000e+01"},
{12, 'f', 5, "12.00000"}, {12, 'f', 5, "12.00000"},
{12, 'g', 5, "12"}, {12, 'g', 5, "12"},
// {12, 'g', -1, "12"}, {12, 'g', -1, "12"},
{123456700, 'e', 5, "1.23457e+08"}, {123456700, 'e', 5, "1.23457e+08"},
{123456700, 'f', 5, "123456700.00000"}, {123456700, 'f', 5, "123456700.00000"},
{123456700, 'g', 5, "1.2346e+08"}, {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, 'e', 5, "1.23450e+06"},
{1.2345e6, 'f', 5, "1234500.00000"}, {1.2345e6, 'f', 5, "1234500.00000"},
@ -232,36 +234,38 @@ func TestFloat64Text(t *testing.T) {
{1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
{1e23, 'g', 17, "9.9999999999999992e+22"}, {1e23, 'g', 17, "9.9999999999999992e+22"},
// {1e23, 'e', -1, "1e+23"}, {1e23, 'e', -1, "1e+23"},
// {1e23, 'f', -1, "100000000000000000000000"}, {1e23, 'f', -1, "100000000000000000000000"},
// {1e23, 'g', -1, "1e+23"}, {1e23, 'g', -1, "1e+23"},
{below1e23, 'e', 17, "9.99999999999999748e+22"}, {below1e23, 'e', 17, "9.99999999999999748e+22"},
{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
{below1e23, 'g', 17, "9.9999999999999975e+22"}, {below1e23, 'g', 17, "9.9999999999999975e+22"},
// {below1e23, 'e', -1, "9.999999999999997e+22"}, {below1e23, 'e', -1, "9.999999999999997e+22"},
// {below1e23, 'f', -1, "99999999999999970000000"}, {below1e23, 'f', -1, "99999999999999970000000"},
// {below1e23, 'g', -1, "9.999999999999997e+22"}, {below1e23, 'g', -1, "9.999999999999997e+22"},
{above1e23, 'e', 17, "1.00000000000000008e+23"}, {above1e23, 'e', 17, "1.00000000000000008e+23"},
{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
// {above1e23, 'g', 17, "1.0000000000000001e+23"}, {above1e23, 'g', 17, "1.0000000000000001e+23"},
// {above1e23, 'e', -1, "1.0000000000000001e+23"}, {above1e23, 'e', -1, "1.0000000000000001e+23"},
// {above1e23, 'f', -1, "100000000000000010000000"}, {above1e23, 'f', -1, "100000000000000010000000"},
// {above1e23, 'g', -1, "1.0000000000000001e+23"}, {above1e23, 'g', -1, "1.0000000000000001e+23"},
// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, {5e-304 / 1e20, 'g', -1, "5e-324"},
// {fdiv(-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', -1, "32"},
// {32, 'g', 0, "3e+01"}, {32, 'g', 0, "3e+01"},
// {100, 'x', -1, "%x"}, {100, 'x', -1, "%x"},
// {math.NaN(), 'g', -1, "NaN"}, // {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
// {-math.NaN(), 'g', -1, "NaN"}, // {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
{math.Inf(0), 'g', -1, "+Inf"}, {math.Inf(0), 'g', -1, "+Inf"},
{math.Inf(-1), 'g', -1, "-Inf"}, {math.Inf(-1), 'g', -1, "-Inf"},
{-math.Inf(0), 'g', -1, "-Inf"}, {-math.Inf(0), 'g', -1, "-Inf"},
@ -279,18 +283,24 @@ func TestFloat64Text(t *testing.T) {
{1.5, 'f', 0, "2"}, {1.5, 'f', 0, "2"},
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ // 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/ // 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. // Issue 2625.
{383260575764816448, 'f', 0, "383260575764816448"}, {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) got := f.Text(test.format, test.prec)
if got != test.want { if got != test.want {
t.Errorf("%v: got %s; want %s", test, got, test.want) t.Errorf("%v: got %s; want %s", test, got, test.want)
continue
} }
if test.format == 'b' && test.x == 0 { 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) { func TestFloatText(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
x string x string
@ -367,10 +386,20 @@ func TestFloatText(t *testing.T) {
// make sure "stupid" exponents don't stall the machine // make sure "stupid" exponents don't stall the machine
{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"}, {"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
{"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
{"1e646456993", 64, 'p', 0, "+Inf"},
{"1e1000000000", 64, 'p', 0, "+Inf"}, {"1e1000000000", 64, 'p', 0, "+Inf"},
{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"}, {"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"}, {"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 // TODO(gri) need tests for actual large Floats
{"0", 53, 'b', 0, "0"}, {"0", 53, 'b', 0, "0"},
@ -438,9 +467,6 @@ func TestFloatFormat(t *testing.T) {
value interface{} // float32, float64, or string (== 512bit *Float) value interface{} // float32, float64, or string (== 512bit *Float)
want string want string
}{ }{
// TODO(gri) uncomment the disabled 'g'/'G' formats
// below once (*Float).Text supports prec < 0
// from fmt/fmt_test.go // from fmt/fmt_test.go
{"%+.3e", 0.0, "+0.000e+00"}, {"%+.3e", 0.0, "+0.000e+00"},
{"%+.3e", 1.0, "+1.000e+00"}, {"%+.3e", 1.0, "+1.000e+00"},
@ -471,9 +497,9 @@ func TestFloatFormat(t *testing.T) {
{"%f", 1234.5678e-8, "0.000012"}, {"%f", 1234.5678e-8, "0.000012"},
{"%f", -7.0, "-7.000000"}, {"%f", -7.0, "-7.000000"},
{"%f", -1e-9, "-0.000000"}, {"%f", -1e-9, "-0.000000"},
// {"%g", 1234.5678e3, "1.2345678e+06"}, {"%g", 1234.5678e3, "1.2345678e+06"},
// {"%g", float32(1234.5678e3), "1.2345678e+06"}, {"%g", float32(1234.5678e3), "1.2345678e+06"},
// {"%g", 1234.5678e-8, "1.2345678e-05"}, {"%g", 1234.5678e-8, "1.2345678e-05"},
{"%g", -7.0, "-7"}, {"%g", -7.0, "-7"},
{"%g", -1e-9, "-1e-09"}, {"%g", -1e-9, "-1e-09"},
{"%g", float32(-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", 1234.5678e-8, "1.234568E-05"},
{"%E", -7.0, "-7.000000E+00"}, {"%E", -7.0, "-7.000000E+00"},
{"%E", -1e-9, "-1.000000E-09"}, {"%E", -1e-9, "-1.000000E-09"},
// {"%G", 1234.5678e3, "1.2345678E+06"}, {"%G", 1234.5678e3, "1.2345678E+06"},
// {"%G", float32(1234.5678e3), "1.2345678E+06"}, {"%G", float32(1234.5678e3), "1.2345678E+06"},
// {"%G", 1234.5678e-8, "1.2345678E-05"}, {"%G", 1234.5678e-8, "1.2345678E-05"},
{"%G", -7.0, "-7"}, {"%G", -7.0, "-7"},
{"%G", -1e-9, "-1E-09"}, {"%G", -1e-9, "-1E-09"},
{"%G", float32(-1e-9), "-1E-09"}, {"%G", float32(-1e-9), "-1E-09"},
@ -500,9 +526,9 @@ func TestFloatFormat(t *testing.T) {
{"%-20f", 1.23456789e3, "1234.567890 "}, {"%-20f", 1.23456789e3, "1234.567890 "},
{"%20.8f", 1.23456789e3, " 1234.56789000"}, {"%20.8f", 1.23456789e3, " 1234.56789000"},
{"%20.8f", 1.23456789e-3, " 0.00123457"}, {"%20.8f", 1.23456789e-3, " 0.00123457"},
// {"%g", 1.23456789e3, "1234.56789"}, {"%g", 1.23456789e3, "1234.56789"},
// {"%g", 1.23456789e-3, "0.00123456789"}, {"%g", 1.23456789e-3, "0.00123456789"},
// {"%g", 1.23456789e20, "1.23456789e+20"}, {"%g", 1.23456789e20, "1.23456789e+20"},
{"%20e", math.Inf(1), " +Inf"}, {"%20e", math.Inf(1), " +Inf"},
{"%-20f", math.Inf(-1), "-Inf "}, {"%-20f", math.Inf(-1), "-Inf "},
@ -541,7 +567,6 @@ func TestFloatFormat(t *testing.T) {
{"%v", -1e-9, "-1e-09"}, {"%v", -1e-9, "-1e-09"},
{"%v", float32(-1e-9), "-1e-09"}, {"%v", float32(-1e-9), "-1e-09"},
{"%010v", 0.0, "0000000000"}, {"%010v", 0.0, "0000000000"},
{"%010v", 0.0, "0000000000"},
// *Float cases // *Float cases
{"%.20f", "1e-20", "0.00000000000000000001"}, {"%.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 1.2 1
// +Inf +Inf 0 // +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 package big
import ( import (
"bytes"
"fmt" "fmt"
"strconv" "strconv"
"strings"
) )
// Text converts the floating-point number x to a string according // 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' // 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 // 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 // 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. // 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 { func (x *Float) Text(format byte, prec int) string {
const extra = 10 // TODO(gri) determine a good/better value here const extra = 10 // TODO(gri) determine a good/better value here
return string(x.Append(make([]byte, 0, prec+extra), format, prec)) return string(x.Append(make([]byte, 0, prec+extra), format, prec))
} }
// String formats x like x.Text('g', 10). // 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 { func (x *Float) String() string {
return x.Text('g', 10) 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 // 1) convert Float to multiprecision decimal
var d decimal // == 0.0 var d decimal // == 0.0
if x.form == finite { if x.form == finite {
// x != 0
d.init(x.mant, int(x.exp)-x.mant.bitLen()) 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 shortest := false
if prec < 0 { if prec < 0 {
shortest = true shortest = true
panic("unimplemented") roundShortest(&d, x)
// TODO(gri) complete this
// roundShortest(&d, f.mant, int(f.exp))
// Precision for shortest representation mode. // Precision for shortest representation mode.
switch fmt { switch fmt {
case 'e', 'E': case 'e', 'E':
@ -158,6 +157,80 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
return append(buf, '%', fmt) 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 // %e: d.ddddde±dd
func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte { func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
// first digit // first digit
@ -219,11 +292,7 @@ func fmtF(buf []byte, prec int, d decimal) []byte {
if prec > 0 { if prec > 0 {
buf = append(buf, '.') buf = append(buf, '.')
for i := 0; i < prec; i++ { for i := 0; i < prec; i++ {
ch := byte('0') buf = append(buf, d.at(d.exp+i))
if j := d.exp + i; 0 <= j && j < len(d.mant) {
ch = d.mant[j]
}
buf = append(buf, ch)
} }
} }
@ -255,7 +324,7 @@ func (x *Float) fmtB(buf []byte) []byte {
m = nat(nil).shr(m, uint(w-x.prec)) m = nat(nil).shr(m, uint(w-x.prec))
} }
buf = append(buf, m.decimalString()...) buf = append(buf, m.utoa(10)...)
buf = append(buf, 'p') buf = append(buf, 'p')
e := int64(x.exp) - int64(x.prec) e := int64(x.exp) - int64(x.prec)
if e >= 0 { if e >= 0 {
@ -289,7 +358,7 @@ func (x *Float) fmtP(buf []byte) []byte {
m = m[i:] m = m[i:]
buf = append(buf, "0x."...) 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') buf = append(buf, 'p')
if x.exp >= 0 { if x.exp >= 0 {
buf = append(buf, '+') 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 sign control, '0' for space or zero padding,
// and '-' for left or right justification. See the fmt package // and '-' for left or right justification. See the fmt package
// for details. // 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) { func (x *Float) Format(s fmt.State, format rune) {
prec, hasPrec := s.Precision() prec, hasPrec := s.Precision()
if !hasPrec { if !hasPrec {
@ -336,8 +401,7 @@ func (x *Float) Format(s fmt.State, format rune) {
fallthrough fallthrough
case 'g', 'G': case 'g', 'G':
if !hasPrec { 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: default:
fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String()) 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. // 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 x is prime, it returns true.
// If it returns false, x is not prime. n must be > 0. // 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 { func (x *Int) ProbablyPrime(n int) bool {
if n <= 0 { if n <= 0 {
panic("non-positive n for ProbablyPrime") 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 // modSqrt3Mod4 uses the identity
// returns z. The modulus p must be an odd prime. If x is not a square mod p, // (a^((p+1)/4))^2 mod p
// ModSqrt leaves z unchanged and returns nil. This function panics if p is // == u^(p+1) mod p
// not an odd integer. // == u^2 mod p
func (z *Int) ModSqrt(x, p *Int) *Int { // to calculate the square root of any quadratic residue mod p quickly for 3
switch Jacobi(x, p) { // mod 4 primes.
case -1: func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int {
return nil // x is not a square mod p z.Set(p) // z = p
case 0: z.Add(z, intOne) // z = p + 1
return z.SetInt64(0) // sqrt(0) mod p = 0 z.Rsh(z, 2) // z = (p + 1) / 4
case 1: z.Exp(x, z, p) // z = x^z mod p
break return z
}
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
x = new(Int).Mod(x, p)
} }
// 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. // Break p-1 into s*2^e such that s is odd.
var s Int var s Int
s.Sub(p, intOne) 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. // Lsh sets z = x << n and returns z.
func (z *Int) Lsh(x *Int, n uint) *Int { func (z *Int) Lsh(x *Int, n uint) *Int {
z.abs = z.abs.shl(x.abs, n) 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 z.neg = true // z cannot be zero if x is positive
return z 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 ( import (
"bytes" "bytes"
"encoding/gob"
"encoding/hex" "encoding/hex"
"encoding/json"
"encoding/xml"
"fmt" "fmt"
"math/rand" "math/rand"
"testing" "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) { func TestBitwise(t *testing.T) {
x := new(Int) x := new(Int)
y := new(Int) y := new(Int)
@ -1408,138 +1452,6 @@ func TestJacobiPanic(t *testing.T) {
panic(failureMsg) 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) { func TestIssue2607(t *testing.T) {
// This code sequence used to hang. // This code sequence used to hang.
n := NewInt(10) n := NewInt(10)

View file

@ -12,30 +12,34 @@ import (
"io" "io"
) )
func (x *Int) String() string { // TODO(gri) Should rename itoa to utoa (there's no sign). That
switch { // would permit the introduction of itoa which is like utoa but
case x == nil: // 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>" 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 { // Append appends the string representation of x, as generated by
switch ch { // x.Text(base), to buf and returns the extended buffer.
case 'b': func (x *Int) Append(buf []byte, base int) []byte {
return lowercaseDigits[0:2] if x == nil {
case 'o': return append(buf, "<nil>"...)
return lowercaseDigits[0:8]
case 'd', 's', 'v':
return lowercaseDigits[0:10]
case 'x':
return lowercaseDigits[0:16]
case 'X':
return uppercaseDigits[0:16]
} }
return "" // unknown format 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 // write count copies of text to s
@ -60,15 +64,24 @@ func writeMultiple(s fmt.State, text string, count int) {
// right justification. // right justification.
// //
func (x *Int) Format(s fmt.State, ch rune) { func (x *Int) Format(s fmt.State, ch rune) {
cs := charset(ch) // determine base
var base int
// special cases switch ch {
switch { case 'b':
case cs == "": base = 2
case 'o':
base = 8
case 'd', 's', 'v':
base = 10
case 'x', 'X':
base = 16
default:
// unknown format // unknown format
fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
return return
case x == nil: }
if x == nil {
fmt.Fprint(s, "<nil>") fmt.Fprint(s, "<nil>")
return 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.utoa(base)
digits := x.abs.string(cs) 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 // number of characters for the three classes of number padding
var left int // space characters to left of digits for right justification ("%8d") 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 { switch {
case len(digits) < precision: case len(digits) < precision:
zeros = precision - len(digits) // count of zero padding 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") 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, sign, 1)
writeMultiple(s, prefix, 1) writeMultiple(s, prefix, 1)
writeMultiple(s, "0", zeros) writeMultiple(s, "0", zeros)
writeMultiple(s, digits, 1) s.Write(digits)
writeMultiple(s, " ", right) writeMultiple(s, " ", right)
} }

View file

@ -17,19 +17,19 @@ var stringTests = []struct {
val int64 val int64
ok bool ok bool
}{ }{
{in: "", ok: false}, {in: ""},
{in: "a", ok: false}, {in: "a"},
{in: "z", ok: false}, {in: "z"},
{in: "+", ok: false}, {in: "+"},
{in: "-", ok: false}, {in: "-"},
{in: "0b", ok: false}, {in: "0b"},
{in: "0x", ok: false}, {in: "0x"},
{in: "2", base: 2, ok: false}, {in: "2", base: 2},
{in: "0b2", base: 0, ok: false}, {in: "0b2", base: 0},
{in: "08", ok: false}, {in: "08"},
{in: "8", base: 8, ok: false}, {in: "8", base: 8},
{in: "0xg", base: 0, ok: false}, {in: "0xg", base: 0},
{in: "g", base: 16, ok: false}, {in: "g", base: 16},
{"0", "0", 0, 0, true}, {"0", "0", 0, 0, true},
{"0", "0", 10, 0, true}, {"0", "0", 10, 0, true},
{"0", "0", 16, 0, true}, {"0", "0", 16, 0, true},
@ -41,7 +41,7 @@ var stringTests = []struct {
{"-10", "-10", 16, -16, true}, {"-10", "-10", 16, -16, true},
{"+10", "10", 16, 16, true}, {"+10", "10", 16, 16, true},
{"0x10", "16", 0, 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},
{"+0x10", "16", 0, 16, true}, {"+0x10", "16", 0, 16, true},
{"00", "0", 0, 0, true}, {"00", "0", 0, 0, true},
@ -58,6 +58,57 @@ var stringTests = []struct {
{"1001010111", "1001010111", 2, 0x257, true}, {"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 { func format(base int) string {
switch base { switch base {
case 2: case 2:
@ -79,15 +130,13 @@ func TestGetString(t *testing.T) {
z.SetInt64(test.val) z.SetInt64(test.val)
if test.base == 10 { if test.base == 10 {
s := z.String() if got := z.String(); got != test.out {
if s != test.out { t.Errorf("#%da got %s; want %s", i, got, test.out)
t.Errorf("#%da got %s; want %s", i, s, test.out)
} }
} }
s := fmt.Sprintf(format(test.base), z) if got := fmt.Sprintf(format(test.base), z); got != test.out {
if s != test.out { t.Errorf("#%db got %s; want %s", i, got, test.out)
t.Errorf("#%db got %s; want %s", i, s, test.out)
} }
} }
} }

View file

@ -2,31 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package big implements multi-precision arithmetic (big numbers). // This file implements unsigned multi-precision integers (natural
// The following numeric types are supported: // numbers). They are the building blocks for the implementation
// // of signed integers, rationals, and floating-point numbers.
// 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 contains operations on unsigned multi-precision integers. package big
// These are the building blocks for the operations on signed integers
// and rationals.
import "math/rand" import "math/rand"
@ -216,23 +196,36 @@ func basicMul(z, x, y nat) {
} }
} }
// montgomery computes x*y*2^(-n*_W) mod m, // montgomery computes z mod m = x*y*2**(-n*_W) mod m,
// assuming k = -1/m mod 2^_W. // assuming k = -1/m mod 2**_W.
// z is used for storing the result which is returned; // z is used for storing the result which is returned;
// z must not alias x, y or m. // 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 { 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 = z.make(n)
z.clear() z.clear()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
d := y[i] d := y[i]
c1 += addMulVVW(z, x, d) c2 = addMulVVW(z, x, d)
t := z[0] * k t := z[0] * k
c2 = addMulVVW(z, m, t) c3 = addMulVVW(z, m, t)
copy(z, z[1:]) copy(z, z[1:])
z[n-1] = c1 + c2 cx := c1 + c2
if z[n-1] < c1 { cy := cx + c3
z[n-1] = cy
if cx < c2 || cy < c3 {
c1 = 1 c1 = 1
} else { } else {
c1 = 0 c1 = 0
@ -1082,7 +1075,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
x = rr x = rr
// Ideally the precomputations would be performed outside, and reused // 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". // Iteration for Multiplicative Inverses Modulo Prime Powers".
k0 := 2 - m[0] k0 := 2 - m[0]
t := m[0] - 1 t := m[0] - 1
@ -1092,7 +1085,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
} }
k0 = -k0 k0 = -k0
// RR = 2ˆ(2*_W*len(m)) mod m // RR = 2**(2*_W*len(m)) mod m
RR = RR.setWord(1) RR = RR.setWord(1)
zz = zz.shl(RR, uint(2*numWords*_W)) zz = zz.shl(RR, uint(2*numWords*_W))
_, RR = RR.div(RR, zz, m) _, RR = RR.div(RR, zz, m)
@ -1141,9 +1134,12 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
return zz.norm() return zz.norm()
} }
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime. // probablyPrime performs n Miller-Rabin tests to check whether x is prime.
// If it returns true, n is prime with probability 1 - 1/4^reps. // If x is prime, it returns true.
// If it returns false, n is not prime. // 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 { func (n nat) probablyPrime(reps int) bool {
if len(n) == 0 { if len(n) == 0 {
return false return false

View file

@ -158,7 +158,7 @@ var mulRangesN = []struct {
func TestMulRangeN(t *testing.T) { func TestMulRangeN(t *testing.T) {
for i, r := range mulRangesN { 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 { if prod != r.prod {
t.Errorf("#%d: got %s; want %s", i, 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++ { for i := uint(0); i <= 3*_W; i++ {
n := y.trailingZeroBits() n := y.trailingZeroBits()
if n != i { 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) y = y.shl(y, 1)
} }
@ -341,25 +341,57 @@ var montgomeryTests = []struct {
"0xffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
"0xffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
"0xfffffffffffffffffffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffffffffffffffffffff",
0x0000000000000000, 1,
"0xffffffffffffffffffffffffffffffffffffffffff", "0x1000000000000000000000000000000000000000000",
"0xffffffffffffffffffffffffffffffffff", "0x10000000000000000000000000000000000",
},
{
"0x000000000ffffff5",
"0x000000000ffffff0",
"0x0000000010000001",
0xff0000000fffffff,
"0x000000000bfffff4",
"0x0000000003400001",
}, },
{ {
"0x0000000080000000", "0x0000000080000000",
"0x00000000ffffffff", "0x00000000ffffffff",
"0x0000000010000001", "0x1000000000000001",
0xff0000000fffffff, 0xfffffffffffffff,
"0x0000000088000000", "0x0800000008000001",
"0x0000000007800001", "0x0800000008000001",
}, },
{ {
"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", "0x0000000080000000",
"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", "0x0000000080000000",
"0xffffffff00000001",
0xfffffffeffffffff,
"0xbfffffff40000001",
"0xbfffffff40000001",
},
{
"0x0000000080000000",
"0x0000000080000000",
"0x00ffffff00000001",
0xfffffeffffffff,
"0xbfffff40000001",
"0xbfffff40000001",
},
{
"0x0000000080000000",
"0x0000000080000000",
"0x0000ffff00000001",
0xfffeffffffff,
"0xbfff40000001",
"0xbfff40000001",
},
{
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
0xdecc8f1249812adf, 0xdecc8f1249812adf,
"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79", "0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd", "0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
}, },
{ {
"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
@ -372,10 +404,27 @@ var montgomeryTests = []struct {
} }
func TestMontgomery(t *testing.T) { func TestMontgomery(t *testing.T) {
one := NewInt(1)
_B := new(Int).Lsh(one, _W)
for i, test := range montgomeryTests { for i, test := range montgomeryTests {
x := natFromString(test.x) x := natFromString(test.x)
y := natFromString(test.y) y := natFromString(test.y)
m := natFromString(test.m) 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 var out nat
if _W == 32 { if _W == 32 {
@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) {
out = natFromString(test.out64) 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 := nat(nil).montgomery(x, y, m, k0, len(m))
z = z.norm() z = z.norm()
if z.cmp(out) != 0 { 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) z := nat(nil).expNN(x, y, m)
if z.cmp(out) != 0 { 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) { func TestFibo(t *testing.T) {
for i, want := range fiboNums { for i, want := range fiboNums {
n := i * 10 n := i * 10
got := fibo(n).decimalString() got := string(fibo(n).utoa(10))
if got != want { if got != want {
t.Errorf("fibo(%d) failed: got %s want %s", n, 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