mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[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:
commit
b386c34ef9
700 changed files with 23857 additions and 22716 deletions
5
AUTHORS
5
AUTHORS
|
|
@ -48,6 +48,7 @@ Alexandre Normand <alexandre.normand@gmail.com>
|
|||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Alexey Borzenkov <snaury@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Aliaksandr Valialkin <valyala@gmail.com>
|
||||
Alif Rachmawadi <subosito@gmail.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
|
|
@ -200,6 +201,7 @@ Dustin Sallings <dsallings@gmail.com>
|
|||
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
|
||||
Eden Li <eden.li@gmail.com>
|
||||
Edward Muller <edwardam@interlix.com>
|
||||
Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
|
|
@ -267,6 +269,7 @@ Hector Martin Cantero <hector@marcansoft.com>
|
|||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
Hsin-Ho Yeh <yhh92u@gmail.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
|
|
@ -313,6 +316,7 @@ Jihyun Yu <yjh0502@gmail.com>
|
|||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
|
|
@ -328,6 +332,7 @@ John Jenkins <twodopeshaggy@gmail.com>
|
|||
John Potocny <johnp@vividcortex.com>
|
||||
John Shahid <jvshahid@gmail.com>
|
||||
John Tuley <john@tuley.org>
|
||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||
Jonathan Gold <jgold.bg@gmail.com>
|
||||
Jonathan Mark <jhmark@xenops.com>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
|
|
|
|||
11
CONTRIBUTORS
11
CONTRIBUTORS
|
|
@ -76,6 +76,7 @@ Alexei Sholik <alcosholik@gmail.com>
|
|||
Alexey Borzenkov <snaury@gmail.com>
|
||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||
Alexis Imperial-Legrand <ail@google.com>
|
||||
Aliaksandr Valialkin <valyala@gmail.com>
|
||||
Alif Rachmawadi <subosito@gmail.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amrut Joshi <amrut.joshi@gmail.com>
|
||||
|
|
@ -116,6 +117,7 @@ Anthony Starks <ajstarks@gmail.com>
|
|||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Areski Belaid <areski@gmail.com>
|
||||
Arkadi Pyuro <arkadi@google.com>
|
||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Arne Hormann <arnehormann@gmail.com>
|
||||
Arnout Engelen <arnout@bzzt.net>
|
||||
|
|
@ -135,6 +137,7 @@ Ben Fried <ben.fried@gmail.com>
|
|||
Ben Lynn <benlynn@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
Benjamin Prosnitz <bprosnitz@google.com>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
Benoit Sigoure <tsunanet@gmail.com>
|
||||
Berengar Lehr <Berengar.Lehr@gmx.de>
|
||||
|
|
@ -178,6 +181,7 @@ Cezar Sá Espinola <cezarsa@gmail.com>
|
|||
ChaiShushan <chaishushan@gmail.com>
|
||||
Charles L. Dorian <cldorian@gmail.com>
|
||||
Charles Lee <zombie.fml@gmail.com>
|
||||
Charles Weill <weill@google.com>
|
||||
Chris Broadfoot <cbro@golang.org>
|
||||
Chris Dollin <ehog.hedge@gmail.com>
|
||||
Chris Farmiloe <chrisfarms@gmail.com>
|
||||
|
|
@ -232,6 +236,7 @@ Dave Day <djd@golang.org>
|
|||
Dave Grijalva <dgrijalva@ngmoco.com>
|
||||
David Anderson <danderson@google.com>
|
||||
David Barnett <dbarnett@google.com>
|
||||
David Benjamin <davidben@google.com>
|
||||
David Bürgin <676c7473@gmail.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David Chase <drchase@google.com>
|
||||
|
|
@ -277,6 +282,7 @@ Dustin Sallings <dsallings@gmail.com>
|
|||
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
|
||||
Eden Li <eden.li@gmail.com>
|
||||
Edward Muller <edwardam@interlix.com>
|
||||
Egon Elbre <egonelbre@gmail.com>
|
||||
Ehren Kret <ehren.kret@gmail.com>
|
||||
Eivind Uggedal <eivind@uggedal.com>
|
||||
|
|
@ -359,6 +365,7 @@ Hector Martin Cantero <hector@marcansoft.com>
|
|||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
Hossein Sheikh Attar <hattar@google.com>
|
||||
Hsin-Ho Yeh <yhh92u@gmail.com>
|
||||
|
|
@ -379,6 +386,7 @@ Jacob Baskin <jbaskin@google.com>
|
|||
Jacob H. Haven <jacob@cloudflare.com>
|
||||
Jae Kwon <jae@tendermint.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Čajka <jcajka@redhat.com>
|
||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
James Aguilar <jaguilar@google.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
|
|
@ -422,6 +430,7 @@ Jim Cote <jfcote87@gmail.com>
|
|||
Jim McGrath <jimmc2@gmail.com>
|
||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
|
|
@ -444,6 +453,7 @@ John Potocny <johnp@vividcortex.com>
|
|||
John Shahid <jvshahid@gmail.com>
|
||||
John Tuley <john@tuley.org>
|
||||
Jonathan Allie <jonallie@google.com>
|
||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||
Jonathan Feinberg <feinberg@google.com>
|
||||
Jonathan Gold <jgold.bg@gmail.com>
|
||||
Jonathan Hseu <jhseu@google.com>
|
||||
|
|
@ -756,6 +766,7 @@ Sebastien Binet <seb.binet@gmail.com>
|
|||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||
Sergey Arseev <sergey.arseev@intel.com>
|
||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Files in this directory are data for Go's API checker ("go tool api", in src/cmd/api).
|
||||
|
||||
Each file is a list of of API features, one per line.
|
||||
Each file is a list of API features, one per line.
|
||||
|
||||
go1.txt (and similarly named files) are frozen once a version has been
|
||||
shipped. Each file adds new lines but does not remove any.
|
||||
|
|
|
|||
|
|
@ -1983,13 +1983,13 @@ pkg log/syslog (openbsd-amd64-cgo), const LOG_SYSLOG = 40
|
|||
pkg log/syslog (openbsd-amd64-cgo), const LOG_USER = 8
|
||||
pkg log/syslog (openbsd-amd64-cgo), const LOG_UUCP = 64
|
||||
pkg log/syslog (openbsd-amd64-cgo), const LOG_WARNING = 4
|
||||
pkg math, const E = 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Ln10 = 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Ln2 = 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Log10E = 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279
|
||||
pkg math, const Log2E = 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009
|
||||
pkg math, const MaxFloat32 = 340282346638528859811704183484516925440
|
||||
pkg math, const MaxFloat64 = 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const E = 2.71828 // 271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Ln10 = 2.30259 // 23025850929940456840179914546843642076011014886287729760333279/10000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Ln2 = 0.693147 // 693147180559945309417232121458176568075500134360255254120680009/1000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Log10E = 0.434294 // 10000000000000000000000000000000000000000000000000000000000000/23025850929940456840179914546843642076011014886287729760333279
|
||||
pkg math, const Log2E = 1.4427 // 1000000000000000000000000000000000000000000000000000000000000000/693147180559945309417232121458176568075500134360255254120680009
|
||||
pkg math, const MaxFloat32 = 3.40282e+38 // 340282346638528859811704183484516925440
|
||||
pkg math, const MaxFloat64 = 1.79769e+308 // 179769313486231570814527423731704356798100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const MaxInt16 = 32767
|
||||
pkg math, const MaxInt32 = 2147483647
|
||||
pkg math, const MaxInt64 = 9223372036854775807
|
||||
|
|
@ -2002,14 +2002,14 @@ pkg math, const MinInt16 = -32768
|
|||
pkg math, const MinInt32 = -2147483648
|
||||
pkg math, const MinInt64 = -9223372036854775808
|
||||
pkg math, const MinInt8 = -128
|
||||
pkg math, const Phi = 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Pi = 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SmallestNonzeroFloat32 = 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SmallestNonzeroFloat64 = 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Sqrt2 = 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtE = 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtPhi = 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtPi = 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Phi = 1.61803 // 80901699437494742410229341718281905886015458990288143106772431/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Pi = 3.14159 // 314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SmallestNonzeroFloat32 = 1.4013e-45 // 17516230804060213386546619791123951641/12500000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SmallestNonzeroFloat64 = 4.94066e-324 // 4940656458412465441765687928682213723651/1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const Sqrt2 = 1.41421 // 70710678118654752440084436210484903928483593768847403658833987/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtE = 1.64872 // 164872127070012814684865078781416357165377610071014801157507931/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtPhi = 1.27202 // 63600982475703448212621123086874574585780402092004812430832019/50000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math, const SqrtPi = 1.77245 // 177245385090551602729816748334114518279754945612238712821380779/100000000000000000000000000000000000000000000000000000000000000
|
||||
pkg math/big, const MaxBase = 36
|
||||
pkg math/big, method (*Int) MarshalJSON() ([]uint8, error)
|
||||
pkg math/big, method (*Int) SetUint64(uint64) *Int
|
||||
|
|
|
|||
268
api/go1.6.txt
Normal file
268
api/go1.6.txt
Normal 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
|
||||
160
api/next.txt
160
api/next.txt
|
|
@ -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
|
||||
|
|
@ -176,7 +176,7 @@ This form is used to name global functions and data.
|
|||
Adding <code><></code> to the name, as in <span style="white-space: nowrap"><code>foo<>(SB)</code></span>, makes the name
|
||||
visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
|
||||
Adding an offset to the name refers to that offset from the symbol's address, so
|
||||
<code>a+4(SB)</code> is four bytes past the start of <code>foo</code>.
|
||||
<code>foo+4(SB)</code> is four bytes past the start of <code>foo</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
273
doc/conduct.html
Normal file
273
doc/conduct.html
Normal 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 <dev@chimeracoder.net>
|
||||
<li>Andrew Gerrand <adg@golang.org>
|
||||
<li>Dave Cheney <dave@cheney.net>
|
||||
<li>Jason Buberel <jbuberel@google.com>
|
||||
<li>Peggy Li <peggyli.224@gmail.com>
|
||||
<li>Sarah Adams <sadams.codes@gmail.com>
|
||||
<li>Steve Francia <steve.francia@gmail.com>
|
||||
<li>Verónica López <gveronicalg@gmail.com>
|
||||
</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>Don’t 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>
|
||||
|
|
@ -91,10 +91,16 @@ We pride ourselves on being meticulous; no issue is too small.
|
|||
|
||||
<p>
|
||||
Security-related issues should be reported to
|
||||
<a href="mailto:security@golang.org">security@golang.org</a>.
|
||||
<a href="mailto:security@golang.org">security@golang.org</a>.<br>
|
||||
See the <a href="/security">security policy</a> for more details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Community-related issues should be reported to
|
||||
<a href="mailto:conduct@golang.org">conduct@golang.org</a>.<br>
|
||||
See the <a href="/conduct">Code of Conduct</a> for more details.
|
||||
</p>
|
||||
|
||||
<h3><a href="/doc/contribute.html">Contributing code</a></h3>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ discussed below, helps manage the code review process through a Google-hosted
|
|||
system called <a href="https://code.google.com/p/gerrit/">Gerrit</a>.
|
||||
</p>
|
||||
|
||||
<h3>Set up authentication for code review</h3>
|
||||
<h3 id="auth">Set up authentication for code review</h3>
|
||||
|
||||
<p>
|
||||
Gerrit uses Google Accounts for authentication. If you don't have
|
||||
|
|
@ -120,7 +120,7 @@ Your secret authentication token is now in a <code>.gitcookie</code> file
|
|||
and Git is configured to use this file.
|
||||
</p>
|
||||
|
||||
<h3>Register with Gerrit</h3>
|
||||
<h3 id="gerrit">Register with Gerrit</h3>
|
||||
|
||||
<p>
|
||||
Now that you have your authentication token,
|
||||
|
|
@ -132,7 +132,7 @@ to Google Accounts. Sign in using the same Google Account you used above.
|
|||
That is all that is required.
|
||||
</p>
|
||||
|
||||
<h3>Contributor License Agreement</h3>
|
||||
<h3 id="cla">Contributor License Agreement</h3>
|
||||
|
||||
<p>Gerrit serves as the gatekeeper and uses your e-mail address as the key.
|
||||
To send your first change to the Go project from a given address,
|
||||
|
|
@ -167,7 +167,14 @@ you can create one by clicking "New Contributor Agreement" and following the ste
|
|||
This rigmarole only needs to be done for your first submission for each email address.
|
||||
</p>
|
||||
|
||||
<h3>Install the git-codereview command</h3>
|
||||
<p>
|
||||
If the copyright holder for the code you are submitting changes—for example,
|
||||
if you start contributing code on behalf of a new company—please send email
|
||||
to let us know, so that we can make sure an appropriate agreement is completed
|
||||
and update the <code>AUTHORS</code> file.
|
||||
</p>
|
||||
|
||||
<h3 id="git-codereview">Install the git-codereview command</h3>
|
||||
|
||||
<p>
|
||||
Now install the <code>git-codereview</code> command by running,
|
||||
|
|
@ -201,7 +208,7 @@ if you intend to use plain Git for daily work, install the hooks in a new Git
|
|||
checkout by running <code>git-codereview</code> <code>hooks</code>.
|
||||
</p>
|
||||
|
||||
<h3>Set up git aliases</h3>
|
||||
<h3 id="git-config">Set up git aliases</h3>
|
||||
|
||||
<p>
|
||||
The <code>git-codereview</code> command can be run directly from the shell
|
||||
|
|
@ -243,7 +250,7 @@ To install them, copy this text into your Git configuration file
|
|||
sync = codereview sync
|
||||
</pre>
|
||||
|
||||
<h3>Understanding the git-codereview command</h3>
|
||||
<h3 id="help">Understanding the git-codereview command</h3>
|
||||
|
||||
<p>After installing the <code>git-codereview</code> command, you can run</p>
|
||||
|
||||
|
|
@ -256,7 +263,7 @@ to learn more about its commands.
|
|||
You can also read the <a href="https://godoc.org/golang.org/x/review/git-codereview">command documentation</a>.
|
||||
</p>
|
||||
|
||||
<h3>Switch to the master branch</h3>
|
||||
<h3 id="master">Switch to the master branch</h3>
|
||||
|
||||
<p>
|
||||
Most Go installations use a release branch, but new changes should
|
||||
|
|
@ -276,7 +283,7 @@ $ git sync
|
|||
<code>git</code> <code>pull</code> <code>-r</code>.)
|
||||
</p>
|
||||
|
||||
<h3>Make a change</h3>
|
||||
<h3 id="change">Make a change</h3>
|
||||
|
||||
<p>
|
||||
The entire checked-out tree is writable.
|
||||
|
|
@ -405,7 +412,7 @@ Do not edit or delete it.
|
|||
runs <code>git</code> <code>commit</code> <code>--amend</code>.)
|
||||
</p>
|
||||
|
||||
<h3>Mail the change for review</h3>
|
||||
<h3 id="mail">Mail the change for review</h3>
|
||||
|
||||
<p>
|
||||
Once the change is ready, mail it out for review:
|
||||
|
|
@ -455,7 +462,7 @@ remote: New Changes:
|
|||
remote: https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
|
||||
</pre>
|
||||
|
||||
<h3>Reviewing code</h3>
|
||||
<h3 id="review">Reviewing code</h3>
|
||||
|
||||
<p>
|
||||
Running <code>git</code> <code>mail</code> will send an email to you and the
|
||||
|
|
@ -467,7 +474,7 @@ You must reply through the web interface.
|
|||
(Unlike with the old Rietveld review system, replying by mail has no effect.)
|
||||
</p>
|
||||
|
||||
<h3>Revise and upload</h3>
|
||||
<h3 id="revise">Revise and upload</h3>
|
||||
|
||||
<p>
|
||||
You must respond to review comments through the web interface.
|
||||
|
|
@ -494,7 +501,7 @@ You can see a list of your pending changes by running <code>git</code>
|
|||
<code>change</code> <code><i><branch></i></code>.
|
||||
</p>
|
||||
|
||||
<h3>Synchronize your client</h3>
|
||||
<h3 id="sync">Synchronize your client</h3>
|
||||
|
||||
<p>
|
||||
While you were working, others might have submitted changes to the repository.
|
||||
|
|
@ -612,7 +619,7 @@ Then run <code>git</code> <code>rebase</code> <code>--continue</code> to
|
|||
restore the change commit.
|
||||
</p>
|
||||
|
||||
<h3>Reviewing code by others</h3>
|
||||
<h3 id="download">Reviewing code by others</h3>
|
||||
|
||||
<p>
|
||||
You can import a change proposed by someone else into your local Git repository.
|
||||
|
|
@ -629,7 +636,7 @@ $ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 &&
|
|||
To revert, change back to the branch you were working in.
|
||||
</p>
|
||||
|
||||
<h3>Submit the change after the review</h3>
|
||||
<h3 id="submit">Submit the change after the review</h3>
|
||||
|
||||
<p>
|
||||
After the code has been <code>LGTM</code>'ed, an approver may
|
||||
|
|
@ -648,7 +655,7 @@ the commit hashes in the repository will be changed by
|
|||
the submit operation.
|
||||
</p>
|
||||
|
||||
<h3>More information</h3>
|
||||
<h3 id="more">More information</h3>
|
||||
|
||||
<p>
|
||||
In addition to the information here, the Go community maintains a <a href="https://golang.org/wiki/CodeReview">CodeReview</a> wiki page.
|
||||
|
|
@ -674,7 +681,7 @@ These files will be periodically updated based on the commit logs.
|
|||
<p>Code that you contribute should use the standard copyright header:</p>
|
||||
|
||||
<pre>
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
</pre>
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ href="/src/runtime/runtime-gdb.py">src/runtime/runtime-gdb.py</a> in
|
|||
the Go source distribution. It depends on some special magic types
|
||||
(<code>hash<T,U></code>) and variables (<code>runtime.m</code> and
|
||||
<code>runtime.g</code>) that the linker
|
||||
(<a href="/src/cmd/ld/dwarf.c">src/cmd/ld/dwarf.c</a>) ensures are described in
|
||||
(<a href="/src/cmd/link/internal/ld/dwarf.go">src/cmd/link/internal/ld/dwarf.go</a>) ensures are described in
|
||||
the DWARF code.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,24 @@ git pull
|
|||
git checkout <i>release-branch</i>
|
||||
</pre>
|
||||
|
||||
<h2 id="policy">Release Policy</h2>
|
||||
|
||||
<p>
|
||||
Each major Go release obsoletes and ends support for the previous one.
|
||||
For example, if Go 1.5 has been released, then it is the current release
|
||||
and Go 1.4 and earlier are no longer supported.
|
||||
We fix critical problems in the current release as needed by issuing minor revisions
|
||||
(for example, Go 1.5.1, Go 1.5.2, and so on).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a special case, we issue minor revisions for critical security problems
|
||||
in both the current release and the previous release.
|
||||
For example, if Go 1.5 is the current release then we will issue minor revisions
|
||||
to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
|
||||
See the <a href="/security">security policy</a> for more details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -29,6 +47,14 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.1">Go
|
|||
1.5.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.5.2 (released 2015/12/02) includes bug fixes to the compiler, linker, and
|
||||
the <code>mime/multipart</code>, <code>net</code>, and <code>runtime</code>
|
||||
packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.2">Go
|
||||
1.5.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.4">go1.4 (released 2014/12/10)</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
894
doc/go1.6.html
Normal file
894
doc/go1.6.html
Normal 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 != "" && !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 -}}
|
||||
<
|
||||
{{"{{"}}- 45}}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
formats as <code>23<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>
|
||||
<title>{{"{{"}}block "title"}}Page Title{{"{{"}}end}}</title>
|
||||
<body>
|
||||
<h1>{{"{{"}}template "title"}}</h1>
|
||||
{{"{{"}}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><![CDATA[ ... ]]></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 “localhost.” not “localhost”.
|
||||
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>
|
||||
|
||||
|
|
@ -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/)
|
||||
|
|
@ -860,6 +860,36 @@ value to hold the error and a type switch to discriminate cases. The
|
|||
syntax tree example is also doable, although not as elegantly.
|
||||
</p>
|
||||
|
||||
<h3 id="covariant_types">
|
||||
Why does Go not have covariant result types?</h3>
|
||||
|
||||
<p>
|
||||
Covariant result types would mean that an interface like
|
||||
|
||||
<pre>
|
||||
type Copyable interface {
|
||||
Copy() interface{}
|
||||
}
|
||||
</pre>
|
||||
|
||||
would be satisfied by the method
|
||||
|
||||
<pre>
|
||||
func (v Value) Copy() Value
|
||||
</pre>
|
||||
|
||||
because <code>Value</code> implements the empty interface.
|
||||
In Go method types must match exactly, so <code>Value</code> does not
|
||||
implement <code>Copyable</code>.
|
||||
Go separates the notion of what a
|
||||
type does—its methods—from the type's implementation.
|
||||
If two methods return different types, they are not doing the same thing.
|
||||
Programmers who want covariant result types are often trying to
|
||||
express a type hierarchy through interfaces.
|
||||
In Go it's more natural to have a clean separation between interface
|
||||
and implementation.
|
||||
</p>
|
||||
|
||||
<h2 id="values">Values</h2>
|
||||
|
||||
<h3 id="conversions">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of October 20, 2015",
|
||||
"Subtitle": "Version of January 5, 2016",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -101,15 +101,14 @@ The following terms are used to denote specific Unicode character classes:
|
|||
newline = /* the Unicode code point U+000A */ .
|
||||
unicode_char = /* an arbitrary Unicode code point except newline */ .
|
||||
unicode_letter = /* a Unicode code point classified as "Letter" */ .
|
||||
unicode_digit = /* a Unicode code point classified as "Decimal Digit" */ .
|
||||
unicode_digit = /* a Unicode code point classified as "Number, decimal digit" */ .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In <a href="http://www.unicode.org/versions/Unicode6.3.0/">The Unicode Standard 6.3</a>,
|
||||
Section 4.5 "General Category"
|
||||
defines a set of character categories. Go treats
|
||||
those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters,
|
||||
and those in category Nd as Unicode digits.
|
||||
In <a href="http://www.unicode.org/versions/Unicode8.0.0/">The Unicode Standard 8.0</a>,
|
||||
Section 4.5 "General Category" defines a set of character categories.
|
||||
Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo
|
||||
as Unicode letters, and those in the Number category Nd as Unicode digits.
|
||||
</p>
|
||||
|
||||
<h3 id="Letters_and_digits">Letters and digits</h3>
|
||||
|
|
@ -1051,12 +1050,18 @@ but are otherwise ignored.
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
// A struct corresponding to the TimeStamp protocol buffer.
|
||||
// The tag strings define the protocol buffer field numbers.
|
||||
struct {
|
||||
microsec uint64 "field 1"
|
||||
serverIP6 uint64 "field 2"
|
||||
process string "field 3"
|
||||
x, y float64 "" // an empty tag string is like an absent tag
|
||||
name string "any string is permitted as a tag"
|
||||
_ [4]byte "ceci n'est pas un champ de structure"
|
||||
}
|
||||
|
||||
// A struct corresponding to a TimeStamp protocol buffer.
|
||||
// The tag strings define the protocol buffer field numbers;
|
||||
// they follow the convention outlined by the reflect package.
|
||||
struct {
|
||||
microsec uint64 `protobuf:"1"`
|
||||
serverIP6 uint64 `protobuf:"2"`
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
|
@ -1108,7 +1113,7 @@ one unnamed result it may be written as an unparenthesized type.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
The final parameter in a function signature may have
|
||||
The final incoming parameter in a function signature may have
|
||||
a type prefixed with <code>...</code>.
|
||||
A function with such a parameter is called <i>variadic</i> and
|
||||
may be invoked with zero or more arguments for that parameter.
|
||||
|
|
@ -1789,26 +1794,27 @@ It can be used to construct a set of related constants:
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
const ( // iota is reset to 0
|
||||
const ( // iota is reset to 0
|
||||
c0 = iota // c0 == 0
|
||||
c1 = iota // c1 == 1
|
||||
c2 = iota // c2 == 2
|
||||
)
|
||||
|
||||
const (
|
||||
a = 1 << iota // a == 1 (iota has been reset)
|
||||
const ( // iota is reset to 0
|
||||
a = 1 << iota // a == 1
|
||||
b = 1 << iota // b == 2
|
||||
c = 1 << iota // c == 4
|
||||
c = 3 // c == 3 (iota is not used but still incremented)
|
||||
d = 1 << iota // d == 8
|
||||
)
|
||||
|
||||
const (
|
||||
const ( // iota is reset to 0
|
||||
u = iota * 42 // u == 0 (untyped integer constant)
|
||||
v float64 = iota * 42 // v == 42.0 (float64 constant)
|
||||
w = iota * 42 // w == 84 (untyped integer constant)
|
||||
)
|
||||
|
||||
const x = iota // x == 0 (iota has been reset)
|
||||
const y = iota // y == 0 (iota has been reset)
|
||||
const x = iota // x == 0 (iota has been reset)
|
||||
const y = iota // y == 0 (iota has been reset)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
|
@ -2083,7 +2089,7 @@ Receiver = Parameters .
|
|||
|
||||
<p>
|
||||
The receiver is specified via an extra parameter section preceding the method
|
||||
name. That parameter section must declare a single parameter, the receiver.
|
||||
name. That parameter section must declare a single non-variadic parameter, the receiver.
|
||||
Its type must be of the form <code>T</code> or <code>*T</code> (possibly using
|
||||
parentheses) where <code>T</code> is a type name. The type denoted by <code>T</code> is called
|
||||
the receiver <i>base type</i>; it must not be a pointer or interface type and
|
||||
|
|
@ -5323,7 +5329,7 @@ the "for" statement's block but the <code>goto</code> is not.
|
|||
|
||||
<p>
|
||||
A "fallthrough" statement transfers control to the first statement of the
|
||||
next case clause in a <a href="#Expression_switches">expression "switch" statement</a>.
|
||||
next case clause in an <a href="#Expression_switches">expression "switch" statement</a>.
|
||||
It may be used only as the final non-empty statement in such a clause.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -48,3 +48,9 @@ Each month in places around the world, groups of Go programmers ("gophers")
|
|||
meet to talk about Go. Find a chapter near you.
|
||||
</p>
|
||||
|
||||
<h3 id="conduct"><a href="/conduct">Code of Conduct</a></h3>
|
||||
<p>
|
||||
Guidelines for participating in Go community spaces
|
||||
and a reporting process for handling issues.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,17 @@ The full set of supported combinations is listed in the discussion of
|
|||
<a href="#environment">environment variables</a> below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the main installation page for the <a href="/doc/install#requirements">overall system requirements</a>.
|
||||
The following additional constraints apply to systems that can be built only from source:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>For Linux on PowerPC 64-bit, the minimum supported kernel version is 2.6.37, meaning that
|
||||
Go does not support CentOS 6 on these systems.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<h2 id="go14">Install Go compiler binaries</h2>
|
||||
|
|
@ -139,7 +150,7 @@ and used as <code>GOROOT_BOOTSTRAP</code> to bootstrap a local build.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
To use gccgo, you need to arrange for <code>$GOROOT_BOOSTRAP/bin/go</code> to be
|
||||
To use gccgo, you need to arrange for <code>$GOROOT_BOOTSTRAP/bin/go</code> to be
|
||||
the go tool that comes as part of gccgo 5. For example on Ubuntu Vivid:
|
||||
</p>
|
||||
|
||||
|
|
@ -173,7 +184,7 @@ Then clone the repository and check out the latest release tag:</p>
|
|||
<pre>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
$ cd go
|
||||
$ git checkout go1.5.1
|
||||
$ git checkout go1.5.2
|
||||
</pre>
|
||||
|
||||
<h2 id="head">(Optional) Switch to the master branch</h2>
|
||||
|
|
@ -352,7 +363,7 @@ New releases are announced on the
|
|||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list.
|
||||
Each announcement mentions the latest release tag, for instance,
|
||||
<code>go1.5.1</code>.
|
||||
<code>go1.5.2</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ If your OS or architecture is not on the list, you may be able to
|
|||
</tr>
|
||||
<tr><td colspan="3"><hr></td></tr>
|
||||
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
|
||||
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; install from source for ARM</td></tr>
|
||||
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported</td></tr>
|
||||
<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
|
||||
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
|
||||
</table>
|
||||
|
|
@ -220,19 +220,29 @@ and building a simple program, as follows.
|
|||
|
||||
<p>
|
||||
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
|
||||
<code>$HOME/work</code> for example, and set the <code>GOPATH</code> environment
|
||||
<code class="testUnix">$HOME/work</code>
|
||||
<code class="testWindows" style="display: none">%HOME%\work</code>
|
||||
for example, and set the <code>GOPATH</code> environment
|
||||
variable to point to that location.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<pre class="testUnix">
|
||||
$ <b>export GOPATH=$HOME/work</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>set GOPATH=%HOME%\work</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<span class="testUnix">
|
||||
You should put the above command in your shell startup script
|
||||
(<code>$HOME/.profile</code> for example) or, if you use Windows,
|
||||
follow the <a href="#windows_env">instructions above</a> to set the
|
||||
(<code>$HOME/.profile</code> for example).
|
||||
</span>
|
||||
<span class="testWindows">
|
||||
On Windows, follow the <a href="#windows_env">instructions above</a> to set the
|
||||
<code>GOPATH</code> environment variable on your system.
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -256,21 +266,30 @@ func main() {
|
|||
Then compile it with the <code>go</code> tool:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<pre class="testUnix">
|
||||
$ <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>go install github.com/user/hello</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The above command will put an executable command named <code>hello</code>
|
||||
The command above will put an executable command named <code>hello</code>
|
||||
(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
|
||||
Execute the command to see the greeting:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<pre class="testUnix">
|
||||
$ <b>$GOPATH/bin/hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>%GOPATH%\bin\hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If you see the "hello, world" message then your Go installation is working.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Concurrent computation of pi.
|
||||
// See http://goo.gl/ZuTZM.
|
||||
// See https://goo.gl/la6Kli.
|
||||
//
|
||||
// This demonstrates Go's ability to handle
|
||||
// large numbers of concurrent processes.
|
||||
|
|
|
|||
14
misc/cgo/errors/issue13129.go
Normal file
14
misc/cgo/errors/issue13129.go
Normal 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
|
||||
}
|
||||
12
misc/cgo/errors/issue13423.go
Normal file
12
misc/cgo/errors/issue13423.go
Normal 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
|
||||
}
|
||||
24
misc/cgo/errors/issue13635.go
Normal file
24
misc/cgo/errors/issue13635.go
Normal 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
|
||||
)
|
||||
}
|
||||
|
|
@ -125,7 +125,6 @@ var ptrTests = []ptrTest{
|
|||
fail: true,
|
||||
},
|
||||
/*
|
||||
TODO(khr): reenable when write barriers are fixed.
|
||||
{
|
||||
// Storing a Go pointer into C memory should fail.
|
||||
name: "barrier",
|
||||
|
|
@ -211,6 +210,24 @@ var ptrTests = []ptrTest{
|
|||
fail: true,
|
||||
expensive: true,
|
||||
},
|
||||
{
|
||||
// Exported functions may not return Go pointers.
|
||||
name: "export1",
|
||||
c: `extern unsigned char *GoFn();`,
|
||||
support: `//export GoFn
|
||||
func GoFn() *byte { return new(byte) }`,
|
||||
body: `C.GoFn()`,
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
// Returning a C pointer is fine.
|
||||
name: "exportok",
|
||||
c: `#include <stdlib.h>
|
||||
extern unsigned char *GoFn();`,
|
||||
support: `//export GoFn
|
||||
func GoFn() *byte { return (*byte)(C.malloc(1)) }`,
|
||||
body: `C.GoFn()`,
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ check() {
|
|||
echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file
|
||||
exit 1
|
||||
fi
|
||||
expect $file $file:$line:
|
||||
}
|
||||
|
||||
expect() {
|
||||
file=$1
|
||||
shift
|
||||
if go build $file >errs 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
|
||||
exit 1
|
||||
|
|
@ -19,11 +25,13 @@ check() {
|
|||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
|
||||
exit 1
|
||||
fi
|
||||
if ! fgrep $file:$line: errs >/dev/null 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error on line $line but saw:
|
||||
cat 1>&2 errs
|
||||
exit 1
|
||||
fi
|
||||
for error; do
|
||||
if ! fgrep $error errs >/dev/null 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output to contain \"$error\" but saw:
|
||||
cat 1>&2 errs
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check err1.go
|
||||
|
|
@ -33,6 +41,9 @@ check issue7757.go
|
|||
check issue8442.go
|
||||
check issue11097a.go
|
||||
check issue11097b.go
|
||||
expect issue13129.go C.ushort
|
||||
check issue13423.go
|
||||
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
||||
|
||||
if ! go run ptr.go; then
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -1,42 +1,9 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
|
||||
* modified by Michael Mellor)
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
// +build test_run
|
||||
|
||||
// Run the game of life in C using Go for parallelization.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
// +build test_run
|
||||
|
||||
// Pass numbers along a chain of threads.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"../stdio"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"../stdio"
|
||||
)
|
||||
|
||||
const N = 10
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
// +build test_run
|
||||
|
||||
// Compute Fibonacci numbers with two goroutines
|
||||
// that pass integers back and forth. No actual
|
||||
|
|
@ -14,9 +14,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"../stdio"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"../stdio"
|
||||
)
|
||||
|
||||
func fibber(c, out chan int64, i int64) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
// +build test_run
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ void callPanic(void);
|
|||
int callGoReturnVal(void);
|
||||
int returnAfterGrow(void);
|
||||
int returnAfterGrowFromGo(void);
|
||||
void callGoWithString(void);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
|
|
@ -178,7 +179,6 @@ func testCallbackCallers(t *testing.T) {
|
|||
pc := make([]uintptr, 100)
|
||||
n := 0
|
||||
name := []string{
|
||||
"test.goCallback",
|
||||
"runtime.call16",
|
||||
"runtime.cgocallbackg1",
|
||||
"runtime.cgocallbackg",
|
||||
|
|
@ -193,10 +193,10 @@ func testCallbackCallers(t *testing.T) {
|
|||
"runtime.goexit",
|
||||
}
|
||||
if unsafe.Sizeof((*byte)(nil)) == 8 {
|
||||
name[1] = "runtime.call32"
|
||||
name[0] = "runtime.call32"
|
||||
}
|
||||
nestedCall(func() {
|
||||
n = runtime.Callers(2, pc)
|
||||
n = runtime.Callers(4, pc)
|
||||
})
|
||||
if n != len(name) {
|
||||
t.Errorf("expected %d frames, got %d", len(name), n)
|
||||
|
|
@ -277,6 +277,22 @@ func goReturnVal() (r C.int) {
|
|||
return
|
||||
}
|
||||
|
||||
// Test that C can pass in a Go string from a string constant.
|
||||
func testCallGoWithString(t *testing.T) {
|
||||
C.callGoWithString()
|
||||
want := "string passed from C to Go"
|
||||
if stringFromGo != want {
|
||||
t.Errorf("string passed through C is %s, want %s", stringFromGo, want)
|
||||
}
|
||||
}
|
||||
|
||||
var stringFromGo string
|
||||
|
||||
//export goWithString
|
||||
func goWithString(s string) {
|
||||
stringFromGo = s
|
||||
}
|
||||
|
||||
func testCallbackStack(t *testing.T) {
|
||||
// Make cgo call and callback with different amount of stack stack available.
|
||||
// We do not do any explicit checks, just ensure that it does not crash.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "_cgo_export.h"
|
||||
|
|
@ -80,3 +81,10 @@ returnAfterGrowFromGo(void)
|
|||
return goReturnVal();
|
||||
}
|
||||
|
||||
void
|
||||
callGoWithString(void)
|
||||
{
|
||||
extern void goWithString(GoString);
|
||||
const char *str = "string passed from C to Go";
|
||||
goWithString((GoString){str, strlen(str)});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,5 +68,6 @@ func Test10303(t *testing.T) { test10303(t, 10) }
|
|||
func Test11925(t *testing.T) { test11925(t) }
|
||||
func Test12030(t *testing.T) { test12030(t) }
|
||||
func TestGCC68255(t *testing.T) { testGCC68255(t) }
|
||||
func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
|
|
|
|||
11
misc/cgo/test/cgo_unix_test.go
Normal file
11
misc/cgo/test/cgo_unix_test.go
Normal 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) }
|
||||
10
misc/cgo/test/issue13402.go
Normal file
10
misc/cgo/test/issue13402.go
Normal 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
|
||||
|
|
@ -14,6 +14,11 @@ void scatter() {
|
|||
printf("scatter = %p\n", p);
|
||||
}
|
||||
|
||||
// Adding this explicit extern declaration makes this a test for
|
||||
// https://gcc.gnu.org/PR68072 aka https://golang.org/issue/13344 .
|
||||
// It used to cause a cgo error when building with GCC 6.
|
||||
extern int hola;
|
||||
|
||||
// this example is in issue 3253
|
||||
int hola = 0;
|
||||
int testHola() { return hola; }
|
||||
|
|
|
|||
10
misc/cgo/test/issue4029.c
Normal file
10
misc/cgo/test/issue4029.c
Normal 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();
|
||||
}
|
||||
|
|
@ -9,32 +9,35 @@ package cgotest
|
|||
/*
|
||||
#include <dlfcn.h>
|
||||
#cgo linux LDFLAGS: -ldl
|
||||
|
||||
extern void call4029(void *arg);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var callbacks int
|
||||
|
||||
//export IMPIsOpaque
|
||||
func IMPIsOpaque() {
|
||||
fmt.Println("isOpaque")
|
||||
callbacks++
|
||||
}
|
||||
|
||||
//export IMPInitWithFrame
|
||||
func IMPInitWithFrame() {
|
||||
fmt.Println("IInitWithFrame")
|
||||
callbacks++
|
||||
}
|
||||
|
||||
//export IMPDrawRect
|
||||
func IMPDrawRect() {
|
||||
fmt.Println("drawRect:")
|
||||
callbacks++
|
||||
}
|
||||
|
||||
//export IMPWindowResize
|
||||
func IMPWindowResize() {
|
||||
fmt.Println("windowDidResize:")
|
||||
callbacks++
|
||||
}
|
||||
|
||||
func test4029(t *testing.T) {
|
||||
|
|
@ -42,6 +45,9 @@ func test4029(t *testing.T) {
|
|||
loadThySelf(t, "IMPDrawRect")
|
||||
loadThySelf(t, "IMPInitWithFrame")
|
||||
loadThySelf(t, "IMPIsOpaque")
|
||||
if callbacks != 4 {
|
||||
t.Errorf("got %d callbacks, expected 4", callbacks)
|
||||
}
|
||||
}
|
||||
|
||||
func loadThySelf(t *testing.T, symbol string) {
|
||||
|
|
@ -58,4 +64,5 @@ func loadThySelf(t *testing.T, symbol string) {
|
|||
return
|
||||
}
|
||||
t.Log(symbol, symbol_address)
|
||||
C.call4029(symbol_address)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ func test8694(t *testing.T) {
|
|||
t.Skip("test8694 is disabled on ARM because 5l cannot handle thumb library.")
|
||||
}
|
||||
// Really just testing that this compiles, but check answer anyway.
|
||||
x := complex64(2 + 3i)
|
||||
x := C.complexfloat(2 + 3i)
|
||||
x2 := x * x
|
||||
cx2 := C.complexFloatSquared(x)
|
||||
if cx2 != x2 {
|
||||
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2)
|
||||
}
|
||||
|
||||
y := complex128(2 + 3i)
|
||||
y := C.complexdouble(2 + 3i)
|
||||
y2 := y * y
|
||||
cy2 := C.complexDoubleSquared(y)
|
||||
if cy2 != y2 {
|
||||
|
|
|
|||
71
misc/cgo/test/sigaltstack.go
Normal file
71
misc/cgo/test/sigaltstack.go
Normal 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)
|
||||
}
|
||||
185
misc/cgo/testcarchive/main2.c
Normal file
185
misc/cgo/testcarchive/main2.c
Normal 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;
|
||||
}
|
||||
153
misc/cgo/testcarchive/main3.c
Normal file
153
misc/cgo/testcarchive/main3.c
Normal 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;
|
||||
}
|
||||
194
misc/cgo/testcarchive/main4.c
Normal file
194
misc/cgo/testcarchive/main4.c
Normal 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;
|
||||
}
|
||||
45
misc/cgo/testcarchive/src/libgo2/libgo2.go
Normal file
45
misc/cgo/testcarchive/src/libgo2/libgo2.go
Normal 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() {
|
||||
}
|
||||
44
misc/cgo/testcarchive/src/libgo3/libgo3.go
Normal file
44
misc/cgo/testcarchive/src/libgo3/libgo3.go
Normal 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() {
|
||||
}
|
||||
52
misc/cgo/testcarchive/src/libgo4/libgo4.go
Normal file
52
misc/cgo/testcarchive/src/libgo4/libgo4.go
Normal 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() {
|
||||
}
|
||||
|
|
@ -23,11 +23,16 @@ fi
|
|||
|
||||
rm -rf libgo.a libgo.h testp pkg
|
||||
|
||||
status=0
|
||||
|
||||
# Installing first will create the header files we want.
|
||||
|
||||
GOPATH=$(pwd) go install -buildmode=c-archive libgo
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c pkg/$(go env GOOS)_$(go env GOARCH)/libgo.a
|
||||
$bin arg1 arg2
|
||||
if ! $bin arg1 arg2; then
|
||||
echo "FAIL test1a"
|
||||
status=1
|
||||
fi
|
||||
rm -f libgo.a libgo.h testp
|
||||
|
||||
# Test building libgo other than installing it.
|
||||
|
|
@ -35,10 +40,49 @@ rm -f libgo.a libgo.h testp
|
|||
|
||||
GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
|
||||
$bin arg1 arg2
|
||||
if ! $bin arg1 arg2; then
|
||||
echo "FAIL test1b"
|
||||
status=1
|
||||
fi
|
||||
rm -f libgo.a libgo.h testp
|
||||
|
||||
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
|
||||
$bin arg1 arg2
|
||||
if ! $bin arg1 arg2; then
|
||||
echo "FAIL test1c"
|
||||
status=1
|
||||
fi
|
||||
rm -rf libgo.a libgo.h testp pkg
|
||||
|
||||
case "$(go env GOOS)/$(go env GOARCH)" in
|
||||
"darwin/arm" | "darwin/arm64")
|
||||
echo "Skipping test2; see https://golang.org/issue/13701"
|
||||
;;
|
||||
*)
|
||||
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo2.a libgo2
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main2.c libgo2.a
|
||||
if ! $bin; then
|
||||
echo "FAIL test2"
|
||||
status=1
|
||||
fi
|
||||
rm -rf libgo2.a libgo2.h testp pkg
|
||||
;;
|
||||
esac
|
||||
|
||||
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo3.a libgo3
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main3.c libgo3.a
|
||||
if ! $bin; then
|
||||
echo "FAIL test3"
|
||||
status=1
|
||||
fi
|
||||
rm -rf libgo3.a libgo3.h testp pkg
|
||||
|
||||
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo4.a libgo4
|
||||
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main4.c libgo4.a
|
||||
if ! $bin; then
|
||||
echo "FAIL test4"
|
||||
status=1
|
||||
fi
|
||||
rm -rf libgo4.a libgo4.h testp pkg
|
||||
|
||||
exit $status
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define fd (10)
|
||||
#define fd (100)
|
||||
|
||||
// Tests libgo2.so, which does not export any functions.
|
||||
// Read a string from the file descriptor and print it.
|
||||
|
|
|
|||
214
misc/cgo/testcshared/main4.c
Normal file
214
misc/cgo/testcshared/main4.c
Normal 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;
|
||||
}
|
||||
197
misc/cgo/testcshared/main5.c
Normal file
197
misc/cgo/testcshared/main5.c
Normal 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;
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ import (
|
|||
// that the C code can also use.
|
||||
|
||||
const (
|
||||
fd = 10
|
||||
fd = 100
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
45
misc/cgo/testcshared/src/libgo4/libgo4.go
Normal file
45
misc/cgo/testcshared/src/libgo4/libgo4.go
Normal 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() {
|
||||
}
|
||||
44
misc/cgo/testcshared/src/libgo5/libgo5.go
Normal file
44
misc/cgo/testcshared/src/libgo5/libgo5.go
Normal 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() {
|
||||
}
|
||||
|
|
@ -16,6 +16,13 @@ fi
|
|||
|
||||
goos=$(go env GOOS)
|
||||
goarch=$(go env GOARCH)
|
||||
goroot=$(go env GOROOT)
|
||||
if [ ! -d "$goroot" ]; then
|
||||
echo 'misc/cgo/testcshared/test.bash cannnot find GOROOT' 1>&2
|
||||
echo '$GOROOT:' "$GOROOT" 1>&2
|
||||
echo 'go env GOROOT:' "$goroot" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Directory where cgo headers and outputs will be installed.
|
||||
# The installation directory format varies depending on the platform.
|
||||
|
|
@ -28,12 +35,13 @@ fi
|
|||
androidpath=/data/local/tmp/testcshared-$$
|
||||
|
||||
function cleanup() {
|
||||
rm -rf libgo.$libext libgo2.$libext libgo.h testp testp2 testp3 pkg
|
||||
|
||||
rm -rf $(go env GOROOT)/${installdir}
|
||||
rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext
|
||||
rm -f libgo.h libgo4.h libgo5.h
|
||||
rm -f testp testp2 testp3 testp4 testp5
|
||||
rm -rf pkg "${goroot}/${installdir}"
|
||||
|
||||
if [ "$goos" == "android" ]; then
|
||||
adb shell rm -rf $androidpath
|
||||
adb shell rm -rf "$androidpath"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
|
@ -93,6 +101,8 @@ if [ "$goos" == "android" ]; then
|
|||
GOGCCFLAGS="${GOGCCFLAGS} -pie"
|
||||
fi
|
||||
|
||||
status=0
|
||||
|
||||
# test0: exported symbols in shared lib are accessible.
|
||||
# TODO(iant): using _shared here shouldn't really be necessary.
|
||||
$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c libgo.$libext
|
||||
|
|
@ -101,7 +111,7 @@ binpush testp
|
|||
output=$(run LD_LIBRARY_PATH=. ./testp)
|
||||
if [ "$output" != "PASS" ]; then
|
||||
echo "FAIL test0 got ${output}"
|
||||
exit 1
|
||||
status=1
|
||||
fi
|
||||
|
||||
# test1: shared library can be dynamically loaded and exported symbols are accessible.
|
||||
|
|
@ -110,7 +120,7 @@ binpush testp
|
|||
output=$(run ./testp ./libgo.$libext)
|
||||
if [ "$output" != "PASS" ]; then
|
||||
echo "FAIL test1 got ${output}"
|
||||
exit 1
|
||||
status=1
|
||||
fi
|
||||
|
||||
# test2: tests libgo2 which does not export any functions.
|
||||
|
|
@ -125,7 +135,7 @@ binpush testp2
|
|||
output=$(run LD_LIBRARY_PATH=. ./testp2)
|
||||
if [ "$output" != "PASS" ]; then
|
||||
echo "FAIL test2 got ${output}"
|
||||
exit 1
|
||||
status=1
|
||||
fi
|
||||
|
||||
# test3: tests main.main is exported on android.
|
||||
|
|
@ -135,7 +145,42 @@ if [ "$goos" == "android" ]; then
|
|||
output=$(run ./testp ./libgo.so)
|
||||
if [ "$output" != "PASS" ]; then
|
||||
echo "FAIL test3 got ${output}"
|
||||
exit 1
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
echo "ok"
|
||||
|
||||
# test4: tests signal handlers
|
||||
GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4
|
||||
binpush libgo4.$libext
|
||||
$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl
|
||||
binpush testp4
|
||||
output=$(run ./testp4 ./libgo4.$libext 2>&1)
|
||||
if test "$output" != "PASS"; then
|
||||
echo "FAIL test4 got ${output}"
|
||||
if test "$goos" != "android"; then
|
||||
echo "re-running test4 in verbose mode"
|
||||
./testp4 ./libgo4.$libext verbose
|
||||
fi
|
||||
status=1
|
||||
fi
|
||||
|
||||
# test5: tests signal handlers with os/signal.Notify
|
||||
GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5
|
||||
binpush libgo5.$libext
|
||||
$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl
|
||||
binpush testp5
|
||||
output=$(run ./testp5 ./libgo5.$libext 2>&1)
|
||||
if test "$output" != "PASS"; then
|
||||
echo "FAIL test5 got ${output}"
|
||||
if test "$goos" != "android"; then
|
||||
echo "re-running test5 in verbose mode"
|
||||
./testp5 ./libgo5.$libext verbose
|
||||
fi
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test $status = 0; then
|
||||
echo "ok"
|
||||
fi
|
||||
|
||||
exit $status
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
extern int *GoFn(void);
|
||||
extern int *GoFn(int *);
|
||||
|
||||
// Yes, you can have definitions if you use //export, as long as they are weak.
|
||||
int f(void) __attribute__ ((weak));
|
||||
|
||||
int f() {
|
||||
int *p = GoFn();
|
||||
int i;
|
||||
int *p = GoFn(&i);
|
||||
if (*p != 12345)
|
||||
return 0;
|
||||
return 1;
|
||||
|
|
@ -20,9 +21,9 @@ int f() {
|
|||
import "C"
|
||||
|
||||
//export GoFn
|
||||
func GoFn() *C.int {
|
||||
i := C.int(12345)
|
||||
return &i
|
||||
func GoFn(p *C.int) *C.int {
|
||||
*p = C.int(12345)
|
||||
return p
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
|
|
@ -29,10 +29,24 @@ if $CC --version | grep clang >& /dev/null; then
|
|||
ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
|
||||
major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
|
||||
minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
|
||||
if test $major -lt 3 || test $major -eq 3 -a $minor -lt 6; then
|
||||
echo "skipping msan test; clang version $major.$minor older than 3.6"
|
||||
if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
|
||||
echo "skipping msan test; clang version $major.$minor (older than 3.6)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Clang before 3.8 does not work with Linux at or after 4.1.
|
||||
# golang.org/issue/12898.
|
||||
if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
|
||||
if test "$(uname)" = Linux; then
|
||||
linuxver=$(uname -r)
|
||||
linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/')
|
||||
linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
|
||||
if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then
|
||||
echo "skipping msan test; clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
status=0
|
||||
|
|
@ -47,7 +61,12 @@ if ! go run -msan msan.go; then
|
|||
status=1
|
||||
fi
|
||||
|
||||
if ! go run -msan msan2.go; then
|
||||
if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
|
||||
echo "FAIL: msan2 with -fsanitize=memory"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! go run -msan -a msan2.go; then
|
||||
echo "FAIL: msan2"
|
||||
status=1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -285,23 +285,23 @@ func readNotes(f *elf.File) ([]*note, error) {
|
|||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("read namesize failed:", err)
|
||||
return nil, fmt.Errorf("read namesize failed: %v", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read descsize failed:", err)
|
||||
return nil, fmt.Errorf("read descsize failed: %v", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &tag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read type failed:", err)
|
||||
return nil, fmt.Errorf("read type failed: %v", err)
|
||||
}
|
||||
name, err := readwithpad(r, namesize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read name failed:", err)
|
||||
return nil, fmt.Errorf("read name failed: %v", err)
|
||||
}
|
||||
desc, err := readwithpad(r, descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read desc failed:", err)
|
||||
return nil, fmt.Errorf("read desc failed: %v", err)
|
||||
}
|
||||
notes = append(notes, ¬e{name: string(name), tag: tag, desc: string(desc), section: sect})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,14 @@ package main
|
|||
import "fmt"
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -pthread
|
||||
#cgo LDFLAGS: -pthread
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
int *p;
|
||||
static void sigsegv() {
|
||||
|
|
@ -18,16 +23,65 @@ static void sigsegv() {
|
|||
exit(2);
|
||||
}
|
||||
|
||||
static void sighandler(int signum) {
|
||||
static void segvhandler(int signum) {
|
||||
if (signum == SIGSEGV) {
|
||||
exit(0); // success
|
||||
}
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t sigioSeen;
|
||||
|
||||
// Use up some stack space.
|
||||
static void recur(int i, char *p) {
|
||||
char a[1024];
|
||||
|
||||
*p = '\0';
|
||||
if (i > 0) {
|
||||
recur(i - 1, a);
|
||||
}
|
||||
}
|
||||
|
||||
static void iohandler(int signum) {
|
||||
char a[1024];
|
||||
|
||||
recur(4, a);
|
||||
sigioSeen = 1;
|
||||
}
|
||||
|
||||
static void* sigioThread(void* arg __attribute__ ((unused))) {
|
||||
raise(SIGIO);
|
||||
}
|
||||
|
||||
static void sigioOnThread() {
|
||||
pthread_t tid;
|
||||
int i;
|
||||
|
||||
pthread_create(&tid, NULL, sigioThread, NULL);
|
||||
pthread_join(tid, NULL);
|
||||
|
||||
// Wait until the signal has been delivered.
|
||||
i = 0;
|
||||
while (!sigioSeen) {
|
||||
if (sched_yield() < 0) {
|
||||
perror("sched_yield");
|
||||
}
|
||||
i++;
|
||||
if (i > 10000) {
|
||||
fprintf(stderr, "looping too long waiting for signal\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__ ((constructor)) sigsetup(void) {
|
||||
struct sigaction act;
|
||||
act.sa_handler = &sighandler;
|
||||
sigaction(SIGSEGV, &act, 0);
|
||||
|
||||
memset(&act, 0, sizeof act);
|
||||
act.sa_handler = segvhandler;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
|
||||
act.sa_handler = iohandler;
|
||||
sigaction(SIGIO, &act, NULL);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
|||
|
|
@ -327,3 +327,14 @@ func toASCII(s string) string {
|
|||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// isHeaderOnlyType checks if the given type flag is of the type that has no
|
||||
// data section even if a size is specified.
|
||||
func isHeaderOnlyType(flag byte) bool {
|
||||
switch flag {
|
||||
case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func Example() {
|
|||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"todo.txt", "Get animal handling licence."},
|
||||
{"todo.txt", "Get animal handling license."},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &tar.Header{
|
||||
|
|
@ -76,5 +76,5 @@ func Example() {
|
|||
// Geoffrey
|
||||
// Gonzo
|
||||
// Contents of todo.txt:
|
||||
// Get animal handling licence.
|
||||
// Get animal handling license.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ type Reader struct {
|
|||
hdrBuff [blockSize]byte // buffer to use in readHeader
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
// A numBytesReader is an io.Reader with a numBytes method, returning the number
|
||||
// of bytes remaining in the underlying encoded data.
|
||||
type numBytesReader interface {
|
||||
|
|
@ -113,78 +117,82 @@ func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
|
|||
//
|
||||
// io.EOF is returned at the end of the input.
|
||||
func (tr *Reader) Next() (*Header, error) {
|
||||
var hdr *Header
|
||||
if tr.err == nil {
|
||||
tr.skipUnread()
|
||||
}
|
||||
if tr.err != nil {
|
||||
return hdr, tr.err
|
||||
return nil, tr.err
|
||||
}
|
||||
hdr = tr.readHeader()
|
||||
if hdr == nil {
|
||||
return hdr, tr.err
|
||||
}
|
||||
// Check for PAX/GNU header.
|
||||
switch hdr.Typeflag {
|
||||
case TypeXHeader:
|
||||
// PAX extended header
|
||||
headers, err := parsePAX(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// We actually read the whole file,
|
||||
// but this skips alignment padding
|
||||
tr.skipUnread()
|
||||
|
||||
var hdr *Header
|
||||
var extHdrs map[string]string
|
||||
|
||||
// Externally, Next iterates through the tar archive as if it is a series of
|
||||
// files. Internally, the tar format often uses fake "files" to add meta
|
||||
// data that describes the next file. These meta data "files" should not
|
||||
// normally be visible to the outside. As such, this loop iterates through
|
||||
// one or more "header files" until it finds a "normal file".
|
||||
loop:
|
||||
for {
|
||||
tr.err = tr.skipUnread()
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
|
||||
hdr = tr.readHeader()
|
||||
if hdr == nil {
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
mergePAX(hdr, headers)
|
||||
|
||||
// Check for a PAX format sparse file
|
||||
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
|
||||
if err != nil {
|
||||
tr.err = err
|
||||
return nil, err
|
||||
}
|
||||
if sp != nil {
|
||||
// Current file is a PAX format GNU sparse file.
|
||||
// Set the current file reader to a sparse file reader.
|
||||
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||
// Check for PAX/GNU special headers and files.
|
||||
switch hdr.Typeflag {
|
||||
case TypeXHeader:
|
||||
extHdrs, tr.err = parsePAX(tr)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
continue loop // This is a meta header affecting the next header
|
||||
case TypeGNULongName, TypeGNULongLink:
|
||||
var realname []byte
|
||||
realname, tr.err = ioutil.ReadAll(tr)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
|
||||
// Convert GNU extensions to use PAX headers.
|
||||
if extHdrs == nil {
|
||||
extHdrs = make(map[string]string)
|
||||
}
|
||||
var p parser
|
||||
switch hdr.Typeflag {
|
||||
case TypeGNULongName:
|
||||
extHdrs[paxPath] = p.parseString(realname)
|
||||
case TypeGNULongLink:
|
||||
extHdrs[paxLinkpath] = p.parseString(realname)
|
||||
}
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil, tr.err
|
||||
}
|
||||
continue loop // This is a meta header affecting the next header
|
||||
default:
|
||||
mergePAX(hdr, extHdrs)
|
||||
|
||||
// Check for a PAX format sparse file
|
||||
sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
|
||||
if err != nil {
|
||||
tr.err = err
|
||||
return nil, err
|
||||
}
|
||||
if sp != nil {
|
||||
// Current file is a PAX format GNU sparse file.
|
||||
// Set the current file reader to a sparse file reader.
|
||||
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
}
|
||||
break loop // This is a file, so stop
|
||||
}
|
||||
return hdr, nil
|
||||
case TypeGNULongName:
|
||||
// We have a GNU long name header. Its contents are the real file name.
|
||||
realname, err := ioutil.ReadAll(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, tr.err = tr.Next()
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
hdr.Name = cString(realname)
|
||||
return hdr, nil
|
||||
case TypeGNULongLink:
|
||||
// We have a GNU long link header.
|
||||
realname, err := ioutil.ReadAll(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, tr.err = tr.Next()
|
||||
if tr.err != nil {
|
||||
return nil, tr.err
|
||||
}
|
||||
hdr.Linkname = cString(realname)
|
||||
return hdr, nil
|
||||
}
|
||||
return hdr, tr.err
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
|
||||
|
|
@ -355,6 +363,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sbuf := string(buf)
|
||||
|
||||
// For GNU PAX sparse format 0.0 support.
|
||||
// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
|
||||
|
|
@ -363,35 +372,17 @@ func parsePAX(r io.Reader) (map[string]string, error) {
|
|||
headers := make(map[string]string)
|
||||
// Each record is constructed as
|
||||
// "%d %s=%s\n", length, keyword, value
|
||||
for len(buf) > 0 {
|
||||
// or the header was empty to start with.
|
||||
var sp int
|
||||
// The size field ends at the first space.
|
||||
sp = bytes.IndexByte(buf, ' ')
|
||||
if sp == -1 {
|
||||
for len(sbuf) > 0 {
|
||||
key, value, residual, err := parsePAXRecord(sbuf)
|
||||
if err != nil {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
// Parse the first token as a decimal integer.
|
||||
n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
|
||||
if err != nil || n < 5 || int64(len(buf)) < n {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
// Extract everything between the decimal and the n -1 on the
|
||||
// beginning to eat the ' ', -1 on the end to skip the newline.
|
||||
var record []byte
|
||||
record, buf = buf[sp+1:n-1], buf[n:]
|
||||
// The first equals is guaranteed to mark the end of the key.
|
||||
// Everything else is value.
|
||||
eq := bytes.IndexByte(record, '=')
|
||||
if eq == -1 {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
key, value := record[:eq], record[eq+1:]
|
||||
sbuf = residual
|
||||
|
||||
keyStr := string(key)
|
||||
if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
|
||||
// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
|
||||
sparseMap.Write(value)
|
||||
sparseMap.WriteString(value)
|
||||
sparseMap.Write([]byte{','})
|
||||
} else {
|
||||
// Normal key. Set the value in the headers map.
|
||||
|
|
@ -406,9 +397,42 @@ func parsePAX(r io.Reader) (map[string]string, error) {
|
|||
return headers, nil
|
||||
}
|
||||
|
||||
// cString parses bytes as a NUL-terminated C-style string.
|
||||
// parsePAXRecord parses the input PAX record string into a key-value pair.
|
||||
// If parsing is successful, it will slice off the currently read record and
|
||||
// return the remainder as r.
|
||||
//
|
||||
// A PAX record is of the following form:
|
||||
// "%d %s=%s\n" % (size, key, value)
|
||||
func parsePAXRecord(s string) (k, v, r string, err error) {
|
||||
// The size field ends at the first space.
|
||||
sp := strings.IndexByte(s, ' ')
|
||||
if sp == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Parse the first token as a decimal integer.
|
||||
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
|
||||
if perr != nil || n < 5 || int64(len(s)) < n {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// Extract everything between the space and the final newline.
|
||||
rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
|
||||
if nl != "\n" {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
|
||||
// The first equals separates the key from the value.
|
||||
eq := strings.IndexByte(rec, '=')
|
||||
if eq == -1 {
|
||||
return "", "", s, ErrHeader
|
||||
}
|
||||
return rec[:eq], rec[eq+1:], rem, nil
|
||||
}
|
||||
|
||||
// parseString parses bytes as a NUL-terminated C-style string.
|
||||
// If a NUL byte is not found then the whole slice is returned as a string.
|
||||
func cString(b []byte) string {
|
||||
func (*parser) parseString(b []byte) string {
|
||||
n := 0
|
||||
for n < len(b) && b[n] != 0 {
|
||||
n++
|
||||
|
|
@ -416,19 +440,51 @@ func cString(b []byte) string {
|
|||
return string(b[0:n])
|
||||
}
|
||||
|
||||
func (tr *Reader) octal(b []byte) int64 {
|
||||
// Check for binary format first.
|
||||
// parseNumeric parses the input as being encoded in either base-256 or octal.
|
||||
// This function may return negative numbers.
|
||||
// If parsing fails or an integer overflow occurs, err will be set.
|
||||
func (p *parser) parseNumeric(b []byte) int64 {
|
||||
// Check for base-256 (binary) format first.
|
||||
// If the first bit is set, then all following bits constitute a two's
|
||||
// complement encoded number in big-endian byte order.
|
||||
if len(b) > 0 && b[0]&0x80 != 0 {
|
||||
var x int64
|
||||
for i, c := range b {
|
||||
if i == 0 {
|
||||
c &= 0x7f // ignore signal bit in first byte
|
||||
}
|
||||
x = x<<8 | int64(c)
|
||||
// Handling negative numbers relies on the following identity:
|
||||
// -a-1 == ^a
|
||||
//
|
||||
// If the number is negative, we use an inversion mask to invert the
|
||||
// data bytes and treat the value as an unsigned number.
|
||||
var inv byte // 0x00 if positive or zero, 0xff if negative
|
||||
if b[0]&0x40 != 0 {
|
||||
inv = 0xff
|
||||
}
|
||||
return x
|
||||
|
||||
var x uint64
|
||||
for i, c := range b {
|
||||
c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
|
||||
if i == 0 {
|
||||
c &= 0x7f // Ignore signal bit in first byte
|
||||
}
|
||||
if (x >> 56) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
x = x<<8 | uint64(c)
|
||||
}
|
||||
if (x >> 63) > 0 {
|
||||
p.err = ErrHeader // Integer overflow
|
||||
return 0
|
||||
}
|
||||
if inv == 0xff {
|
||||
return ^int64(x)
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
// Normal case is base-8 (octal) format.
|
||||
return p.parseOctal(b)
|
||||
}
|
||||
|
||||
func (p *parser) parseOctal(b []byte) int64 {
|
||||
// Because unused fields are filled with NULs, we need
|
||||
// to skip leading NULs. Fields may also be padded with
|
||||
// spaces or NULs.
|
||||
|
|
@ -439,9 +495,9 @@ func (tr *Reader) octal(b []byte) int64 {
|
|||
if len(b) == 0 {
|
||||
return 0
|
||||
}
|
||||
x, err := strconv.ParseUint(cString(b), 8, 64)
|
||||
if err != nil {
|
||||
tr.err = err
|
||||
x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
|
||||
if perr != nil {
|
||||
p.err = ErrHeader
|
||||
}
|
||||
return int64(x)
|
||||
}
|
||||
|
|
@ -492,9 +548,10 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
given := tr.octal(header[148:156])
|
||||
var p parser
|
||||
given := p.parseOctal(header[148:156])
|
||||
unsigned, signed := checksum(header)
|
||||
return given == unsigned || given == signed
|
||||
return p.err == nil && (given == unsigned || given == signed)
|
||||
}
|
||||
|
||||
// readHeader reads the next block header and assumes that the underlying reader
|
||||
|
|
@ -531,22 +588,19 @@ func (tr *Reader) readHeader() *Header {
|
|||
}
|
||||
|
||||
// Unpack
|
||||
var p parser
|
||||
hdr := new(Header)
|
||||
s := slicer(header)
|
||||
|
||||
hdr.Name = cString(s.next(100))
|
||||
hdr.Mode = tr.octal(s.next(8))
|
||||
hdr.Uid = int(tr.octal(s.next(8)))
|
||||
hdr.Gid = int(tr.octal(s.next(8)))
|
||||
hdr.Size = tr.octal(s.next(12))
|
||||
if hdr.Size < 0 {
|
||||
tr.err = ErrHeader
|
||||
return nil
|
||||
}
|
||||
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||
hdr.Name = p.parseString(s.next(100))
|
||||
hdr.Mode = p.parseNumeric(s.next(8))
|
||||
hdr.Uid = int(p.parseNumeric(s.next(8)))
|
||||
hdr.Gid = int(p.parseNumeric(s.next(8)))
|
||||
hdr.Size = p.parseNumeric(s.next(12))
|
||||
hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
||||
s.next(8) // chksum
|
||||
hdr.Typeflag = s.next(1)[0]
|
||||
hdr.Linkname = cString(s.next(100))
|
||||
hdr.Linkname = p.parseString(s.next(100))
|
||||
|
||||
// The remainder of the header depends on the value of magic.
|
||||
// The original (v7) version of tar had no explicit magic field,
|
||||
|
|
@ -566,45 +620,54 @@ func (tr *Reader) readHeader() *Header {
|
|||
|
||||
switch format {
|
||||
case "posix", "gnu", "star":
|
||||
hdr.Uname = cString(s.next(32))
|
||||
hdr.Gname = cString(s.next(32))
|
||||
hdr.Uname = p.parseString(s.next(32))
|
||||
hdr.Gname = p.parseString(s.next(32))
|
||||
devmajor := s.next(8)
|
||||
devminor := s.next(8)
|
||||
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
|
||||
hdr.Devmajor = tr.octal(devmajor)
|
||||
hdr.Devminor = tr.octal(devminor)
|
||||
hdr.Devmajor = p.parseNumeric(devmajor)
|
||||
hdr.Devminor = p.parseNumeric(devminor)
|
||||
}
|
||||
var prefix string
|
||||
switch format {
|
||||
case "posix", "gnu":
|
||||
prefix = cString(s.next(155))
|
||||
prefix = p.parseString(s.next(155))
|
||||
case "star":
|
||||
prefix = cString(s.next(131))
|
||||
hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||
hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||
prefix = p.parseString(s.next(131))
|
||||
hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
||||
hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
||||
}
|
||||
if len(prefix) > 0 {
|
||||
hdr.Name = prefix + "/" + hdr.Name
|
||||
}
|
||||
}
|
||||
|
||||
if tr.err != nil {
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
|
||||
nb := hdr.Size
|
||||
if isHeaderOnlyType(hdr.Typeflag) {
|
||||
nb = 0
|
||||
}
|
||||
if nb < 0 {
|
||||
tr.err = ErrHeader
|
||||
return nil
|
||||
}
|
||||
|
||||
// Maximum value of hdr.Size is 64 GB (12 octal digits),
|
||||
// so there's no risk of int64 overflowing.
|
||||
nb := int64(hdr.Size)
|
||||
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
||||
|
||||
// Set the current file reader.
|
||||
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
||||
tr.curr = ®FileReader{r: tr.r, nb: nb}
|
||||
|
||||
// Check for old GNU sparse format entry.
|
||||
if hdr.Typeflag == TypeGNUSparse {
|
||||
// Get the real size of the file.
|
||||
hdr.Size = tr.octal(header[483:495])
|
||||
hdr.Size = p.parseNumeric(header[483:495])
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the sparse map.
|
||||
sp := tr.readOldGNUSparseMap(header)
|
||||
|
|
@ -626,6 +689,7 @@ func (tr *Reader) readHeader() *Header {
|
|||
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
|
||||
// then one or more extension headers are used to store the rest of the sparse map.
|
||||
func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
||||
var p parser
|
||||
isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
|
||||
spCap := oldGNUSparseMainHeaderNumEntries
|
||||
if isExtended {
|
||||
|
|
@ -636,10 +700,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
|||
|
||||
// Read the four entries from the main tar header
|
||||
for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
|
||||
offset := tr.octal(s.next(oldGNUSparseOffsetSize))
|
||||
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
|
||||
if tr.err != nil {
|
||||
tr.err = ErrHeader
|
||||
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
|
||||
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
if offset == 0 && numBytes == 0 {
|
||||
|
|
@ -657,10 +721,10 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
|||
isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
|
||||
s = slicer(sparseHeader)
|
||||
for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
|
||||
offset := tr.octal(s.next(oldGNUSparseOffsetSize))
|
||||
numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
|
||||
if tr.err != nil {
|
||||
tr.err = ErrHeader
|
||||
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
|
||||
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
|
||||
if p.err != nil {
|
||||
tr.err = p.err
|
||||
return nil
|
||||
}
|
||||
if offset == 0 && numBytes == 0 {
|
||||
|
|
@ -672,85 +736,77 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
|||
return sp
|
||||
}
|
||||
|
||||
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
|
||||
// The sparse map is stored just before the file data and padded out to the nearest block boundary.
|
||||
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
|
||||
// version 1.0. The format of the sparse map consists of a series of
|
||||
// newline-terminated numeric fields. The first field is the number of entries
|
||||
// and is always present. Following this are the entries, consisting of two
|
||||
// fields (offset, numBytes). This function must stop reading at the end
|
||||
// boundary of the block containing the last newline.
|
||||
//
|
||||
// Note that the GNU manual says that numeric values should be encoded in octal
|
||||
// format. However, the GNU tar utility itself outputs these values in decimal.
|
||||
// As such, this library treats values as being encoded in decimal.
|
||||
func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
|
||||
buf := make([]byte, 2*blockSize)
|
||||
sparseHeader := buf[:blockSize]
|
||||
var cntNewline int64
|
||||
var buf bytes.Buffer
|
||||
var blk = make([]byte, blockSize)
|
||||
|
||||
// readDecimal is a helper function to read a decimal integer from the sparse map
|
||||
// while making sure to read from the file in blocks of size blockSize
|
||||
readDecimal := func() (int64, error) {
|
||||
// Look for newline
|
||||
nl := bytes.IndexByte(sparseHeader, '\n')
|
||||
if nl == -1 {
|
||||
if len(sparseHeader) >= blockSize {
|
||||
// This is an error
|
||||
return 0, ErrHeader
|
||||
// feedTokens copies data in numBlock chunks from r into buf until there are
|
||||
// at least cnt newlines in buf. It will not read more blocks than needed.
|
||||
var feedTokens = func(cnt int64) error {
|
||||
for cntNewline < cnt {
|
||||
if _, err := io.ReadFull(r, blk); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
oldLen := len(sparseHeader)
|
||||
newLen := oldLen + blockSize
|
||||
if cap(sparseHeader) < newLen {
|
||||
// There's more header, but we need to make room for the next block
|
||||
copy(buf, sparseHeader)
|
||||
sparseHeader = buf[:newLen]
|
||||
} else {
|
||||
// There's more header, and we can just reslice
|
||||
sparseHeader = sparseHeader[:newLen]
|
||||
buf.Write(blk)
|
||||
for _, c := range blk {
|
||||
if c == '\n' {
|
||||
cntNewline++
|
||||
}
|
||||
}
|
||||
|
||||
// Now that sparseHeader is large enough, read next block
|
||||
if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Look for a newline in the new data
|
||||
nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
|
||||
if nl == -1 {
|
||||
// This is an error
|
||||
return 0, ErrHeader
|
||||
}
|
||||
nl += oldLen // We want the position from the beginning
|
||||
}
|
||||
// Now that we've found a newline, read a number
|
||||
n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
|
||||
if err != nil {
|
||||
return 0, ErrHeader
|
||||
}
|
||||
|
||||
// Update sparseHeader to consume this number
|
||||
sparseHeader = sparseHeader[nl+1:]
|
||||
return n, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the first block
|
||||
if _, err := io.ReadFull(r, sparseHeader); err != nil {
|
||||
// nextToken gets the next token delimited by a newline. This assumes that
|
||||
// at least one newline exists in the buffer.
|
||||
var nextToken = func() string {
|
||||
cntNewline--
|
||||
tok, _ := buf.ReadString('\n')
|
||||
return tok[:len(tok)-1] // Cut off newline
|
||||
}
|
||||
|
||||
// Parse for the number of entries.
|
||||
// Use integer overflow resistant math to check this.
|
||||
if err := feedTokens(1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The first line contains the number of entries
|
||||
numEntries, err := readDecimal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
|
||||
if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
// Read all the entries
|
||||
// Parse for all member entries.
|
||||
// numEntries is trusted after this since a potential attacker must have
|
||||
// committed resources proportional to what this library used.
|
||||
if err := feedTokens(2 * numEntries); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sp := make([]sparseEntry, 0, numEntries)
|
||||
for i := int64(0); i < numEntries; i++ {
|
||||
// Read the offset
|
||||
offset, err := readDecimal()
|
||||
offset, err := strconv.ParseInt(nextToken(), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, ErrHeader
|
||||
}
|
||||
// Read numBytes
|
||||
numBytes, err := readDecimal()
|
||||
numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
|
||||
}
|
||||
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
|
|
@ -801,6 +857,10 @@ func (tr *Reader) numBytes() int64 {
|
|||
// Read reads from the current entry in the tar archive.
|
||||
// It returns 0, io.EOF when it reaches the end of that entry,
|
||||
// until Next is called to advance to the next entry.
|
||||
//
|
||||
// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
|
||||
// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
|
||||
// the Header.Size claims.
|
||||
func (tr *Reader) Read(b []byte) (n int, err error) {
|
||||
if tr.err != nil {
|
||||
return 0, tr.err
|
||||
|
|
|
|||
|
|
@ -288,6 +288,30 @@ var untarTests = []*untarTest{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Matches the behavior of GNU, BSD, and STAR tar utilities.
|
||||
file: "testdata/gnu-multi-hdrs.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "GNU2/GNU2/long-path-name",
|
||||
Linkname: "GNU4/GNU4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Matches the behavior of GNU and BSD tar utilities.
|
||||
file: "testdata/pax-multi-hdrs.tar",
|
||||
headers: []*Header{
|
||||
{
|
||||
Name: "bar",
|
||||
Linkname: "PAX4/PAX4/long-linkpath-name",
|
||||
ModTime: time.Unix(0, 0),
|
||||
Typeflag: '2',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/neg-size.tar",
|
||||
err: ErrHeader,
|
||||
|
|
@ -298,17 +322,11 @@ var untarTests = []*untarTest{
|
|||
},
|
||||
{
|
||||
file: "testdata/issue11169.tar",
|
||||
// TODO(dsnet): Currently the library does not detect that this file is
|
||||
// malformed. Instead it incorrectly believes that file just ends.
|
||||
// At least the library doesn't crash anymore.
|
||||
// err: ErrHeader,
|
||||
err: ErrHeader,
|
||||
},
|
||||
{
|
||||
file: "testdata/issue12435.tar",
|
||||
// TODO(dsnet): Currently the library does not detect that this file is
|
||||
// malformed. Instead, it incorrectly believes that file just ends.
|
||||
// At least the library doesn't crash anymore.
|
||||
// err: ErrHeader,
|
||||
err: ErrHeader,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -727,35 +745,82 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReadGNUSparseMap1x0(t *testing.T) {
|
||||
// This test uses lots of holes so the sparse header takes up more than two blocks
|
||||
numEntries := 100
|
||||
expected := make([]sparseEntry, 0, numEntries)
|
||||
sparseMap := new(bytes.Buffer)
|
||||
|
||||
fmt.Fprintf(sparseMap, "%d\n", numEntries)
|
||||
for i := 0; i < numEntries; i++ {
|
||||
offset := int64(2048 * i)
|
||||
numBytes := int64(1024)
|
||||
expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
|
||||
fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
|
||||
var sp = []sparseEntry{{1, 2}, {3, 4}}
|
||||
for i := 0; i < 98; i++ {
|
||||
sp = append(sp, sparseEntry{54321, 12345})
|
||||
}
|
||||
|
||||
// Make the header the smallest multiple of blockSize that fits the sparseMap
|
||||
headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
|
||||
bufLen := blockSize * headerBlocks
|
||||
buf := make([]byte, bufLen)
|
||||
copy(buf, sparseMap.Bytes())
|
||||
var vectors = []struct {
|
||||
input string // Input data
|
||||
sparseMap []sparseEntry // Expected sparse entries to be outputted
|
||||
cnt int // Expected number of bytes read
|
||||
err error // Expected errors that may be raised
|
||||
}{{
|
||||
input: "",
|
||||
cnt: 0,
|
||||
err: io.ErrUnexpectedEOF,
|
||||
}, {
|
||||
input: "ab",
|
||||
cnt: 2,
|
||||
err: io.ErrUnexpectedEOF,
|
||||
}, {
|
||||
input: strings.Repeat("\x00", 512),
|
||||
cnt: 512,
|
||||
err: io.ErrUnexpectedEOF,
|
||||
}, {
|
||||
input: strings.Repeat("\x00", 511) + "\n",
|
||||
cnt: 512,
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
input: strings.Repeat("\n", 512),
|
||||
cnt: 512,
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
input: "0\n" + strings.Repeat("\x00", 510) + strings.Repeat("a", 512),
|
||||
sparseMap: []sparseEntry{},
|
||||
cnt: 512,
|
||||
}, {
|
||||
input: strings.Repeat("0", 512) + "0\n" + strings.Repeat("\x00", 510),
|
||||
sparseMap: []sparseEntry{},
|
||||
cnt: 1024,
|
||||
}, {
|
||||
input: strings.Repeat("0", 1024) + "1\n2\n3\n" + strings.Repeat("\x00", 506),
|
||||
sparseMap: []sparseEntry{{2, 3}},
|
||||
cnt: 1536,
|
||||
}, {
|
||||
input: strings.Repeat("0", 1024) + "1\n2\n\n" + strings.Repeat("\x00", 509),
|
||||
cnt: 1536,
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
input: strings.Repeat("0", 1024) + "1\n2\n" + strings.Repeat("\x00", 508),
|
||||
cnt: 1536,
|
||||
err: io.ErrUnexpectedEOF,
|
||||
}, {
|
||||
input: "-1\n2\n\n" + strings.Repeat("\x00", 506),
|
||||
cnt: 512,
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
input: "1\nk\n2\n" + strings.Repeat("\x00", 506),
|
||||
cnt: 512,
|
||||
err: ErrHeader,
|
||||
}, {
|
||||
input: "100\n1\n2\n3\n4\n" + strings.Repeat("54321\n0000000000000012345\n", 98) + strings.Repeat("\x00", 512),
|
||||
cnt: 2560,
|
||||
sparseMap: sp,
|
||||
}}
|
||||
|
||||
// Get an reader to read the sparse map
|
||||
r := bytes.NewReader(buf)
|
||||
|
||||
// Read the sparse map
|
||||
sp, err := readGNUSparseMap1x0(r)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(sp, expected) {
|
||||
t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
|
||||
for i, v := range vectors {
|
||||
r := strings.NewReader(v.input)
|
||||
sp, err := readGNUSparseMap1x0(r)
|
||||
if !reflect.DeepEqual(sp, v.sparseMap) && !(len(sp) == 0 && len(v.sparseMap) == 0) {
|
||||
t.Errorf("test %d, readGNUSparseMap1x0(...): got %v, want %v", i, sp, v.sparseMap)
|
||||
}
|
||||
if numBytes := len(v.input) - r.Len(); numBytes != v.cnt {
|
||||
t.Errorf("test %d, bytes read: got %v, want %v", i, numBytes, v.cnt)
|
||||
}
|
||||
if err != v.err {
|
||||
t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -901,3 +966,160 @@ func TestReadTruncation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadHeaderOnly tests that Reader does not attempt to read special
|
||||
// header-only files.
|
||||
func TestReadHeaderOnly(t *testing.T) {
|
||||
f, err := os.Open("testdata/hdr-only.tar")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var hdrs []*Header
|
||||
tr := NewReader(f)
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Next(): got %v, want %v", err, nil)
|
||||
continue
|
||||
}
|
||||
hdrs = append(hdrs, hdr)
|
||||
|
||||
// If a special flag, we should read nothing.
|
||||
cnt, _ := io.ReadFull(tr, []byte{0})
|
||||
if cnt > 0 && hdr.Typeflag != TypeReg {
|
||||
t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
|
||||
}
|
||||
}
|
||||
|
||||
// File is crafted with 16 entries. The later 8 are identical to the first
|
||||
// 8 except that the size is set.
|
||||
if len(hdrs) != 16 {
|
||||
t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
|
||||
hdr1.Size, hdr2.Size = 0, 0
|
||||
if !reflect.DeepEqual(*hdr1, *hdr2) {
|
||||
t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePAXRecord(t *testing.T) {
|
||||
var medName = strings.Repeat("CD", 50)
|
||||
var longName = strings.Repeat("AB", 100)
|
||||
|
||||
var vectors = []struct {
|
||||
input string
|
||||
residual string
|
||||
outputKey string
|
||||
outputVal string
|
||||
ok bool
|
||||
}{
|
||||
{"6 k=v\n\n", "\n", "k", "v", true},
|
||||
{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
|
||||
{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
|
||||
{"110 path=" + medName + "\n", "", "path", medName, true},
|
||||
{"9 foo=ba\n", "", "foo", "ba", true},
|
||||
{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
|
||||
{"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
|
||||
{"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
|
||||
{"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
|
||||
{"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
|
||||
{"1 k=1\n", "1 k=1\n", "", "", false},
|
||||
{"6 k~1\n", "6 k~1\n", "", "", false},
|
||||
{"6_k=1\n", "6_k=1\n", "", "", false},
|
||||
{"6 k=1 ", "6 k=1 ", "", "", false},
|
||||
{"632 k=1\n", "632 k=1\n", "", "", false},
|
||||
{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
|
||||
{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
|
||||
{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
key, val, res, err := parsePAXRecord(v.input)
|
||||
ok := (err == nil)
|
||||
if v.ok != ok {
|
||||
if v.ok {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if ok && (key != v.outputKey || val != v.outputVal) {
|
||||
t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
|
||||
v.input, key, val, v.outputKey, v.outputVal)
|
||||
}
|
||||
if res != v.residual {
|
||||
t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
|
||||
v.input, res, v.residual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNumeric(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input string
|
||||
output int64
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{"", 0, true},
|
||||
{"\x80", 0, true},
|
||||
{"\x80\x00", 0, true},
|
||||
{"\x80\x00\x00", 0, true},
|
||||
{"\xbf", (1 << 6) - 1, true},
|
||||
{"\xbf\xff", (1 << 14) - 1, true},
|
||||
{"\xbf\xff\xff", (1 << 22) - 1, true},
|
||||
{"\xff", -1, true},
|
||||
{"\xff\xff", -1, true},
|
||||
{"\xff\xff\xff", -1, true},
|
||||
{"\xc0", -1 * (1 << 6), true},
|
||||
{"\xc0\x00", -1 * (1 << 14), true},
|
||||
{"\xc0\x00\x00", -1 * (1 << 22), true},
|
||||
{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
|
||||
{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
|
||||
{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
|
||||
{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
|
||||
{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
|
||||
{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
|
||||
{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
|
||||
|
||||
// Test base-8 (octal) encoded values.
|
||||
{"0000000\x00", 0, true},
|
||||
{" \x0000000\x00", 0, true},
|
||||
{" \x0000003\x00", 3, true},
|
||||
{"00000000227\x00", 0227, true},
|
||||
{"032033\x00 ", 032033, true},
|
||||
{"320330\x00 ", 0320330, true},
|
||||
{"0000660\x00 ", 0660, true},
|
||||
{"\x00 0000660\x00 ", 0660, true},
|
||||
{"0123456789abcdef", 0, false},
|
||||
{"0123456789\x00abcdef", 0, false},
|
||||
{"01234567\x0089abcdef", 342391, true},
|
||||
{"0123\x7e\x5f\x264123", 0, false},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var p parser
|
||||
num := p.parseNumeric([]byte(v.input))
|
||||
ok := (p.err == nil)
|
||||
if v.ok != ok {
|
||||
if v.ok {
|
||||
t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if ok && num != v.output {
|
||||
t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
src/archive/tar/testdata/gnu-multi-hdrs.tar
vendored
Normal file
BIN
src/archive/tar/testdata/gnu-multi-hdrs.tar
vendored
Normal file
Binary file not shown.
BIN
src/archive/tar/testdata/hdr-only.tar
vendored
Normal file
BIN
src/archive/tar/testdata/hdr-only.tar
vendored
Normal file
Binary file not shown.
BIN
src/archive/tar/testdata/neg-size.tar
vendored
BIN
src/archive/tar/testdata/neg-size.tar
vendored
Binary file not shown.
BIN
src/archive/tar/testdata/pax-multi-hdrs.tar
vendored
Normal file
BIN
src/archive/tar/testdata/pax-multi-hdrs.tar
vendored
Normal file
Binary file not shown.
|
|
@ -42,6 +42,10 @@ type Writer struct {
|
|||
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
|
||||
}
|
||||
|
||||
type formatter struct {
|
||||
err error // Last error seen
|
||||
}
|
||||
|
||||
// NewWriter creates a new Writer writing to w.
|
||||
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
|
||||
|
||||
|
|
@ -68,17 +72,9 @@ func (tw *Writer) Flush() error {
|
|||
}
|
||||
|
||||
// Write s into b, terminating it with a NUL if there is room.
|
||||
// If the value is too long for the field and allowPax is true add a paxheader record instead
|
||||
func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
|
||||
needsPaxHeader := allowPax && len(s) > len(b) || !isASCII(s)
|
||||
if needsPaxHeader {
|
||||
paxHeaders[paxKeyword] = s
|
||||
return
|
||||
}
|
||||
func (f *formatter) formatString(b []byte, s string) {
|
||||
if len(s) > len(b) {
|
||||
if tw.err == nil {
|
||||
tw.err = ErrFieldTooLong
|
||||
}
|
||||
f.err = ErrFieldTooLong
|
||||
return
|
||||
}
|
||||
ascii := toASCII(s)
|
||||
|
|
@ -89,40 +85,40 @@ func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string,
|
|||
}
|
||||
|
||||
// Encode x as an octal ASCII string and write it into b with leading zeros.
|
||||
func (tw *Writer) octal(b []byte, x int64) {
|
||||
func (f *formatter) formatOctal(b []byte, x int64) {
|
||||
s := strconv.FormatInt(x, 8)
|
||||
// leading zeros, but leave room for a NUL.
|
||||
for len(s)+1 < len(b) {
|
||||
s = "0" + s
|
||||
}
|
||||
tw.cString(b, s, false, paxNone, nil)
|
||||
f.formatString(b, s)
|
||||
}
|
||||
|
||||
// Write x into b, either as octal or as binary (GNUtar/star extension).
|
||||
// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead
|
||||
func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
|
||||
// Try octal first.
|
||||
s := strconv.FormatInt(x, 8)
|
||||
if len(s) < len(b) {
|
||||
tw.octal(b, x)
|
||||
// fitsInBase256 reports whether x can be encoded into n bytes using base-256
|
||||
// encoding. Unlike octal encoding, base-256 encoding does not require that the
|
||||
// string ends with a NUL character. Thus, all n bytes are available for output.
|
||||
//
|
||||
// If operating in binary mode, this assumes strict GNU binary mode; which means
|
||||
// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
|
||||
// equivalent to the sign bit in two's complement form.
|
||||
func fitsInBase256(n int, x int64) bool {
|
||||
var binBits = uint(n-1) * 8
|
||||
return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
|
||||
}
|
||||
|
||||
// Write x into b, as binary (GNUtar/star extension).
|
||||
func (f *formatter) formatNumeric(b []byte, x int64) {
|
||||
if fitsInBase256(len(b), x) {
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
b[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
b[0] |= 0x80 // Highest bit indicates binary format
|
||||
return
|
||||
}
|
||||
|
||||
// If it is too long for octal, and pax is preferred, use a pax header
|
||||
if allowPax && tw.preferPax {
|
||||
tw.octal(b, 0)
|
||||
s := strconv.FormatInt(x, 10)
|
||||
paxHeaders[paxKeyword] = s
|
||||
return
|
||||
}
|
||||
|
||||
// Too big: use binary (big-endian).
|
||||
tw.usedBinary = true
|
||||
for i := len(b) - 1; x > 0 && i >= 0; i-- {
|
||||
b[i] = byte(x)
|
||||
x >>= 8
|
||||
}
|
||||
b[0] |= 0x80 // highest bit indicates binary format
|
||||
f.formatOctal(b, 0) // Last resort, just write zero
|
||||
f.err = ErrFieldTooLong
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -161,6 +157,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
|||
// subsecond time resolution, but for now let's just capture
|
||||
// too long fields or non ascii characters
|
||||
|
||||
var f formatter
|
||||
var header []byte
|
||||
|
||||
// We need to select which scratch buffer to use carefully,
|
||||
|
|
@ -175,10 +172,40 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
|||
copy(header, zeroBlock)
|
||||
s := slicer(header)
|
||||
|
||||
// Wrappers around formatter that automatically sets paxHeaders if the
|
||||
// argument extends beyond the capacity of the input byte slice.
|
||||
var formatString = func(b []byte, s string, paxKeyword string) {
|
||||
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
|
||||
if needsPaxHeader {
|
||||
paxHeaders[paxKeyword] = s
|
||||
return
|
||||
}
|
||||
f.formatString(b, s)
|
||||
}
|
||||
var formatNumeric = func(b []byte, x int64, paxKeyword string) {
|
||||
// Try octal first.
|
||||
s := strconv.FormatInt(x, 8)
|
||||
if len(s) < len(b) {
|
||||
f.formatOctal(b, x)
|
||||
return
|
||||
}
|
||||
|
||||
// If it is too long for octal, and PAX is preferred, use a PAX header.
|
||||
if paxKeyword != paxNone && tw.preferPax {
|
||||
f.formatOctal(b, 0)
|
||||
s := strconv.FormatInt(x, 10)
|
||||
paxHeaders[paxKeyword] = s
|
||||
return
|
||||
}
|
||||
|
||||
tw.usedBinary = true
|
||||
f.formatNumeric(b, x)
|
||||
}
|
||||
|
||||
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
||||
pathHeaderBytes := s.next(fileNameSize)
|
||||
|
||||
tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders)
|
||||
formatString(pathHeaderBytes, hdr.Name, paxPath)
|
||||
|
||||
// Handle out of range ModTime carefully.
|
||||
var modTime int64
|
||||
|
|
@ -186,25 +213,25 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
|||
modTime = hdr.ModTime.Unix()
|
||||
}
|
||||
|
||||
tw.octal(s.next(8), hdr.Mode) // 100:108
|
||||
tw.numeric(s.next(8), int64(hdr.Uid), true, paxUid, paxHeaders) // 108:116
|
||||
tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124
|
||||
tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders) // 124:136
|
||||
tw.numeric(s.next(12), modTime, false, paxNone, nil) // 136:148 --- consider using pax for finer granularity
|
||||
s.next(8) // chksum (148:156)
|
||||
s.next(1)[0] = hdr.Typeflag // 156:157
|
||||
f.formatOctal(s.next(8), hdr.Mode) // 100:108
|
||||
formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
|
||||
formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
|
||||
formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
|
||||
formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity
|
||||
s.next(8) // chksum (148:156)
|
||||
s.next(1)[0] = hdr.Typeflag // 156:157
|
||||
|
||||
tw.cString(s.next(100), hdr.Linkname, true, paxLinkpath, paxHeaders)
|
||||
formatString(s.next(100), hdr.Linkname, paxLinkpath)
|
||||
|
||||
copy(s.next(8), []byte("ustar\x0000")) // 257:265
|
||||
tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297
|
||||
tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329
|
||||
tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil) // 329:337
|
||||
tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil) // 337:345
|
||||
copy(s.next(8), []byte("ustar\x0000")) // 257:265
|
||||
formatString(s.next(32), hdr.Uname, paxUname) // 265:297
|
||||
formatString(s.next(32), hdr.Gname, paxGname) // 297:329
|
||||
formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
|
||||
formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
|
||||
|
||||
// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
||||
prefixHeaderBytes := s.next(155)
|
||||
tw.cString(prefixHeaderBytes, "", false, paxNone, nil) // 345:500 prefix
|
||||
formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix
|
||||
|
||||
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
|
||||
if tw.usedBinary {
|
||||
|
|
@ -220,19 +247,20 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
|||
delete(paxHeaders, paxPath)
|
||||
|
||||
// Update the path fields
|
||||
tw.cString(pathHeaderBytes, suffix, false, paxNone, nil)
|
||||
tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
|
||||
formatString(pathHeaderBytes, suffix, paxNone)
|
||||
formatString(prefixHeaderBytes, prefix, paxNone)
|
||||
}
|
||||
}
|
||||
|
||||
// The chksum field is terminated by a NUL and a space.
|
||||
// This is different from the other octal fields.
|
||||
chksum, _ := checksum(header)
|
||||
tw.octal(header[148:155], chksum)
|
||||
f.formatOctal(header[148:155], chksum) // Never fails
|
||||
header[155] = ' '
|
||||
|
||||
if tw.err != nil {
|
||||
// problem with header; probably integer too big for a field.
|
||||
// Check if there were any formatting errors.
|
||||
if f.err != nil {
|
||||
tw.err = f.err
|
||||
return tw.err
|
||||
}
|
||||
|
||||
|
|
@ -310,7 +338,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
|
|||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
fmt.Fprint(&buf, paxHeader(k+"="+paxHeaders[k]))
|
||||
fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
|
||||
}
|
||||
|
||||
ext.Size = int64(len(buf.Bytes()))
|
||||
|
|
@ -326,17 +354,18 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
// paxHeader formats a single pax record, prefixing it with the appropriate length
|
||||
func paxHeader(msg string) string {
|
||||
const padding = 2 // Extra padding for space and newline
|
||||
size := len(msg) + padding
|
||||
// formatPAXRecord formats a single PAX record, prefixing it with the
|
||||
// appropriate length.
|
||||
func formatPAXRecord(k, v string) string {
|
||||
const padding = 3 // Extra padding for ' ', '=', and '\n'
|
||||
size := len(k) + len(v) + padding
|
||||
size += len(strconv.Itoa(size))
|
||||
record := fmt.Sprintf("%d %s\n", size, msg)
|
||||
record := fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
|
||||
// Final adjustment if adding size field increased the record size.
|
||||
if len(record) != size {
|
||||
// Final adjustment if adding size increased
|
||||
// the number of digits in size
|
||||
size = len(record)
|
||||
record = fmt.Sprintf("%d %s\n", size, msg)
|
||||
record = fmt.Sprintf("%d %s=%s\n", size, k, v)
|
||||
}
|
||||
return record
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
|
@ -486,24 +487,6 @@ func TestPaxHeadersSorted(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPAXHeader(t *testing.T) {
|
||||
medName := strings.Repeat("CD", 50)
|
||||
longName := strings.Repeat("AB", 100)
|
||||
paxTests := [][2]string{
|
||||
{paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
|
||||
{"a=b", "6 a=b\n"}, // Single digit length
|
||||
{"a=names", "11 a=names\n"}, // Test case involving carries
|
||||
{paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
|
||||
{paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
|
||||
|
||||
for _, test := range paxTests {
|
||||
key, expected := test[0], test[1]
|
||||
if result := paxHeader(key); result != expected {
|
||||
t.Fatalf("paxHeader: got %s, expected %s", result, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUSTARLongName(t *testing.T) {
|
||||
// Create an archive with a path that failed to split with USTAR extension in previous versions.
|
||||
fileinfo, err := os.Stat("testdata/small.txt")
|
||||
|
|
@ -625,3 +608,115 @@ func TestSplitUSTARPath(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatPAXRecord(t *testing.T) {
|
||||
var medName = strings.Repeat("CD", 50)
|
||||
var longName = strings.Repeat("AB", 100)
|
||||
|
||||
var vectors = []struct {
|
||||
inputKey string
|
||||
inputVal string
|
||||
output string
|
||||
}{
|
||||
{"k", "v", "6 k=v\n"},
|
||||
{"path", "/etc/hosts", "19 path=/etc/hosts\n"},
|
||||
{"path", longName, "210 path=" + longName + "\n"},
|
||||
{"path", medName, "110 path=" + medName + "\n"},
|
||||
{"foo", "ba", "9 foo=ba\n"},
|
||||
{"foo", "bar", "11 foo=bar\n"},
|
||||
{"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
|
||||
{"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
|
||||
{"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
|
||||
{"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
output := formatPAXRecord(v.inputKey, v.inputVal)
|
||||
if output != v.output {
|
||||
t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
|
||||
v.inputKey, v.inputVal, output, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFitsInBase256(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input int64
|
||||
width int
|
||||
ok bool
|
||||
}{
|
||||
{+1, 8, true},
|
||||
{0, 8, true},
|
||||
{-1, 8, true},
|
||||
{1 << 56, 8, false},
|
||||
{(1 << 56) - 1, 8, true},
|
||||
{-1 << 56, 8, true},
|
||||
{(-1 << 56) - 1, 8, false},
|
||||
{121654, 8, true},
|
||||
{-9849849, 8, true},
|
||||
{math.MaxInt64, 9, true},
|
||||
{0, 9, true},
|
||||
{math.MinInt64, 9, true},
|
||||
{math.MaxInt64, 12, true},
|
||||
{0, 12, true},
|
||||
{math.MinInt64, 12, true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
ok := fitsInBase256(v.width, v.input)
|
||||
if ok != v.ok {
|
||||
t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNumeric(t *testing.T) {
|
||||
var vectors = []struct {
|
||||
input int64
|
||||
output string
|
||||
ok bool
|
||||
}{
|
||||
// Test base-256 (binary) encoded values.
|
||||
{-1, "\xff", true},
|
||||
{-1, "\xff\xff", true},
|
||||
{-1, "\xff\xff\xff", true},
|
||||
{(1 << 0), "0", false},
|
||||
{(1 << 8) - 1, "\x80\xff", true},
|
||||
{(1 << 8), "0\x00", false},
|
||||
{(1 << 16) - 1, "\x80\xff\xff", true},
|
||||
{(1 << 16), "00\x00", false},
|
||||
{-1 * (1 << 0), "\xff", true},
|
||||
{-1*(1<<0) - 1, "0", false},
|
||||
{-1 * (1 << 8), "\xff\x00", true},
|
||||
{-1*(1<<8) - 1, "0\x00", false},
|
||||
{-1 * (1 << 16), "\xff\x00\x00", true},
|
||||
{-1*(1<<16) - 1, "00\x00", false},
|
||||
{537795476381659745, "0000000\x00", false},
|
||||
{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{-615126028225187231, "0000000\x00", false},
|
||||
{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
|
||||
{math.MaxInt64, "0000000\x00", false},
|
||||
{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "0000000\x00", false},
|
||||
{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
|
||||
{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
|
||||
}
|
||||
|
||||
for _, v := range vectors {
|
||||
var f formatter
|
||||
output := make([]byte, len(v.output))
|
||||
f.formatNumeric(output, v.input)
|
||||
ok := (f.err == nil)
|
||||
if ok != v.ok {
|
||||
if v.ok {
|
||||
t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
|
||||
} else {
|
||||
t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
|
||||
}
|
||||
}
|
||||
if string(output) != v.output {
|
||||
t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package zip_test
|
|||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
|
@ -73,3 +74,31 @@ func ExampleReader() {
|
|||
// Contents of README:
|
||||
// This is the source code repository for the Go programming language.
|
||||
}
|
||||
|
||||
func ExampleWriter_RegisterCompressor() {
|
||||
// Override the default Deflate compressor with a higher compression
|
||||
// level.
|
||||
|
||||
// Create a buffer to write our archive to.
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Create a new zip archive.
|
||||
w := zip.NewWriter(buf)
|
||||
|
||||
var fw *flate.Writer
|
||||
|
||||
// Register the deflator.
|
||||
w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
|
||||
var err error
|
||||
if fw == nil {
|
||||
// Creating a flate compressor for every file is
|
||||
// expensive, create one and reuse it.
|
||||
fw, err = flate.NewWriter(out, flate.BestCompression)
|
||||
} else {
|
||||
fw.Reset(out)
|
||||
}
|
||||
return fw, err
|
||||
})
|
||||
|
||||
// Proceed to add files to w.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ var (
|
|||
)
|
||||
|
||||
type Reader struct {
|
||||
r io.ReaderAt
|
||||
File []*File
|
||||
Comment string
|
||||
r io.ReaderAt
|
||||
File []*File
|
||||
Comment string
|
||||
decompressors map[uint16]Decompressor
|
||||
}
|
||||
|
||||
type ReadCloser struct {
|
||||
|
|
@ -34,6 +35,7 @@ type ReadCloser struct {
|
|||
|
||||
type File struct {
|
||||
FileHeader
|
||||
zip *Reader
|
||||
zipr io.ReaderAt
|
||||
zipsize int64
|
||||
headerOffset int64
|
||||
|
|
@ -95,7 +97,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
|||
// a bad one, and then only report a ErrFormat or UnexpectedEOF if
|
||||
// the file count modulo 65536 is incorrect.
|
||||
for {
|
||||
f := &File{zipr: r, zipsize: size}
|
||||
f := &File{zip: z, zipr: r, zipsize: size}
|
||||
err = readDirectoryHeader(f, buf)
|
||||
if err == ErrFormat || err == io.ErrUnexpectedEOF {
|
||||
break
|
||||
|
|
@ -113,6 +115,26 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RegisterDecompressor registers or overrides a custom decompressor for a
|
||||
// specific method ID. If a decompressor for a given method is not found,
|
||||
// Reader will default to looking up the decompressor at the package level.
|
||||
//
|
||||
// Must not be called concurrently with Open on any Files in the Reader.
|
||||
func (z *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
|
||||
if z.decompressors == nil {
|
||||
z.decompressors = make(map[uint16]Decompressor)
|
||||
}
|
||||
z.decompressors[method] = dcomp
|
||||
}
|
||||
|
||||
func (z *Reader) decompressor(method uint16) Decompressor {
|
||||
dcomp := z.decompressors[method]
|
||||
if dcomp == nil {
|
||||
dcomp = decompressor(method)
|
||||
}
|
||||
return dcomp
|
||||
}
|
||||
|
||||
// Close closes the Zip file, rendering it unusable for I/O.
|
||||
func (rc *ReadCloser) Close() error {
|
||||
return rc.f.Close()
|
||||
|
|
@ -140,7 +162,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
|
|||
}
|
||||
size := int64(f.CompressedSize64)
|
||||
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
|
||||
dcomp := decompressor(f.Method)
|
||||
dcomp := f.zip.decompressor(f.Method)
|
||||
if dcomp == nil {
|
||||
err = ErrAlgorithm
|
||||
return
|
||||
|
|
@ -261,39 +283,59 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
|||
f.Extra = d[filenameLen : filenameLen+extraLen]
|
||||
f.Comment = string(d[filenameLen+extraLen:])
|
||||
|
||||
needUSize := f.UncompressedSize == ^uint32(0)
|
||||
needCSize := f.CompressedSize == ^uint32(0)
|
||||
needHeaderOffset := f.headerOffset == int64(^uint32(0))
|
||||
|
||||
if len(f.Extra) > 0 {
|
||||
// Best effort to find what we need.
|
||||
// Other zip authors might not even follow the basic format,
|
||||
// and we'll just ignore the Extra content in that case.
|
||||
b := readBuf(f.Extra)
|
||||
for len(b) >= 4 { // need at least tag and size
|
||||
tag := b.uint16()
|
||||
size := b.uint16()
|
||||
if int(size) > len(b) {
|
||||
return ErrFormat
|
||||
break
|
||||
}
|
||||
if tag == zip64ExtraId {
|
||||
// update directory values from the zip64 extra block
|
||||
// update directory values from the zip64 extra block.
|
||||
// They should only be consulted if the sizes read earlier
|
||||
// are maxed out.
|
||||
// See golang.org/issue/13367.
|
||||
eb := readBuf(b[:size])
|
||||
if len(eb) >= 8 {
|
||||
|
||||
if needUSize {
|
||||
needUSize = false
|
||||
if len(eb) < 8 {
|
||||
return ErrFormat
|
||||
}
|
||||
f.UncompressedSize64 = eb.uint64()
|
||||
}
|
||||
if len(eb) >= 8 {
|
||||
if needCSize {
|
||||
needCSize = false
|
||||
if len(eb) < 8 {
|
||||
return ErrFormat
|
||||
}
|
||||
f.CompressedSize64 = eb.uint64()
|
||||
}
|
||||
if len(eb) >= 8 {
|
||||
if needHeaderOffset {
|
||||
needHeaderOffset = false
|
||||
if len(eb) < 8 {
|
||||
return ErrFormat
|
||||
}
|
||||
f.headerOffset = int64(eb.uint64())
|
||||
}
|
||||
break
|
||||
}
|
||||
b = b[size:]
|
||||
}
|
||||
// Should have consumed the whole header.
|
||||
// But popular zip & JAR creation tools are broken and
|
||||
// may pad extra zeros at the end, so accept those
|
||||
// too. See golang.org/issue/8186.
|
||||
for _, v := range b {
|
||||
if v != 0 {
|
||||
return ErrFormat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if needUSize || needCSize || needHeaderOffset {
|
||||
return ErrFormat
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) {
|
|||
|
||||
// isZip64 reports whether the file size exceeds the 32 bit limit
|
||||
func (fh *FileHeader) isZip64() bool {
|
||||
return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
|
||||
return fh.CompressedSize64 >= uint32max || fh.UncompressedSize64 >= uint32max
|
||||
}
|
||||
|
||||
func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ import (
|
|||
)
|
||||
|
||||
// TODO(adg): support zip file comments
|
||||
// TODO(adg): support specifying deflate level
|
||||
|
||||
// Writer implements a zip file writer.
|
||||
type Writer struct {
|
||||
cw *countWriter
|
||||
dir []*header
|
||||
last *fileWriter
|
||||
closed bool
|
||||
cw *countWriter
|
||||
dir []*header
|
||||
last *fileWriter
|
||||
closed bool
|
||||
compressors map[uint16]Compressor
|
||||
}
|
||||
|
||||
type header struct {
|
||||
|
|
@ -78,7 +78,7 @@ func (w *Writer) Close() error {
|
|||
b.uint16(h.ModifiedTime)
|
||||
b.uint16(h.ModifiedDate)
|
||||
b.uint32(h.CRC32)
|
||||
if h.isZip64() || h.offset > uint32max {
|
||||
if h.isZip64() || h.offset >= uint32max {
|
||||
// the file needs a zip64 header. store maxint in both
|
||||
// 32 bit size fields (and offset later) to signal that the
|
||||
// zip64 extra header should be used.
|
||||
|
|
@ -220,7 +220,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
|||
compCount: &countWriter{w: w.cw},
|
||||
crc32: crc32.NewIEEE(),
|
||||
}
|
||||
comp := compressor(fh.Method)
|
||||
comp := w.compressor(fh.Method)
|
||||
if comp == nil {
|
||||
return nil, ErrAlgorithm
|
||||
}
|
||||
|
|
@ -270,6 +270,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// RegisterCompressor registers or overrides a custom compressor for a specific
|
||||
// method ID. If a compressor for a given method is not found, Writer will
|
||||
// default to looking up the compressor at the package level.
|
||||
func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
|
||||
if w.compressors == nil {
|
||||
w.compressors = make(map[uint16]Compressor)
|
||||
}
|
||||
w.compressors[method] = comp
|
||||
}
|
||||
|
||||
func (w *Writer) compressor(method uint16) Compressor {
|
||||
comp := w.compressors[method]
|
||||
if comp == nil {
|
||||
comp = compressor(method)
|
||||
}
|
||||
return comp
|
||||
}
|
||||
|
||||
type fileWriter struct {
|
||||
*header
|
||||
zipw io.Writer
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"hash"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
|
|
@ -19,6 +20,9 @@ import (
|
|||
)
|
||||
|
||||
func TestOver65kFiles(t *testing.T) {
|
||||
if testing.Short() && testenv.Builder() == "" {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
w := NewWriter(buf)
|
||||
const nFiles = (1 << 16) + 42
|
||||
|
|
@ -233,10 +237,24 @@ func TestZip64(t *testing.T) {
|
|||
testZip64DirectoryRecordLength(buf, t)
|
||||
}
|
||||
|
||||
func TestZip64EdgeCase(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("slow test; skipping")
|
||||
}
|
||||
// Test a zip file with uncompressed size 0xFFFFFFFF.
|
||||
// That's the magic marker for a 64-bit file, so even though
|
||||
// it fits in a 32-bit field we must use the 64-bit field.
|
||||
// Go 1.5 and earlier got this wrong,
|
||||
// writing an invalid zip file.
|
||||
const size = 1<<32 - 1 - int64(len("END\n")) // before the "END\n" part
|
||||
buf := testZip64(t, size)
|
||||
testZip64DirectoryRecordLength(buf, t)
|
||||
}
|
||||
|
||||
func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||
const chunkSize = 1024
|
||||
chunks := int(size / chunkSize)
|
||||
// write 2^32 bytes plus "END\n" to a zip file
|
||||
// write size bytes plus "END\n" to a zip file
|
||||
buf := new(rleBuffer)
|
||||
w := NewWriter(buf)
|
||||
f, err := w.CreateHeader(&FileHeader{
|
||||
|
|
@ -257,6 +275,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
|||
t.Fatal("write chunk:", err)
|
||||
}
|
||||
}
|
||||
if frag := int(size % chunkSize); frag > 0 {
|
||||
_, err := f.Write(chunk[:frag])
|
||||
if err != nil {
|
||||
t.Fatal("write chunk:", err)
|
||||
}
|
||||
}
|
||||
end := []byte("END\n")
|
||||
_, err = f.Write(end)
|
||||
if err != nil {
|
||||
|
|
@ -283,6 +307,12 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
|||
t.Fatal("read:", err)
|
||||
}
|
||||
}
|
||||
if frag := int(size % chunkSize); frag > 0 {
|
||||
_, err := io.ReadFull(rc, chunk[:frag])
|
||||
if err != nil {
|
||||
t.Fatal("read:", err)
|
||||
}
|
||||
}
|
||||
gotEnd, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
t.Fatal("read end:", err)
|
||||
|
|
@ -294,14 +324,14 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
|||
if err != nil {
|
||||
t.Fatal("closing:", err)
|
||||
}
|
||||
if size == 1<<32 {
|
||||
if size+int64(len("END\n")) >= 1<<32-1 {
|
||||
if got, want := f0.UncompressedSize, uint32(uint32max); got != want {
|
||||
t.Errorf("UncompressedSize %d, want %d", got, want)
|
||||
t.Errorf("UncompressedSize %#x, want %#x", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
|
||||
t.Errorf("UncompressedSize64 %d, want %d", got, want)
|
||||
t.Errorf("UncompressedSize64 %#x, want %#x", got, want)
|
||||
}
|
||||
|
||||
return buf
|
||||
|
|
@ -373,9 +403,14 @@ func testValidHeader(h *FileHeader, t *testing.T) {
|
|||
}
|
||||
|
||||
b := buf.Bytes()
|
||||
if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != nil {
|
||||
zf, err := NewReader(bytes.NewReader(b), int64(len(b)))
|
||||
if err != nil {
|
||||
t.Fatalf("got %v, expected nil", err)
|
||||
}
|
||||
zh := zf.File[0].FileHeader
|
||||
if zh.Name != h.Name || zh.Method != h.Method || zh.UncompressedSize64 != uint64(len("hi")) {
|
||||
t.Fatalf("got %q/%d/%d expected %q/%d/%d", zh.Name, zh.Method, zh.UncompressedSize64, h.Name, h.Method, len("hi"))
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 4302.
|
||||
|
|
@ -388,20 +423,29 @@ func TestHeaderInvalidTagAndSize(t *testing.T) {
|
|||
h := FileHeader{
|
||||
Name: filename,
|
||||
Method: Deflate,
|
||||
Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len
|
||||
Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len, but Extra is best-effort parsing
|
||||
}
|
||||
h.SetModTime(ts)
|
||||
|
||||
testInvalidHeader(&h, t)
|
||||
testValidHeader(&h, t)
|
||||
}
|
||||
|
||||
func TestHeaderTooShort(t *testing.T) {
|
||||
h := FileHeader{
|
||||
Name: "foo.txt",
|
||||
Method: Deflate,
|
||||
Extra: []byte{zip64ExtraId}, // missing size
|
||||
Extra: []byte{zip64ExtraId}, // missing size and second half of tag, but Extra is best-effort parsing
|
||||
}
|
||||
testInvalidHeader(&h, t)
|
||||
testValidHeader(&h, t)
|
||||
}
|
||||
|
||||
func TestHeaderIgnoredSize(t *testing.T) {
|
||||
h := FileHeader{
|
||||
Name: "foo.txt",
|
||||
Method: Deflate,
|
||||
Extra: []byte{zip64ExtraId & 0xFF, zip64ExtraId >> 8, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, // bad size but shouldn't be consulted
|
||||
}
|
||||
testValidHeader(&h, t)
|
||||
}
|
||||
|
||||
// Issue 4393. It is valid to have an extra data header
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
|
|||
|
||||
// Read reads data into p.
|
||||
// It returns the number of bytes read into p.
|
||||
// It calls Read at most once on the underlying Reader,
|
||||
// The bytes are taken from at most one Read on the underlying Reader,
|
||||
// hence n may be less than len(p).
|
||||
// At EOF, the count will be zero and err will be io.EOF.
|
||||
func (b *Reader) Read(p []byte) (n int, err error) {
|
||||
|
|
|
|||
|
|
@ -36,10 +36,11 @@ const (
|
|||
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
|
||||
var ErrTooLarge = errors.New("bytes.Buffer: too large")
|
||||
|
||||
// Bytes returns a slice of the contents of the unread portion of the buffer;
|
||||
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
|
||||
// returned slice, the contents of the buffer will change provided there
|
||||
// are no intervening method calls on the Buffer.
|
||||
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
|
||||
// The slice is valid for use only until the next buffer modification (that is,
|
||||
// only until the next call to a method like Read, Write, Reset, or Truncate).
|
||||
// The slice aliases the buffer content at least until the next buffer modification,
|
||||
// so immediate changes to the slice will affect the result of future reads.
|
||||
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
|
||||
|
||||
// String returns the contents of the unread portion of the buffer
|
||||
|
|
@ -60,7 +61,8 @@ func (b *Buffer) Len() int { return len(b.buf) - b.off }
|
|||
// total space allocated for the buffer's data.
|
||||
func (b *Buffer) Cap() int { return cap(b.buf) }
|
||||
|
||||
// Truncate discards all but the first n unread bytes from the buffer.
|
||||
// Truncate discards all but the first n unread bytes from the buffer
|
||||
// but continues to use the same allocated storage.
|
||||
// It panics if n is negative or greater than the length of the buffer.
|
||||
func (b *Buffer) Truncate(n int) {
|
||||
b.lastRead = opInvalid
|
||||
|
|
@ -74,8 +76,9 @@ func (b *Buffer) Truncate(n int) {
|
|||
b.buf = b.buf[0 : b.off+n]
|
||||
}
|
||||
|
||||
// Reset resets the buffer so it has no content.
|
||||
// b.Reset() is the same as b.Truncate(0).
|
||||
// Reset resets the buffer to be empty,
|
||||
// but it retains the underlying storage for use by future writes.
|
||||
// Reset is the same as Truncate(0).
|
||||
func (b *Buffer) Reset() { b.Truncate(0) }
|
||||
|
||||
// grow grows the buffer to guarantee space for n more bytes.
|
||||
|
|
|
|||
|
|
@ -680,7 +680,14 @@ func (w *Walker) emitObj(obj types.Object) {
|
|||
switch obj := obj.(type) {
|
||||
case *types.Const:
|
||||
w.emitf("const %s %s", obj.Name(), w.typeString(obj.Type()))
|
||||
w.emitf("const %s = %s", obj.Name(), obj.Val())
|
||||
x := obj.Val()
|
||||
short := x.String()
|
||||
exact := x.ExactString()
|
||||
if short == exact {
|
||||
w.emitf("const %s = %s", obj.Name(), short)
|
||||
} else {
|
||||
w.emitf("const %s = %s // %s", obj.Name(), short, exact)
|
||||
}
|
||||
case *types.Var:
|
||||
w.emitf("var %s %s", obj.Name(), w.typeString(obj.Type()))
|
||||
case *types.TypeName:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func main() {
|
|||
}
|
||||
|
||||
out, err := exec.Command("go", "tool", "api",
|
||||
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5"),
|
||||
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"),
|
||||
"-next", file("next"),
|
||||
"-except", file("except")).CombinedOutput()
|
||||
if err != nil {
|
||||
|
|
|
|||
2
src/cmd/api/testdata/src/pkg/p1/golden.txt
vendored
2
src/cmd/api/testdata/src/pkg/p1/golden.txt
vendored
|
|
@ -10,7 +10,7 @@ pkg p1, const ConstChase2 = 11
|
|||
pkg p1, const ConstChase2 ideal-int
|
||||
pkg p1, const ConversionConst = 5
|
||||
pkg p1, const ConversionConst MyInt
|
||||
pkg p1, const FloatConst = 3/2
|
||||
pkg p1, const FloatConst = 1.5 // 3/2
|
||||
pkg p1, const FloatConst ideal-float
|
||||
pkg p1, const StrConst = "foo"
|
||||
pkg p1, const StrConst ideal-string
|
||||
|
|
|
|||
48
src/cmd/asm/doc.go
Normal file
48
src/cmd/asm/doc.go
Normal 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
|
||||
|
|
@ -87,7 +87,7 @@ func Set(GOARCH string) *Arch {
|
|||
}
|
||||
|
||||
func jumpX86(word string) bool {
|
||||
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP")
|
||||
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN"
|
||||
}
|
||||
|
||||
func archX86(linkArch *obj.LinkArch) *Arch {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ func init() {
|
|||
type MultiFlag []string
|
||||
|
||||
func (m *MultiFlag) String() string {
|
||||
if len(*m) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprint(*m)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ The standard C numeric types are available under the names
|
|||
C.char, C.schar (signed char), C.uchar (unsigned char),
|
||||
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
|
||||
C.long, C.ulong (unsigned long), C.longlong (long long),
|
||||
C.ulonglong (unsigned long long), C.float, C.double.
|
||||
C.ulonglong (unsigned long long), C.float, C.double,
|
||||
C.complexfloat (complex float), and C.complexdouble (complex double).
|
||||
The C type void* is represented by Go's unsafe.Pointer.
|
||||
The C types __int128_t and __uint128_t are represented by [16]byte.
|
||||
|
||||
|
|
@ -238,7 +239,7 @@ the type of the pointer.
|
|||
|
||||
Go code may pass a Go pointer to C provided the Go memory to which it
|
||||
points does not contain any Go pointers. The C code must preserve
|
||||
this property: it must not store any Go pointers into Go memory, even
|
||||
this property: it must not store any Go pointers in Go memory, even
|
||||
temporarily. When passing a pointer to a field in a struct, the Go
|
||||
memory in question is the memory occupied by the field, not the entire
|
||||
struct. When passing a pointer to an element in an array or slice,
|
||||
|
|
@ -247,25 +248,29 @@ array of the slice.
|
|||
|
||||
C code may not keep a copy of a Go pointer after the call returns.
|
||||
|
||||
If Go code passes a Go pointer to a C function, the C function must
|
||||
return. There is no specific time limit, but a C function that simply
|
||||
blocks holding a Go pointer while other goroutines are running may
|
||||
eventually cause the program to run out of memory and fail (because
|
||||
the garbage collector may not be able to make progress).
|
||||
|
||||
A Go function called by C code may not return a Go pointer. A Go
|
||||
function called by C code may take C pointers as arguments, and it may
|
||||
store non-pointer or C pointer data through those pointers, but it may
|
||||
not store a Go pointer into memory pointed to by a C pointer. A Go
|
||||
not store a Go pointer in memory pointed to by a C pointer. A Go
|
||||
function called by C code may take a Go pointer as an argument, but it
|
||||
must preserve the property that the Go memory to which it points does
|
||||
not contain any Go pointers.
|
||||
|
||||
These rules are partially enforced by cgo by default. It is possible
|
||||
to defeat this enforcement by using the unsafe package, and of course
|
||||
there is nothing stopping the C code from doing anything it likes.
|
||||
However, programs that break these rules are likely to fail in
|
||||
unexpected and unpredictable ways.
|
||||
Go code may not store a Go pointer in C memory. C code may store Go
|
||||
pointers in C memory, subject to the rule above: it must stop storing
|
||||
the Go pointer when the C function returns.
|
||||
|
||||
These rules are checked dynamically at runtime. The checking is
|
||||
controlled by the cgocheck setting of the GODEBUG environment
|
||||
variable. The default setting is GODEBUG=cgocheck=1, which implements
|
||||
reasonably cheap dynamic checks. These checks may be disabled
|
||||
entirely using GODEBUG=cgocheck=0. Complete checking of pointer
|
||||
handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
|
||||
|
||||
It is possible to defeat this enforcement by using the unsafe package,
|
||||
and of course there is nothing stopping the C code from doing anything
|
||||
it likes. However, programs that break these rules are likely to fail
|
||||
in unexpected and unpredictable ways.
|
||||
|
||||
Using cgo directly
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ var nameToC = map[string]string{
|
|||
"ulong": "unsigned long",
|
||||
"longlong": "long long",
|
||||
"ulonglong": "unsigned long long",
|
||||
"complexfloat": "float complex",
|
||||
"complexdouble": "double complex",
|
||||
"complexfloat": "float _Complex",
|
||||
"complexdouble": "double _Complex",
|
||||
}
|
||||
|
||||
// cname returns the C name to use for C.s.
|
||||
|
|
@ -491,6 +491,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
name, _ := e.Val(dwarf.AttrName).(string)
|
||||
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if name == "" || typOff == 0 {
|
||||
if e.Val(dwarf.AttrSpecification) != nil {
|
||||
// Since we are reading all the DWARF,
|
||||
// assume we will see the variable elsewhere.
|
||||
break
|
||||
}
|
||||
fatalf("malformed DWARF TagVariable entry")
|
||||
}
|
||||
if !strings.HasPrefix(name, "__cgo__") {
|
||||
|
|
@ -593,6 +598,12 @@ func (p *Package) rewriteCalls(f *File) {
|
|||
// each pointer argument x with _cgoCheckPointer(x).(T).
|
||||
func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
|
||||
for i, param := range name.FuncType.Params {
|
||||
if len(call.Args) <= i {
|
||||
// Avoid a crash; this will be caught when the
|
||||
// generated file is compiled.
|
||||
return
|
||||
}
|
||||
|
||||
// An untyped nil does not need a pointer check, and
|
||||
// when _cgoCheckPointer returns the untyped nil the
|
||||
// type assertion we are going to insert will fail.
|
||||
|
|
@ -606,12 +617,6 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
|
|||
continue
|
||||
}
|
||||
|
||||
if len(call.Args) <= i {
|
||||
// Avoid a crash; this will be caught when the
|
||||
// generated file is compiled.
|
||||
return
|
||||
}
|
||||
|
||||
c := &ast.CallExpr{
|
||||
Fun: ast.NewIdent("_cgoCheckPointer"),
|
||||
Args: []ast.Expr{
|
||||
|
|
@ -675,6 +680,7 @@ func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
|
|||
// hasPointer is used by needsPointerCheck. If top is true it returns
|
||||
// whether t is or contains a pointer that might point to a pointer.
|
||||
// If top is false it returns whether t is or contains a pointer.
|
||||
// f may be nil.
|
||||
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
||||
switch t := t.(type) {
|
||||
case *ast.ArrayType:
|
||||
|
|
@ -738,6 +744,10 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
|||
// pointer.
|
||||
return true
|
||||
}
|
||||
if f == nil {
|
||||
// Conservative approach: assume pointer.
|
||||
return true
|
||||
}
|
||||
name := f.Name[t.Sel.Name]
|
||||
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
|
||||
return p.hasPointer(f, name.Type.Go, top)
|
||||
|
|
@ -768,7 +778,7 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
|
|||
// This is the address of something that is not an
|
||||
// index expression. We only need to examine the
|
||||
// single value to which it points.
|
||||
// TODO: what is true is shadowed?
|
||||
// TODO: what if true is shadowed?
|
||||
return append(args, ast.NewIdent("true"))
|
||||
}
|
||||
if !p.hasSideEffects(f, index.X) {
|
||||
|
|
@ -1304,12 +1314,12 @@ var dwarfToName = map[string]string{
|
|||
"long unsigned int": "ulong",
|
||||
"unsigned int": "uint",
|
||||
"short unsigned int": "ushort",
|
||||
"unsigned short": "ushort", // Used by Clang; issue 13129.
|
||||
"short int": "short",
|
||||
"long long int": "longlong",
|
||||
"long long unsigned int": "ulonglong",
|
||||
"signed char": "schar",
|
||||
"float complex": "complexfloat",
|
||||
"double complex": "complexdouble",
|
||||
"unsigned char": "uchar",
|
||||
}
|
||||
|
||||
const signedDelta = 64
|
||||
|
|
@ -1679,7 +1689,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
|
||||
switch dtype.(type) {
|
||||
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
|
||||
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
|
||||
s := dtype.Common().Name
|
||||
if s != "" {
|
||||
if ss, ok := dwarfToName[s]; ok {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ func (p *Package) writeDefs() {
|
|||
}
|
||||
|
||||
if *gccgo {
|
||||
fmt.Fprint(fgo2, gccgoGoProlog)
|
||||
fmt.Fprint(fc, p.cPrologGccgo())
|
||||
} else {
|
||||
fmt.Fprint(fgo2, goProlog)
|
||||
|
|
@ -811,12 +812,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
}
|
||||
fmt.Fprintf(fgcc, "}\n")
|
||||
|
||||
// Build the wrapper function compiled by gc.
|
||||
goname := exp.Func.Name.Name
|
||||
// Build the wrapper function compiled by cmd/compile.
|
||||
goname := "_cgoexpwrap" + cPrefix + "_"
|
||||
if fn.Recv != nil {
|
||||
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
|
||||
goname += fn.Recv.List[0].Names[0].Name + "_"
|
||||
}
|
||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
|
||||
goname += exp.Func.Name.Name
|
||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
||||
|
|
@ -829,44 +831,75 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
|
||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||
|
||||
// Calling a function with a receiver from C requires
|
||||
// a Go wrapper function.
|
||||
// This code uses printer.Fprint, not conf.Fprint,
|
||||
// because we don't want //line comments in the middle
|
||||
// of the function types.
|
||||
fmt.Fprintf(fgo2, "\n")
|
||||
fmt.Fprintf(fgo2, "func %s(", goname)
|
||||
comma := false
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgo2, "func %s(recv ", goname)
|
||||
conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
fmt.Fprintf(fgo2, ", p%d ", i)
|
||||
conf.Fprint(fgo2, fset, atype)
|
||||
})
|
||||
fmt.Fprintf(fgo2, ")")
|
||||
if gccResult != "void" {
|
||||
fmt.Fprint(fgo2, " (")
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
}
|
||||
conf.Fprint(fgo2, fset, atype)
|
||||
})
|
||||
fmt.Fprint(fgo2, ")")
|
||||
}
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
fmt.Fprint(fgo2, "\t")
|
||||
if gccResult != "void" {
|
||||
fmt.Fprint(fgo2, "return ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
|
||||
forFieldList(fntype.Params,
|
||||
fmt.Fprintf(fgo2, "recv ")
|
||||
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
||||
comma = true
|
||||
}
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if comma {
|
||||
fmt.Fprintf(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d ", i)
|
||||
printer.Fprint(fgo2, fset, atype)
|
||||
comma = true
|
||||
})
|
||||
fmt.Fprintf(fgo2, ")")
|
||||
if gccResult != "void" {
|
||||
fmt.Fprint(fgo2, " (")
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d", i)
|
||||
fmt.Fprintf(fgo2, "r%d ", i)
|
||||
printer.Fprint(fgo2, fset, atype)
|
||||
})
|
||||
fmt.Fprint(fgo2, ")\n")
|
||||
fmt.Fprint(fgo2, "}\n")
|
||||
fmt.Fprint(fgo2, ")")
|
||||
}
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
if gccResult == "void" {
|
||||
fmt.Fprint(fgo2, "\t")
|
||||
} else {
|
||||
// Verify that any results don't contain any
|
||||
// Go pointers.
|
||||
addedDefer := false
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if !p.hasPointer(nil, atype, false) {
|
||||
return
|
||||
}
|
||||
if !addedDefer {
|
||||
fmt.Fprint(fgo2, "\tdefer func() {\n")
|
||||
addedDefer = true
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
|
||||
})
|
||||
if addedDefer {
|
||||
fmt.Fprint(fgo2, "\t}()\n")
|
||||
}
|
||||
fmt.Fprint(fgo2, "\treturn ")
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgo2, "recv.")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d", i)
|
||||
})
|
||||
fmt.Fprint(fgo2, ")\n")
|
||||
fmt.Fprint(fgo2, "}\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
||||
|
|
@ -1251,6 +1284,15 @@ func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
|
|||
|
||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
||||
|
||||
//go:linkname _cgoCheckResult runtime.cgoCheckResult
|
||||
func _cgoCheckResult(interface{})
|
||||
`
|
||||
|
||||
const gccgoGoProlog = `
|
||||
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
||||
|
||||
func _cgoCheckResult(interface{})
|
||||
`
|
||||
|
||||
const goStringDef = `
|
||||
|
|
@ -1305,7 +1347,8 @@ var builtinDefs = map[string]string{
|
|||
}
|
||||
|
||||
func (p *Package) cPrologGccgo() string {
|
||||
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
|
||||
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
|
||||
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
|
||||
}
|
||||
|
||||
const cPrologGccgo = `
|
||||
|
|
@ -1360,6 +1403,39 @@ void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
|
|||
runtime_throw("runtime: C malloc failed");
|
||||
return p;
|
||||
}
|
||||
|
||||
struct __go_type_descriptor;
|
||||
typedef struct __go_empty_interface {
|
||||
const struct __go_type_descriptor *__type_descriptor;
|
||||
void *__object;
|
||||
} Eface;
|
||||
|
||||
extern Eface runtimeCgoCheckPointer(Eface, Slice)
|
||||
__asm__("runtime.cgoCheckPointer")
|
||||
__attribute__((weak));
|
||||
|
||||
extern Eface localCgoCheckPointer(Eface, Slice)
|
||||
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
|
||||
|
||||
Eface localCgoCheckPointer(Eface ptr, Slice args) {
|
||||
if(runtimeCgoCheckPointer) {
|
||||
return runtimeCgoCheckPointer(ptr, args);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
extern void runtimeCgoCheckResult(Eface)
|
||||
__asm__("runtime.cgoCheckResult")
|
||||
__attribute__((weak));
|
||||
|
||||
extern void localCgoCheckResult(Eface)
|
||||
__asm__("GCCGOSYMBOLPREF._cgoCheckResult");
|
||||
|
||||
void localCgoCheckResult(Eface val) {
|
||||
if(runtimeCgoCheckResult) {
|
||||
runtimeCgoCheckResult(val);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func (p *Package) gccExportHeaderProlog() string {
|
||||
|
|
@ -1385,8 +1461,8 @@ typedef GoUintGOINTBITS GoUint;
|
|||
typedef __SIZE_TYPE__ GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
typedef __complex float GoComplex64;
|
||||
typedef __complex double GoComplex128;
|
||||
typedef float _Complex GoComplex64;
|
||||
typedef double _Complex GoComplex128;
|
||||
|
||||
/*
|
||||
static assertion to make sure the file is being used on architecture
|
||||
|
|
@ -1394,7 +1470,7 @@ typedef __complex double GoComplex128;
|
|||
*/
|
||||
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
|
||||
|
||||
typedef struct { char *p; GoInt n; } GoString;
|
||||
typedef struct { const char *p; GoInt n; } GoString;
|
||||
typedef void *GoMap;
|
||||
typedef void *GoChan;
|
||||
typedef struct { void *t; void *v; } GoInterface;
|
||||
|
|
|
|||
|
|
@ -365,24 +365,25 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
gc.Cgenr(nl, &n1, res)
|
||||
var n2 gc.Node
|
||||
gc.Cgenr(nr, &n2, nil)
|
||||
var ax gc.Node
|
||||
gc.Nodreg(&ax, t, x86.REG_AX)
|
||||
var ax, oldax, dx, olddx gc.Node
|
||||
savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT64])
|
||||
savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT64])
|
||||
gmove(&n1, &ax)
|
||||
gins(a, &n2, nil)
|
||||
gc.Regfree(&n2)
|
||||
gc.Regfree(&n1)
|
||||
|
||||
var dx gc.Node
|
||||
if t.Width == 1 {
|
||||
// byte multiply behaves differently.
|
||||
gc.Nodreg(&ax, t, x86.REG_AH)
|
||||
|
||||
gc.Nodreg(&dx, t, x86.REG_DX)
|
||||
gmove(&ax, &dx)
|
||||
var byteAH, byteDX gc.Node
|
||||
gc.Nodreg(&byteAH, t, x86.REG_AH)
|
||||
gc.Nodreg(&byteDX, t, x86.REG_DX)
|
||||
gmove(&byteAH, &byteDX)
|
||||
}
|
||||
|
||||
gc.Nodreg(&dx, t, x86.REG_DX)
|
||||
gmove(&dx, res)
|
||||
|
||||
restx(&ax, &oldax)
|
||||
restx(&dx, &olddx)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1365,7 +1365,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
|
|||
case obj.APCDATA,
|
||||
obj.AFUNCDATA,
|
||||
obj.AVARDEF,
|
||||
obj.AVARKILL:
|
||||
obj.AVARKILL,
|
||||
obj.AUSEFIELD:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -710,7 +710,8 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
|
|||
obj.APCDATA,
|
||||
obj.AFUNCDATA,
|
||||
obj.AVARDEF,
|
||||
obj.AVARKILL:
|
||||
obj.AVARKILL,
|
||||
obj.AUSEFIELD:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
package big
|
||||
|
||||
// A decimal represents an unsigned floating-point number in decimal representation.
|
||||
// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
|
||||
// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= d.mant < 1,
|
||||
// with the most-significant mantissa digit at index 0. For the zero decimal, the
|
||||
// mantissa length and exponent are 0.
|
||||
// The zero value for decimal represents a ready-to-use 0.0.
|
||||
|
|
@ -29,6 +29,14 @@ type decimal struct {
|
|||
exp int // exponent
|
||||
}
|
||||
|
||||
// at returns the i'th mantissa digit, starting with the most significant digit at 0.
|
||||
func (d *decimal) at(i int) byte {
|
||||
if 0 <= i && i < len(d.mant) {
|
||||
return d.mant[i]
|
||||
}
|
||||
return '0'
|
||||
}
|
||||
|
||||
// Maximum shift amount that can be done in one pass without overflow.
|
||||
// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
|
||||
const maxShift = _W - 4
|
||||
|
|
@ -72,7 +80,7 @@ func (x *decimal) init(m nat, shift int) {
|
|||
}
|
||||
|
||||
// Convert mantissa into decimal representation.
|
||||
s := m.decimalString() // TODO(gri) avoid string conversion here
|
||||
s := m.utoa(10)
|
||||
n := len(s)
|
||||
x.exp = n
|
||||
// Trim trailing zeros; instead the exponent is tracking
|
||||
|
|
@ -92,12 +100,6 @@ func (x *decimal) init(m nat, shift int) {
|
|||
}
|
||||
}
|
||||
|
||||
// Possibly optimization: The current implementation of nat.string takes
|
||||
// a charset argument. When a right shift is needed, we could provide
|
||||
// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
|
||||
// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
|
||||
// single +'0' pass at the end).
|
||||
|
||||
// shr implements x >> s, for s <= maxShift.
|
||||
func shr(x *decimal, s uint) {
|
||||
// Division by 1<<s using shift-and-subtract algorithm.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ const (
|
|||
// rounding error is described by the Float's Accuracy.
|
||||
type RoundingMode byte
|
||||
|
||||
// The following rounding modes are supported.
|
||||
// These constants define supported rounding modes.
|
||||
const (
|
||||
ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
|
||||
ToNearestAway // == IEEE 754-2008 roundTiesToAway
|
||||
|
|
@ -298,7 +298,7 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) {
|
|||
// not require 0.5 <= |mant| < 1.0. Specifically:
|
||||
//
|
||||
// mant := new(Float)
|
||||
// new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true
|
||||
// new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0
|
||||
//
|
||||
// Special cases are:
|
||||
//
|
||||
|
|
@ -1123,7 +1123,7 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) {
|
|||
|
||||
// Rat returns the rational number corresponding to x;
|
||||
// or nil if x is an infinity.
|
||||
// The result is Exact is x is not an Inf.
|
||||
// The result is Exact if x is not an Inf.
|
||||
// If a non-nil *Rat argument z is provided, Rat stores
|
||||
// the result in z instead of allocating a new Rat.
|
||||
func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
|
||||
|
|
|
|||
|
|
@ -72,37 +72,46 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
|
|||
// ebase**exp. Finally, mantissa normalization (shift left) requires
|
||||
// a correcting multiplication by 2**(-shiftcount). Multiplications
|
||||
// are commutative, so we can apply them in any order as long as there
|
||||
// is no loss of precision. We only have powers of 2 and 10; keep
|
||||
// track via separate exponents exp2 and exp10.
|
||||
// is no loss of precision. We only have powers of 2 and 10, and
|
||||
// we split powers of 10 into the product of the same powers of
|
||||
// 2 and 5. This reduces the size of the multiplication factor
|
||||
// needed for base-10 exponents.
|
||||
|
||||
// normalize mantissa and get initial binary exponent
|
||||
var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
|
||||
// normalize mantissa and determine initial exponent contributions
|
||||
exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
|
||||
exp5 := int64(0)
|
||||
|
||||
// determine binary or decimal exponent contribution of decimal point
|
||||
var exp10 int64
|
||||
if fcount < 0 {
|
||||
// The mantissa has a "decimal" point ddd.dddd; and
|
||||
// -fcount is the number of digits to the right of '.'.
|
||||
// Adjust relevant exponent accodingly.
|
||||
d := int64(fcount)
|
||||
switch b {
|
||||
case 16:
|
||||
fcount *= 4 // hexadecimal digits are 4 bits each
|
||||
fallthrough
|
||||
case 10:
|
||||
exp5 = d
|
||||
fallthrough // 10**e == 5**e * 2**e
|
||||
case 2:
|
||||
exp2 += int64(fcount)
|
||||
default: // b == 10
|
||||
exp10 = int64(fcount)
|
||||
exp2 += d
|
||||
case 16:
|
||||
exp2 += d * 4 // hexadecimal digits are 4 bits each
|
||||
default:
|
||||
panic("unexpected mantissa base")
|
||||
}
|
||||
// we don't need fcount anymore
|
||||
// fcount consumed - not needed anymore
|
||||
}
|
||||
|
||||
// take actual exponent into account
|
||||
if ebase == 2 {
|
||||
switch ebase {
|
||||
case 10:
|
||||
exp5 += exp
|
||||
fallthrough
|
||||
case 2:
|
||||
exp2 += exp
|
||||
} else { // ebase == 10
|
||||
exp10 += exp
|
||||
default:
|
||||
panic("unexpected exponent base")
|
||||
}
|
||||
// we don't need exp anymore
|
||||
// exp consumed - not needed anymore
|
||||
|
||||
// apply 2**exp2
|
||||
if MinExp <= exp2 && exp2 <= MaxExp {
|
||||
|
|
@ -115,49 +124,76 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
if exp10 == 0 {
|
||||
// no decimal exponent to consider
|
||||
if exp5 == 0 {
|
||||
// no decimal exponent contribution
|
||||
z.round(0)
|
||||
return
|
||||
}
|
||||
// exp10 != 0
|
||||
// exp5 != 0
|
||||
|
||||
// apply 10**exp10
|
||||
// apply 5**exp5
|
||||
p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
|
||||
if exp10 < 0 {
|
||||
z.Quo(z, p.pow10(-exp10))
|
||||
if exp5 < 0 {
|
||||
z.Quo(z, p.pow5(uint64(-exp5)))
|
||||
} else {
|
||||
z.Mul(z, p.pow10(exp10))
|
||||
z.Mul(z, p.pow5(uint64(exp5)))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// These powers of 10 can be represented exactly as a float64.
|
||||
var pow10tab = [...]float64{
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||
// These powers of 5 fit into a uint64.
|
||||
//
|
||||
// for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
|
||||
// fmt.Println(q)
|
||||
// }
|
||||
//
|
||||
var pow5tab = [...]uint64{
|
||||
1,
|
||||
5,
|
||||
25,
|
||||
125,
|
||||
625,
|
||||
3125,
|
||||
15625,
|
||||
78125,
|
||||
390625,
|
||||
1953125,
|
||||
9765625,
|
||||
48828125,
|
||||
244140625,
|
||||
1220703125,
|
||||
6103515625,
|
||||
30517578125,
|
||||
152587890625,
|
||||
762939453125,
|
||||
3814697265625,
|
||||
19073486328125,
|
||||
95367431640625,
|
||||
476837158203125,
|
||||
2384185791015625,
|
||||
11920928955078125,
|
||||
59604644775390625,
|
||||
298023223876953125,
|
||||
1490116119384765625,
|
||||
7450580596923828125,
|
||||
}
|
||||
|
||||
// pow10 sets z to 10**n and returns z.
|
||||
// pow5 sets z to 5**n and returns z.
|
||||
// n must not be negative.
|
||||
func (z *Float) pow10(n int64) *Float {
|
||||
if n < 0 {
|
||||
panic("pow10 called with negative argument")
|
||||
}
|
||||
|
||||
const m = int64(len(pow10tab) - 1)
|
||||
func (z *Float) pow5(n uint64) *Float {
|
||||
const m = uint64(len(pow5tab) - 1)
|
||||
if n <= m {
|
||||
return z.SetFloat64(pow10tab[n])
|
||||
return z.SetUint64(pow5tab[n])
|
||||
}
|
||||
// n > m
|
||||
|
||||
z.SetFloat64(pow10tab[m])
|
||||
z.SetUint64(pow5tab[m])
|
||||
n -= m
|
||||
|
||||
// use more bits for f than for z
|
||||
// TODO(gri) what is the right number?
|
||||
f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
|
||||
f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
|
||||
|
||||
for n > 0 {
|
||||
if n&1 != 0 {
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ func TestFloatSetFloat64String(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func fdiv(a, b float64) float64 { return a / b }
|
||||
|
||||
const (
|
||||
below1e23 = 99999999999999974834176
|
||||
above1e23 = 100000000000000008388608
|
||||
|
|
@ -187,11 +189,11 @@ func TestFloat64Text(t *testing.T) {
|
|||
{1, 'e', 5, "1.00000e+00"},
|
||||
{1, 'f', 5, "1.00000"},
|
||||
{1, 'g', 5, "1"},
|
||||
// {1, 'g', -1, "1"},
|
||||
// {20, 'g', -1, "20"},
|
||||
// {1234567.8, 'g', -1, "1.2345678e+06"},
|
||||
// {200000, 'g', -1, "200000"},
|
||||
// {2000000, 'g', -1, "2e+06"},
|
||||
{1, 'g', -1, "1"},
|
||||
{20, 'g', -1, "20"},
|
||||
{1234567.8, 'g', -1, "1.2345678e+06"},
|
||||
{200000, 'g', -1, "200000"},
|
||||
{2000000, 'g', -1, "2e+06"},
|
||||
|
||||
// g conversion and zero suppression
|
||||
{400, 'g', 2, "4e+02"},
|
||||
|
|
@ -207,22 +209,22 @@ func TestFloat64Text(t *testing.T) {
|
|||
{0, 'e', 5, "0.00000e+00"},
|
||||
{0, 'f', 5, "0.00000"},
|
||||
{0, 'g', 5, "0"},
|
||||
// {0, 'g', -1, "0"},
|
||||
{0, 'g', -1, "0"},
|
||||
|
||||
{-1, 'e', 5, "-1.00000e+00"},
|
||||
{-1, 'f', 5, "-1.00000"},
|
||||
{-1, 'g', 5, "-1"},
|
||||
// {-1, 'g', -1, "-1"},
|
||||
{-1, 'g', -1, "-1"},
|
||||
|
||||
{12, 'e', 5, "1.20000e+01"},
|
||||
{12, 'f', 5, "12.00000"},
|
||||
{12, 'g', 5, "12"},
|
||||
// {12, 'g', -1, "12"},
|
||||
{12, 'g', -1, "12"},
|
||||
|
||||
{123456700, 'e', 5, "1.23457e+08"},
|
||||
{123456700, 'f', 5, "123456700.00000"},
|
||||
{123456700, 'g', 5, "1.2346e+08"},
|
||||
// {123456700, 'g', -1, "1.234567e+08"},
|
||||
{123456700, 'g', -1, "1.234567e+08"},
|
||||
|
||||
{1.2345e6, 'e', 5, "1.23450e+06"},
|
||||
{1.2345e6, 'f', 5, "1234500.00000"},
|
||||
|
|
@ -232,36 +234,38 @@ func TestFloat64Text(t *testing.T) {
|
|||
{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
|
||||
{1e23, 'g', 17, "9.9999999999999992e+22"},
|
||||
|
||||
// {1e23, 'e', -1, "1e+23"},
|
||||
// {1e23, 'f', -1, "100000000000000000000000"},
|
||||
// {1e23, 'g', -1, "1e+23"},
|
||||
{1e23, 'e', -1, "1e+23"},
|
||||
{1e23, 'f', -1, "100000000000000000000000"},
|
||||
{1e23, 'g', -1, "1e+23"},
|
||||
|
||||
{below1e23, 'e', 17, "9.99999999999999748e+22"},
|
||||
{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
|
||||
{below1e23, 'g', 17, "9.9999999999999975e+22"},
|
||||
|
||||
// {below1e23, 'e', -1, "9.999999999999997e+22"},
|
||||
// {below1e23, 'f', -1, "99999999999999970000000"},
|
||||
// {below1e23, 'g', -1, "9.999999999999997e+22"},
|
||||
{below1e23, 'e', -1, "9.999999999999997e+22"},
|
||||
{below1e23, 'f', -1, "99999999999999970000000"},
|
||||
{below1e23, 'g', -1, "9.999999999999997e+22"},
|
||||
|
||||
{above1e23, 'e', 17, "1.00000000000000008e+23"},
|
||||
{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
|
||||
// {above1e23, 'g', 17, "1.0000000000000001e+23"},
|
||||
{above1e23, 'g', 17, "1.0000000000000001e+23"},
|
||||
|
||||
// {above1e23, 'e', -1, "1.0000000000000001e+23"},
|
||||
// {above1e23, 'f', -1, "100000000000000010000000"},
|
||||
// {above1e23, 'g', -1, "1.0000000000000001e+23"},
|
||||
{above1e23, 'e', -1, "1.0000000000000001e+23"},
|
||||
{above1e23, 'f', -1, "100000000000000010000000"},
|
||||
{above1e23, 'g', -1, "1.0000000000000001e+23"},
|
||||
|
||||
// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
|
||||
// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
|
||||
{5e-304 / 1e20, 'g', -1, "5e-324"},
|
||||
{-5e-304 / 1e20, 'g', -1, "-5e-324"},
|
||||
{fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic
|
||||
{fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic
|
||||
|
||||
// {32, 'g', -1, "32"},
|
||||
// {32, 'g', 0, "3e+01"},
|
||||
{32, 'g', -1, "32"},
|
||||
{32, 'g', 0, "3e+01"},
|
||||
|
||||
// {100, 'x', -1, "%x"},
|
||||
{100, 'x', -1, "%x"},
|
||||
|
||||
// {math.NaN(), 'g', -1, "NaN"},
|
||||
// {-math.NaN(), 'g', -1, "NaN"},
|
||||
// {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
|
||||
// {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
|
||||
{math.Inf(0), 'g', -1, "+Inf"},
|
||||
{math.Inf(-1), 'g', -1, "-Inf"},
|
||||
{-math.Inf(0), 'g', -1, "-Inf"},
|
||||
|
|
@ -279,18 +283,24 @@ func TestFloat64Text(t *testing.T) {
|
|||
{1.5, 'f', 0, "2"},
|
||||
|
||||
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
|
||||
// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
|
||||
{2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
|
||||
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
|
||||
// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
|
||||
{2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
|
||||
|
||||
// Issue 2625.
|
||||
{383260575764816448, 'f', 0, "383260575764816448"},
|
||||
// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
|
||||
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
|
||||
} {
|
||||
f := new(Float).SetFloat64(test.x)
|
||||
// The test cases are from the strconv package which tests float64 values.
|
||||
// When formatting values with prec = -1 (shortest representation),
|
||||
// the actually available mantissa precision matters.
|
||||
// For denormalized values, that precision is < 53 (SetFloat64 default).
|
||||
// Compute and set the actual precision explicitly.
|
||||
f := new(Float).SetPrec(actualPrec(test.x)).SetFloat64(test.x)
|
||||
got := f.Text(test.format, test.prec)
|
||||
if got != test.want {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.want)
|
||||
continue
|
||||
}
|
||||
|
||||
if test.format == 'b' && test.x == 0 {
|
||||
|
|
@ -308,6 +318,15 @@ func TestFloat64Text(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// actualPrec returns the number of actually used mantissa bits.
|
||||
func actualPrec(x float64) uint {
|
||||
if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 {
|
||||
// x is denormalized
|
||||
return 64 - nlz64(bits&(1<<52-1))
|
||||
}
|
||||
return 53
|
||||
}
|
||||
|
||||
func TestFloatText(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
|
|
@ -367,10 +386,20 @@ func TestFloatText(t *testing.T) {
|
|||
|
||||
// make sure "stupid" exponents don't stall the machine
|
||||
{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
|
||||
{"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
|
||||
{"1e646456993", 64, 'p', 0, "+Inf"},
|
||||
{"1e1000000000", 64, 'p', 0, "+Inf"},
|
||||
{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
|
||||
{"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
|
||||
{"1e-646456994", 64, 'p', 0, "0"},
|
||||
{"1e-1000000000", 64, 'p', 0, "0"},
|
||||
|
||||
// minimum and maximum values
|
||||
{"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"},
|
||||
{"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"},
|
||||
{"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"},
|
||||
{"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"},
|
||||
|
||||
// TODO(gri) need tests for actual large Floats
|
||||
|
||||
{"0", 53, 'b', 0, "0"},
|
||||
|
|
@ -438,9 +467,6 @@ func TestFloatFormat(t *testing.T) {
|
|||
value interface{} // float32, float64, or string (== 512bit *Float)
|
||||
want string
|
||||
}{
|
||||
// TODO(gri) uncomment the disabled 'g'/'G' formats
|
||||
// below once (*Float).Text supports prec < 0
|
||||
|
||||
// from fmt/fmt_test.go
|
||||
{"%+.3e", 0.0, "+0.000e+00"},
|
||||
{"%+.3e", 1.0, "+1.000e+00"},
|
||||
|
|
@ -471,9 +497,9 @@ func TestFloatFormat(t *testing.T) {
|
|||
{"%f", 1234.5678e-8, "0.000012"},
|
||||
{"%f", -7.0, "-7.000000"},
|
||||
{"%f", -1e-9, "-0.000000"},
|
||||
// {"%g", 1234.5678e3, "1.2345678e+06"},
|
||||
// {"%g", float32(1234.5678e3), "1.2345678e+06"},
|
||||
// {"%g", 1234.5678e-8, "1.2345678e-05"},
|
||||
{"%g", 1234.5678e3, "1.2345678e+06"},
|
||||
{"%g", float32(1234.5678e3), "1.2345678e+06"},
|
||||
{"%g", 1234.5678e-8, "1.2345678e-05"},
|
||||
{"%g", -7.0, "-7"},
|
||||
{"%g", -1e-9, "-1e-09"},
|
||||
{"%g", float32(-1e-9), "-1e-09"},
|
||||
|
|
@ -482,9 +508,9 @@ func TestFloatFormat(t *testing.T) {
|
|||
{"%E", 1234.5678e-8, "1.234568E-05"},
|
||||
{"%E", -7.0, "-7.000000E+00"},
|
||||
{"%E", -1e-9, "-1.000000E-09"},
|
||||
// {"%G", 1234.5678e3, "1.2345678E+06"},
|
||||
// {"%G", float32(1234.5678e3), "1.2345678E+06"},
|
||||
// {"%G", 1234.5678e-8, "1.2345678E-05"},
|
||||
{"%G", 1234.5678e3, "1.2345678E+06"},
|
||||
{"%G", float32(1234.5678e3), "1.2345678E+06"},
|
||||
{"%G", 1234.5678e-8, "1.2345678E-05"},
|
||||
{"%G", -7.0, "-7"},
|
||||
{"%G", -1e-9, "-1E-09"},
|
||||
{"%G", float32(-1e-9), "-1E-09"},
|
||||
|
|
@ -500,9 +526,9 @@ func TestFloatFormat(t *testing.T) {
|
|||
{"%-20f", 1.23456789e3, "1234.567890 "},
|
||||
{"%20.8f", 1.23456789e3, " 1234.56789000"},
|
||||
{"%20.8f", 1.23456789e-3, " 0.00123457"},
|
||||
// {"%g", 1.23456789e3, "1234.56789"},
|
||||
// {"%g", 1.23456789e-3, "0.00123456789"},
|
||||
// {"%g", 1.23456789e20, "1.23456789e+20"},
|
||||
{"%g", 1.23456789e3, "1234.56789"},
|
||||
{"%g", 1.23456789e-3, "0.00123456789"},
|
||||
{"%g", 1.23456789e20, "1.23456789e+20"},
|
||||
{"%20e", math.Inf(1), " +Inf"},
|
||||
{"%-20f", math.Inf(-1), "-Inf "},
|
||||
|
||||
|
|
@ -541,7 +567,6 @@ func TestFloatFormat(t *testing.T) {
|
|||
{"%v", -1e-9, "-1e-09"},
|
||||
{"%v", float32(-1e-9), "-1e-09"},
|
||||
{"%010v", 0.0, "0000000000"},
|
||||
{"%010v", 0.0, "0000000000"},
|
||||
|
||||
// *Float cases
|
||||
{"%.20f", "1e-20", "0.00000000000000000001"},
|
||||
|
|
@ -571,3 +596,67 @@ func TestFloatFormat(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseFloatSmallExp(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, s := range []string{
|
||||
"1e0",
|
||||
"1e-1",
|
||||
"1e-2",
|
||||
"1e-3",
|
||||
"1e-4",
|
||||
"1e-5",
|
||||
"1e-10",
|
||||
"1e-20",
|
||||
"1e-50",
|
||||
"1e1",
|
||||
"1e2",
|
||||
"1e3",
|
||||
"1e4",
|
||||
"1e5",
|
||||
"1e10",
|
||||
"1e20",
|
||||
"1e50",
|
||||
} {
|
||||
var x Float
|
||||
_, _, err := x.Parse(s, 0)
|
||||
if err != nil {
|
||||
b.Fatalf("%s: %v", s, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseFloatLargeExp(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, s := range []string{
|
||||
"1e0",
|
||||
"1e-10",
|
||||
"1e-20",
|
||||
"1e-30",
|
||||
"1e-40",
|
||||
"1e-50",
|
||||
"1e-100",
|
||||
"1e-500",
|
||||
"1e-1000",
|
||||
"1e-5000",
|
||||
"1e-10000",
|
||||
"1e10",
|
||||
"1e20",
|
||||
"1e30",
|
||||
"1e40",
|
||||
"1e50",
|
||||
"1e100",
|
||||
"1e500",
|
||||
"1e1000",
|
||||
"1e5000",
|
||||
"1e10000",
|
||||
} {
|
||||
var x Float
|
||||
_, _, err := x.Parse(s, 0)
|
||||
if err != nil {
|
||||
b.Fatalf("%s: %v", s, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,3 +109,33 @@ func ExampleFloat_Cmp() {
|
|||
// +Inf 1.2 1
|
||||
// +Inf +Inf 0
|
||||
}
|
||||
|
||||
func ExampleRoundingMode() {
|
||||
operands := []float64{2.6, 2.5, 2.1, -2.1, -2.5, -2.6}
|
||||
|
||||
fmt.Print(" x")
|
||||
for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
|
||||
fmt.Printf(" %s", mode)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
for _, f64 := range operands {
|
||||
fmt.Printf("%4g", f64)
|
||||
for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
|
||||
// sample operands above require 2 bits to represent mantissa
|
||||
// set binary precision to 2 to round them to integer values
|
||||
f := new(big.Float).SetPrec(2).SetMode(mode).SetFloat64(f64)
|
||||
fmt.Printf(" %*g", len(mode.String()), f)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// x ToNearestEven ToNearestAway ToZero AwayFromZero ToNegativeInf ToPositiveInf
|
||||
// 2.6 3 3 2 3 2 3
|
||||
// 2.5 2 3 2 3 2 3
|
||||
// 2.1 2 2 2 3 2 3
|
||||
// -2.1 -2 -2 -2 -3 -3 -2
|
||||
// -2.5 -2 -3 -2 -3 -3 -2
|
||||
// -2.6 -3 -3 -2 -3 -3 -2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
package big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Text converts the floating-point number x to a string according
|
||||
|
|
@ -37,16 +37,16 @@ import (
|
|||
// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
|
||||
// it is the number of digits after the decimal point. For 'g' and 'G' it is
|
||||
// the total number of digits. A negative precision selects the smallest
|
||||
// number of digits necessary to identify the value x uniquely.
|
||||
// number of decimal digits necessary to identify the value x uniquely using
|
||||
// x.Prec() mantissa bits.
|
||||
// The prec value is ignored for the 'b' or 'p' format.
|
||||
//
|
||||
// BUG(gri) Float.Text does not accept negative precisions (issue #10991).
|
||||
func (x *Float) Text(format byte, prec int) string {
|
||||
const extra = 10 // TODO(gri) determine a good/better value here
|
||||
return string(x.Append(make([]byte, 0, prec+extra), format, prec))
|
||||
}
|
||||
|
||||
// String formats x like x.Text('g', 10).
|
||||
// (String must be called explicitly, Float.Format does not support %s verb.)
|
||||
func (x *Float) String() string {
|
||||
return x.Text('g', 10)
|
||||
}
|
||||
|
|
@ -83,6 +83,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
|
|||
// 1) convert Float to multiprecision decimal
|
||||
var d decimal // == 0.0
|
||||
if x.form == finite {
|
||||
// x != 0
|
||||
d.init(x.mant, int(x.exp)-x.mant.bitLen())
|
||||
}
|
||||
|
||||
|
|
@ -90,9 +91,7 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
|
|||
shortest := false
|
||||
if prec < 0 {
|
||||
shortest = true
|
||||
panic("unimplemented")
|
||||
// TODO(gri) complete this
|
||||
// roundShortest(&d, f.mant, int(f.exp))
|
||||
roundShortest(&d, x)
|
||||
// Precision for shortest representation mode.
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
|
|
@ -158,6 +157,80 @@ func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
|
|||
return append(buf, '%', fmt)
|
||||
}
|
||||
|
||||
func roundShortest(d *decimal, x *Float) {
|
||||
// if the mantissa is zero, the number is zero - stop now
|
||||
if len(d.mant) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
|
||||
// (possibly exclusive) round to x for the given precision of x.
|
||||
// Compute the lower and upper bound in decimal form and find the
|
||||
// shortest decimal number d such that lower <= d <= upper.
|
||||
|
||||
// TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
|
||||
// See if we can use it (in adjusted form) here as well.
|
||||
|
||||
// 1) Compute normalized mantissa mant and exponent exp for x such
|
||||
// that the lsb of mant corresponds to 1/2 ulp for the precision of
|
||||
// x (i.e., for mant we want x.prec + 1 bits).
|
||||
mant := nat(nil).set(x.mant)
|
||||
exp := int(x.exp) - mant.bitLen()
|
||||
s := mant.bitLen() - int(x.prec+1)
|
||||
switch {
|
||||
case s < 0:
|
||||
mant = mant.shl(mant, uint(-s))
|
||||
case s > 0:
|
||||
mant = mant.shr(mant, uint(+s))
|
||||
}
|
||||
exp += s
|
||||
// x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
|
||||
|
||||
// 2) Compute lower bound by subtracting 1/2 ulp.
|
||||
var lower decimal
|
||||
var tmp nat
|
||||
lower.init(tmp.sub(mant, natOne), exp)
|
||||
|
||||
// 3) Compute upper bound by adding 1/2 ulp.
|
||||
var upper decimal
|
||||
upper.init(tmp.add(mant, natOne), exp)
|
||||
|
||||
// The upper and lower bounds are possible outputs only if
|
||||
// the original mantissa is even, so that ToNearestEven rounding
|
||||
// would round to the original mantissa and not the neighbors.
|
||||
inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
|
||||
|
||||
// Now we can figure out the minimum number of digits required.
|
||||
// Walk along until d has distinguished itself from upper and lower.
|
||||
for i, m := range d.mant {
|
||||
l := lower.at(i)
|
||||
u := upper.at(i)
|
||||
|
||||
// Okay to round down (truncate) if lower has a different digit
|
||||
// or if lower is inclusive and is exactly the result of rounding
|
||||
// down (i.e., and we have reached the final digit of lower).
|
||||
okdown := l != m || inclusive && i+1 == len(lower.mant)
|
||||
|
||||
// Okay to round up if upper has a different digit and either upper
|
||||
// is inclusive or upper is bigger than the result of rounding up.
|
||||
okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
|
||||
|
||||
// If it's okay to do either, then round to the nearest one.
|
||||
// If it's okay to do only one, do it.
|
||||
switch {
|
||||
case okdown && okup:
|
||||
d.round(i + 1)
|
||||
return
|
||||
case okdown:
|
||||
d.roundDown(i + 1)
|
||||
return
|
||||
case okup:
|
||||
d.roundUp(i + 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// %e: d.ddddde±dd
|
||||
func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
|
||||
// first digit
|
||||
|
|
@ -219,11 +292,7 @@ func fmtF(buf []byte, prec int, d decimal) []byte {
|
|||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
for i := 0; i < prec; i++ {
|
||||
ch := byte('0')
|
||||
if j := d.exp + i; 0 <= j && j < len(d.mant) {
|
||||
ch = d.mant[j]
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
buf = append(buf, d.at(d.exp+i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +324,7 @@ func (x *Float) fmtB(buf []byte) []byte {
|
|||
m = nat(nil).shr(m, uint(w-x.prec))
|
||||
}
|
||||
|
||||
buf = append(buf, m.decimalString()...)
|
||||
buf = append(buf, m.utoa(10)...)
|
||||
buf = append(buf, 'p')
|
||||
e := int64(x.exp) - int64(x.prec)
|
||||
if e >= 0 {
|
||||
|
|
@ -289,7 +358,7 @@ func (x *Float) fmtP(buf []byte) []byte {
|
|||
m = m[i:]
|
||||
|
||||
buf = append(buf, "0x."...)
|
||||
buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
|
||||
buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
|
||||
buf = append(buf, 'p')
|
||||
if x.exp >= 0 {
|
||||
buf = append(buf, '+')
|
||||
|
|
@ -314,10 +383,6 @@ func min(x, y int) int {
|
|||
// '+' and ' ' for sign control, '0' for space or zero padding,
|
||||
// and '-' for left or right justification. See the fmt package
|
||||
// for details.
|
||||
//
|
||||
// BUG(gri) A missing precision for the 'g' format, or a negative
|
||||
// (via '*') precision is not yet supported. Instead the
|
||||
// default precision (6) is used in that case (issue #10991).
|
||||
func (x *Float) Format(s fmt.State, format rune) {
|
||||
prec, hasPrec := s.Precision()
|
||||
if !hasPrec {
|
||||
|
|
@ -336,8 +401,7 @@ func (x *Float) Format(s fmt.State, format rune) {
|
|||
fallthrough
|
||||
case 'g', 'G':
|
||||
if !hasPrec {
|
||||
// TODO(gri) uncomment once (*Float).Text handles prec < 0
|
||||
// prec = -1 // default precision for 'g', 'G'
|
||||
prec = -1 // default precision for 'g', 'G'
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
|
||||
|
|
|
|||
|
|
@ -551,8 +551,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
|
|||
}
|
||||
|
||||
// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
|
||||
// If it returns true, x is prime with probability 1 - 1/4^n.
|
||||
// If it returns false, x is not prime. n must be > 0.
|
||||
// If x is prime, it returns true.
|
||||
// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
|
||||
//
|
||||
// It is not suitable for judging primes that an adversary may have crafted
|
||||
// to fool this test.
|
||||
func (x *Int) ProbablyPrime(n int) bool {
|
||||
if n <= 0 {
|
||||
panic("non-positive n for ProbablyPrime")
|
||||
|
|
@ -640,23 +643,23 @@ func Jacobi(x, y *Int) int {
|
|||
}
|
||||
}
|
||||
|
||||
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
|
||||
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
|
||||
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
|
||||
// not an odd integer.
|
||||
func (z *Int) ModSqrt(x, p *Int) *Int {
|
||||
switch Jacobi(x, p) {
|
||||
case -1:
|
||||
return nil // x is not a square mod p
|
||||
case 0:
|
||||
return z.SetInt64(0) // sqrt(0) mod p = 0
|
||||
case 1:
|
||||
break
|
||||
}
|
||||
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
|
||||
x = new(Int).Mod(x, p)
|
||||
}
|
||||
// modSqrt3Mod4 uses the identity
|
||||
// (a^((p+1)/4))^2 mod p
|
||||
// == u^(p+1) mod p
|
||||
// == u^2 mod p
|
||||
// to calculate the square root of any quadratic residue mod p quickly for 3
|
||||
// mod 4 primes.
|
||||
func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int {
|
||||
z.Set(p) // z = p
|
||||
z.Add(z, intOne) // z = p + 1
|
||||
z.Rsh(z, 2) // z = (p + 1) / 4
|
||||
z.Exp(x, z, p) // z = x^z mod p
|
||||
return z
|
||||
}
|
||||
|
||||
// modSqrtTonelliShanks uses the Tonelli-Shanks algorithm to find the square
|
||||
// root of a quadratic residue modulo any prime.
|
||||
func (z *Int) modSqrtTonelliShanks(x, p *Int) *Int {
|
||||
// Break p-1 into s*2^e such that s is odd.
|
||||
var s Int
|
||||
s.Sub(p, intOne)
|
||||
|
|
@ -703,6 +706,31 @@ func (z *Int) ModSqrt(x, p *Int) *Int {
|
|||
}
|
||||
}
|
||||
|
||||
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
|
||||
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
|
||||
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
|
||||
// not an odd integer.
|
||||
func (z *Int) ModSqrt(x, p *Int) *Int {
|
||||
switch Jacobi(x, p) {
|
||||
case -1:
|
||||
return nil // x is not a square mod p
|
||||
case 0:
|
||||
return z.SetInt64(0) // sqrt(0) mod p = 0
|
||||
case 1:
|
||||
break
|
||||
}
|
||||
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
|
||||
x = new(Int).Mod(x, p)
|
||||
}
|
||||
|
||||
// Check whether p is 3 mod 4, and if so, use the faster algorithm.
|
||||
if len(p.abs) > 0 && p.abs[0]%4 == 3 {
|
||||
return z.modSqrt3Mod4Prime(x, p)
|
||||
}
|
||||
// Otherwise, use Tonelli-Shanks.
|
||||
return z.modSqrtTonelliShanks(x, p)
|
||||
}
|
||||
|
||||
// Lsh sets z = x << n and returns z.
|
||||
func (z *Int) Lsh(x *Int, n uint) *Int {
|
||||
z.abs = z.abs.shl(x.abs, n)
|
||||
|
|
@ -904,65 +932,3 @@ func (z *Int) Not(x *Int) *Int {
|
|||
z.neg = true // z cannot be zero if x is positive
|
||||
return z
|
||||
}
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const intGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (x *Int) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
|
||||
i := x.abs.bytes(buf) - 1 // i >= 0
|
||||
b := intGobVersion << 1 // make space for sign bit
|
||||
if x.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[i] = b
|
||||
return buf[i:], nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Int) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Int{}
|
||||
return nil
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != intGobVersion {
|
||||
return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
|
||||
}
|
||||
z.neg = b&1 != 0
|
||||
z.abs = z.abs.setBytes(buf[1:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (z *Int) MarshalJSON() ([]byte, error) {
|
||||
// TODO(gri): get rid of the []byte/string conversions
|
||||
return []byte(z.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (z *Int) UnmarshalJSON(text []byte) error {
|
||||
// TODO(gri): get rid of the []byte/string conversions
|
||||
if _, ok := z.SetString(string(text), 0); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (z *Int) MarshalText() (text []byte, err error) {
|
||||
return []byte(z.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (z *Int) UnmarshalText(text []byte) error {
|
||||
if _, ok := z.SetString(string(text), 0); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,7 @@ package big
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
|
@ -1187,6 +1184,53 @@ func BenchmarkBitsetNegOrig(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
// tri generates the trinomial 2**(n*2) - 2**n - 1, which is always 3 mod 4 and
|
||||
// 7 mod 8, so that 2 is always a quadratic residue.
|
||||
func tri(n uint) *Int {
|
||||
x := NewInt(1)
|
||||
x.Lsh(x, n)
|
||||
x2 := new(Int).Lsh(x, n)
|
||||
x2.Sub(x2, x)
|
||||
x2.Sub(x2, intOne)
|
||||
return x2
|
||||
}
|
||||
|
||||
func BenchmarkModSqrt225_Tonelli(b *testing.B) {
|
||||
p := tri(225)
|
||||
x := NewInt(2)
|
||||
for i := 0; i < b.N; i++ {
|
||||
x.SetUint64(2)
|
||||
x.modSqrtTonelliShanks(x, p)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkModSqrt224_3Mod4(b *testing.B) {
|
||||
p := tri(225)
|
||||
x := new(Int).SetUint64(2)
|
||||
for i := 0; i < b.N; i++ {
|
||||
x.SetUint64(2)
|
||||
x.modSqrt3Mod4Prime(x, p)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
|
||||
p := tri(5430)
|
||||
x := new(Int).SetUint64(2)
|
||||
for i := 0; i < b.N; i++ {
|
||||
x.SetUint64(2)
|
||||
x.modSqrtTonelliShanks(x, p)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
|
||||
p := tri(5430)
|
||||
x := new(Int).SetUint64(2)
|
||||
for i := 0; i < b.N; i++ {
|
||||
x.SetUint64(2)
|
||||
x.modSqrt3Mod4Prime(x, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitwise(t *testing.T) {
|
||||
x := new(Int)
|
||||
y := new(Int)
|
||||
|
|
@ -1408,138 +1452,6 @@ func TestJacobiPanic(t *testing.T) {
|
|||
panic(failureMsg)
|
||||
}
|
||||
|
||||
var encodingTests = []string{
|
||||
"-539345864568634858364538753846587364875430589374589",
|
||||
"-678645873",
|
||||
"-100",
|
||||
"-2",
|
||||
"-1",
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"10",
|
||||
"42",
|
||||
"1234567890",
|
||||
"298472983472983471903246121093472394872319615612417471234712061",
|
||||
}
|
||||
|
||||
func TestIntGobEncoding(t *testing.T) {
|
||||
var medium bytes.Buffer
|
||||
enc := gob.NewEncoder(&medium)
|
||||
dec := gob.NewDecoder(&medium)
|
||||
for _, test := range encodingTests {
|
||||
medium.Reset() // empty buffer for each test case (in case of failures)
|
||||
var tx Int
|
||||
tx.SetString(test, 10)
|
||||
if err := enc.Encode(&tx); err != nil {
|
||||
t.Errorf("encoding of %s failed: %s", &tx, err)
|
||||
}
|
||||
var rx Int
|
||||
if err := dec.Decode(&rx); err != nil {
|
||||
t.Errorf("decoding of %s failed: %s", &tx, err)
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
|
||||
// TODO: top-level nils.
|
||||
func TestGobEncodingNilIntInSlice(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
dec := gob.NewDecoder(buf)
|
||||
|
||||
var in = make([]*Int, 1)
|
||||
err := enc.Encode(&in)
|
||||
if err != nil {
|
||||
t.Errorf("gob encode failed: %q", err)
|
||||
}
|
||||
var out []*Int
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
t.Fatalf("gob decode failed: %q", err)
|
||||
}
|
||||
if len(out) != 1 {
|
||||
t.Fatalf("wrong len; want 1 got %d", len(out))
|
||||
}
|
||||
var zero Int
|
||||
if out[0].Cmp(&zero) != 0 {
|
||||
t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntJSONEncoding(t *testing.T) {
|
||||
for _, test := range encodingTests {
|
||||
var tx Int
|
||||
tx.SetString(test, 10)
|
||||
b, err := json.Marshal(&tx)
|
||||
if err != nil {
|
||||
t.Errorf("marshaling of %s failed: %s", &tx, err)
|
||||
}
|
||||
var rx Int
|
||||
if err := json.Unmarshal(b, &rx); err != nil {
|
||||
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intVals = []string{
|
||||
"-141592653589793238462643383279502884197169399375105820974944592307816406286",
|
||||
"-1415926535897932384626433832795028841971",
|
||||
"-141592653589793",
|
||||
"-1",
|
||||
"0",
|
||||
"1",
|
||||
"141592653589793",
|
||||
"1415926535897932384626433832795028841971",
|
||||
"141592653589793238462643383279502884197169399375105820974944592307816406286",
|
||||
}
|
||||
|
||||
func TestIntJSONEncodingTextMarshaller(t *testing.T) {
|
||||
for _, num := range intVals {
|
||||
var tx Int
|
||||
tx.SetString(num, 0)
|
||||
b, err := json.Marshal(&tx)
|
||||
if err != nil {
|
||||
t.Errorf("marshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
var rx Int
|
||||
if err := json.Unmarshal(b, &rx); err != nil {
|
||||
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntXMLEncodingTextMarshaller(t *testing.T) {
|
||||
for _, num := range intVals {
|
||||
var tx Int
|
||||
tx.SetString(num, 0)
|
||||
b, err := xml.Marshal(&tx)
|
||||
if err != nil {
|
||||
t.Errorf("marshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
var rx Int
|
||||
if err := xml.Unmarshal(b, &rx); err != nil {
|
||||
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
|
||||
continue
|
||||
}
|
||||
if rx.Cmp(&tx) != 0 {
|
||||
t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue2607(t *testing.T) {
|
||||
// This code sequence used to hang.
|
||||
n := NewInt(10)
|
||||
|
|
|
|||
|
|
@ -12,30 +12,34 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
func (x *Int) String() string {
|
||||
switch {
|
||||
case x == nil:
|
||||
// TODO(gri) Should rename itoa to utoa (there's no sign). That
|
||||
// would permit the introduction of itoa which is like utoa but
|
||||
// reserves a byte for a possible sign that's passed in. That
|
||||
// would permit Int.Text to be implemented w/o the need for
|
||||
// string copy if the number is negative.
|
||||
|
||||
// Text returns the string representation of x in the given base.
|
||||
// Base must be between 2 and 36, inclusive. The result uses the
|
||||
// lower-case letters 'a' to 'z' for digit values >= 10. No base
|
||||
// prefix (such as "0x") is added to the string.
|
||||
func (x *Int) Text(base int) string {
|
||||
if x == nil {
|
||||
return "<nil>"
|
||||
case x.neg:
|
||||
return "-" + x.abs.decimalString()
|
||||
}
|
||||
return x.abs.decimalString()
|
||||
return string(x.abs.itoa(x.neg, base))
|
||||
}
|
||||
|
||||
func charset(ch rune) string {
|
||||
switch ch {
|
||||
case 'b':
|
||||
return lowercaseDigits[0:2]
|
||||
case 'o':
|
||||
return lowercaseDigits[0:8]
|
||||
case 'd', 's', 'v':
|
||||
return lowercaseDigits[0:10]
|
||||
case 'x':
|
||||
return lowercaseDigits[0:16]
|
||||
case 'X':
|
||||
return uppercaseDigits[0:16]
|
||||
// Append appends the string representation of x, as generated by
|
||||
// x.Text(base), to buf and returns the extended buffer.
|
||||
func (x *Int) Append(buf []byte, base int) []byte {
|
||||
if x == nil {
|
||||
return append(buf, "<nil>"...)
|
||||
}
|
||||
return "" // unknown format
|
||||
return append(buf, x.abs.itoa(x.neg, base)...)
|
||||
}
|
||||
|
||||
func (x *Int) String() string {
|
||||
return x.Text(10)
|
||||
}
|
||||
|
||||
// write count copies of text to s
|
||||
|
|
@ -60,15 +64,24 @@ func writeMultiple(s fmt.State, text string, count int) {
|
|||
// right justification.
|
||||
//
|
||||
func (x *Int) Format(s fmt.State, ch rune) {
|
||||
cs := charset(ch)
|
||||
|
||||
// special cases
|
||||
switch {
|
||||
case cs == "":
|
||||
// determine base
|
||||
var base int
|
||||
switch ch {
|
||||
case 'b':
|
||||
base = 2
|
||||
case 'o':
|
||||
base = 8
|
||||
case 'd', 's', 'v':
|
||||
base = 10
|
||||
case 'x', 'X':
|
||||
base = 16
|
||||
default:
|
||||
// unknown format
|
||||
fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
|
||||
return
|
||||
case x == nil:
|
||||
}
|
||||
|
||||
if x == nil {
|
||||
fmt.Fprint(s, "<nil>")
|
||||
return
|
||||
}
|
||||
|
|
@ -97,8 +110,15 @@ func (x *Int) Format(s fmt.State, ch rune) {
|
|||
}
|
||||
}
|
||||
|
||||
// determine digits with base set by len(cs) and digit characters from cs
|
||||
digits := x.abs.string(cs)
|
||||
digits := x.abs.utoa(base)
|
||||
if ch == 'X' {
|
||||
// faster than bytes.ToUpper
|
||||
for i, d := range digits {
|
||||
if 'a' <= d && d <= 'z' {
|
||||
digits[i] = 'A' + (d - 'a')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// number of characters for the three classes of number padding
|
||||
var left int // space characters to left of digits for right justification ("%8d")
|
||||
|
|
@ -111,7 +131,7 @@ func (x *Int) Format(s fmt.State, ch rune) {
|
|||
switch {
|
||||
case len(digits) < precision:
|
||||
zeros = precision - len(digits) // count of zero padding
|
||||
case digits == "0" && precision == 0:
|
||||
case len(digits) == 1 && digits[0] == '0' && precision == 0:
|
||||
return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
|
||||
}
|
||||
}
|
||||
|
|
@ -137,7 +157,7 @@ func (x *Int) Format(s fmt.State, ch rune) {
|
|||
writeMultiple(s, sign, 1)
|
||||
writeMultiple(s, prefix, 1)
|
||||
writeMultiple(s, "0", zeros)
|
||||
writeMultiple(s, digits, 1)
|
||||
s.Write(digits)
|
||||
writeMultiple(s, " ", right)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,19 +17,19 @@ var stringTests = []struct {
|
|||
val int64
|
||||
ok bool
|
||||
}{
|
||||
{in: "", ok: false},
|
||||
{in: "a", ok: false},
|
||||
{in: "z", ok: false},
|
||||
{in: "+", ok: false},
|
||||
{in: "-", ok: false},
|
||||
{in: "0b", ok: false},
|
||||
{in: "0x", ok: false},
|
||||
{in: "2", base: 2, ok: false},
|
||||
{in: "0b2", base: 0, ok: false},
|
||||
{in: "08", ok: false},
|
||||
{in: "8", base: 8, ok: false},
|
||||
{in: "0xg", base: 0, ok: false},
|
||||
{in: "g", base: 16, ok: false},
|
||||
{in: ""},
|
||||
{in: "a"},
|
||||
{in: "z"},
|
||||
{in: "+"},
|
||||
{in: "-"},
|
||||
{in: "0b"},
|
||||
{in: "0x"},
|
||||
{in: "2", base: 2},
|
||||
{in: "0b2", base: 0},
|
||||
{in: "08"},
|
||||
{in: "8", base: 8},
|
||||
{in: "0xg", base: 0},
|
||||
{in: "g", base: 16},
|
||||
{"0", "0", 0, 0, true},
|
||||
{"0", "0", 10, 0, true},
|
||||
{"0", "0", 16, 0, true},
|
||||
|
|
@ -41,7 +41,7 @@ var stringTests = []struct {
|
|||
{"-10", "-10", 16, -16, true},
|
||||
{"+10", "10", 16, 16, true},
|
||||
{"0x10", "16", 0, 16, true},
|
||||
{in: "0x10", base: 16, ok: false},
|
||||
{in: "0x10", base: 16},
|
||||
{"-0x10", "-16", 0, -16, true},
|
||||
{"+0x10", "16", 0, 16, true},
|
||||
{"00", "0", 0, 0, true},
|
||||
|
|
@ -58,6 +58,57 @@ var stringTests = []struct {
|
|||
{"1001010111", "1001010111", 2, 0x257, true},
|
||||
}
|
||||
|
||||
func TestIntText(t *testing.T) {
|
||||
z := new(Int)
|
||||
for _, test := range stringTests {
|
||||
if !test.ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_, ok := z.SetString(test.in, test.base)
|
||||
if !ok {
|
||||
t.Errorf("%v: failed to parse", test)
|
||||
continue
|
||||
}
|
||||
|
||||
base := test.base
|
||||
if base == 0 {
|
||||
base = 10
|
||||
}
|
||||
|
||||
if got := z.Text(base); got != test.out {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendText(t *testing.T) {
|
||||
z := new(Int)
|
||||
var buf []byte
|
||||
for _, test := range stringTests {
|
||||
if !test.ok {
|
||||
continue
|
||||
}
|
||||
|
||||
_, ok := z.SetString(test.in, test.base)
|
||||
if !ok {
|
||||
t.Errorf("%v: failed to parse", test)
|
||||
continue
|
||||
}
|
||||
|
||||
base := test.base
|
||||
if base == 0 {
|
||||
base = 10
|
||||
}
|
||||
|
||||
i := len(buf)
|
||||
buf = z.Append(buf, base)
|
||||
if got := string(buf[i:]); got != test.out {
|
||||
t.Errorf("%v: got %s; want %s", test, got, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func format(base int) string {
|
||||
switch base {
|
||||
case 2:
|
||||
|
|
@ -79,15 +130,13 @@ func TestGetString(t *testing.T) {
|
|||
z.SetInt64(test.val)
|
||||
|
||||
if test.base == 10 {
|
||||
s := z.String()
|
||||
if s != test.out {
|
||||
t.Errorf("#%da got %s; want %s", i, s, test.out)
|
||||
if got := z.String(); got != test.out {
|
||||
t.Errorf("#%da got %s; want %s", i, got, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
s := fmt.Sprintf(format(test.base), z)
|
||||
if s != test.out {
|
||||
t.Errorf("#%db got %s; want %s", i, s, test.out)
|
||||
if got := fmt.Sprintf(format(test.base), z); got != test.out {
|
||||
t.Errorf("#%db got %s; want %s", i, got, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,31 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package big implements multi-precision arithmetic (big numbers).
|
||||
// The following numeric types are supported:
|
||||
//
|
||||
// Int signed integers
|
||||
// Rat rational numbers
|
||||
// Float floating-point numbers
|
||||
//
|
||||
// Methods are typically of the form:
|
||||
//
|
||||
// func (z *T) Unary(x *T) *T // z = op x
|
||||
// func (z *T) Binary(x, y *T) *T // z = x op y
|
||||
// func (x *T) M() T1 // v = x.M()
|
||||
//
|
||||
// with T one of Int, Rat, or Float. For unary and binary operations, the
|
||||
// result is the receiver (usually named z in that case); if it is one of
|
||||
// the operands x or y it may be overwritten (and its memory reused).
|
||||
// To enable chaining of operations, the result is also returned. Methods
|
||||
// returning a result other than *Int, *Rat, or *Float take an operand as
|
||||
// the receiver (usually named x in that case).
|
||||
//
|
||||
package big
|
||||
// This file implements unsigned multi-precision integers (natural
|
||||
// numbers). They are the building blocks for the implementation
|
||||
// of signed integers, rationals, and floating-point numbers.
|
||||
|
||||
// This file contains operations on unsigned multi-precision integers.
|
||||
// These are the building blocks for the operations on signed integers
|
||||
// and rationals.
|
||||
package big
|
||||
|
||||
import "math/rand"
|
||||
|
||||
|
|
@ -216,23 +196,36 @@ func basicMul(z, x, y nat) {
|
|||
}
|
||||
}
|
||||
|
||||
// montgomery computes x*y*2^(-n*_W) mod m,
|
||||
// assuming k = -1/m mod 2^_W.
|
||||
// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
|
||||
// assuming k = -1/m mod 2**_W.
|
||||
// z is used for storing the result which is returned;
|
||||
// z must not alias x, y or m.
|
||||
// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
|
||||
// https://eprint.iacr.org/2011/239.pdf
|
||||
// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
|
||||
// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
|
||||
// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
|
||||
func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
|
||||
var c1, c2 Word
|
||||
// This code assumes x, y, m are all the same length, n.
|
||||
// (required by addMulVVW and the for loop).
|
||||
// It also assumes that x, y are already reduced mod m,
|
||||
// or else the result will not be properly reduced.
|
||||
if len(x) != n || len(y) != n || len(m) != n {
|
||||
panic("math/big: mismatched montgomery number lengths")
|
||||
}
|
||||
var c1, c2, c3 Word
|
||||
z = z.make(n)
|
||||
z.clear()
|
||||
for i := 0; i < n; i++ {
|
||||
d := y[i]
|
||||
c1 += addMulVVW(z, x, d)
|
||||
c2 = addMulVVW(z, x, d)
|
||||
t := z[0] * k
|
||||
c2 = addMulVVW(z, m, t)
|
||||
|
||||
c3 = addMulVVW(z, m, t)
|
||||
copy(z, z[1:])
|
||||
z[n-1] = c1 + c2
|
||||
if z[n-1] < c1 {
|
||||
cx := c1 + c2
|
||||
cy := cx + c3
|
||||
z[n-1] = cy
|
||||
if cx < c2 || cy < c3 {
|
||||
c1 = 1
|
||||
} else {
|
||||
c1 = 0
|
||||
|
|
@ -1082,7 +1075,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
|
|||
x = rr
|
||||
|
||||
// Ideally the precomputations would be performed outside, and reused
|
||||
// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
|
||||
// k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
|
||||
// Iteration for Multiplicative Inverses Modulo Prime Powers".
|
||||
k0 := 2 - m[0]
|
||||
t := m[0] - 1
|
||||
|
|
@ -1092,7 +1085,7 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
|
|||
}
|
||||
k0 = -k0
|
||||
|
||||
// RR = 2ˆ(2*_W*len(m)) mod m
|
||||
// RR = 2**(2*_W*len(m)) mod m
|
||||
RR = RR.setWord(1)
|
||||
zz = zz.shl(RR, uint(2*numWords*_W))
|
||||
_, RR = RR.div(RR, zz, m)
|
||||
|
|
@ -1141,9 +1134,12 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
|
|||
return zz.norm()
|
||||
}
|
||||
|
||||
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
|
||||
// If it returns true, n is prime with probability 1 - 1/4^reps.
|
||||
// If it returns false, n is not prime.
|
||||
// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
|
||||
// If x is prime, it returns true.
|
||||
// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
|
||||
//
|
||||
// It is not suitable for judging primes that an adversary may have crafted
|
||||
// to fool this test.
|
||||
func (n nat) probablyPrime(reps int) bool {
|
||||
if len(n) == 0 {
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ var mulRangesN = []struct {
|
|||
|
||||
func TestMulRangeN(t *testing.T) {
|
||||
for i, r := range mulRangesN {
|
||||
prod := nat(nil).mulRange(r.a, r.b).decimalString()
|
||||
prod := string(nat(nil).mulRange(r.a, r.b).utoa(10))
|
||||
if prod != r.prod {
|
||||
t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
|
||||
}
|
||||
|
|
@ -326,7 +326,7 @@ func TestTrailingZeroBits(t *testing.T) {
|
|||
for i := uint(0); i <= 3*_W; i++ {
|
||||
n := y.trailingZeroBits()
|
||||
if n != i {
|
||||
t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
|
||||
t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i)
|
||||
}
|
||||
y = y.shl(y, 1)
|
||||
}
|
||||
|
|
@ -341,25 +341,57 @@ var montgomeryTests = []struct {
|
|||
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
0x0000000000000000,
|
||||
"0xffffffffffffffffffffffffffffffffffffffffff",
|
||||
"0xffffffffffffffffffffffffffffffffff",
|
||||
1,
|
||||
"0x1000000000000000000000000000000000000000000",
|
||||
"0x10000000000000000000000000000000000",
|
||||
},
|
||||
{
|
||||
"0x000000000ffffff5",
|
||||
"0x000000000ffffff0",
|
||||
"0x0000000010000001",
|
||||
0xff0000000fffffff,
|
||||
"0x000000000bfffff4",
|
||||
"0x0000000003400001",
|
||||
},
|
||||
{
|
||||
"0x0000000080000000",
|
||||
"0x00000000ffffffff",
|
||||
"0x0000000010000001",
|
||||
0xff0000000fffffff,
|
||||
"0x0000000088000000",
|
||||
"0x0000000007800001",
|
||||
"0x1000000000000001",
|
||||
0xfffffffffffffff,
|
||||
"0x0800000008000001",
|
||||
"0x0800000008000001",
|
||||
},
|
||||
{
|
||||
"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
|
||||
"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
|
||||
"0x0000000080000000",
|
||||
"0x0000000080000000",
|
||||
"0xffffffff00000001",
|
||||
0xfffffffeffffffff,
|
||||
"0xbfffffff40000001",
|
||||
"0xbfffffff40000001",
|
||||
},
|
||||
{
|
||||
"0x0000000080000000",
|
||||
"0x0000000080000000",
|
||||
"0x00ffffff00000001",
|
||||
0xfffffeffffffff,
|
||||
"0xbfffff40000001",
|
||||
"0xbfffff40000001",
|
||||
},
|
||||
{
|
||||
"0x0000000080000000",
|
||||
"0x0000000080000000",
|
||||
"0x0000ffff00000001",
|
||||
0xfffeffffffff,
|
||||
"0xbfff40000001",
|
||||
"0xbfff40000001",
|
||||
},
|
||||
{
|
||||
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
|
||||
"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
|
||||
"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
|
||||
0xdecc8f1249812adf,
|
||||
"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
|
||||
"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
|
||||
"0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
|
||||
"0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
|
||||
},
|
||||
{
|
||||
"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
|
||||
|
|
@ -372,10 +404,27 @@ var montgomeryTests = []struct {
|
|||
}
|
||||
|
||||
func TestMontgomery(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
_B := new(Int).Lsh(one, _W)
|
||||
for i, test := range montgomeryTests {
|
||||
x := natFromString(test.x)
|
||||
y := natFromString(test.y)
|
||||
m := natFromString(test.m)
|
||||
for len(x) < len(m) {
|
||||
x = append(x, 0)
|
||||
}
|
||||
for len(y) < len(m) {
|
||||
y = append(y, 0)
|
||||
}
|
||||
|
||||
if x.cmp(m) > 0 {
|
||||
_, r := nat(nil).div(nil, x, m)
|
||||
t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16))
|
||||
}
|
||||
if y.cmp(m) > 0 {
|
||||
_, r := nat(nil).div(nil, x, m)
|
||||
t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16))
|
||||
}
|
||||
|
||||
var out nat
|
||||
if _W == 32 {
|
||||
|
|
@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) {
|
|||
out = natFromString(test.out64)
|
||||
}
|
||||
|
||||
k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
|
||||
// t.Logf("#%d: len=%d\n", i, len(m))
|
||||
|
||||
// check output in table
|
||||
xi := &Int{abs: x}
|
||||
yi := &Int{abs: y}
|
||||
mi := &Int{abs: m}
|
||||
p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi)
|
||||
if out.cmp(p.abs.norm()) != 0 {
|
||||
t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16))
|
||||
}
|
||||
|
||||
// check k0 in table
|
||||
k := new(Int).Mod(&Int{abs: m}, _B)
|
||||
k = new(Int).Sub(_B, k)
|
||||
k = new(Int).Mod(k, _B)
|
||||
k0 := Word(new(Int).ModInverse(k, _B).Uint64())
|
||||
if k0 != Word(test.k0) {
|
||||
t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0)
|
||||
}
|
||||
|
||||
// check montgomery with correct k0 produces correct output
|
||||
z := nat(nil).montgomery(x, y, m, k0, len(m))
|
||||
z = z.norm()
|
||||
if z.cmp(out) != 0 {
|
||||
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
|
||||
t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -429,7 +498,7 @@ func TestExpNN(t *testing.T) {
|
|||
|
||||
z := nat(nil).expNN(x, y, m)
|
||||
if z.cmp(out) != 0 {
|
||||
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
|
||||
t.Errorf("#%d got %s want %s", i, z.utoa(10), out.utoa(10))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -486,7 +555,7 @@ var fiboNums = []string{
|
|||
func TestFibo(t *testing.T) {
|
||||
for i, want := range fiboNums {
|
||||
n := i * 10
|
||||
got := fibo(n).decimalString()
|
||||
got := string(fibo(n).utoa(10))
|
||||
if got != want {
|
||||
t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue