mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] all: merge branch 'master' into dev.link
Change-Id: I446db56b20ef2189e23e225a91a17736c1d11e4c
This commit is contained in:
commit
3187b05b87
71 changed files with 1541 additions and 832 deletions
20
.gitattributes
vendored
20
.gitattributes
vendored
|
|
@ -1,16 +1,16 @@
|
|||
# Treat all files in the Go repo as binary, with no git magic updating
|
||||
# line endings. Windows users contributing to Go will need to use a
|
||||
# modern version of git and editors capable of LF line endings.
|
||||
# line endings. This produces predictable results in different environments.
|
||||
#
|
||||
# Windows users contributing to Go will need to use a modern version
|
||||
# of git and editors capable of LF line endings.
|
||||
#
|
||||
# Windows .bat files are known to have multiple bugs when run with LF
|
||||
# endings, and so they are checked in with CRLF endings, with a test
|
||||
# in test/winbatch.go to catch problems. (See golang.org/issue/37791.)
|
||||
#
|
||||
# We'll prevent accidental CRLF line endings from entering the repo
|
||||
# via the git-review gofmt checks.
|
||||
# via the git-codereview gofmt checks and tests.
|
||||
#
|
||||
# See golang.org/issue/9281
|
||||
# See golang.org/issue/9281.
|
||||
|
||||
* -text
|
||||
|
||||
# The only exception is Windows files that must absolutely be CRLF or
|
||||
# might not work. Batch files are known to have multiple bugs when run
|
||||
# with LF endings. See golang.org/issue/37791 for more information.
|
||||
|
||||
*.bat text eol=crlf
|
||||
|
|
|
|||
1
AUTHORS
1
AUTHORS
|
|
@ -1397,6 +1397,7 @@ Upthere, Inc.
|
|||
Uriel Mangado <uriel@berlinblue.org>
|
||||
Vadim Grek <vadimprog@gmail.com>
|
||||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
|
||||
Vendasta
|
||||
Veselkov Konstantin <kostozyb@gmail.com>
|
||||
Victor Vrantchan <vrancean+github@gmail.com>
|
||||
|
|
|
|||
|
|
@ -2195,6 +2195,7 @@ Vadim Grek <vadimprog@gmail.com>
|
|||
Vadim Vygonets <unixdj@gmail.com>
|
||||
Val Polouchkine <vpolouch@justin.tv>
|
||||
Valentin Vidic <vvidic@valentin-vidic.from.hr>
|
||||
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
|
||||
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
||||
Venil Noronha <veniln@vmware.com>
|
||||
Veselkov Konstantin <kostozyb@gmail.com>
|
||||
|
|
|
|||
132
api/go1.15.txt
Normal file
132
api/go1.15.txt
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
pkg bufio, var ErrBadReadCount error
|
||||
pkg crypto, method (Hash) String() string
|
||||
pkg crypto/ecdsa, func SignASN1(io.Reader, *PrivateKey, []uint8) ([]uint8, error)
|
||||
pkg crypto/ecdsa, func VerifyASN1(*PublicKey, []uint8, []uint8) bool
|
||||
pkg crypto/ecdsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
|
||||
pkg crypto/ecdsa, method (*PublicKey) Equal(crypto.PublicKey) bool
|
||||
pkg crypto/ed25519, method (PrivateKey) Equal(crypto.PrivateKey) bool
|
||||
pkg crypto/ed25519, method (PublicKey) Equal(crypto.PublicKey) bool
|
||||
pkg crypto/elliptic, func MarshalCompressed(Curve, *big.Int, *big.Int) []uint8
|
||||
pkg crypto/elliptic, func UnmarshalCompressed(Curve, []uint8) (*big.Int, *big.Int)
|
||||
pkg crypto/rsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
|
||||
pkg crypto/rsa, method (*PublicKey) Equal(crypto.PublicKey) bool
|
||||
pkg crypto/tls, method (*Dialer) Dial(string, string) (net.Conn, error)
|
||||
pkg crypto/tls, method (*Dialer) DialContext(context.Context, string, string) (net.Conn, error)
|
||||
pkg crypto/tls, method (ClientAuthType) String() string
|
||||
pkg crypto/tls, method (CurveID) String() string
|
||||
pkg crypto/tls, method (SignatureScheme) String() string
|
||||
pkg crypto/tls, type Config struct, VerifyConnection func(ConnectionState) error
|
||||
pkg crypto/tls, type Dialer struct
|
||||
pkg crypto/tls, type Dialer struct, Config *Config
|
||||
pkg crypto/tls, type Dialer struct, NetDialer *net.Dialer
|
||||
pkg crypto/x509, func CreateRevocationList(io.Reader, *RevocationList, *Certificate, crypto.Signer) ([]uint8, error)
|
||||
pkg crypto/x509, type RevocationList struct
|
||||
pkg crypto/x509, type RevocationList struct, ExtraExtensions []pkix.Extension
|
||||
pkg crypto/x509, type RevocationList struct, NextUpdate time.Time
|
||||
pkg crypto/x509, type RevocationList struct, Number *big.Int
|
||||
pkg crypto/x509, type RevocationList struct, RevokedCertificates []pkix.RevokedCertificate
|
||||
pkg crypto/x509, type RevocationList struct, SignatureAlgorithm SignatureAlgorithm
|
||||
pkg crypto/x509, type RevocationList struct, ThisUpdate time.Time
|
||||
pkg database/sql, method (*DB) SetConnMaxIdleTime(time.Duration)
|
||||
pkg database/sql, method (*Row) Err() error
|
||||
pkg database/sql, type DBStats struct, MaxIdleTimeClosed int64
|
||||
pkg database/sql/driver, type Validator interface { IsValid }
|
||||
pkg database/sql/driver, type Validator interface, IsValid() bool
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 4096
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 64
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 128
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 16384
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 32
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND = 2048
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 512
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH = 1024
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 256
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 32768
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ideal-int
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 8192
|
||||
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE = 256
|
||||
pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM = 16
|
||||
pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI = 32768
|
||||
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO = 128
|
||||
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED = 512
|
||||
pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_DLL = 8192
|
||||
pkg debug/pe, const IMAGE_FILE_DLL ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE = 2
|
||||
pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE = 32
|
||||
pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED = 4
|
||||
pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 8
|
||||
pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP = 2048
|
||||
pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED = 1
|
||||
pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 1024
|
||||
pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_SYSTEM = 4096
|
||||
pkg debug/pe, const IMAGE_FILE_SYSTEM ideal-int
|
||||
pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY = 16384
|
||||
pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION = 10
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM = 13
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE = 1
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI = 5
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI = 7
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN = 0
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int
|
||||
pkg go/printer, const StdFormat = 16
|
||||
pkg go/printer, const StdFormat Mode
|
||||
pkg math/big, method (*Int) FillBytes([]uint8) []uint8
|
||||
pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error)
|
||||
pkg net/url, method (*URL) EscapedFragment() string
|
||||
pkg net/url, method (*URL) Redacted() string
|
||||
pkg net/url, type URL struct, RawFragment string
|
||||
pkg os, method (*File) ReadFrom(io.Reader) (int64, error)
|
||||
pkg os, var ErrDeadlineExceeded error
|
||||
pkg regexp, method (*Regexp) SubexpIndex(string) int
|
||||
pkg strconv, func FormatComplex(complex128, uint8, int, int) string
|
||||
pkg strconv, func ParseComplex(string, int) (complex128, error)
|
||||
pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)
|
||||
pkg testing, method (*B) TempDir() string
|
||||
pkg testing, method (*T) Deadline() (time.Time, bool)
|
||||
pkg testing, method (*T) TempDir() string
|
||||
pkg testing, type TB interface, TempDir() string
|
||||
pkg time, method (*Ticker) Reset(Duration)
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
pkg testing, method (*T) Deadline() (time.Time, bool)
|
||||
pkg time, method (*Ticker) Reset(Duration)
|
||||
pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)
|
||||
|
|
@ -30,7 +30,7 @@ adds <a href="#test">caching of successful test results</a>,
|
|||
runs <a href="#test-vet">vet automatically during tests</a>,
|
||||
and
|
||||
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
|
||||
A new <a href="#cgo">compiler option whitelist</a> may cause
|
||||
A new <a href="#cgo">hard-coded set of safe compiler options</a> may cause
|
||||
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
|
||||
flag</code></a> errors in code that built successfully with older
|
||||
releases.
|
||||
|
|
@ -267,7 +267,7 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
|
|||
|
||||
<p>
|
||||
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
|
||||
are now checked against a whitelist of permitted options.
|
||||
are now checked against a list of permitted options.
|
||||
This closes a security hole in which a downloaded package uses
|
||||
compiler options like
|
||||
<span style="white-space: nowrap"><code>-fplugin</code></span>
|
||||
|
|
|
|||
300
doc/go1.15.html
300
doc/go1.15.html
|
|
@ -55,6 +55,13 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
on Windows.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 227003 -->
|
||||
The <code>-race</code> and <code>-msan</code> flags now always
|
||||
enable <code>-d=checkptr</code>, which checks uses
|
||||
of <code>unsafe.Pointer</code>. This was previously the case on all
|
||||
OSes except Windows.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 211139 -->
|
||||
Go-built DLLs no longer cause the process to exit when it receives a
|
||||
signal (such as Ctrl-C at a terminal).
|
||||
|
|
@ -211,10 +218,24 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
|
||||
<p><!-- CL 232862 -->
|
||||
Go now retries system calls that return <code>EINTR</code>. This
|
||||
became more common in Go 1.14 with the addition of asynchronous
|
||||
preemption, but is now handled transparently.
|
||||
<p><!-- CL 221779 -->
|
||||
If <code>panic</code> is invoked with a value whose type is derived from any
|
||||
of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
|
||||
<code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
|
||||
<code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
|
||||
then the value will be printed, instead of just its address.
|
||||
Previously, this was only true for values of exactly these types.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 228900 -->
|
||||
On a Unix system, if the <code>kill</code> command
|
||||
or <code>kill</code> system call is used to send
|
||||
a <code>SIGSEGV</code>, <code>SIGBUS</code>,
|
||||
or <code>SIGFPE</code> signal to a Go program, and if the signal
|
||||
is not being handled via
|
||||
<a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
|
||||
the Go program will now reliably crash with a stack trace.
|
||||
In earlier releases the behavior was unpredictable.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 221182, CL 229998 -->
|
||||
|
|
@ -222,8 +243,14 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
counts, and has lower worst-case latency.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
<p><!-- CL 216401 -->
|
||||
Converting a small integer value into an interface value no longer
|
||||
causes allocation.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 216818 -->
|
||||
Non-blocking receives on closed channels now perform as well as
|
||||
non-blocking receives on open channels.
|
||||
</p>
|
||||
|
||||
<h2 id="compiler">Compiler</h2>
|
||||
|
|
@ -245,6 +272,15 @@ TODO
|
|||
aggressively eliminating unused type metadata.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 219357, CL 231600 -->
|
||||
The toolchain now mitigates
|
||||
<a href="https://www.intel.com/content/www/us/en/support/articles/000055650/processors.html">Intel
|
||||
CPU erratum SKX102</a> on <code>GOARCH=amd64</code> by aligning
|
||||
functions to 32 byte boundaries and padding jump instructions. While
|
||||
this padding increases binary sizes, this is more than made up for
|
||||
by the binary size improvements mentioned above.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 222661 -->
|
||||
Go 1.15 adds a <code>-spectre</code> flag to both the
|
||||
compiler and the assembler, to allow enabling Spectre mitigations.
|
||||
|
|
@ -253,6 +289,19 @@ TODO
|
|||
See the <a href="https://github.com/golang/go/wiki/Spectre">Spectre wiki page</a> for details.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 228578 -->
|
||||
The compiler now rejects <code>//go:</code> compiler directives that
|
||||
have no meaning for the declaration they are applied to with a
|
||||
"misplaced compiler directive" error. Such misapplied directives
|
||||
were broken before, but were silently ignored by the compiler.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 206658, CL 205066 -->
|
||||
The compiler's <code>-json</code> optimization logging now reports
|
||||
large (>= 128 byte) copies and includes explanations of escape
|
||||
analysis decisions.
|
||||
</p>
|
||||
|
||||
<h2 id="linker">Linker</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -283,6 +332,14 @@ TODO
|
|||
improvements expected in future releases.
|
||||
</p>
|
||||
|
||||
<h2 id="objdump">Objdump</h2>
|
||||
|
||||
<p><!-- CL 225459 -->
|
||||
The <a href="/cmd/objdump/">objdump</a> tool now supports
|
||||
disassembling in GNU assembler syntax with the <code>-gnu</code>
|
||||
flag.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Core library</h2>
|
||||
|
||||
<h3 id="time/tzdata">New embedded tzdata package</h3>
|
||||
|
|
@ -299,10 +356,6 @@ TODO
|
|||
Either approach increases the size of the program by about 800 KB.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<h3 id="cgo">Cgo</h3>
|
||||
|
||||
<p><!-- CL 235817 -->
|
||||
|
|
@ -321,10 +374,6 @@ TODO
|
|||
in mind.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<dl id="debug/pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 222637 -->
|
||||
|
|
@ -336,10 +385,53 @@ TODO
|
|||
</dd>
|
||||
</dl><!-- debug/pe -->
|
||||
|
||||
<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 231417, CL 225460 -->
|
||||
The <code>PrivateKey</code> and <code>PublicKey</code> types in the
|
||||
<a href="/pkg/crypto/rsa"><code>crypto/rsa</code></a>,
|
||||
<a href="/pkg/crypto/ecdsa"><code>crypto/ecdsa</code></a>, and
|
||||
<a href="/pkg/crypto/ed25519"><code>crypto/ed25519</code></a> packages
|
||||
now have an <code>Equal</code> method to compare keys for equivalence
|
||||
or to make type-safe interfaces for public keys. The method signature
|
||||
is compatible with
|
||||
<a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal"><code>go-cmp</code>'s
|
||||
definition of equality</a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 224937 -->
|
||||
<a href="/pkg/crypto/#Hash"><code>Hash</code></a> now implements
|
||||
<a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto -->
|
||||
|
||||
<dl id="crypto/ecdsa"><dt><a href="/pkg/crypto/ecdsa/">crypto/ecdsa</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 217940 -->
|
||||
The new <a href="/pkg/crypto/ecdsa/#SignASN1"><code>SignASN1</code></a>
|
||||
and <a href="/pkg/crypto/ecdsa/#VerifyASN1"><code>VerifyASN1</code></a>
|
||||
functions allow generating and verifying ECDSA signatures in the standard
|
||||
ASN.1 DER encoding.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/ecdsa -->
|
||||
|
||||
<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 202819 -->
|
||||
The new <a href="/pkg/crypto/elliptic/#MarshalCompressed"><code>MarshalCompressed</code></a>
|
||||
and <a href="/pkg/crypto/elliptic/#UnmarshalCompressed"><code>UnmarshalCompressed</code></a>
|
||||
functions allow encoding and decoding NIST elliptic curve points in compressed format.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/elliptic -->
|
||||
|
||||
<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 226203 -->
|
||||
VerifyPKCS1v15 now rejects invalid short signatures with missing leading zeroes.
|
||||
<a href="/pkg/crypto/rsa/#VerifyPKCS1v15"><code>VerifyPKCS1v15</code></a>
|
||||
now rejects invalid short signatures with missing leading zeroes, according to RFC 8017.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/rsa -->
|
||||
|
|
@ -353,21 +445,137 @@ TODO
|
|||
<a href="/pkg/crypto/tls/#Dialer.DialContext"><code>DialContext</code></a>
|
||||
method permits using a context to both connect and handshake with a TLS server.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 229122 -->
|
||||
The new
|
||||
<a href="/pkg/crypto/tls/#Config.VerifyConnection"><code>VerifyConnection</code></a>
|
||||
callback on the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> type
|
||||
allows custom verification logic for every connection. It has access to the
|
||||
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
|
||||
which includes peer certificates, SCTs, and stapled OCSP responses.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 230679 -->
|
||||
Auto-generated session ticket keys are now automatically rotated every 24 hours,
|
||||
with a lifetime of 7 days, to limit their impact on forward secrecy.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 231317 -->
|
||||
Session ticket lifetimes in TLS 1.2 and earlier, where the session keys
|
||||
are reused for resumed connections, are now limited to 7 days, also to
|
||||
limit their impact on forward secrecy.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 231038 -->
|
||||
The client-side downgrade protection checks specified in RFC 8446 are now
|
||||
enforced. This has the potential to cause connection errors for clients
|
||||
encountering middleboxes that behave like unauthorized downgrade attacks.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 208226 -->
|
||||
<a href="/pkg/crypto/tls/#SignatureScheme"><code>SignatureScheme</code></a>,
|
||||
<a href="/pkg/crypto/tls/#CurveID"><code>CurveID</code></a>, and
|
||||
<a href="/pkg/crypto/tls/#ClientAuthType"><code>ClientAuthType</code></a>
|
||||
now implement <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 236737 -->
|
||||
The <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
|
||||
fields <code>OCSPResponse</code> and <code>SignedCertificateTimestamps</code>
|
||||
are now repopulated on client-side resumed connections.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dl><!-- crypto/tls -->
|
||||
|
||||
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 231378, CL 231380, CL 231381 -->
|
||||
If either the name on the certificate or the name being verified (with
|
||||
<a href="/pkg/crypto/x509/#VerifyOptions.DNSName"><code>VerifyOptions.DNSName</code></a>
|
||||
or <a href="/pkg/crypto/x509/#Certificate.VerifyHostname"><code>VerifyHostname</code></a>)
|
||||
are invalid, they will now be compared case-insensitively without further
|
||||
processing (without honoring wildcards or stripping trailing dots).
|
||||
Invalid names include those with any characters other than letters,
|
||||
digits, hyphens and underscores, those with empty labels, and names on
|
||||
certificates with trailing dots.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 231379 -->
|
||||
The deprecated, legacy behavior of treating the <code>CommonName</code>
|
||||
field as a hostname when no Subject Alternative Names are present is now
|
||||
disabled by default. It can be temporarily re-enabled by adding the value
|
||||
<code>x509ignoreCN=0</code> to the <code>GODEBUG</code> environment
|
||||
variable. If the <code>CommonName</code> is an invalid hostname, it's
|
||||
always ignored.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 217298 -->
|
||||
The new <a href="/pkg/crypto/x509/#CreateRevocationList"><code>CreateRevocationList</code></a>
|
||||
function and <a href="/pkg/crypto/x509/#RevocationList"><code>RevocationList</code></a> type
|
||||
allow creating RFC 5280-compliant X.509 v2 Certificate Revocation Lists.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 227098 -->
|
||||
<a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
|
||||
now automatically generates the <code>SubjectKeyId</code> if the template
|
||||
is a CA and doesn't explicitly specify one.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 228777 -->
|
||||
<a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
|
||||
now returns an error if the template specifies <code>MaxPathLen</code> but is not a CA.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 205237 -->
|
||||
TODO: <a href="https://golang.org/cl/205237">https://golang.org/cl/205237</a>: load roots from colon separated SSL_CERT_DIR in loadSystemRoots
|
||||
On Unix systems other than macOS, the <code>SSL_CERT_DIR</code>
|
||||
environment variable can now be a colon-separated list.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 227037 -->
|
||||
On macOS, binaries are now always linked against
|
||||
<code>Security.framework</code> to extract the system trust roots,
|
||||
regardless of whether cgo is available. The resulting behavior should be
|
||||
more consistent with the OS verifier.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
<dl id="crypto/x509/pkix"><dt><a href="/pkg/crypto/x509/pkix/">crypto/x509/pkix</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 229864 -->
|
||||
<a href="/pkg/crypto/x509/pkix/#Name.String"><code>Name.String</code></a>
|
||||
now prints non-standard attributes from
|
||||
<a href="/pkg/crypto/x509/pkix/#Name.Names"><code>Names</code></a> if
|
||||
<a href="/pkg/crypto/x509/pkix/#Name.ExtraNames"><code>ExtraNames</code></a> is empty.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/x509/pkix -->
|
||||
|
||||
<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 191783 -->
|
||||
Decoding a JSON array into a slice no longer reuses any existing slice elements,
|
||||
following the rules that the package documentation already stated.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 199837 -->
|
||||
Introduce an internal limit to the maximum depth of nesting when decoding.
|
||||
This reduces the possibility that a deeply nested input could use large quantities
|
||||
of stack memory, or even cause a "goroutine stack exceeds limit" panic.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/json -->
|
||||
|
||||
<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 203417 -->
|
||||
TODO: <a href="https://golang.org/cl/203417">https://golang.org/cl/203417</a>: fix reserved namespace check to be case-insensitive
|
||||
The encoder has always taken care to avoid using namespace prefixes beginning with
|
||||
<code>xml</code>,
|
||||
which are reserved by the XML specification.
|
||||
Now, following the specification more closely,
|
||||
that check is case-insensitive, so that prefixes beginning with
|
||||
<code>XML</code>, <code>XmL</code>,
|
||||
and so on are also avoided.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/xml -->
|
||||
|
|
@ -390,7 +598,8 @@ TODO
|
|||
<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 215001 -->
|
||||
TODO: <a href="https://golang.org/cl/215001">https://golang.org/cl/215001</a>: do not remove trailing zeros for %g and %G with #(sharp) flag
|
||||
The printing verbs <code>%#g</code> and <code>%#G</code> now preserve
|
||||
trailing zeros for floating-point values.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- fmt -->
|
||||
|
|
@ -410,7 +619,8 @@ TODO
|
|||
<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 230397 -->
|
||||
TODO: <a href="https://golang.org/cl/230397">https://golang.org/cl/230397</a>: add (*Int).FillBytes
|
||||
The new <a href="/pkg/math/big/#Int.FillBytes"><code>Int.FillBytes</code></a>
|
||||
method allows serializing to fixed-size pre-allocated byte slices.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- math/big -->
|
||||
|
|
@ -441,8 +651,10 @@ TODO
|
|||
|
||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 231418 -->
|
||||
TODO: <a href="https://golang.org/cl/231418">https://golang.org/cl/231418</a>: only support "chunked" in inbound Transfer-Encoding headers
|
||||
<p><!-- CL 231418, CL 231419 -->
|
||||
Parsing is now stricter as a hardening measure against request smuggling attacks:
|
||||
non-ASCII white space is no longer trimmed like SP and HTAB, and support for the
|
||||
"<code>identity</code>" <code>Transfer-Encoding</code> was dropped.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net/http -->
|
||||
|
|
@ -457,7 +669,9 @@ TODO
|
|||
</p>
|
||||
|
||||
<p><!-- CL 224897 -->
|
||||
TODO: <a href="https://golang.org/cl/224897">https://golang.org/cl/224897</a>: make Switching Protocol requests (e.g. Websockets) cancelable
|
||||
When a Switching Protocol (like WebSocket) request handled by
|
||||
<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
|
||||
is canceled, the backend connection is now correctly closed.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
|
@ -506,6 +720,14 @@ TODO
|
|||
which <code>Timeout</code> returns <code>true</code> although a
|
||||
deadline has not been exceeded.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 232862 -->
|
||||
Packages <code>os</code> and <code>net</code> now automatically
|
||||
retry system calls that fail with <code>EINTR</code>. Previously
|
||||
this led to spurious failures, which became more common in Go
|
||||
1.14 with the addition of asynchronous preemption. Now this is
|
||||
handled transparently.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
|
@ -525,7 +747,7 @@ TODO
|
|||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 228902 -->
|
||||
Package reflect now disallows accessing methods of all
|
||||
Package <code>reflect</code> now disallows accessing methods of all
|
||||
non-exported fields, whereas previously it allowed accessing
|
||||
those of non-exported, embedded fields. Code that relies on the
|
||||
previous behavior should be updated to instead access the
|
||||
|
|
@ -546,26 +768,6 @@ TODO
|
|||
|
||||
<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 221779 -->
|
||||
If <code>panic</code> is invoked with a value whose type is derived from any
|
||||
of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
|
||||
<code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
|
||||
<code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
|
||||
then the value will be printed, instead of just its address.
|
||||
Previously, this was only true for values of exactly these types.
|
||||
</p>
|
||||
|
||||
<p><!-- CL -->
|
||||
On a Unix system, if the <code>kill</code> command
|
||||
or <code>kill</code> system call is used to send
|
||||
a <code>SIGSEGV</code>, <code>SIGBUS</code>,
|
||||
or <code>SIGFPE</code> signal to a Go program, and if the signal
|
||||
is not being handled via
|
||||
<a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
|
||||
the Go program will now reliably crash with a stack trace.
|
||||
In earlier releases the behavior was unpredictable.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 216557 -->
|
||||
Several functions, including
|
||||
<a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
|
||||
|
|
@ -573,16 +775,6 @@ TODO
|
|||
<a href="/pkg/runtime/#GoroutineProfile"><code>GoroutineProfile</code></a>,
|
||||
no longer block if a garbage collection is in progress.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 216401 -->
|
||||
Converting small integer values into an interface value no
|
||||
longer causes allocation.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 216818 -->
|
||||
Non-blocking receives on closed channels now perform as well as
|
||||
non-blocking receives on open channels.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
|
|
|||
|
|
@ -73,19 +73,29 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
|
|||
if err != nil {
|
||||
t.Fatalf("Stat failed: %v", err)
|
||||
}
|
||||
// Debug paths are stored slash-separated, so convert to system-native.
|
||||
srcPath = filepath.FromSlash(srcPath)
|
||||
fi2, err := os.Stat(srcPath)
|
||||
if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" && strings.HasPrefix(srcPath, gorootFinal) {
|
||||
if os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2)) {
|
||||
// srcPath has had GOROOT_FINAL substituted for GOROOT, and it doesn't
|
||||
// match the actual file. GOROOT probably hasn't been moved to its final
|
||||
// location yet, so try the original location instead.
|
||||
fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Stat failed: %v", err)
|
||||
}
|
||||
if !os.SameFile(fi1, fi2) {
|
||||
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
|
||||
}
|
||||
if srcLineNo != "89" {
|
||||
t.Fatalf("line number = %v; want 89", srcLineNo)
|
||||
if srcLineNo != "99" {
|
||||
t.Fatalf("line number = %v; want 99", srcLineNo)
|
||||
}
|
||||
}
|
||||
|
||||
// This is line 88. The test depends on that.
|
||||
// This is line 98. The test depends on that.
|
||||
func TestAddr2Line(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
|
|
|
|||
1
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
1
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
|
|
@ -420,6 +420,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
|
|||
UXTBW R2, R6 // 461c0053
|
||||
UXTHW R7, R20 // f43c0053
|
||||
VCNT V0.B8, V0.B8 // 0058200e
|
||||
VCNT V0.B16, V0.B16 // 0058204e
|
||||
WFE // 5f2003d5
|
||||
WFI // 7f2003d5
|
||||
YIELD // 3f2003d5
|
||||
|
|
|
|||
|
|
@ -990,7 +990,7 @@ produces a file named a.out, even if cmd/link does so by invoking the host
|
|||
linker in external linking mode.
|
||||
|
||||
By default, cmd/link will decide the linking mode as follows: if the only
|
||||
packages using cgo are those on a whitelist of standard library
|
||||
packages using cgo are those on a list of known standard library
|
||||
packages (net, os/user, runtime/cgo), cmd/link will use internal linking
|
||||
mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
|
||||
will use external linking mode. The first rule means that a build of
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ func TestFormats(t *testing.T) {
|
|||
}
|
||||
|
||||
importPath := filepath.Join("cmd/compile", path)
|
||||
if blacklistedPackages[filepath.ToSlash(importPath)] {
|
||||
if ignoredPackages[filepath.ToSlash(importPath)] {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +344,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
|
|||
for index, file := range files {
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
if call, ok := n.(*ast.CallExpr); ok {
|
||||
// ignore blacklisted functions
|
||||
if blacklistedFunctions[nodeString(call.Fun)] {
|
||||
if ignoredFunctions[nodeString(call.Fun)] {
|
||||
return true
|
||||
}
|
||||
// look for an arguments that might be a format string
|
||||
|
|
@ -354,7 +353,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
|
|||
// make sure we have enough arguments
|
||||
n := numFormatArgs(s)
|
||||
if i+1+n > len(call.Args) {
|
||||
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
|
||||
t.Errorf("%s: not enough format args (ignore %s?)", posString(call), nodeString(call.Fun))
|
||||
break // ignore this call
|
||||
}
|
||||
// assume last n arguments are to be formatted;
|
||||
|
|
@ -549,14 +548,14 @@ func formatReplace(in string, f func(i int, s string) string) string {
|
|||
return string(append(buf, in[i0:]...))
|
||||
}
|
||||
|
||||
// blacklistedPackages is the set of packages which can
|
||||
// ignoredPackages is the set of packages which can
|
||||
// be ignored.
|
||||
var blacklistedPackages = map[string]bool{}
|
||||
var ignoredPackages = map[string]bool{}
|
||||
|
||||
// blacklistedFunctions is the set of functions which may have
|
||||
// ignoredFunctions is the set of functions which may have
|
||||
// format-like arguments but which don't do any formatting and
|
||||
// thus may be ignored.
|
||||
var blacklistedFunctions = map[string]bool{}
|
||||
var ignoredFunctions = map[string]bool{}
|
||||
|
||||
func init() {
|
||||
// verify that knownFormats entries are correctly formatted
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ var knownFormats = map[string]string{
|
|||
"float64 %.3f": "",
|
||||
"float64 %.6g": "",
|
||||
"float64 %g": "",
|
||||
"int %#x": "",
|
||||
"int %-12d": "",
|
||||
"int %-6d": "",
|
||||
"int %-8o": "",
|
||||
|
|
@ -203,6 +204,7 @@ var knownFormats = map[string]string{
|
|||
"uint64 %b": "",
|
||||
"uint64 %d": "",
|
||||
"uint64 %x": "",
|
||||
"uint8 %#x": "",
|
||||
"uint8 %d": "",
|
||||
"uint8 %v": "",
|
||||
"uint8 %x": "",
|
||||
|
|
|
|||
|
|
@ -898,6 +898,20 @@ var blockJump = map[ssa.BlockKind]struct {
|
|||
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
||||
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
||||
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
|
||||
ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL},
|
||||
ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI},
|
||||
}
|
||||
|
||||
// To model a 'LEnoov' ('<=' without overflow checking) branching
|
||||
var leJumps = [2][2]gc.IndexJump{
|
||||
{{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0]
|
||||
{{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1]
|
||||
}
|
||||
|
||||
// To model a 'GTnoov' ('>' without overflow checking) branching
|
||||
var gtJumps = [2][2]gc.IndexJump{
|
||||
{{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0]
|
||||
{{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1]
|
||||
}
|
||||
|
||||
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||
|
|
@ -941,7 +955,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
|||
ssa.BlockARMLT, ssa.BlockARMGE,
|
||||
ssa.BlockARMLE, ssa.BlockARMGT,
|
||||
ssa.BlockARMULT, ssa.BlockARMUGT,
|
||||
ssa.BlockARMULE, ssa.BlockARMUGE:
|
||||
ssa.BlockARMULE, ssa.BlockARMUGE,
|
||||
ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
|
||||
jmp := blockJump[b.Kind]
|
||||
switch next {
|
||||
case b.Succs[0].Block():
|
||||
|
|
@ -958,6 +973,12 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
|||
}
|
||||
}
|
||||
|
||||
case ssa.BlockARMLEnoov:
|
||||
s.CombJump(b, next, &leJumps)
|
||||
|
||||
case ssa.BlockARMGTnoov:
|
||||
s.CombJump(b, next, >Jumps)
|
||||
|
||||
default:
|
||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,13 +141,13 @@ func isSelfAssign(dst, src *Node) bool {
|
|||
return samesafeexpr(dst.Left, src.Left)
|
||||
}
|
||||
|
||||
// mayAffectMemory reports whether n evaluation may affect program memory state.
|
||||
// If expression can't affect it, then it can be safely ignored by the escape analysis.
|
||||
// mayAffectMemory reports whether evaluation of n may affect the program's
|
||||
// memory state. If the expression can't affect memory state, then it can be
|
||||
// safely ignored by the escape analysis.
|
||||
func mayAffectMemory(n *Node) bool {
|
||||
// We may want to use "memory safe" black list instead of general
|
||||
// "side-effect free", which can include all calls and other ops
|
||||
// that can affect allocate or change global state.
|
||||
// It's safer to start from a whitelist for now.
|
||||
// We may want to use a list of "memory safe" ops instead of generally
|
||||
// "side-effect free", which would include all calls and other ops that can
|
||||
// allocate or change global state. For now, it's safer to start with the latter.
|
||||
//
|
||||
// We're ignoring things like division by zero, index out of range,
|
||||
// and nil pointer dereference here.
|
||||
|
|
|
|||
|
|
@ -451,6 +451,7 @@ var passes = [...]pass{
|
|||
{name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
|
||||
{name: "lowered cse", fn: cse},
|
||||
{name: "elim unread autos", fn: elimUnreadAutos},
|
||||
{name: "tighten tuple selectors", fn: tightenTupleSelectors, required: true},
|
||||
{name: "lowered deadcode", fn: deadcode, required: true},
|
||||
{name: "checkLower", fn: checkLower, required: true},
|
||||
{name: "late phielim", fn: phielim},
|
||||
|
|
@ -509,6 +510,8 @@ var passOrder = [...]constraint{
|
|||
{"decompose builtin", "late opt"},
|
||||
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
|
||||
{"decompose builtin", "softfloat"},
|
||||
// tuple selectors must be tightened to generators and de-duplicated before scheduling
|
||||
{"tighten tuple selectors", "schedule"},
|
||||
// remove critical edges before phi tighten, so that phi args get better placement
|
||||
{"critical", "phi tighten"},
|
||||
// don't layout blocks until critical edges have been removed
|
||||
|
|
|
|||
|
|
@ -223,60 +223,6 @@ func cse(f *Func) {
|
|||
}
|
||||
}
|
||||
|
||||
// Fixup tuple selectors.
|
||||
//
|
||||
// If we have rewritten a tuple generator to a new one in a different
|
||||
// block, copy its selectors to the new generator's block, so tuple
|
||||
// generator and selectors stay together.
|
||||
//
|
||||
// Note: that there must be only one selector of each type per tuple
|
||||
// generator. CSE may have left us with more than one so we de-duplicate
|
||||
// them using a map. See issue 16741.
|
||||
selectors := make(map[struct {
|
||||
id ID
|
||||
op Op
|
||||
}]*Value)
|
||||
for _, b := range f.Blocks {
|
||||
for _, selector := range b.Values {
|
||||
if selector.Op != OpSelect0 && selector.Op != OpSelect1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the tuple generator to use as a key for de-duplication.
|
||||
tuple := selector.Args[0]
|
||||
if !tuple.Type.IsTuple() {
|
||||
f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString())
|
||||
}
|
||||
|
||||
// If there is a pre-existing selector in the target block then
|
||||
// use that. Do this even if the selector is already in the
|
||||
// target block to avoid duplicate tuple selectors.
|
||||
key := struct {
|
||||
id ID
|
||||
op Op
|
||||
}{tuple.ID, selector.Op}
|
||||
if t := selectors[key]; t != nil {
|
||||
if selector != t {
|
||||
selector.copyOf(t)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If the selector is in the wrong block copy it into the target
|
||||
// block.
|
||||
if selector.Block != tuple.Block {
|
||||
t := selector.copyInto(tuple.Block)
|
||||
selector.copyOf(t)
|
||||
selectors[key] = t
|
||||
continue
|
||||
}
|
||||
|
||||
// The selector is in the target block. Add it to the map so it
|
||||
// cannot be duplicated.
|
||||
selectors[key] = selector
|
||||
}
|
||||
}
|
||||
|
||||
if f.pass.stats > 0 {
|
||||
f.LogStat("CSE REWRITES", rewrites)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -704,6 +704,10 @@
|
|||
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
|
||||
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
|
||||
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
|
||||
(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
|
||||
(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
|
||||
(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
|
||||
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
|
||||
|
||||
// absorb flag constants into boolean values
|
||||
(Equal (FlagEQ)) -> (MOVWconst [1])
|
||||
|
|
@ -1417,42 +1421,42 @@
|
|||
(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no)
|
||||
(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no)
|
||||
(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no)
|
||||
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no)
|
||||
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no)
|
||||
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no)
|
||||
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LTnoov (CMP x y) yes no)
|
||||
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMPconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LEnoov (CMP x y) yes no)
|
||||
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMPconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LTnoov (CMN x y) yes no)
|
||||
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMNconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LEnoov (CMN x y) yes no)
|
||||
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMNconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no)
|
||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no)
|
||||
|
|
@ -1485,43 +1489,43 @@
|
|||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no)
|
||||
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no)
|
||||
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no)
|
||||
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GTnoov (CMP x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMPconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GEnoov (CMP x y) yes no)
|
||||
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMPconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GTnoov (CMN x y) yes no)
|
||||
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMNconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GEnoov (CMN x y) yes no)
|
||||
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMNconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no)
|
||||
|
|
|
|||
|
|
@ -584,6 +584,10 @@ func init() {
|
|||
{name: "ULE", controls: 1},
|
||||
{name: "UGT", controls: 1},
|
||||
{name: "UGE", controls: 1},
|
||||
{name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
|
||||
{name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
|
||||
{name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
|
||||
{name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
|
||||
}
|
||||
|
||||
archs = append(archs, arch{
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ const (
|
|||
BlockARMULE
|
||||
BlockARMUGT
|
||||
BlockARMUGE
|
||||
BlockARMLTnoov
|
||||
BlockARMLEnoov
|
||||
BlockARMGTnoov
|
||||
BlockARMGEnoov
|
||||
|
||||
BlockARM64EQ
|
||||
BlockARM64NE
|
||||
|
|
@ -195,6 +199,10 @@ var blockString = [...]string{
|
|||
BlockARMULE: "ULE",
|
||||
BlockARMUGT: "UGT",
|
||||
BlockARMUGE: "UGE",
|
||||
BlockARMLTnoov: "LTnoov",
|
||||
BlockARMLEnoov: "LEnoov",
|
||||
BlockARMGTnoov: "GTnoov",
|
||||
BlockARMGEnoov: "GEnoov",
|
||||
|
||||
BlockARM64EQ: "EQ",
|
||||
BlockARM64NE: "NE",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,6 @@ package ssa
|
|||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -18,6 +17,7 @@ var (
|
|||
y64 int64 = math.MinInt64 + 1
|
||||
x32 int32 = math.MaxInt32 - 2
|
||||
x32b int32 = math.MaxInt32 - 2
|
||||
x32c int32 = math.MaxInt32 - 2
|
||||
y32 int32 = math.MinInt32 + 1
|
||||
one64 int64 = 1
|
||||
one32 int32 = 1
|
||||
|
|
@ -25,6 +25,8 @@ var (
|
|||
v64_n int64 = -11
|
||||
v32 int32 = 11
|
||||
v32_n int32 = -11
|
||||
uv32 uint32 = 19
|
||||
uz uint8 = 1 // for lowering to SLL/SRL/SRA
|
||||
)
|
||||
|
||||
var crTests = []struct {
|
||||
|
|
@ -39,6 +41,8 @@ var crTests = []struct {
|
|||
{"MAddVar32", testMAddVar32},
|
||||
{"MSubVar64", testMSubVar64},
|
||||
{"MSubVar32", testMSubVar32},
|
||||
{"AddShift32", testAddShift32},
|
||||
{"SubShift32", testSubShift32},
|
||||
}
|
||||
|
||||
var crBenches = []struct {
|
||||
|
|
@ -58,9 +62,6 @@ var crBenches = []struct {
|
|||
// and machine code sequences are covered.
|
||||
// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
|
||||
func TestCondRewrite(t *testing.T) {
|
||||
if runtime.GOARCH == "arm" {
|
||||
t.Skip("fix on arm expected!")
|
||||
}
|
||||
for _, test := range crTests {
|
||||
t.Run(test.name, test.tf)
|
||||
}
|
||||
|
|
@ -408,6 +409,66 @@ func testMSubVar32(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// 32-bit ADDshift, pick up 1~2 scenarios randomly for each condition
|
||||
func testAddShift32(t *testing.T) {
|
||||
if x32+v32<<1 < 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x + %#x<<%#x < 0' failed", x32, v32, 1)
|
||||
}
|
||||
|
||||
if x32+v32>>1 <= 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x + %#x>>%#x <= 0' failed", x32, v32, 1)
|
||||
}
|
||||
|
||||
if x32+int32(uv32>>1) > 0 {
|
||||
t.Errorf("'%#x + int32(%#x>>%#x) > 0' failed", x32, uv32, 1)
|
||||
}
|
||||
|
||||
if x32+v32<<uz >= 0 {
|
||||
t.Errorf("'%#x + %#x<<%#x >= 0' failed", x32, v32, uz)
|
||||
}
|
||||
|
||||
if x32+v32>>uz > 0 {
|
||||
t.Errorf("'%#x + %#x>>%#x > 0' failed", x32, v32, uz)
|
||||
}
|
||||
|
||||
if x32+int32(uv32>>uz) < 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x + int32(%#x>>%#x) < 0' failed", x32, uv32, uz)
|
||||
}
|
||||
}
|
||||
|
||||
// 32-bit SUBshift, pick up 1~2 scenarios randomly for each condition
|
||||
func testSubShift32(t *testing.T) {
|
||||
if y32-v32<<1 > 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x - %#x<<%#x > 0' failed", y32, v32, 1)
|
||||
}
|
||||
|
||||
if y32-v32>>1 < 0 {
|
||||
t.Errorf("'%#x - %#x>>%#x < 0' failed", y32, v32, 1)
|
||||
}
|
||||
|
||||
if y32-int32(uv32>>1) >= 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x - int32(%#x>>%#x) >= 0' failed", y32, uv32, 1)
|
||||
}
|
||||
|
||||
if y32-v32<<uz < 0 {
|
||||
t.Errorf("'%#x - %#x<<%#x < 0' failed", y32, v32, uz)
|
||||
}
|
||||
|
||||
if y32-v32>>uz >= 0 {
|
||||
} else {
|
||||
t.Errorf("'%#x - %#x>>%#x >= 0' failed", y32, v32, uz)
|
||||
}
|
||||
|
||||
if y32-int32(uv32>>uz) <= 0 {
|
||||
t.Errorf("'%#x - int32(%#x>>%#x) <= 0' failed", y32, uv32, uz)
|
||||
}
|
||||
}
|
||||
|
||||
var rnd = rand.New(rand.NewSource(0))
|
||||
var sink int64
|
||||
|
||||
|
|
|
|||
59
src/cmd/compile/internal/ssa/tuple.go
Normal file
59
src/cmd/compile/internal/ssa/tuple.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2020 The Go 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 ssa
|
||||
|
||||
// tightenTupleSelectors ensures that tuple selectors (Select0 and
|
||||
// Select1 ops) are in the same block as their tuple generator. The
|
||||
// function also ensures that there are no duplicate tuple selectors.
|
||||
// These properties are expected by the scheduler but may not have
|
||||
// been maintained by the optimization pipeline up to this point.
|
||||
//
|
||||
// See issues 16741 and 39472.
|
||||
func tightenTupleSelectors(f *Func) {
|
||||
selectors := make(map[struct {
|
||||
id ID
|
||||
op Op
|
||||
}]*Value)
|
||||
for _, b := range f.Blocks {
|
||||
for _, selector := range b.Values {
|
||||
if selector.Op != OpSelect0 && selector.Op != OpSelect1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the tuple generator to use as a key for de-duplication.
|
||||
tuple := selector.Args[0]
|
||||
if !tuple.Type.IsTuple() {
|
||||
f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString())
|
||||
}
|
||||
|
||||
// If there is a pre-existing selector in the target block then
|
||||
// use that. Do this even if the selector is already in the
|
||||
// target block to avoid duplicate tuple selectors.
|
||||
key := struct {
|
||||
id ID
|
||||
op Op
|
||||
}{tuple.ID, selector.Op}
|
||||
if t := selectors[key]; t != nil {
|
||||
if selector != t {
|
||||
selector.copyOf(t)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If the selector is in the wrong block copy it into the target
|
||||
// block.
|
||||
if selector.Block != tuple.Block {
|
||||
t := selector.copyInto(tuple.Block)
|
||||
selector.copyOf(t)
|
||||
selectors[key] = t
|
||||
continue
|
||||
}
|
||||
|
||||
// The selector is in the target block. Add it to the map so it
|
||||
// cannot be duplicated.
|
||||
selectors[key] = selector
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/cmd/dist/test.go
vendored
9
src/cmd/dist/test.go
vendored
|
|
@ -178,15 +178,6 @@ func (t *tester) run() {
|
|||
return
|
||||
}
|
||||
|
||||
// We must unset GOROOT_FINAL before tests, because runtime/debug requires
|
||||
// correct access to source code, so if we have GOROOT_FINAL in effect,
|
||||
// at least runtime/debug test will fail.
|
||||
// If GOROOT_FINAL was set before, then now all the commands will appear stale.
|
||||
// Nothing we can do about that other than not checking them below.
|
||||
// (We call checkNotStale but only with "std" not "cmd".)
|
||||
os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test
|
||||
os.Unsetenv("GOROOT_FINAL")
|
||||
|
||||
for _, name := range t.runNames {
|
||||
if !t.isRegisteredTestName(name) {
|
||||
fatalf("unknown test %q", name)
|
||||
|
|
|
|||
|
|
@ -124,7 +124,6 @@ func TestMain(m *testing.M) {
|
|||
fmt.Printf("SKIP\n")
|
||||
return
|
||||
}
|
||||
os.Unsetenv("GOROOT_FINAL")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
|
|
@ -180,6 +179,11 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
testGOROOT = goEnv("GOROOT")
|
||||
os.Setenv("TESTGO_GOROOT", testGOROOT)
|
||||
// Ensure that GOROOT is set explicitly.
|
||||
// Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
|
||||
// yet been moved to its final location, programs that invoke runtime.GOROOT
|
||||
// may accidentally use the wrong path.
|
||||
os.Setenv("GOROOT", testGOROOT)
|
||||
|
||||
// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
|
||||
// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
|
||||
|
|
@ -216,8 +220,10 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
testCC = strings.TrimSpace(string(out))
|
||||
|
||||
if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
|
||||
cmd := exec.Command(testGo, "env", "CGO_ENABLED")
|
||||
cmd.Stderr = new(strings.Builder)
|
||||
if out, err := cmd.Output(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
|
||||
canRun = false
|
||||
} else {
|
||||
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ package web
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
|
@ -47,6 +48,13 @@ var securityPreservingHTTPClient = &http.Client{
|
|||
lastHop := via[len(via)-1].URL
|
||||
return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL)
|
||||
}
|
||||
|
||||
// Go's http.DefaultClient allows 10 redirects before returning an error.
|
||||
// The securityPreservingHTTPClient also uses this default policy to avoid
|
||||
// Go command hangs.
|
||||
if len(via) >= 10 {
|
||||
return errors.New("stopped after 10 redirects")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ func gcBackendConcurrency(gcflags []string) int {
|
|||
CheckFlags:
|
||||
for _, flag := range gcflags {
|
||||
// Concurrent compilation is presumed incompatible with any gcflags,
|
||||
// except for a small whitelist of commonly used flags.
|
||||
// except for known commonly used flags.
|
||||
// If the user knows better, they can manually add their own -c to the gcflags.
|
||||
switch flag {
|
||||
case "-N", "-l", "-S", "-B", "-C", "-I":
|
||||
|
|
|
|||
|
|
@ -174,6 +174,25 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Request for $GOPROXY/redirect/<count>/... goes to redirects.
|
||||
if strings.HasPrefix(path, "redirect/") {
|
||||
path = path[len("redirect/"):]
|
||||
if j := strings.Index(path, "/"); j >= 0 {
|
||||
count, err := strconv.Atoi(path[:j])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// The last redirect.
|
||||
if count <= 1 {
|
||||
http.Redirect(w, r, fmt.Sprintf("/mod/%s", path[j+1:]), 302)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, fmt.Sprintf("/mod/redirect/%d/%s", count-1, path[j+1:]), 302)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Request for $GOPROXY/sumdb/<name>/supported
|
||||
// is checking whether it's OK to access sumdb via the proxy.
|
||||
if path == "sumdb/"+testSumDBName+"/supported" {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ func (ts *testScript) setup() {
|
|||
"GOPROXY=" + proxyURL,
|
||||
"GOPRIVATE=",
|
||||
"GOROOT=" + testGOROOT,
|
||||
"GOROOT_FINAL=" + os.Getenv("GOROOT_FINAL"), // causes spurious rebuilds and breaks the "stale" built-in if not propagated
|
||||
"TESTGO_GOROOT=" + testGOROOT,
|
||||
"GOSUMDB=" + testSumDBVerifierKey,
|
||||
"GONOPROXY=",
|
||||
|
|
|
|||
1
src/cmd/go/testdata/script/README
vendored
1
src/cmd/go/testdata/script/README
vendored
|
|
@ -34,6 +34,7 @@ Scripts also have access to these other environment variables:
|
|||
GOPATH=$WORK/gopath
|
||||
GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
|
||||
GOROOT=<actual GOROOT>
|
||||
GOROOT_FINAL=<actual GOROOT_FINAL>
|
||||
TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT>
|
||||
HOME=/no-home
|
||||
PATH=<actual PATH>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
[short] skip
|
||||
|
||||
# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting
|
||||
# binary instead of GOROOT. Explicitly unset it here.
|
||||
env GOROOT_FINAL=
|
||||
|
||||
# Set up two identical directories that can be used as GOPATH.
|
||||
env GO111MODULE=on
|
||||
mkdir $WORK/a/src/paths $WORK/b/src/paths
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
mkdir $WORK/new/bin
|
||||
|
||||
# In this test, we are specifically checking the logic for deriving
|
||||
# the value of GOROOT from runtime.GOROOT.
|
||||
# GOROOT_FINAL changes the default behavior of runtime.GOROOT,
|
||||
# and will thus cause the test to fail if it is set when our
|
||||
# new cmd/go is built.
|
||||
env GOROOT_FINAL=
|
||||
|
||||
go build -o $WORK/new/bin/go$GOEXE cmd/go &
|
||||
go build -o $WORK/bin/check$GOEXE check.go &
|
||||
wait
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ cd $WORK/gopkgdir/x
|
|||
! go list .
|
||||
stderr 'cannot find main module'
|
||||
! stderr 'Gopkg.lock'
|
||||
! stderr 'go mod init'
|
||||
|
||||
-- $WORK/test/Gopkg.lock --
|
||||
-- $WORK/test/x/x.go --
|
||||
|
|
|
|||
10
src/cmd/go/testdata/script/mod_get_too_many_redirects.txt
vendored
Normal file
10
src/cmd/go/testdata/script/mod_get_too_many_redirects.txt
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
env GO111MODULE=on
|
||||
env GOPROXYBASE=$GOPROXY
|
||||
env GOPROXY=$GOPROXYBASE/redirect/11
|
||||
env GOSUMDB=off
|
||||
|
||||
! go get -d rsc.io/quote@v1.2.0
|
||||
stderr 'stopped after 10 redirects'
|
||||
|
||||
env GOPROXY=$GOPROXYBASE/redirect/9
|
||||
go get -d rsc.io/quote@v1.2.0
|
||||
|
|
@ -36,7 +36,7 @@ func findGorootModules(t *testing.T) []gorootModule {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Name() == "vendor" || info.Name() == "testdata" {
|
||||
if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if path == filepath.Join(runtime.GOROOT(), "pkg") {
|
||||
|
|
|
|||
|
|
@ -460,7 +460,6 @@ var optab = []Optab{
|
|||
{AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
|
||||
{ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
|
||||
{AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
|
||||
{AVCNT, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0},
|
||||
{AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0},
|
||||
{AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0},
|
||||
{AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0},
|
||||
|
|
@ -2773,6 +2772,7 @@ func buildop(ctxt *obj.Link) {
|
|||
oprangeset(AVSRI, t)
|
||||
|
||||
case AVREV32:
|
||||
oprangeset(AVCNT, t)
|
||||
oprangeset(AVRBIT, t)
|
||||
oprangeset(AVREV64, t)
|
||||
oprangeset(AVREV16, t)
|
||||
|
|
@ -4523,7 +4523,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||
c.ctxt.Diag("invalid arrangement: %v\n", p)
|
||||
}
|
||||
|
||||
if (p.As == AVMOV || p.As == AVRBIT) && (af != ARNG_16B && af != ARNG_8B) {
|
||||
if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) {
|
||||
c.ctxt.Diag("invalid arrangement: %v", p)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ func init() {
|
|||
}
|
||||
|
||||
func Framepointer_enabled(goos, goarch string) bool {
|
||||
return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && goos == "linux")
|
||||
return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && (goos == "linux" || goos == "darwin"))
|
||||
}
|
||||
|
||||
func addexp(s string) {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
|
|||
t.Fatalf("go list: %v\n%s", err, out)
|
||||
}
|
||||
if string(out) != "false\n" {
|
||||
if os.Getenv("GOROOT_FINAL_OLD") != "" {
|
||||
t.Skip("cmd/link is stale, but $GOROOT_FINAL_OLD is set")
|
||||
if strings.HasPrefix(testenv.Builder(), "darwin-") {
|
||||
t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598")
|
||||
}
|
||||
t.Fatalf("cmd/link is stale - run go install cmd/link")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,15 +616,15 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) {
|
|||
}
|
||||
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
|
||||
|
||||
// For the moment, whitelist DWARF subprogram DIEs for
|
||||
// For the moment, allow DWARF subprogram DIEs for
|
||||
// auto-generated wrapper functions. What seems to happen
|
||||
// here is that we get different line numbers on formal
|
||||
// params; I am guessing that the pos is being inherited
|
||||
// from the spot where the wrapper is needed.
|
||||
whitelist := strings.HasPrefix(name, "go.info.go.interface") ||
|
||||
allowed := strings.HasPrefix(name, "go.info.go.interface") ||
|
||||
strings.HasPrefix(name, "go.info.go.builtin") ||
|
||||
strings.HasPrefix(name, "go.debuglines")
|
||||
if !whitelist {
|
||||
if !allowed {
|
||||
l.strictDupMsgs++
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,11 @@ func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string)
|
|||
args = append(args, flags...)
|
||||
args = append(args, "fmthello.go")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), args...)
|
||||
cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
|
||||
// "Bad line" bug #36683 is sensitive to being run in the source directory.
|
||||
cmd.Dir = "testdata"
|
||||
// Ensure that the source file location embedded in the binary matches our
|
||||
// actual current GOROOT, instead of GOROOT_FINAL if set.
|
||||
cmd.Env = append(os.Environ(), "GOROOT_FINAL=")
|
||||
t.Logf("Running %v", cmd.Args)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -278,6 +278,8 @@ type ClientSessionState struct {
|
|||
serverCertificates []*x509.Certificate // Certificate chain presented by the server
|
||||
verifiedChains [][]*x509.Certificate // Certificate chains we built for verification
|
||||
receivedAt time.Time // When the session ticket was received from the server
|
||||
ocspResponse []byte // Stapled OCSP response presented by the server
|
||||
scts [][]byte // SCTs presented by the server
|
||||
|
||||
// TLS 1.3 fields.
|
||||
nonce []byte // Ticket nonce sent by the server, to derive PSK
|
||||
|
|
|
|||
|
|
@ -728,10 +728,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
|||
return false, errors.New("tls: server resumed a session with a different cipher suite")
|
||||
}
|
||||
|
||||
// Restore masterSecret and peerCerts from previous state
|
||||
// Restore masterSecret, peerCerts, and ocspResponse from previous state
|
||||
hs.masterSecret = hs.session.masterSecret
|
||||
c.peerCertificates = hs.session.serverCertificates
|
||||
c.verifiedChains = hs.session.verifiedChains
|
||||
c.ocspResponse = hs.session.ocspResponse
|
||||
// Let the ServerHello SCTs override the session SCTs from the original
|
||||
// connection, if any are provided
|
||||
if len(c.scts) == 0 && len(hs.session.scts) != 0 {
|
||||
c.scts = hs.session.scts
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
|
@ -788,6 +795,8 @@ func (hs *clientHandshakeState) readSessionTicket() error {
|
|||
serverCertificates: c.peerCertificates,
|
||||
verifiedChains: c.verifiedChains,
|
||||
receivedAt: c.config.time(),
|
||||
ocspResponse: c.ocspResponse,
|
||||
scts: c.scts,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -2430,3 +2431,83 @@ func TestDowngradeCanary(t *testing.T) {
|
|||
t.Errorf("client unexpectedly reacted to a canary in TLS 1.0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResumptionKeepsOCSPAndSCT(t *testing.T) {
|
||||
t.Run("TLSv12", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS12) })
|
||||
t.Run("TLSv13", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS13) })
|
||||
}
|
||||
|
||||
func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
||||
issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse test issuer")
|
||||
}
|
||||
roots := x509.NewCertPool()
|
||||
roots.AddCert(issuer)
|
||||
clientConfig := &Config{
|
||||
MaxVersion: ver,
|
||||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
ServerName: "example.golang",
|
||||
RootCAs: roots,
|
||||
}
|
||||
serverConfig := testConfig.Clone()
|
||||
serverConfig.MaxVersion = ver
|
||||
serverConfig.Certificates[0].OCSPStaple = []byte{1, 2, 3}
|
||||
serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{4, 5, 6}}
|
||||
|
||||
_, ccs, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
// after a new session we expect to see OCSPResponse and
|
||||
// SignedCertificateTimestamps populated as usual
|
||||
if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
|
||||
t.Errorf("client ConnectionState contained unexpected OCSPResponse: wanted %v, got %v",
|
||||
serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
|
||||
}
|
||||
if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
|
||||
t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps: wanted %v, got %v",
|
||||
serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
|
||||
}
|
||||
|
||||
// if the server doesn't send any SCTs, repopulate the old SCTs
|
||||
oldSCTs := serverConfig.Certificates[0].SignedCertificateTimestamps
|
||||
serverConfig.Certificates[0].SignedCertificateTimestamps = nil
|
||||
_, ccs, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
if !ccs.DidResume {
|
||||
t.Fatalf("expected session to be resumed")
|
||||
}
|
||||
// after a resumed session we also expect to see OCSPResponse
|
||||
// and SignedCertificateTimestamps populated
|
||||
if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
|
||||
t.Errorf("client ConnectionState contained unexpected OCSPResponse after resumption: wanted %v, got %v",
|
||||
serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
|
||||
}
|
||||
if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, oldSCTs) {
|
||||
t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
|
||||
oldSCTs, ccs.SignedCertificateTimestamps)
|
||||
}
|
||||
|
||||
// Only test overriding the SCTs for TLS 1.2, since in 1.3
|
||||
// the server won't send the message containing them
|
||||
if ver == VersionTLS13 {
|
||||
return
|
||||
}
|
||||
|
||||
// if the server changes the SCTs it sends, they should override the saved SCTs
|
||||
serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{7, 8, 9}}
|
||||
_, ccs, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
if !ccs.DidResume {
|
||||
t.Fatalf("expected session to be resumed")
|
||||
}
|
||||
if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
|
||||
t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
|
||||
serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,6 +334,8 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error {
|
|||
c.didResume = true
|
||||
c.peerCertificates = hs.session.serverCertificates
|
||||
c.verifiedChains = hs.session.verifiedChains
|
||||
c.ocspResponse = hs.session.ocspResponse
|
||||
c.scts = hs.session.scts
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -666,6 +668,8 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
|
|||
nonce: msg.nonce,
|
||||
useBy: c.config.time().Add(lifetime),
|
||||
ageAdd: msg.ageAdd,
|
||||
ocspResponse: c.ocspResponse,
|
||||
scts: c.scts,
|
||||
}
|
||||
|
||||
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
|
|
|
|||
|
|
@ -2129,16 +2129,13 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
|||
authorityKeyId = parent.SubjectKeyId
|
||||
}
|
||||
|
||||
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
|
||||
pki := publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}
|
||||
subjectKeyId := template.SubjectKeyId
|
||||
if len(subjectKeyId) == 0 && template.IsCA {
|
||||
// SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2
|
||||
b, err := asn1.Marshal(pki)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := sha1.Sum(b)
|
||||
// SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2:
|
||||
// (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
|
||||
// value of the BIT STRING subjectPublicKey (excluding the tag,
|
||||
// length, and number of unused bits).
|
||||
h := sha1.Sum(publicKeyBytes)
|
||||
subjectKeyId = h[:]
|
||||
}
|
||||
|
||||
|
|
@ -2147,6 +2144,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
|||
return
|
||||
}
|
||||
|
||||
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
|
||||
c := tbsCertificate{
|
||||
Version: 2,
|
||||
SerialNumber: template.SerialNumber,
|
||||
|
|
@ -2154,7 +2152,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
|||
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
|
||||
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
|
||||
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
||||
PublicKey: pki,
|
||||
PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
|
||||
Extensions: extensions,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
_ "unsafe" // for go:linkname
|
||||
)
|
||||
|
||||
// An Importer provides the context for importing packages from source code.
|
||||
|
|
@ -133,7 +134,7 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
|
|||
// build.Context's VFS.
|
||||
conf.FakeImportC = true
|
||||
} else {
|
||||
conf.UsesCgo = true
|
||||
setUsesCgo(&conf)
|
||||
file, err := p.cgo(bp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -260,3 +261,6 @@ func (p *Importer) joinPath(elem ...string) string {
|
|||
}
|
||||
return filepath.Join(elem...)
|
||||
}
|
||||
|
||||
//go:linkname setUsesCgo go/types.srcimporter_setUsesCgo
|
||||
func setUsesCgo(conf *types.Config)
|
||||
|
|
|
|||
|
|
@ -105,14 +105,14 @@ type Config struct {
|
|||
// Do not use casually!
|
||||
FakeImportC bool
|
||||
|
||||
// If UsesCgo is set, the type checker expects the
|
||||
// If go115UsesCgo is set, the type checker expects the
|
||||
// _cgo_gotypes.go file generated by running cmd/cgo to be
|
||||
// provided as a package source file. Qualified identifiers
|
||||
// referring to package C will be resolved to cgo-provided
|
||||
// declarations within _cgo_gotypes.go.
|
||||
//
|
||||
// It is an error to set both FakeImportC and UsesCgo.
|
||||
UsesCgo bool
|
||||
// It is an error to set both FakeImportC and go115UsesCgo.
|
||||
go115UsesCgo bool
|
||||
|
||||
// If Error != nil, it is called with each error found
|
||||
// during type checking; err has dynamic type Error.
|
||||
|
|
@ -140,6 +140,10 @@ type Config struct {
|
|||
DisableUnusedImportCheck bool
|
||||
}
|
||||
|
||||
func srcimporter_setUsesCgo(conf *Config) {
|
||||
conf.go115UsesCgo = true
|
||||
}
|
||||
|
||||
// Info holds result type information for a type-checked package.
|
||||
// Only the information for which a map is provided is collected.
|
||||
// If the package has type errors, the collected information may
|
||||
|
|
|
|||
|
|
@ -248,10 +248,10 @@ func (check *Checker) handleBailout(err *error) {
|
|||
// Files checks the provided files as part of the checker's package.
|
||||
func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
|
||||
|
||||
var errBadCgo = errors.New("cannot use FakeImportC and UsesCgo together")
|
||||
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
|
||||
|
||||
func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
||||
if check.conf.FakeImportC && check.conf.UsesCgo {
|
||||
if check.conf.FakeImportC && check.conf.go115UsesCgo {
|
||||
return errBadCgo
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,10 +141,10 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package {
|
|||
}
|
||||
|
||||
// no package yet => import it
|
||||
if path == "C" && (check.conf.FakeImportC || check.conf.UsesCgo) {
|
||||
if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {
|
||||
imp = NewPackage("C", "C")
|
||||
imp.fake = true // package scope is not populated
|
||||
imp.cgo = check.conf.UsesCgo
|
||||
imp.cgo = check.conf.go115UsesCgo
|
||||
} else {
|
||||
// ordinary import
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -240,8 +240,7 @@ func htmlNameFilter(args ...interface{}) string {
|
|||
}
|
||||
s = strings.ToLower(s)
|
||||
if t := attrType(s); t != contentTypePlain {
|
||||
// TODO: Split attr and element name part filters so we can whitelist
|
||||
// attributes.
|
||||
// TODO: Split attr and element name part filters so we can recognize known attributes.
|
||||
return filterFailsafe
|
||||
}
|
||||
for _, r := range s {
|
||||
|
|
|
|||
|
|
@ -479,7 +479,7 @@ func DupCloseOnExec(fd int) (int, string, error) {
|
|||
return dupCloseOnExecOld(fd)
|
||||
}
|
||||
|
||||
// dupCloseOnExecUnixOld is the traditional way to dup an fd and
|
||||
// dupCloseOnExecOld is the traditional way to dup an fd and
|
||||
// set its O_CLOEXEC bit, using two system calls.
|
||||
func dupCloseOnExecOld(fd int) (int, string, error) {
|
||||
syscall.ForkLock.RLock()
|
||||
|
|
|
|||
|
|
@ -150,4 +150,3 @@ set GOBUILDFAIL=1
|
|||
if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
|
||||
|
||||
:end
|
||||
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ func valueOrDefault(value, def string) string {
|
|||
|
||||
// NOTE: This is not intended to reflect the actual Go version being used.
|
||||
// It was changed at the time of Go 1.1 release because the former User-Agent
|
||||
// had ended up on a blacklist for some intrusion detection systems.
|
||||
// had ended up blocked by some intrusion detection systems.
|
||||
// See https://codereview.appspot.com/7532043.
|
||||
const defaultUserAgent = "Go-http-client/1.1"
|
||||
|
||||
|
|
|
|||
|
|
@ -1698,9 +1698,9 @@ func (c *conn) closeWriteAndWait() {
|
|||
time.Sleep(rstAvoidanceDelay)
|
||||
}
|
||||
|
||||
// validNextProto reports whether the proto is not a blacklisted ALPN
|
||||
// protocol name. Empty and built-in protocol types are blacklisted
|
||||
// and can't be overridden with alternate implementations.
|
||||
// validNextProto reports whether the proto is a valid ALPN protocol name.
|
||||
// Everything is valid except the empty string and built-in protocol types,
|
||||
// so that those can't be overridden with alternate implementations.
|
||||
func validNextProto(proto string) bool {
|
||||
switch proto {
|
||||
case "", "http/1.1", "http/1.0":
|
||||
|
|
|
|||
|
|
@ -202,10 +202,8 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
|
|||
break
|
||||
}
|
||||
|
||||
// On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause
|
||||
// open(2) to be restarted for regular files. This is easy to reproduce on
|
||||
// fuse file systems (see https://golang.org/issue/11180).
|
||||
if runtime.GOOS == "darwin" && e == syscall.EINTR {
|
||||
// We have to check EINTR here, per issues 11180 and 39237.
|
||||
if e == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ package os
|
|||
import (
|
||||
"internal/syscall/unix"
|
||||
"io"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
|
@ -178,7 +177,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
|
|||
}
|
||||
|
||||
// See comment in openFileNolog.
|
||||
if runtime.GOOS == "darwin" && e == syscall.EINTR {
|
||||
if e == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ func (e *PtyError) Error() string {
|
|||
|
||||
func (e *PtyError) Unwrap() error { return e.Errno }
|
||||
|
||||
// Open returns a master pty and the name of the linked slave tty.
|
||||
func Open() (master *os.File, slave string, err error) {
|
||||
// Open returns a control pty and the name of the linked process tty.
|
||||
func Open() (pty *os.File, processTTY string, err error) {
|
||||
m, err := C.posix_openpt(C.O_RDWR)
|
||||
if err != nil {
|
||||
return nil, "", ptyError("posix_openpt", err)
|
||||
|
|
@ -54,6 +54,6 @@ func Open() (master *os.File, slave string, err error) {
|
|||
C.close(m)
|
||||
return nil, "", ptyError("unlockpt", err)
|
||||
}
|
||||
slave = C.GoString(C.ptsname(m))
|
||||
return os.NewFile(uintptr(m), "pty-master"), slave, nil
|
||||
processTTY = C.GoString(C.ptsname(m))
|
||||
return os.NewFile(uintptr(m), "pty"), processTTY, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal/internal/pty"
|
||||
ptypkg "os/signal/internal/pty"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -71,20 +71,20 @@ func TestTerminalSignal(t *testing.T) {
|
|||
// The test only fails when using a "slow device," in this
|
||||
// case a pseudo-terminal.
|
||||
|
||||
master, sname, err := pty.Open()
|
||||
pty, procTTYName, err := ptypkg.Open()
|
||||
if err != nil {
|
||||
ptyErr := err.(*pty.PtyError)
|
||||
ptyErr := err.(*ptypkg.PtyError)
|
||||
if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES {
|
||||
t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping")
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer master.Close()
|
||||
slave, err := os.OpenFile(sname, os.O_RDWR, 0)
|
||||
defer pty.Close()
|
||||
procTTY, err := os.OpenFile(procTTYName, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer slave.Close()
|
||||
defer procTTY.Close()
|
||||
|
||||
// Start an interactive shell.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
|
|
@ -92,9 +92,9 @@ func TestTerminalSignal(t *testing.T) {
|
|||
cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i")
|
||||
// Clear HISTFILE so that we don't read or clobber the user's bash history.
|
||||
cmd.Env = append(os.Environ(), "HISTFILE=")
|
||||
cmd.Stdin = slave
|
||||
cmd.Stdout = slave
|
||||
cmd.Stderr = slave
|
||||
cmd.Stdin = procTTY
|
||||
cmd.Stdout = procTTY
|
||||
cmd.Stderr = procTTY
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Setsid: true,
|
||||
Setctty: true,
|
||||
|
|
@ -105,21 +105,21 @@ func TestTerminalSignal(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := slave.Close(); err != nil {
|
||||
t.Errorf("closing slave: %v", err)
|
||||
if err := procTTY.Close(); err != nil {
|
||||
t.Errorf("closing procTTY: %v", err)
|
||||
}
|
||||
|
||||
progReady := make(chan bool)
|
||||
sawPrompt := make(chan bool, 10)
|
||||
const prompt = "prompt> "
|
||||
|
||||
// Read data from master in the background.
|
||||
// Read data from pty in the background.
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
defer wg.Wait()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
input := bufio.NewReader(master)
|
||||
input := bufio.NewReader(pty)
|
||||
var line, handled []byte
|
||||
for {
|
||||
b, err := input.ReadByte()
|
||||
|
|
@ -130,11 +130,11 @@ func TestTerminalSignal(t *testing.T) {
|
|||
if perr, ok := err.(*os.PathError); ok {
|
||||
err = perr.Err
|
||||
}
|
||||
// EOF means master is closed.
|
||||
// EOF means pty is closed.
|
||||
// EIO means child process is done.
|
||||
// "file already closed" means deferred close of master has happened.
|
||||
// "file already closed" means deferred close of pty has happened.
|
||||
if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") {
|
||||
t.Logf("error reading from master: %v", err)
|
||||
t.Logf("error reading from pty: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
}()
|
||||
|
||||
// Set the bash prompt so that we can see it.
|
||||
if _, err := master.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
|
||||
if _, err := pty.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
|
||||
t.Fatalf("setting prompt: %v", err)
|
||||
}
|
||||
select {
|
||||
|
|
@ -172,7 +172,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
|
||||
// Start a small program that reads from stdin
|
||||
// (namely the code at the top of this function).
|
||||
if _, err := master.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
|
||||
if _, err := pty.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
time.Sleep(pause)
|
||||
|
||||
// Send a ^Z to stop the program.
|
||||
if _, err := master.Write([]byte{26}); err != nil {
|
||||
if _, err := pty.Write([]byte{26}); err != nil {
|
||||
t.Fatalf("writing ^Z to pty: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
}
|
||||
|
||||
// Restart the stopped program.
|
||||
if _, err := master.Write([]byte("fg\n")); err != nil {
|
||||
if _, err := pty.Write([]byte("fg\n")); err != nil {
|
||||
t.Fatalf("writing %q to pty: %v", "fg", err)
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
|
||||
// Write some data for the program to read,
|
||||
// which should cause it to exit.
|
||||
if _, err := master.Write([]byte{'\n'}); err != nil {
|
||||
if _, err := pty.Write([]byte{'\n'}); err != nil {
|
||||
t.Fatalf("writing %q to pty: %v", "\n", err)
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ func TestTerminalSignal(t *testing.T) {
|
|||
}
|
||||
|
||||
// Exit the shell with the program's exit status.
|
||||
if _, err := master.Write([]byte("exit $?\n")); err != nil {
|
||||
if _, err := pty.Write([]byte("exit $?\n")); err != nil {
|
||||
t.Fatalf("writing %q to pty: %v", "exit", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,6 @@ if errorlevel 1 goto fail
|
|||
echo.
|
||||
:norebuild
|
||||
|
||||
:: we must unset GOROOT_FINAL before tests, because runtime/debug requires
|
||||
:: correct access to source code, so if we have GOROOT_FINAL in effect,
|
||||
:: at least runtime/debug test will fail.
|
||||
set GOROOT_FINAL=
|
||||
|
||||
:: get CGO_ENABLED
|
||||
..\bin\go env > env.bat
|
||||
if errorlevel 1 goto fail
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ var _cgo_sigaction unsafe.Pointer
|
|||
//go:nosplit
|
||||
//go:nowritebarrierrec
|
||||
func sigaction(sig uint32, new, old *sigactiont) {
|
||||
// The runtime package is explicitly blacklisted from sanitizer
|
||||
// instrumentation in racewalk.go, but we might be calling into instrumented C
|
||||
// functions here — so we need the pointer parameters to be properly marked.
|
||||
// racewalk.go avoids adding sanitizing instrumentation to package runtime,
|
||||
// but we might be calling into instrumented C functions here,
|
||||
// so we need the pointer parameters to be properly marked.
|
||||
//
|
||||
// Mark the input as having been written before the call and the output as
|
||||
// read after.
|
||||
// Mark the input as having been written before the call
|
||||
// and the output as read after.
|
||||
if msanenabled && new != nil {
|
||||
msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func debugCallCheck(pc uintptr) string {
|
|||
"debugCall16384",
|
||||
"debugCall32768",
|
||||
"debugCall65536":
|
||||
// These functions are whitelisted so that the debugger can initiate multiple function calls.
|
||||
// These functions are allowed so that the debugger can initiate multiple function calls.
|
||||
// See: https://golang.org/cl/161137/
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -976,6 +976,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
|
|||
throw("malloc called with no P")
|
||||
}
|
||||
}
|
||||
var span *mspan
|
||||
var x unsafe.Pointer
|
||||
noscan := typ == nil || typ.ptrdata == 0
|
||||
if size <= maxSmallSize {
|
||||
|
|
@ -1028,10 +1029,10 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
|
|||
return x
|
||||
}
|
||||
// Allocate a new maxTinySize block.
|
||||
span := c.alloc[tinySpanClass]
|
||||
span = c.alloc[tinySpanClass]
|
||||
v := nextFreeFast(span)
|
||||
if v == 0 {
|
||||
v, _, shouldhelpgc = c.nextFree(tinySpanClass)
|
||||
v, span, shouldhelpgc = c.nextFree(tinySpanClass)
|
||||
}
|
||||
x = unsafe.Pointer(v)
|
||||
(*[2]uint64)(x)[0] = 0
|
||||
|
|
@ -1052,7 +1053,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
|
|||
}
|
||||
size = uintptr(class_to_size[sizeclass])
|
||||
spc := makeSpanClass(sizeclass, noscan)
|
||||
span := c.alloc[spc]
|
||||
span = c.alloc[spc]
|
||||
v := nextFreeFast(span)
|
||||
if v == 0 {
|
||||
v, span, shouldhelpgc = c.nextFree(spc)
|
||||
|
|
@ -1063,15 +1064,14 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
var s *mspan
|
||||
shouldhelpgc = true
|
||||
systemstack(func() {
|
||||
s = largeAlloc(size, needzero, noscan)
|
||||
span = largeAlloc(size, needzero, noscan)
|
||||
})
|
||||
s.freeindex = 1
|
||||
s.allocCount = 1
|
||||
x = unsafe.Pointer(s.base())
|
||||
size = s.elemsize
|
||||
span.freeindex = 1
|
||||
span.allocCount = 1
|
||||
x = unsafe.Pointer(span.base())
|
||||
size = span.elemsize
|
||||
}
|
||||
|
||||
var scanSize uintptr
|
||||
|
|
@ -1112,7 +1112,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
|
|||
// This may be racing with GC so do it atomically if there can be
|
||||
// a race marking the bit.
|
||||
if gcphase != _GCoff {
|
||||
gcmarknewobject(uintptr(x), size, scanSize)
|
||||
gcmarknewobject(span, uintptr(x), size, scanSize)
|
||||
}
|
||||
|
||||
if raceenabled {
|
||||
|
|
|
|||
|
|
@ -1627,11 +1627,21 @@ func gcDumpObject(label string, obj, off uintptr) {
|
|||
//
|
||||
//go:nowritebarrier
|
||||
//go:nosplit
|
||||
func gcmarknewobject(obj, size, scanSize uintptr) {
|
||||
func gcmarknewobject(span *mspan, obj, size, scanSize uintptr) {
|
||||
if useCheckmark { // The world should be stopped so this should not happen.
|
||||
throw("gcmarknewobject called while doing checkmark")
|
||||
}
|
||||
markBitsForAddr(obj).setMarked()
|
||||
|
||||
// Mark object.
|
||||
objIndex := span.objIndex(obj)
|
||||
span.markBitsForIndex(objIndex).setMarked()
|
||||
|
||||
// Mark span.
|
||||
arena, pageIdx, pageMask := pageIndexOf(span.base())
|
||||
if arena.pageMarks[pageIdx]&pageMask == 0 {
|
||||
atomic.Or8(&arena.pageMarks[pageIdx], pageMask)
|
||||
}
|
||||
|
||||
gcw := &getg().m.p.ptr().gcw
|
||||
gcw.bytesMarked += uint64(size)
|
||||
gcw.scanWork += int64(scanSize)
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ func updatememstats() {
|
|||
|
||||
// Calculate memory allocator stats.
|
||||
// During program execution we only count number of frees and amount of freed memory.
|
||||
// Current number of alive object in the heap and amount of alive heap memory
|
||||
// Current number of alive objects in the heap and amount of alive heap memory
|
||||
// are calculated by scanning all spans.
|
||||
// Total number of mallocs is calculated as number of frees plus number of alive objects.
|
||||
// Similarly, total amount of allocated memory is calculated as amount of freed memory
|
||||
|
|
|
|||
|
|
@ -296,6 +296,13 @@ func wbBufFlush1(_p_ *p) {
|
|||
continue
|
||||
}
|
||||
mbits.setMarked()
|
||||
|
||||
// Mark span.
|
||||
arena, pageIdx, pageMask := pageIndexOf(span.base())
|
||||
if arena.pageMarks[pageIdx]&pageMask == 0 {
|
||||
atomic.Or8(&arena.pageMarks[pageIdx], pageMask)
|
||||
}
|
||||
|
||||
if span.spanclass.noscan() {
|
||||
gcw.bytesMarked += uint64(span.elemsize)
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -563,8 +563,8 @@ func moduledataverify1(datap *moduledata) {
|
|||
// given program counter address, or else nil.
|
||||
//
|
||||
// If pc represents multiple functions because of inlining, it returns
|
||||
// the a *Func describing the innermost function, but with an entry
|
||||
// of the outermost function.
|
||||
// the *Func describing the innermost function, but with an entry of
|
||||
// the outermost function.
|
||||
func FuncForPC(pc uintptr) *Func {
|
||||
f := findfunc(pc)
|
||||
if !f.valid() {
|
||||
|
|
|
|||
|
|
@ -253,6 +253,8 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
|||
// 'comparing to zero' expressions
|
||||
|
||||
// var + const
|
||||
// 'x-const' might be canonicalized to 'x+(-const)', so we check both
|
||||
// CMN and CMP for subtraction expressions to make the pattern robust.
|
||||
func CmpToZero_ex1(a int64, e int32) int {
|
||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if a+3 < 0 {
|
||||
|
|
@ -269,37 +271,41 @@ func CmpToZero_ex1(a int64, e int32) int {
|
|||
return 2
|
||||
}
|
||||
|
||||
// arm64:`CMP`,-`SUB`,`(BMI|BPL)`
|
||||
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
|
||||
if a-7 < 0 {
|
||||
return 3
|
||||
}
|
||||
|
||||
// arm64:`CMP`,-`SUB`,`(BMI|BPL)`
|
||||
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
|
||||
if a-11 >= 0 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// arm64:`CMP`,-`SUB`,`BEQ`,`(BMI|BPL)`
|
||||
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`BEQ`,`(BMI|BPL)`
|
||||
if a-19 > 0 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+3 < 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+13 >= 0 {
|
||||
return 6
|
||||
}
|
||||
|
||||
// arm64:`CMPW`,-`SUBW`,`(BMI|BPL)`
|
||||
// arm64:`CMPW|CMNW`,`(BMI|BPL)`
|
||||
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||
if e-7 < 0 {
|
||||
return 7
|
||||
}
|
||||
|
||||
// arm64:`CMPW`,-`SUBW`,`(BMI|BPL)`
|
||||
// arm64:`CMPW|CMNW`,`(BMI|BPL)`
|
||||
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||
if e-11 >= 0 {
|
||||
return 8
|
||||
}
|
||||
|
|
@ -326,11 +332,13 @@ func CmpToZero_ex2(a, b, c int64, e, f, g int32) int {
|
|||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+f < 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if f+g >= 0 {
|
||||
return 6
|
||||
}
|
||||
|
|
@ -350,11 +358,13 @@ func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int {
|
|||
}
|
||||
|
||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||
if e+f*g > 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||
if f+g*h <= 0 {
|
||||
return 6
|
||||
}
|
||||
|
|
@ -384,3 +394,16 @@ func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int {
|
|||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToZero_ex5(e, f int32, u uint32) int {
|
||||
// arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
|
||||
if e+f<<1 > 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm:`CMP`,-`SUB`,`(BMI|BPL)`
|
||||
if f-int32(u>>2) >= 0 {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
12
test/fixedbugs/issue39472.go
Normal file
12
test/fixedbugs/issue39472.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// compile -N
|
||||
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
func f(x float64) bool {
|
||||
x += 1
|
||||
return (x != 0) == (x != 0)
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Check that batch files are maintained as CRLF files (consistent behaviour
|
||||
// on all operating systems). See https://github.com/golang/go/issues/37791
|
||||
// Check that batch files are maintained as CRLF files (consistent
|
||||
// behavior on all operating systems). See golang.org/issue/37791.
|
||||
|
||||
package main
|
||||
|
||||
|
|
@ -13,18 +13,56 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
batches, _ := filepath.Glob(runtime.GOROOT() + "/src/*.bat")
|
||||
for _, bat := range batches {
|
||||
body, _ := ioutil.ReadFile(bat)
|
||||
if !bytes.Contains(body, []byte("\r\n")) {
|
||||
fmt.Printf("Windows batch file %s does not contain CRLF line termination.\nTry running git checkout src/*.bat to fix this.\n", bat)
|
||||
os.Exit(1)
|
||||
// Ensure that the GOROOT/src/all.bat file exists and has strict CRLF line endings.
|
||||
enforceBatchStrictCRLF(filepath.Join(runtime.GOROOT(), "src", "all.bat"))
|
||||
|
||||
// Walk the entire Go repository source tree (without GOROOT/pkg),
|
||||
// skipping directories that start with "." and named "testdata",
|
||||
// and ensure all .bat files found have exact CRLF line endings.
|
||||
err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if path == filepath.Join(runtime.GOROOT(), "pkg") {
|
||||
// GOROOT/pkg is known to contain generated artifacts, not source code.
|
||||
// Skip it to avoid false positives. (Also see golang.org/issue/37929.)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if filepath.Ext(fi.Name()) == ".bat" {
|
||||
enforceBatchStrictCRLF(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func enforceBatchStrictCRLF(path string) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
cr, lf := bytes.Count(b, []byte{13}), bytes.Count(b, []byte{10})
|
||||
crlf := bytes.Count(b, []byte{13, 10})
|
||||
if cr != crlf || lf != crlf {
|
||||
if rel, err := filepath.Rel(runtime.GOROOT(), path); err == nil {
|
||||
// Make the test failure more readable by showing a path relative to GOROOT.
|
||||
path = rel
|
||||
}
|
||||
fmt.Printf("Windows batch file %s does not use strict CRLF line termination.\n", path)
|
||||
fmt.Printf("Please convert it to CRLF before checking it in due to golang.org/issue/37791.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue