diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index 9a4d7b27591dc..23fec84fb65e3 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -9,6 +9,6 @@ For asking questions, see: * [Gophers Slack](https://gophers.slack.com), use the [invite app](https://invite.slack.golangbridge.org/) for access -* [Stack Overflow](http://stackoverflow.com/questions/tagged/go) with questions tagged "go" +* [Stack Overflow](https://stackoverflow.com/questions/tagged/go) with questions tagged "go" * **IRC** channel #go-nuts on Freenode diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000..c1154524fbdf4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.10-alpine + +RUN apk add --no-cache bash build-base nodejs + +ENV GOROOT=/usr/local/go-wasm +ADD src $GOROOT/src +ADD misc $GOROOT/misc +ADD test $GOROOT/test +RUN ln -s $GOROOT/misc/wasm/go_js_wasm_exec /usr/local/bin/go_js_wasm_exec + +RUN echo "dev" > $GOROOT/VERSION +RUN cd $GOROOT/src && ./make.bash +ENV PATH=$GOROOT/bin:$PATH +RUN cd $GOROOT/test && go build run.go + +ENV GOARCH=wasm +ENV GOOS=js +RUN go install -v std +RUN go test -short std +RUN cd $GOROOT/test && ./run -v diff --git a/README.md b/README.md index 8cf23cae1e12f..49231bf25d2c1 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,14 @@ BSD-style license found in the LICENSE file. Official binary distributions are available at https://golang.org/dl/. After downloading a binary release, visit https://golang.org/doc/install -or load doc/install.html in your web browser for installation +or load [doc/install.html](./doc/install.html) in your web browser for installation instructions. #### Install From Source If a binary distribution is not available for your combination of operating system and architecture, visit -https://golang.org/doc/install/source or load doc/install-source.html +https://golang.org/doc/install/source or load [doc/install-source.html](./doc/install-source.html) in your web browser for source installation instructions. ### Contributing diff --git a/api/except.txt b/api/except.txt index 997df042b6509..b85003eda237a 100644 --- a/api/except.txt +++ b/api/except.txt @@ -377,9 +377,11 @@ pkg syscall (windows-386), type CertContext struct, CertInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr +pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr pkg syscall (windows-amd64), type CertContext struct, CertInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr +pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 diff --git a/doc/code.html b/doc/code.html index f22e6b4919ec1..c0efcde66f3b0 100644 --- a/doc/code.html +++ b/doc/code.html @@ -110,6 +110,10 @@

Workspaces

and dependencies in a single workspace.

+

+Note that symbolic links should not be used to link files or directories into your workspace. +

+

Commands and libraries are built from different kinds of source packages. We will discuss the distinction later. @@ -669,7 +673,7 @@

Getting help

For real-time help, ask the helpful gophers in #go-nuts on the -Freenode IRC server. +Freenode IRC server.

diff --git a/doc/contribute.html b/doc/contribute.html index d802bd72a16e6..e7970537dd343 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -418,7 +418,7 @@

Overview

  • Step 4: Send the changes for review to Gerrit using git -codereview mail(which doesn't use e-mail, despite the name). +codereview mail (which doesn't use e-mail, despite the name).
     $ git codereview mail     # send changes to Gerrit
     
    @@ -639,7 +639,7 @@

    Good commit messages

    large arguments, so use the McGillicutty algorithm to improve accuracy above 1e10. -The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm +The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm Fixes #159 @@ -984,8 +984,8 @@

    Quickly testing your changes

  • In this section, we'll call the directory into which you cloned the Go repository $GODIR. -The go tool built by $GODIR/make.bashwill be installed -in $GODIR/bin/goand you +The go tool built by $GODIR/make.bash will be installed +in $GODIR/bin/go and you can invoke it to test your code. For instance, if you have modified the compiler and you want to test how it affects the diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html index 19d36f7d97bfa..ca9d9a7c46475 100644 --- a/doc/debugging_with_gdb.html +++ b/doc/debugging_with_gdb.html @@ -47,7 +47,7 @@ to use GDB when it works, not as a guarantee of success. Besides this overview you might want to consult the -GDB manual. +GDB manual.

    diff --git a/doc/devel/release.html b/doc/devel/release.html index 30d1611509d46..584340b005f9b 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -48,6 +48,15 @@

    Minor revisions

    1.10.2 milestone on our issue tracker for details.

    +

    +go1.10.3 (released 2018/06/05) includes fixes to the go command, and the +crypto/tls, crypto/x509, and strings packages. +In particular, it adds +minimal support to the go command for the vgo transition. +See the Go +1.10.3 milestone on our issue tracker for details. +

    +

    go1.9 (released 2017/08/24)

    @@ -101,6 +110,15 @@

    Minor revisions

    1.9.6 milestone on our issue tracker for details.

    +

    +go1.9.7 (released 2018/06/05) includes fixes to the go command, and the +crypto/x509, and strings packages. +In particular, it adds +minimal support to the go command for the vgo transition. +See the Go +1.9.7 milestone on our issue tracker for details. +

    +

    go1.8 (released 2017/02/16)

    diff --git a/doc/docs.html b/doc/docs.html index 21a9a63d51c01..955eb3044e92f 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -195,7 +195,7 @@

    Talks

    -

    A Video Tour of Go

    +

    A Video Tour of Go

    Three things that make Go fast, fun, and productive: interfaces, reflection, and concurrency. Builds a toy web crawler to diff --git a/doc/editors.html b/doc/editors.html index 617a1001303ef..6f787864c60af 100644 --- a/doc/editors.html +++ b/doc/editors.html @@ -9,7 +9,7 @@

    Introduction

    This document lists commonly used editor plugins and IDEs from the Go ecosystem that make Go development more productive and seamless. A comprehensive list of editor support and IDEs for Go development is available at - the wiki. + the wiki.

    Options

    diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html index 1286fcc2be7b7..6374cd0cbe7eb 100644 --- a/doc/gccgo_contribute.html +++ b/doc/gccgo_contribute.html @@ -22,7 +22,7 @@

    Legal Prerequisites

    You must follow the Go copyright rules for all changes to the gccgo frontend and the associated libgo library. Code that is part of GCC rather than gccgo must follow -the general GCC +the general GCC contribution rules.

    @@ -30,9 +30,9 @@

    Code

    The master sources for the gccgo frontend may be found at -http://go.googlesource.com/gofrontend. +https://go.googlesource.com/gofrontend. They are mirrored -at http://github.com/golang/gofrontend. +at https://github.com/golang/gofrontend. The master sources are not buildable by themselves, but only in conjunction with GCC (in the future, other compilers may be supported). Changes made to the gccgo frontend are also applied to diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html index d4eac12f11de7..a974bb3680610 100644 --- a/doc/gccgo_install.html +++ b/doc/gccgo_install.html @@ -9,7 +9,7 @@ for GCC, the widely used GNU compiler. Although the frontend itself is under a BSD-style license, gccgo is normally used as part of GCC and is then covered by -the GNU General Public +the GNU General Public License (the license covers gccgo itself as part of GCC; it does not cover code generated by gccgo).

    @@ -25,7 +25,7 @@

    Releases

    The simplest way to install gccgo is to install a GCC binary release built to include Go support. GCC binary releases are available from -various +various websites and are typically included as part of GNU/Linux distributions. We expect that most people who build these binaries will include Go support. @@ -79,7 +79,7 @@

    Source code

    yourself, the gccgo source code is accessible via Subversion. The GCC web site -has instructions for getting the +has instructions for getting the GCC source code. The gccgo source code is included. As a convenience, a stable version of the Go support is available in a branch of the main GCC code @@ -101,7 +101,7 @@

    Building

    Building gccgo is just like building GCC with one or two additional options. See -the instructions on the gcc web +the instructions on the gcc web site. When you run configure, add the option --enable-languages=c,c++,go (along with other languages you may want to build). If you are targeting a 32-bit x86, @@ -156,7 +156,7 @@

    Prerequisites

    A number of prerequisites are required to build GCC, as described on -the gcc web +the gcc web site. It is important to install all the prerequisites before running the gcc configure script. The prerequisite libraries can be conveniently downloaded using the diff --git a/doc/go1.11.html b/doc/go1.11.html new file mode 100644 index 0000000000000..4eb4c42abe683 --- /dev/null +++ b/doc/go1.11.html @@ -0,0 +1,337 @@ + + + + + + +

    DRAFT RELEASE NOTES - Introduction to Go 1.11

    + +

    + + Go 1.11 is not yet released. These are work-in-progress + release notes. Go 1.11 is expected to be released in August 2018. + +

    + +

    + The latest Go release, version 1.11, arrives six months after Go 1.10. + Most of its changes are in the implementation of the toolchain, runtime, and libraries. + As always, the release maintains the Go 1 promise of compatibility. + We expect almost all Go programs to continue to compile and run as before. +

    + +

    Changes to the language

    + +

    + There are no changes to the language specification. +

    + +

    Ports

    + +

    + As announced in the Go 1.10 release notes, Go 1.11 now requires + OpenBSD 6.2 or later, macOS 10.10 Yosemite or later, or Windows 7 or later; + Support for previous versions of these operating systems has been removed. +

    + +

    + There are known issues with NetBSD on i386 hardware. +

    + +

    + TODO: PPC64LE race detector support +

    + +

    WebAssembly

    +

    + Go 1.11 adds an experimental port to WebAssembly (wasm/js). +

    + +

    Core library

    + +

    + All of the changes to the standard library are minor. +

    + +

    Minor changes to the library

    + +

    + As always, there are various minor changes and updates to the library, + made with the Go 1 promise of compatibility + in mind. +

    + + + + + + + + + +
    all
    +
    +

    + TODO: https://golang.org/cl/93875: enable c-shared/c-archive support for freebsd/amd64 +

    + +

    + TODO: https://golang.org/cl/94255: drop support for Windows Vista or below (Windows XP) +

    + +

    + TODO: https://golang.org/cl/115038: remove support for macOS 10.9 and earlier +

    + +
    + +
    crypto
    +
    +

    + TODO: https://golang.org/cl/64451: randomly read an extra byte of randomness in some places. +

    + +
    + +
    crypto/cipher
    +
    +

    + TODO: https://golang.org/cl/48510: add NewGCMWithTagSize for custom tag sizes. +

    + +
    + +
    crypto/rsa
    +
    +

    + TODO: https://golang.org/cl/103876: add PublicKey.Size accessor +

    + +
    + +
    debug/elf
    +
    +

    + TODO: https://golang.org/cl/112115: add machine and OSABI constants +

    + +
    + +
    encoding/asn1
    +
    +

    + TODO: https://golang.org/cl/110561: allow Marshaling and Unmarshaling private tag class +

    + +
    + +
    encoding/base32
    +
    +

    + TODO: https://golang.org/cl/112516: handle surplus padding consistently +

    + +
    + +
    encoding/csv
    +
    +

    + TODO: https://golang.org/cl/99696: disallow quote for use as Comma +

    + +
    + +
    go/build, runtime/internal/sys
    +
    +

    + TODO: https://golang.org/cl/106256: reserve RISC-V arch names +

    + +
    + +
    image/gif
    +
    +

    + TODO: https://golang.org/cl/93076: support non-looping animated gifs (LoopCount=-1) +

    + +
    + +
    io/ioutil
    +
    +

    + TODO: https://golang.org/cl/105675: change TempFile prefix to a pattern +

    + +
    + +
    math/big
    +
    +

    + TODO: https://golang.org/cl/74851: speed-up addMulVVW on amd64 +

    + +
    + +
    net
    +
    +

    + TODO: https://golang.org/cl/72810: add ListenConfig, Dialer.Control to permit socket opts before listen/dial +

    + +

    + TODO: https://golang.org/cl/76391: implement (*syscall.RawConn).Read/Write on Windows +

    + +

    + TODO: https://golang.org/cl/107715: add support for splice(2) in (*TCPConn).ReadFrom on Linux +

    + +

    + TODO: https://golang.org/cl/108297: calling File leaves the socket in nonblocking mode +

    + +
    + +
    net/http
    +
    +

    + TODO: https://golang.org/cl/89275: don't sniff Content-type in Server when X-Content-Type-Options:nosniff +

    + +

    + TODO: https://golang.org/cl/93296: add StatusMisdirectedRequest (421) +

    + +
    + +
    os
    +
    +

    + TODO: https://golang.org/cl/78835: add UserCacheDir +

    + +

    + TODO: https://golang.org/cl/94856: add ModeIrregular flag +

    + +

    + TODO: https://golang.org/cl/99337: enable symlink creation on Windows 10 +

    + +

    + TODO: https://golang.org/cl/100077: use poller when NewFile is called with a blocking descriptor. +

    + +
    + +
    os/signal
    +
    +

    + TODO: https://golang.org/cl/108376: add func Ignored(sig Signal) bool +

    + +
    + +
    os/user
    +
    +

    + TODO: https://golang.org/cl/92456: add a way to enforce pure Go implementation +

    + +
    + +
    runtime
    +
    +

    + TODO: https://golang.org/cl/85887: use sparse mappings for the heap +

    + +

    + TODO: https://golang.org/cl/94076: use native CAS and memory barrier on ARMv7 +

    + +

    + TODO: https://golang.org/cl/106156: use fixed TLS offsets on darwin/amd64 and darwin/386 +

    + +

    + TODO: https://golang.org/cl/109255: enable memory sanitizer on arm64 +

    + +
    + +
    runtime,cmd/ld
    +
    +

    + TODO: https://golang.org/cl/108679: on darwin, create theads using libc +

    + +
    + +
    runtime/pprof
    +
    +

    + TODO: https://golang.org/cl/102696: introduce "allocs" profile +

    + +
    + +
    runtime/traceback
    +
    +

    + TODO: https://golang.org/cl/70993: support tracking goroutine ancestor tracebacks with GODEBUG="tracebackancestors=N" +

    + +
    + +
    sync
    +
    +

    + TODO: https://golang.org/cl/87095: enable profiling of RWMutex +

    + +
    + +
    syscall
    +
    +

    + TODO: https://golang.org/cl/106275: introduce Pointer type and use it instead of uintptr +

    + +
    + +
    text/scanner
    +
    +

    + TODO: https://golang.org/cl/112037: return RawString token rather than String for raw string literals +

    + +
    + +
    text/template
    +
    +

    + TODO: https://golang.org/cl/84480: add variable assignments +

    + +
    + +
    time
    +
    +

    + TODO: https://golang.org/cl/98157: add support for parsing timezones denoted by sign and offset +

    + +
    diff --git a/doc/go1.2.html b/doc/go1.2.html index 5370bbbbd6e1d..1f6051418cff6 100644 --- a/doc/go1.2.html +++ b/doc/go1.2.html @@ -860,13 +860,13 @@

    Minor changes to the library

    The net package adds a new field DualStack to the Dialer struct for TCP connection setup using a dual IP stack as described in -RFC 6555. +RFC 6555.
  • The net/http package will no longer transmit cookies that are incorrect according to -RFC 6265. +RFC 6265. It just logs an error and sends nothing. Also, the net/http package's diff --git a/doc/go1.4.html b/doc/go1.4.html index ca44d56ceb2b6..c8f7c9c5255f4 100644 --- a/doc/go1.4.html +++ b/doc/go1.4.html @@ -420,7 +420,7 @@

    The go generate subcommand

    For example, it can be used to run the yacc compiler-compiler on a .y file to produce the Go source file implementing the grammar, or to automate the generation of String methods for typed constants using the new -stringer +stringer tool in the golang.org/x/tools subrepository.

    @@ -619,9 +619,9 @@

    syscall

    calls on all kernels. It has a nicer structure, with three packages that each hold the implementation of system calls for one of -Unix, -Windows and -Plan 9. +Unix, +Windows and +Plan 9. These packages will be curated more generously, accepting all reasonable changes that reflect kernel interfaces in those operating systems. See the documentation and the article mentioned above for more information. @@ -670,7 +670,7 @@

    Minor changes to the library

  • The crypto/tls package -now supports ALPN as defined in RFC 7301. +now supports ALPN as defined in RFC 7301.
  • diff --git a/doc/go1.6.html b/doc/go1.6.html index 9594736e654fd..902a82d517efd 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -116,7 +116,7 @@

    Compiler Toolchain

    The compiler, linker, and go command have a new flag -msan, analogous to -race and only available on linux/amd64, -that enables interoperation with the Clang MemorySanitizer. +that enables interoperation with the Clang MemorySanitizer. Such interoperation is useful mainly for testing a program containing suspect C or C++ code.

    diff --git a/doc/go1.7.html b/doc/go1.7.html index 2b0f01d8fbbb4..db60702776748 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -89,7 +89,7 @@

    Ports

    -The OpenBSD port now requires OpenBSD 5.6 or later, for access to the getentropy(2) system call. +The OpenBSD port now requires OpenBSD 5.6 or later, for access to the getentropy(2) system call.

    Known Issues

    diff --git a/doc/go_faq.html b/doc/go_faq.html index cc81e49a9bbe5..e83408e6f171b 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -97,14 +97,14 @@

    The mascot and logo were designed by -Renée French, who also designed +Renée French, who also designed Glenda, the Plan 9 bunny. The gopher -is derived from one she used for an WFMU +is derived from one she used for an WFMU T-shirt design some years ago. The logo and mascot are covered by the -Creative Commons Attribution 3.0 +Creative Commons Attribution 3.0 license.

    @@ -1929,7 +1929,7 @@

    Nowadays, most Go programmers use a tool, -goimports, +goimports, which automatically rewrites a Go source file to have the correct imports, eliminating the unused imports issue in practice. This program is easily connected to most editors to run automatically when a Go source file is written. @@ -1968,7 +1968,7 @@

    are not available in Go. For instance, pidigits.go depends on a multi-precision math package, and the C -versions, unlike Go's, use GMP (which is +versions, unlike Go's, use GMP (which is written in optimized assembler). Benchmarks that depend on regular expressions (regex-dna.go, diff --git a/doc/go_spec.html b/doc/go_spec.html index f1300c105a41b..f70ff7a02feee 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -69,7 +69,7 @@

    Source code representation

    Source code is Unicode text encoded in -UTF-8. The text is not +UTF-8. The text is not canonicalized, so a single accented code point is distinct from the same character constructed from combining an accent and a letter; those are treated as two code points. For simplicity, this document @@ -104,7 +104,7 @@

    Characters

    -In The Unicode Standard 8.0, +In The Unicode Standard 8.0, Section 4.5 "General Category" defines a set of character categories. Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo as Unicode letters, and those in the Number category Nd as Unicode digits. @@ -793,7 +793,7 @@

    Numeric types

    The value of an n-bit integer is n bits wide and represented using -two's complement arithmetic. +two's complement arithmetic.

    @@ -3543,7 +3543,7 @@

    Integer operators

    with x / y truncated towards zero -("truncated division"). +("truncated division").

    @@ -6109,7 +6109,7 @@ 

    Import declarations

    Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to -Unicode's +Unicode's L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&'()*,:;<=>?[\]^`{|} diff --git a/doc/install-source.html b/doc/install-source.html index 1928b0ba9b4b7..844fb002f7aa1 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -197,7 +197,7 @@

    Install Git, if needed

    If you do not have a working Git installation, follow the instructions on the -Git downloads page. +Git downloads page.

    (Optional) Install a C compiler

    @@ -388,7 +388,7 @@

    Community resources

    The usual community resources such as -#go-nuts on the Freenode IRC server +#go-nuts on the Freenode IRC server and the Go Nuts mailing list have active developers that can help you with problems diff --git a/doc/install.html b/doc/install.html index ee1516ac47bfb..cd51e7603a5aa 100644 --- a/doc/install.html +++ b/doc/install.html @@ -57,7 +57,7 @@

    System requirements

    A C compiler is required only if you plan to use cgo.
    You only need to install the command line tools for -Xcode. If you have already +Xcode. If you have already installed Xcode 4.3+, you can install it from the Components tab of the Downloads preferences panel.

    @@ -114,31 +114,6 @@

    Linux, Mac OS X, and FreeBSD tarballs

    source $HOME/.profile.

    -

    Installing to a custom location

    - -

    -The Go binary distributions assume they will be installed in -/usr/local/go (or c:\Go under Windows), -but it is possible to install the Go tools to a different location. -In this case you must set the GOROOT environment variable -to point to the directory in which it was installed. -

    - -

    -For example, if you installed Go to your home directory you should add -commands like the following to $HOME/.profile: -

    - -
    -export GOROOT=$HOME/go1.X
    -export PATH=$PATH:$GOROOT/bin
    -
    - -

    -Note: GOROOT must be set only when installing to a custom -location. -

    -
    diff --git a/lib/time/update.bash b/lib/time/update.bash index 26ad79d52def5..629e74fce84f8 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -8,8 +8,8 @@ # Consult https://www.iana.org/time-zones for the latest versions. # Versions to use. -CODE=2017c -DATA=2017c +CODE=2018e +DATA=2018e set -e rm -rf work diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index 0703e08e36e52..08dca214181a8 100644 Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ diff --git a/misc/cgo/life/main.go b/misc/cgo/life/main.go index 45376fd05a97f..145a273bdd1fd 100644 --- a/misc/cgo/life/main.go +++ b/misc/cgo/life/main.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go index 0fa813cab7082..cdc385208c989 100644 --- a/misc/cgo/stdio/chain.go +++ b/misc/cgo/stdio/chain.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go index 56e32552ee6de..58f185c90f051 100644 --- a/misc/cgo/stdio/fib.go +++ b/misc/cgo/stdio/fib.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go index 63bff4c617a13..56220d34be324 100644 --- a/misc/cgo/stdio/hello.go +++ b/misc/cgo/stdio/hello.go @@ -1,4 +1,4 @@ -// cmpout -tags=use_go_run +// run -tags=use_go_run // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/misc/cgo/testplugin/src/issue25756/main.go b/misc/cgo/testplugin/src/issue25756/main.go new file mode 100644 index 0000000000000..817daf42f6827 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/main.go @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +// Run the game of life in C using Go for parallelization. + +package main + +import ( + "flag" + "fmt" + "plugin" +) + +const MAXDIM = 100 + +var dim = flag.Int("dim", 16, "board dimensions") +var gen = flag.Int("gen", 10, "generations") + +func main() { + flag.Parse() + + var a [MAXDIM * MAXDIM]int32 + for i := 2; i < *dim; i += 8 { + for j := 2; j < *dim-3; j += 8 { + for y := 0; y < 3; y++ { + a[i**dim+j+y] = 1 + } + } + } + + p, err := plugin.Open("life.so") + if err != nil { + panic(err) + } + f, err := p.Lookup("Run") + if err != nil { + panic(err) + } + f.(func(int, int, int, []int32))(*gen, *dim, *dim, a[:]) + + for i := 0; i < *dim; i++ { + for j := 0; j < *dim; j++ { + if a[i**dim+j] == 0 { + fmt.Print(" ") + } else { + fmt.Print("X") + } + } + fmt.Print("\n") + } +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/c-life.c b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c new file mode 100644 index 0000000000000..f853163e2f0c1 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c @@ -0,0 +1,56 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include "life.h" +#include "_cgo_export.h" + +const int MYCONST = 0; + +// Do the actual manipulation of the life board in C. This could be +// done easily in Go, we are just using C for demonstration +// purposes. +void +Step(int x, int y, int *a, int *n) +{ + struct GoStart_return r; + + // Use Go to start 4 goroutines each of which handles 1/4 of the + // board. + r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n); + assert(r.r0 == 0 && r.r1 == 100); // test multiple returns + r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n); + assert(r.r0 == 1 && r.r1 == 101); // test multiple returns + GoStart(2, x, y, 0, x / 2, y / 2, y, a, n); + GoStart(3, x, y, x / 2, x, y / 2, y, a, n); + GoWait(0); + GoWait(1); + GoWait(2); + GoWait(3); +} + +// The actual computation. This is called in parallel. +void +DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n) +{ + int x, y, c, i, j; + + for(x = xstart; x < xend; x++) { + for(y = ystart; y < yend; y++) { + c = 0; + for(i = -1; i <= 1; i++) { + for(j = -1; j <= 1; j++) { + if(x+i >= 0 && x+i < xdim && + y+j >= 0 && y+j < ydim && + (i != 0 || j != 0)) + c += a[(x+i)*xdim + (y+j)] != 0; + } + } + if(c == 3 || (c == 2 && a[x*xdim + y] != 0)) + n[x*xdim + y] = 1; + else + n[x*xdim + y] = 0; + } + } +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.go b/misc/cgo/testplugin/src/issue25756/plugin/life.go new file mode 100644 index 0000000000000..675a192fc103e --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/life.go @@ -0,0 +1,39 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// #include "life.h" +import "C" + +import "unsafe" + +func Run(gen, x, y int, a []int32) { + n := make([]int32, x*y) + for i := 0; i < gen; i++ { + C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0]))) + copy(a, n) + } +} + +// Keep the channels visible from Go. +var chans [4]chan bool + +//export GoStart +// Double return value is just for testing. +func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) { + c := make(chan bool, int(C.MYCONST)) + go func() { + C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n) + c <- true + }() + chans[i] = c + return int(i), int(i + 100) +} + +//export GoWait +func GoWait(i C.int) { + <-chans[i] + chans[i] = nil +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.h b/misc/cgo/testplugin/src/issue25756/plugin/life.h new file mode 100644 index 0000000000000..11d2b97226767 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/life.h @@ -0,0 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +extern void Step(int, int, int *, int *); +extern void DoStep(int, int, int, int, int, int, int *, int *); +extern const int MYCONST; diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash index df38204a4e951..bf8ed3cd191ea 100755 --- a/misc/cgo/testplugin/test.bash +++ b/misc/cgo/testplugin/test.bash @@ -15,7 +15,7 @@ goos=$(go env GOOS) goarch=$(go env GOARCH) function cleanup() { - rm -f plugin*.so unnamed*.so iface*.so issue* + rm -f plugin*.so unnamed*.so iface*.so life.so issue* rm -rf host pkg sub iface } trap cleanup EXIT @@ -90,3 +90,12 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/m GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go ./issue24351 + +# Test for issue 25756 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o life.so issue25756/plugin +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue25756 src/issue25756/main.go +# Fails intermittently, but 20 runs should cause the failure +for i in `seq 1 20`; +do + ./issue25756 > /dev/null +done diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index 142080bf55169..8eadff4f7b31b 100755 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -16,13 +16,11 @@ }, }; - const now = () => { - const [sec, nsec] = process.hrtime(); - return sec * 1000 + nsec / 1000000; - }; global.performance = { - timeOrigin: Date.now() - now(), - now: now, + now() { + const [sec, nsec] = process.hrtime(); + return sec * 1000 + nsec / 1000000; + }, }; const util = require("util"); @@ -51,13 +49,15 @@ global.Go = class { constructor() { - this.argv = []; + this.argv = ["js"]; this.env = {}; this.exit = (code) => { if (code !== 0) { console.warn("exit code:", code); } }; + this._callbackTimeouts = new Map(); + this._nextCallbackTimeoutID = 1; const mem = () => { // The buffer may change when requesting more memory. @@ -116,10 +116,12 @@ return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); } + const timeOrigin = Date.now() - performance.now(); this.importObject = { go: { // func wasmExit(code int32) "runtime.wasmExit": (sp) => { + this.exited = true; this.exit(mem().getInt32(sp + 8, true)); }, @@ -133,7 +135,7 @@ // func nanotime() int64 "runtime.nanotime": (sp) => { - setInt64(sp + 8, (performance.timeOrigin + performance.now()) * 1000000); + setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); }, // func walltime() (sec int64, nsec int32) @@ -143,48 +145,71 @@ mem().setInt32(sp + 16, (msec % 1000) * 1000000, true); }, - // func boolVal(value bool) Value + // func scheduleCallback(delay int64) int32 + "runtime.scheduleCallback": (sp) => { + const id = this._nextCallbackTimeoutID; + this._nextCallbackTimeoutID++; + this._callbackTimeouts.set(id, setTimeout( + () => { this._resolveCallbackPromise(); }, + getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early + )); + mem().setInt32(sp + 16, id, true); + }, + + // func clearScheduledCallback(id int32) + "runtime.clearScheduledCallback": (sp) => { + const id = mem().getInt32(sp + 8, true); + clearTimeout(this._callbackTimeouts.get(id)); + this._callbackTimeouts.delete(id); + }, + + // func getRandomData(r []byte) + "runtime.getRandomData": (sp) => { + crypto.getRandomValues(loadSlice(sp + 8)); + }, + + // func boolVal(value bool) ref "syscall/js.boolVal": (sp) => { storeValue(sp + 16, mem().getUint8(sp + 8) !== 0); }, - // func intVal(value int) Value + // func intVal(value int) ref "syscall/js.intVal": (sp) => { storeValue(sp + 16, getInt64(sp + 8)); }, - // func floatVal(value float64) Value + // func floatVal(value float64) ref "syscall/js.floatVal": (sp) => { storeValue(sp + 16, mem().getFloat64(sp + 8, true)); }, - // func stringVal(value string) Value + // func stringVal(value string) ref "syscall/js.stringVal": (sp) => { storeValue(sp + 24, loadString(sp + 8)); }, - // func (v Value) Get(key string) Value - "syscall/js.Value.Get": (sp) => { + // func valueGet(v ref, p string) ref + "syscall/js.valueGet": (sp) => { storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16))); }, - // func (v Value) set(key string, value Value) - "syscall/js.Value.set": (sp) => { + // func valueSet(v ref, p string, x ref) + "syscall/js.valueSet": (sp) => { Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); }, - // func (v Value) Index(i int) Value - "syscall/js.Value.Index": (sp) => { + // func valueIndex(v ref, i int) ref + "syscall/js.valueIndex": (sp) => { storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); }, - // func (v Value) setIndex(i int, value Value) - "syscall/js.Value.setIndex": (sp) => { + // valueSetIndex(v ref, i int, x ref) + "syscall/js.valueSetIndex": (sp) => { Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); }, - // func (v Value) call(name string, args []Value) (Value, bool) - "syscall/js.Value.call": (sp) => { + // func valueCall(v ref, m string, args []ref) (ref, bool) + "syscall/js.valueCall": (sp) => { try { const v = loadValue(sp + 8); const m = Reflect.get(v, loadString(sp + 16)); @@ -197,8 +222,8 @@ } }, - // func (v Value) invoke(args []Value) (Value, bool) - "syscall/js.Value.invoke": (sp) => { + // func valueInvoke(v ref, args []ref) (ref, bool) + "syscall/js.valueInvoke": (sp) => { try { const v = loadValue(sp + 8); const args = loadSliceOfValues(sp + 16); @@ -210,8 +235,8 @@ } }, - // func (v Value) new(args []Value) (Value, bool) - "syscall/js.Value.new": (sp) => { + // func valueNew(v ref, args []ref) (ref, bool) + "syscall/js.valueNew": (sp) => { try { const v = loadValue(sp + 8); const args = loadSliceOfValues(sp + 16); @@ -223,35 +248,35 @@ } }, - // func (v Value) Float() float64 - "syscall/js.Value.Float": (sp) => { + // func valueFloat(v ref) float64 + "syscall/js.valueFloat": (sp) => { mem().setFloat64(sp + 16, parseFloat(loadValue(sp + 8)), true); }, - // func (v Value) Int() int - "syscall/js.Value.Int": (sp) => { + // func valueInt(v ref) int + "syscall/js.valueInt": (sp) => { setInt64(sp + 16, parseInt(loadValue(sp + 8))); }, - // func (v Value) Bool() bool - "syscall/js.Value.Bool": (sp) => { + // func valueBool(v ref) bool + "syscall/js.valueBool": (sp) => { mem().setUint8(sp + 16, !!loadValue(sp + 8)); }, - // func (v Value) Length() int - "syscall/js.Value.Length": (sp) => { + // func valueLength(v ref) int + "syscall/js.valueLength": (sp) => { setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); }, - // func (v Value) prepareString() (Value, int) - "syscall/js.Value.prepareString": (sp) => { + // valuePrepareString(v ref) (ref, int) + "syscall/js.valuePrepareString": (sp) => { const str = encoder.encode(String(loadValue(sp + 8))); storeValue(sp + 16, str); setInt64(sp + 24, str.length); }, - // func (v Value) loadString(b []byte) - "syscall/js.Value.loadString": (sp) => { + // valueLoadString(v ref, b []byte) + "syscall/js.valueLoadString": (sp) => { const str = loadValue(sp + 8); loadSlice(sp + 16).set(str); }, @@ -265,7 +290,19 @@ async run(instance) { this._inst = instance; - this._values = [undefined, null, global, this._inst.exports.mem]; // TODO: garbage collection + this._values = [ // TODO: garbage collection + undefined, + null, + global, + this._inst.exports.mem, + () => { // resolveCallbackPromise + if (this.exited) { + throw new Error("bad callback: Go program has already exited"); + } + setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous + }, + ]; + this.exited = false; const mem = new DataView(this._inst.exports.mem.buffer) @@ -299,7 +336,16 @@ offset += 8; }); - this._inst.exports.run(argc, argv); + while (true) { + const callbackPromise = new Promise((resolve) => { + this._resolveCallbackPromise = resolve; + }); + this._inst.exports.run(argc, argv); + if (this.exited) { + break; + } + await callbackPromise; + } } } @@ -314,9 +360,16 @@ go.env = process.env; go.exit = process.exit; WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { + process.on("exit", () => { // Node.js exits if no callback is pending + if (!go.exited) { + console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!"); + process.exit(1); + } + }); return go.run(result.instance); }).catch((err) => { console.error(err); + go.exited = true; process.exit(1); }); } diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go index 6e29698a14a54..1f89d0c59a159 100644 --- a/src/archive/tar/format.go +++ b/src/archive/tar/format.go @@ -94,7 +94,7 @@ const ( // application can only parse GNU formatted archives. // // Reference: - // http://www.gnu.org/software/tar/manual/html_node/Standard.html + // https://www.gnu.org/software/tar/manual/html_node/Standard.html FormatGNU // Schily's tar format, which is incompatible with USTAR. diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go index 36b551ec2c32a..c545c5b8308e9 100644 --- a/src/archive/zip/struct.go +++ b/src/archive/zip/struct.go @@ -202,7 +202,7 @@ func timeZone(offset time.Duration) *time.Location { // msDosTimeToTime converts an MS-DOS date and time into a time.Time. // The resolution is 2s. -// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx +// See: https://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx func msDosTimeToTime(dosDate, dosTime uint16) time.Time { return time.Date( // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 @@ -222,7 +222,7 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time { // timeToMsDosTime converts a time.Time to an MS-DOS date and time. // The resolution is 2s. -// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx +// See: https://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index 0f1a193345b46..506148ee30089 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -72,7 +72,7 @@ func (w *Writer) SetComment(comment string) error { } // Close finishes writing the zip file by writing the central directory. -// It does not (and cannot) close the underlying writer. +// It does not close the underlying writer. func (w *Writer) Close() error { if w.last != nil && !w.last.closed { if err := w.last.close(); err != nil { diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index dc9d5e95d32ba..a2eca2ed129bb 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -202,6 +202,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { b.lastRead = opInvalid for { i := b.grow(MinRead) + b.buf = b.buf[:i] m, e := r.Read(b.buf[i:cap(b.buf)]) if m < 0 { panic(errNegativeRead) diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index e4bbc12f6a135..acbe5ca0c49e2 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -269,6 +269,39 @@ func TestReadFrom(t *testing.T) { } } +type panicReader struct{ panic bool } + +func (r panicReader) Read(p []byte) (int, error) { + if r.panic { + panic(nil) + } + return 0, io.EOF +} + +// Make sure that an empty Buffer remains empty when +// it is "grown" before a Read that panics +func TestReadFromPanicReader(t *testing.T) { + + // First verify non-panic behaviour + var buf Buffer + i, err := buf.ReadFrom(panicReader{}) + if err != nil { + t.Fatal(err) + } + if i != 0 { + t.Fatalf("unexpected return from bytes.ReadFrom (1): got: %d, want %d", i, 0) + } + check(t, "TestReadFromPanicReader (1)", &buf, "") + + // Confirm that when Reader panics, the emtpy buffer remains empty + var buf2 Buffer + defer func() { + recover() + check(t, "TestReadFromPanicReader (2)", &buf2, "") + }() + buf2.ReadFrom(panicReader{panic: true}) +} + func TestReadFromNegativeReader(t *testing.T) { var b Buffer defer func() { diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s index 647628176ae2c..afd1dfd313705 100644 --- a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s +++ b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s @@ -371,5 +371,683 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 VPEXTRB $-1, X1, AX // c4e37914c8ff VPEXTRD $-1, X1, AX // c4e37916c8ff VPEXTRQ $-1, X1, AX // c4e3f916c8ff + // EVEX: High-16 X registers. + VADDPD X30, X1, X0 // 6291f50858c6 + VADDPD X2, X29, X0 // 62f1950058c2 + VADDPD X30, X29, X0 // 6291950058c6 + VADDPD X2, X1, X28 // 6261f50858e2 + VADDPD X30, X1, X28 // 6201f50858e6 + VADDPD X2, X29, X28 // 6261950058e2 + VADDPD X30, X29, X28 // 6201950058e6 + VADDPD X30, X11, X10 // 6211a50858d6 + VADDPD X12, X29, X10 // 6251950058d4 + VADDPD X30, X29, X10 // 6211950058d6 + VADDPD X12, X11, X28 // 6241a50858e4 + VADDPD X30, X11, X28 // 6201a50858e6 + VADDPD X12, X29, X28 // 6241950058e4 + VADDPD X30, X29, X28 // 6201950058e6 + VADDPD (AX), X29, X0 // 62f195005800 + VADDPD (AX), X1, X28 // 6261f5085820 + VADDPD (AX), X29, X28 // 626195005820 + VADDPD (AX), X29, X10 // 627195005810 + VADDPD (AX), X10, X28 // 6261ad085820 + VADDPD (CX)(AX*1), X29, X0 // 62f19500580401 + VADDPD (CX)(AX*1), X1, X28 // 6261f508582401 + VADDPD (CX)(AX*1), X29, X28 // 62619500582401 + VADDPD (CX)(AX*1), X29, X10 // 62719500581401 + VADDPD (CX)(AX*1), X10, X28 // 6261ad08582401 + VADDPD (CX)(AX*2), X29, X0 // 62f19500580441 + VADDPD (CX)(AX*2), X1, X28 // 6261f508582441 + VADDPD (CX)(AX*2), X29, X28 // 62619500582441 + VADDPD (CX)(AX*2), X29, X10 // 62719500581441 + VADDPD (CX)(AX*2), X10, X28 // 6261ad08582441 + // EVEX: displacement without Disp8. + VADDPD 15(AX), X29, X0 // 62f1950058800f000000 + VADDPD 15(AX), X1, X28 // 6261f50858a00f000000 + VADDPD 15(AX), X29, X28 // 6261950058a00f000000 + VADDPD 15(AX), X29, X10 // 6271950058900f000000 + VADDPD 15(AX), X10, X28 // 6261ad0858a00f000000 + VADDPD 15(CX)(AX*1), X29, X0 // 62f195005884010f000000 + VADDPD 15(CX)(AX*1), X1, X28 // 6261f50858a4010f000000 + VADDPD 15(CX)(AX*1), X29, X28 // 6261950058a4010f000000 + VADDPD 15(CX)(AX*1), X29, X10 // 627195005894010f000000 + VADDPD 15(CX)(AX*1), X10, X28 // 6261ad0858a4010f000000 + VADDPD 15(CX)(AX*2), X29, X0 // 62f195005884410f000000 + VADDPD 15(CX)(AX*2), X1, X28 // 6261f50858a4410f000000 + VADDPD 15(CX)(AX*2), X29, X28 // 6261950058a4410f000000 + VADDPD 15(CX)(AX*2), X29, X10 // 627195005894410f000000 + VADDPD 15(CX)(AX*2), X10, X28 // 6261ad0858a4410f000000 + // EVEX: compressed displacement (Disp8). + VADDPD 2032(DX), X29, X0 // 62f1950058427f + VADDPD 2032(DX), X1, X29 // 6261f508586a7f + VADDPD 2032(DX), X29, X28 // 6261950058627f + VADDPD 2032(DX)(AX*2), X29, X0 // 62f195005844427f + VADDPD 2032(DX)(AX*2), X1, X29 // 6261f508586c427f + VADDPD 2032(DX)(AX*2), X29, X28 // 626195005864427f + VADDPD 4064(DX), Y0, Y29 // 6261fd28586a7f + VADDPD 4064(DX), Y29, Y1 // 62f19520584a7f + VADDPD 4064(DX), Y28, Y29 // 62619d20586a7f + VADDPD 4064(DX)(AX*2), Y0, Y29 // 6261fd28586c427f + VADDPD 4064(DX)(AX*2), Y29, Y1 // 62f19520584c427f + VADDPD 8128(DX), Z0, Z29 // 6261fd48586a7f + VADDPD 8128(DX), Z29, Z1 // 62f19540584a7f + VADDPD 8128(DX), Z28, Z29 // 62619d40586a7f + VADDPD 8128(DX)(AX*2), Z0, Z29 // 6261fd48586c427f + VADDPD 8128(DX)(AX*2), Z29, Z1 // 62f19540584c427f + // EVEX: compressed displacement that does not fit into 8bits. + VADDPD 2048(DX), X29, X0 // 62f19500588200080000 + VADDPD 2048(DX), X1, X29 // 6261f50858aa00080000 + VADDPD 2048(DX), X29, X28 // 6261950058a200080000 + VADDPD 2048(DX)(AX*2), X29, X0 // 62f1950058844200080000 + VADDPD 2048(DX)(AX*2), X1, X29 // 6261f50858ac4200080000 + VADDPD 2048(DX)(AX*2), X29, X28 // 6261950058a44200080000 + VADDPD 4096(DX), Y0, Y29 // 6261fd2858aa00100000 + VADDPD 4096(DX), Y29, Y1 // 62f19520588a00100000 + VADDPD 4096(DX), Y28, Y29 // 62619d2058aa00100000 + VADDPD 4096(DX)(AX*2), Y0, Y29 // 6261fd2858ac4200100000 + VADDPD 4096(DX)(AX*2), Y29, Y1 // 62f19520588c4200100000 + VADDPD 8192(DX), Z0, Z29 // 6261fd4858aa00200000 + VADDPD 8192(DX), Z29, Z1 // 62f19540588a00200000 + VADDPD 8192(DX), Z28, Z29 // 62619d4058aa00200000 + VADDPD 8192(DX)(AX*2), Z0, Z29 // 6261fd4858ac4200200000 + VADDPD 8192(DX)(AX*2), Z29, Z1 // 62f19540588c4200200000 + // EVEX: Y registers; VL=256. + VADDPD Y30, Y1, Y0 // 6291f52858c6 + VADDPD Y0, Y29, Y2 // 62f1952058d0 + VADDPD Y0, Y29, Y30 // 6261952058f0 + VADDPD Y28, Y1, Y2 // 6291f52858d4 + VADDPD Y28, Y1, Y30 // 6201f52858f4 + VADDPD Y28, Y29, Y2 // 6291952058d4 + VADDPD Y28, Y29, Y30 // 6201952058f4 + VADDPD Y10, Y11, Y30 // 6241a52858f2 + VADDPD Y10, Y29, Y12 // 6251952058e2 + VADDPD Y10, Y29, Y30 // 6241952058f2 + VADDPD Y28, Y11, Y12 // 6211a52858e4 + VADDPD Y28, Y11, Y30 // 6201a52858f4 + VADDPD Y28, Y29, Y12 // 6211952058e4 + VADDPD Y28, Y29, Y30 // 6201952058f4 + VADDPD (AX), Y29, Y0 // 62f195205800 + VADDPD (AX), Y1, Y28 // 6261f5285820 + VADDPD (AX), Y29, Y28 // 626195205820 + VADDPD (AX), Y29, Y10 // 627195205810 + VADDPD (AX), Y10, Y28 // 6261ad285820 + VADDPD (CX)(AX*1), Y29, Y0 // 62f19520580401 + VADDPD (CX)(AX*1), Y1, Y28 // 6261f528582401 + VADDPD (CX)(AX*1), Y29, Y28 // 62619520582401 + VADDPD (CX)(AX*1), Y29, Y10 // 62719520581401 + VADDPD (CX)(AX*1), Y10, Y28 // 6261ad28582401 + VADDPD (CX)(AX*2), Y29, Y0 // 62f19520580441 + VADDPD (CX)(AX*2), Y1, Y28 // 6261f528582441 + VADDPD (CX)(AX*2), Y29, Y28 // 62619520582441 + VADDPD (CX)(AX*2), Y29, Y10 // 62719520581441 + VADDPD (CX)(AX*2), Y10, Y28 // 6261ad28582441 + VADDPD 15(AX), Y0, Y29 // 6261fd2858a80f000000 + VADDPD 15(AX), Y28, Y1 // 62f19d2058880f000000 + VADDPD 15(AX), Y28, Y29 // 62619d2058a80f000000 + VADDPD 15(AX), Y10, Y29 // 6261ad2858a80f000000 + VADDPD 15(AX), Y28, Y10 // 62719d2058900f000000 + VADDPD 15(CX)(AX*1), Y0, Y29 // 6261fd2858ac010f000000 + VADDPD 15(CX)(AX*1), Y28, Y1 // 62f19d20588c010f000000 + VADDPD 15(CX)(AX*1), Y28, Y29 // 62619d2058ac010f000000 + VADDPD 15(CX)(AX*1), Y10, Y29 // 6261ad2858ac010f000000 + VADDPD 15(CX)(AX*1), Y28, Y10 // 62719d205894010f000000 + VADDPD 15(CX)(AX*2), Y0, Y29 // 6261fd2858ac410f000000 + VADDPD 15(CX)(AX*2), Y28, Y1 // 62f19d20588c410f000000 + VADDPD 15(CX)(AX*2), Y28, Y29 // 62619d2058ac410f000000 + VADDPD 15(CX)(AX*2), Y10, Y29 // 6261ad2858ac410f000000 + VADDPD 15(CX)(AX*2), Y28, Y10 // 62719d205894410f000000 + VADDPD 2048(DX), Y0, Y29 // 6261fd28586a40 + VADDPD 2048(DX), Y29, Y1 // 62f19520584a40 + VADDPD 2048(DX), Y28, Y29 // 62619d20586a40 + VADDPD 2048(DX)(AX*2), Y0, Y29 // 6261fd28586c4240 + VADDPD 2048(DX)(AX*2), Y29, Y1 // 62f19520584c4240 + VADDPD 2048(DX)(AX*2), Y28, Y29 // 62619d20586c4240 + // EVEX: Z registers; VL=512. + VADDPD Z30, Z0, Z1 // 6291fd4858ce + VADDPD Z0, Z2, Z29 // 6261ed4858e8 + VADDPD Z0, Z30, Z29 // 62618d4058e8 + VADDPD Z28, Z2, Z1 // 6291ed4858cc + VADDPD Z28, Z30, Z1 // 62918d4058cc + VADDPD Z28, Z2, Z29 // 6201ed4858ec + VADDPD Z28, Z30, Z29 // 62018d4058ec + VADDPD Z10, Z30, Z11 // 62518d4058da + VADDPD Z10, Z12, Z29 // 62419d4858ea + VADDPD Z10, Z30, Z29 // 62418d4058ea + VADDPD Z28, Z12, Z11 // 62119d4858dc + VADDPD Z28, Z30, Z11 // 62118d4058dc + VADDPD Z28, Z12, Z29 // 62019d4858ec + VADDPD Z28, Z30, Z29 // 62018d4058ec + VADDPD (AX), Z0, Z29 // 6261fd485828 + VADDPD (AX), Z28, Z1 // 62f19d405808 + VADDPD (AX), Z28, Z29 // 62619d405828 + VADDPD (AX), Z10, Z29 // 6261ad485828 + VADDPD (AX), Z28, Z10 // 62719d405810 + VADDPD (CX)(AX*1), Z0, Z29 // 6261fd48582c01 + VADDPD (CX)(AX*1), Z28, Z1 // 62f19d40580c01 + VADDPD (CX)(AX*1), Z28, Z29 // 62619d40582c01 + VADDPD (CX)(AX*1), Z10, Z29 // 6261ad48582c01 + VADDPD (CX)(AX*1), Z28, Z10 // 62719d40581401 + VADDPD (CX)(AX*2), Z0, Z29 // 6261fd48582c41 + VADDPD (CX)(AX*2), Z28, Z1 // 62f19d40580c41 + VADDPD (CX)(AX*2), Z28, Z29 // 62619d40582c41 + VADDPD (CX)(AX*2), Z10, Z29 // 6261ad48582c41 + VADDPD (CX)(AX*2), Z28, Z10 // 62719d40581441 + VADDPD 15(AX), Z29, Z0 // 62f1954058800f000000 + VADDPD 15(AX), Z1, Z28 // 6261f54858a00f000000 + VADDPD 15(AX), Z29, Z28 // 6261954058a00f000000 + VADDPD 15(AX), Z29, Z10 // 6271954058900f000000 + VADDPD 15(AX), Z10, Z28 // 6261ad4858a00f000000 + VADDPD 15(CX)(AX*1), Z29, Z0 // 62f195405884010f000000 + VADDPD 15(CX)(AX*1), Z1, Z28 // 6261f54858a4010f000000 + VADDPD 15(CX)(AX*1), Z29, Z28 // 6261954058a4010f000000 + VADDPD 15(CX)(AX*1), Z29, Z10 // 627195405894010f000000 + VADDPD 15(CX)(AX*1), Z10, Z28 // 6261ad4858a4010f000000 + VADDPD 15(CX)(AX*2), Z29, Z0 // 62f195405884410f000000 + VADDPD 15(CX)(AX*2), Z1, Z28 // 6261f54858a4410f000000 + VADDPD 15(CX)(AX*2), Z29, Z28 // 6261954058a4410f000000 + VADDPD 15(CX)(AX*2), Z29, Z10 // 627195405894410f000000 + VADDPD 15(CX)(AX*2), Z10, Z28 // 6261ad4858a4410f000000 + VADDPD 2048(DX), Z29, Z0 // 62f19540584220 + VADDPD 2048(DX), Z1, Z29 // 6261f548586a20 + VADDPD 2048(DX), Z29, Z28 // 62619540586220 + VADDPD 2048(DX)(AX*2), Z29, Z0 // 62f1954058444220 + VADDPD 2048(DX)(AX*2), Z1, Z29 // 6261f548586c4220 + VADDPD 2048(DX)(AX*2), Z29, Z28 // 6261954058644220 + // EVEX: KOP (opmask) instructions. + KMOVB K0, K0 // c5f990c0 + KMOVB K7, K7 // c5f990ff + KMOVB K5, K1 // c5f990cd + KMOVB K1, K5 // c5f990e9 + KMOVB (AX), K1 // c5f99008 + KMOVB K0, (AX) // c5f99100 + KMOVB K7, (R10) // c4c179913a + KMOVB K5, AX // c5f993c5 + KMOVB K7, R10 // c57993d7 + KMOVB AX, K5 // c5f992e8 + KMOVB R10, K7 // c4c17992fa + KMOVW K0, K0 // c5f890c0 + KMOVW K7, K7 // c5f890ff + KMOVW K5, K1 // c5f890cd + KMOVW K1, K5 // c5f890e9 + KMOVW (AX), K1 // c5f89008 + KMOVW K0, (AX) // c5f89100 + KMOVW K7, (R10) // c4c178913a + KMOVW K5, AX // c5f893c5 + KMOVW K7, R10 // c57893d7 + KMOVW AX, K5 // c5f892e8 + KMOVW R10, K7 // c4c17892fa + KMOVD K0, K0 // c4e1f990c0 + KMOVD K7, K7 // c4e1f990ff + KMOVD K5, K1 // c4e1f990cd + KMOVD K1, K5 // c4e1f990e9 + KMOVD (AX), K1 // c4e1f99008 + KMOVD AX, K5 // c5fb92e8 + KMOVD R10, K7 // c4c17b92fa + KMOVD K0, (AX) // c4e1f99100 + KMOVD K7, (R10) // c4c1f9913a + KMOVD K5, AX // c5fb93c5 + KMOVD K7, R10 // c57b93d7 + KMOVQ K0, K0 // c4e1f890c0 + KMOVQ K7, K7 // c4e1f890ff + KMOVQ K5, K1 // c4e1f890cd + KMOVQ K1, K5 // c4e1f890e9 + KMOVQ (AX), K1 // c4e1f89008 + KMOVQ AX, K5 // c4e1fb92e8 + KMOVQ R10, K7 // c4c1fb92fa + KMOVQ K0, (AX) // c4e1f89100 + KMOVQ K7, (R10) // c4c1f8913a + KMOVQ K5, AX // c4e1fb93c5 + KMOVQ K7, R10 // c461fb93d7 + KNOTB K7, K0 // c5f944c7 + KNOTB K1, K5 // c5f944e9 + KNOTW K7, K0 // c5f844c7 + KNOTW K1, K5 // c5f844e9 + KNOTD K7, K0 // c4e1f944c7 + KNOTD K1, K5 // c4e1f944e9 + KNOTQ K7, K0 // c4e1f844c7 + KNOTQ K1, K5 // c4e1f844e9 + KORB K7, K5, K0 // c5d545c7 + KORB K0, K7, K5 // c5c545e8 + KORW K7, K5, K0 // c5d445c7 + KORW K0, K7, K5 // c5c445e8 + KORD K7, K5, K0 // c4e1d545c7 + KORD K0, K7, K5 // c4e1c545e8 + KORQ K7, K5, K0 // c4e1d445c7 + KORQ K0, K7, K5 // c4e1c445e8 + KSHIFTLB $0, K7, K0 // c4e37932c700 + KSHIFTLB $196, K1, K5 // c4e37932e9c4 + KSHIFTLW $0, K7, K0 // c4e3f932c700 + KSHIFTLW $196, K1, K5 // c4e3f932e9c4 + KSHIFTLD $0, K7, K0 // c4e37933c700 + KSHIFTLD $196, K1, K5 // c4e37933e9c4 + KSHIFTLQ $0, K7, K0 // c4e3f933c700 + KSHIFTLQ $196, K1, K5 // c4e3f933e9c4 + // EVEX: masking with K1-K7. + VADDPD X2, X1, K1, X0 // 62f1f50958c2 + VADDPD X12, X1, K4, X10 // 6251f50c58d4 + VADDPD X22, X1, K7, X20 // 62a1f50f58e6 + VADDPD (AX), X1, K1, X1 // 62f1f5095808 + VADDPD 8(R10), X10, K4, X10 // 6251ad0c589208000000 + VADDPD (R10)(AX*4), X20, K7, X20 // 62c1dd07582482 + VADDPD Y2, Y1, K1, Y0 // 62f1f52958c2 + VADDPD Y12, Y1, K4, Y10 // 6251f52c58d4 + VADDPD Y22, Y1, K7, Y20 // 62a1f52f58e6 + VADDPD (AX), Y1, K1, Y1 // 62f1f5295808 + VADDPD 8(R10), Y10, K4, Y10 // 6251ad2c589208000000 + VADDPD (R10)(AX*4), Y20, K7, Y20 // 62c1dd27582482 + VADDPD Z2, Z1, K1, Z0 // 62f1f54958c2 + VADDPD Z12, Z1, K4, Z10 // 6251f54c58d4 + VADDPD Z22, Z1, K7, Z20 // 62a1f54f58e6 + VADDPD (AX), Z1, K1, Z1 // 62f1f5495808 + VADDPD 8(R10), Z10, K4, Z10 // 6251ad4c589208000000 + VADDPD (R10)(AX*4), Z20, K7, Z20 // 62c1dd47582482 + // EVEX gather (also tests Z as VSIB index). + VPGATHERDD 360(AX)(X2*4), K1, X1 // 62f27d09904c905a + VPGATHERDD 640(BP)(X15*8), K3, X14 // 62327d0b90b4fd80020000 + VPGATHERDD 960(R10)(X25*2), K7, X24 // 62027d0790844ac0030000 + VPGATHERDD 1280(R10)(X1*4), K4, X0 // 62d27d0c90848a00050000 + VPGATHERDD 360(AX)(Y2*4), K1, Y1 // 62f27d29904c905a + VPGATHERDD 640(BP)(Y15*8), K3, Y14 // 62327d2b90b4fd80020000 + VPGATHERDD 960(R10)(Y25*2), K7, Y24 // 62027d2790844ac0030000 + VPGATHERDD 1280(R10)(Y1*4), K4, Y0 // 62d27d2c90848a00050000 + VPGATHERDD 360(AX)(Z2*4), K1, Z1 // 62f27d49904c905a + VPGATHERDD 640(BP)(Z15*8), K3, Z14 // 62327d4b90b4fd80020000 + VPGATHERDD 960(R10)(Z25*2), K7, Z24 // 62027d4790844ac0030000 + VPGATHERDD 1280(R10)(Z1*4), K4, Z0 // 62d27d4c90848a00050000 + VPGATHERDQ 360(AX)(X2*4), K1, X1 // 62f2fd09904c902d + VPGATHERDQ 640(BP)(X15*8), K3, X14 // 6232fd0b9074fd50 + VPGATHERDQ 960(R10)(X25*2), K7, X24 // 6202fd0790444a78 + VPGATHERDQ 1280(R10)(X1*4), K4, X0 // 62d2fd0c90848a00050000 + VPGATHERDQ 360(AX)(X2*4), K1, Y1 // 62f2fd29904c902d + VPGATHERDQ 640(BP)(X15*8), K3, Y14 // 6232fd2b9074fd50 + VPGATHERDQ 960(R10)(X25*2), K7, Y24 // 6202fd2790444a78 + VPGATHERDQ 1280(R10)(X1*4), K4, Y0 // 62d2fd2c90848a00050000 + VPGATHERDQ 360(AX)(Y2*4), K1, Z1 // 62f2fd49904c902d + VPGATHERDQ 640(BP)(Y15*8), K3, Z14 // 6232fd4b9074fd50 + VPGATHERDQ 960(R10)(Y25*2), K7, Z24 // 6202fd4790444a78 + VPGATHERDQ 1280(R10)(Y1*4), K4, Z0 // 62d2fd4c90848a00050000 + VGATHERDPD 360(R15)(X30*2), K6, X20 // 6282fd069264772d + VGATHERDPD 640(R15)(X20*2), K6, X10 // 6252fd0692546750 + VGATHERDPD 960(R15)(X10*2), K6, X20 // 6282fd0e92645778 + VGATHERDPD 1280(R15)(X0*2), K6, X10 // 6252fd0e92944700050000 + VGATHERDPD 360(R15)(X30*2), K6, Y20 // 6282fd269264772d + VGATHERDPD 640(R15)(X20*2), K6, Y10 // 6252fd2692546750 + VGATHERDPD 960(R15)(X10*2), K6, Y20 // 6282fd2e92645778 + VGATHERDPD 1280(R15)(X0*2), K6, Y10 // 6252fd2e92944700050000 + VGATHERDPD 360(R15)(Y30*2), K6, Z20 // 6282fd469264772d + VGATHERDPD 640(R15)(Y20*2), K6, Z10 // 6252fd4692546750 + VGATHERDPD 960(R15)(Y10*2), K6, Z20 // 6282fd4e92645778 + VGATHERDPD 1280(R15)(Y0*2), K6, Z10 // 6252fd4e92944700050000 + VGATHERDPS 360(R15)(X30*2), K6, X20 // 62827d069264775a + VGATHERDPS 640(R15)(X20*2), K6, X10 // 62527d0692946780020000 + VGATHERDPS 960(R15)(X10*2), K6, X20 // 62827d0e92a457c0030000 + VGATHERDPS 1280(R15)(X0*2), K6, X10 // 62527d0e92944700050000 + VGATHERDPS 360(R15)(Y30*2), K6, Y20 // 62827d269264775a + VGATHERDPS 640(R15)(Y20*2), K6, Y10 // 62527d2692946780020000 + VGATHERDPS 960(R15)(Y10*2), K6, Y20 // 62827d2e92a457c0030000 + VGATHERDPS 1280(R15)(Y0*2), K6, Y10 // 62527d2e92944700050000 + VGATHERDPS 360(R15)(Z30*2), K6, Z20 // 62827d469264775a + VGATHERDPS 640(R15)(Z20*2), K6, Z10 // 62527d4692946780020000 + VGATHERDPS 960(R15)(Z10*2), K6, Z20 // 62827d4e92a457c0030000 + VGATHERDPS 1280(R15)(Z0*2), K6, Z10 // 62527d4e92944700050000 + VGATHERQPS 360(R15)(X30*2), K6, X20 // 62827d069364775a + VGATHERQPS 640(R15)(X20*2), K6, X10 // 62527d0693946780020000 + VGATHERQPS 960(R15)(X10*2), K6, X20 // 62827d0e93a457c0030000 + VGATHERQPS 1280(R15)(X0*2), K6, X10 // 62527d0e93944700050000 + VGATHERQPS 360(R15)(Y30*2), K6, X20 // 62827d269364775a + VGATHERQPS 640(R15)(Y20*2), K6, X10 // 62527d2693946780020000 + VGATHERQPS 960(R15)(Y10*2), K6, X20 // 62827d2e93a457c0030000 + VGATHERQPS 1280(R15)(Y0*2), K6, X10 // 62527d2e93944700050000 + VGATHERQPS 360(R15)(Z30*2), K6, Y20 // 62827d469364775a + VGATHERQPS 640(R15)(Z20*2), K6, Y10 // 62527d4693946780020000 + VGATHERQPS 960(R15)(Z10*2), K6, Y20 // 62827d4e93a457c0030000 + VGATHERQPS 1280(R15)(Z0*2), K6, Y10 // 62527d4e93944700050000 + VPGATHERQD 360(R15)(X30*2), K6, X20 // 62827d069164775a + VPGATHERQD 640(R15)(X20*2), K6, X10 // 62527d0691946780020000 + VPGATHERQD 960(R15)(X10*2), K6, X20 // 62827d0e91a457c0030000 + VPGATHERQD 1280(R15)(X0*2), K6, X10 // 62527d0e91944700050000 + VPGATHERQD 360(R15)(Y30*2), K6, X20 // 62827d269164775a + VPGATHERQD 640(R15)(Y20*2), K6, X10 // 62527d2691946780020000 + VPGATHERQD 960(R15)(Y10*2), K6, X20 // 62827d2e91a457c0030000 + VPGATHERQD 1280(R15)(Y0*2), K6, X10 // 62527d2e91944700050000 + VPGATHERQD 360(R15)(Z30*2), K6, Y20 // 62827d469164775a + VPGATHERQD 640(R15)(Z20*2), K6, Y10 // 62527d4691946780020000 + VPGATHERQD 960(R15)(Z10*2), K6, Y20 // 62827d4e91a457c0030000 + VPGATHERQD 1280(R15)(Z0*2), K6, Y10 // 62527d4e91944700050000 + VPGATHERQQ 360(R15)(X30*2), K6, X20 // 6282fd069164772d + VPGATHERQQ 640(R15)(X20*2), K6, X10 // 6252fd0691546750 + VPGATHERQQ 960(R15)(X10*2), K6, X20 // 6282fd0e91645778 + VPGATHERQQ 1280(R15)(X0*2), K6, X10 // 6252fd0e91944700050000 + VPGATHERQQ 360(R15)(Y30*2), K6, Y20 // 6282fd269164772d + VPGATHERQQ 640(R15)(Y20*2), K6, Y10 // 6252fd2691546750 + VPGATHERQQ 960(R15)(Y10*2), K6, Y20 // 6282fd2e91645778 + VPGATHERQQ 1280(R15)(Y0*2), K6, Y10 // 6252fd2e91944700050000 + VPGATHERQQ 360(R15)(Z30*2), K6, Z20 // 6282fd469164772d + VPGATHERQQ 640(R15)(Z20*2), K6, Z10 // 6252fd4691546750 + VPGATHERQQ 960(R15)(Z10*2), K6, Z20 // 6282fd4e91645778 + VPGATHERQQ 1280(R15)(Z0*2), K6, Z10 // 6252fd4e91944700050000 + VGATHERQPD 360(R15)(X30*2), K6, X20 // 6282fd069364772d + VGATHERQPD 640(R15)(X20*2), K6, X10 // 6252fd0693546750 + VGATHERQPD 960(R15)(X10*2), K6, X20 // 6282fd0e93645778 + VGATHERQPD 1280(R15)(X0*2), K6, X10 // 6252fd0e93944700050000 + VGATHERQPD 360(R15)(Y30*2), K6, Y20 // 6282fd269364772d + VGATHERQPD 640(R15)(Y20*2), K6, Y10 // 6252fd2693546750 + VGATHERQPD 960(R15)(Y10*2), K6, Y20 // 6282fd2e93645778 + VGATHERQPD 1280(R15)(Y0*2), K6, Y10 // 6252fd2e93944700050000 + VGATHERQPD 360(R15)(Z30*2), K6, Z20 // 6282fd469364772d + VGATHERQPD 640(R15)(Z20*2), K6, Z10 // 6252fd4693546750 + VGATHERQPD 960(R15)(Z10*2), K6, Z20 // 6282fd4e93645778 + VGATHERQPD 1280(R15)(Z0*2), K6, Z10 // 6252fd4e93944700050000 + // EVEX: corner cases for High-16 registers. + VADDPD X31, X16, X15 // 6211fd0058ff + VADDPD X23, X15, X16 // 62a1850858c7 + VADDPD Y31, Y16, Y15 // 6211fd2058ff + VADDPD Y23, Y15, Y16 // 62a1852858c7 + VADDPD Z31, Z16, Z15 // 6211fd4058ff + VADDPD Z23, Z15, Z16 // 62a1854858c7 + VGATHERQPD (DX)(X16*1),K1,X31 // 6262fd01933c02 + VGATHERQPD (DX)(X31*1),K1,X16 // 62a2fd0193043a + VGATHERQPD (DX)(X15*1),K1,X23 // 62a2fd09933c3a + VGATHERQPD (DX)(X23*1),K1,X15 // 6272fd01933c3a + VGATHERQPD (DX)(Y16*1),K1,Y31 // 6262fd21933c02 + VGATHERQPD (DX)(Y31*1),K1,Y16 // 62a2fd2193043a + VGATHERQPD (DX)(Y15*1),K1,Y23 // 62a2fd29933c3a + VGATHERQPD (DX)(Y23*1),K1,Y15 // 6272fd21933c3a + VGATHERQPD (DX)(Z16*1),K1,Z31 // 6262fd41933c02 + VGATHERQPD (DX)(Z31*1),K1,Z16 // 62a2fd4193043a + VGATHERQPD (DX)(Z15*1),K1,Z23 // 62a2fd49933c3a + VGATHERQPD (DX)(Z23*1),K1,Z15 // 6272fd41933c3a + // EVEX: VCVTPD2DQ with Y suffix (VL=2). + VCVTPD2DQY (BX), X20 // 62e1ff28e623 + VCVTPD2DQY (R11), X30 // 6241ff28e633 + // XED encoder uses EVEX.X=0 for these; most x86 tools use EVEX.X=1. + // Either way is OK. + VMOVQ SP, X20 // 62e1fd086ee4 or 62a1fd086ee4 + VMOVQ BP, X20 // 62e1fd086ee5 or 62a1fd086ee5 + VMOVQ R14, X20 // 62c1fd086ee6 or 6281fd086ee6 + // "VMOVQ r/m64, xmm1"/6E vs "VMOVQ xmm2/m64, xmm1"/7E with mem operand. + VMOVQ (AX), X20 // 62e1fd086e20 or 62e1fe087e20 + VMOVQ 7(DX), X20 // 62e1fd086ea207000000 or 62e1fe087ea207000000 + VMOVQ -15(R11)(CX*1), X20 // 62c1fd086ea40bf1ffffff or 62c1fe087ea40bf1ffffff + VMOVQ (SP)(AX*2), X20 // 62e1fd086e2444 or 62e1fe087e2444 + // "VMOVQ xmm1, r/m64"/7E vs "VMOVQ xmm1, xmm2/m64"/D6 with mem operand. + VMOVQ X20, (AX) // 62e1fd087e20 or 62e1fd08d620 + VMOVQ X20, 7(DX) // 62e1fd087ea207000000 or 62e1fd08d6a207000000 + VMOVQ X20, -15(R11)(CX*1) // 62c1fd087ea40bf1ffffff or 62c1fd08d6a40bf1ffffff + VMOVQ X20, (SP)(AX*2) // 62e1fd087e2444 or 62e1fd08d62444 + // VMOVHPD: overlapping VEX and EVEX variants. + VMOVHPD (AX), X5, X5 // c5d11628 or c4e1d11628 or 62f1d5281628 or 62f1d5481628 + VMOVHPD 7(DX), X5, X5 // c5d1166a07 or 62f1d52816aa07000000 or 62f1d54816aa07000000 + VMOVHPD -15(R11)(CX*1), X5, X5 // c4c151166c0bf1 or 62d1d52816ac0bf1ffffff or 62d1d54816ac0bf1ffffff + VMOVHPD (SP)(AX*2), X5, X5 // c5d1162c44 or c4e1d1162c44 or 62f1d528162c44 or 62f1d548162c44 + VMOVHPD (AX), X8, X5 // c5b91628 or c4e1b91628 or 62f1bd281628 or 62f1bd481628 + VMOVHPD 7(DX), X8, X5 // c5b9166a07 or 62f1bd2816aa07000000 or 62f1bd4816aa07000000 + VMOVHPD -15(R11)(CX*1), X8, X5 // c4c139166c0bf1 or 62d1bd4816ac0bf1ffffff + VMOVHPD (SP)(AX*2), X8, X5 // c5b9162c44 or c4e1b9162c44 or 62f1bd28162c44 or 62f1bd48162c44 + VMOVHPD (AX), X20, X5 // 62f1dd001628 or 62f1dd201628 or 62f1dd401628 + VMOVHPD 7(DX), X20, X5 // 62f1dd0016aa07000000 or 62f1dd2016aa07000000 or 62f1dd4016aa07000000 + VMOVHPD -15(R11)(CX*1), X20, X5 // 62d1dd0016ac0bf1ffffff or 62d1dd2016ac0bf1ffffff or 62d1dd4016ac0bf1ffffff + VMOVHPD (SP)(AX*2), X20, X5 // 62f1dd00162c44 or 62f1dd20162c44 or 62f1dd40162c44 + VMOVHPD (AX), X5, X8 // c5511600 or c461d11600 or 6271d5281600 or 6271d5481600 + VMOVHPD 7(DX), X5, X8 // c551164207 or 6271d528168207000000 or 6271d548168207000000 + VMOVHPD -15(R11)(CX*1), X5, X8 // c4415116440bf1 or 6251d52816840bf1ffffff or 6251d54816840bf1ffffff + VMOVHPD (SP)(AX*2), X5, X8 // c551160444 or 6271d528160444 or 6271d548160444 + VMOVHPD (AX), X8, X8 // c5391600 or 6271bd281600 or 6271bd481600 + VMOVHPD 7(DX), X8, X8 // c539164207 or 6271bd28168207000000 or 6271bd48168207000000 + VMOVHPD -15(R11)(CX*1), X8, X8 // c4413916440bf1 or 6251bd2816840bf1ffffff or 6251bd4816840bf1ffffff + VMOVHPD (SP)(AX*2), X8, X8 // c539160444 or 6271bd28160444 or 6271bd48160444 + VMOVHPD (AX), X20, X8 // 6271dd001600 or 6271dd201600 or 6271dd401600 + VMOVHPD 7(DX), X20, X8 // 6271dd00168207000000 or 6271dd20168207000000 or 6271dd40168207000000 + VMOVHPD -15(R11)(CX*1), X20, X8 // 6251dd0016840bf1ffffff or 6251dd2016840bf1ffffff or 6251dd4016840bf1ffffff + VMOVHPD (SP)(AX*2), X20, X8 // 6271dd00160444 or 6271dd20160444 or 6271dd40160444 + VMOVHPD (AX), X5, X20 // 62e1d5081620 or 62e1d5281620 or 62e1d5481620 + VMOVHPD 7(DX), X5, X20 // 62e1d50816a207000000 or 62e1d52816a207000000 or 62e1d54816a207000000 + VMOVHPD -15(R11)(CX*1), X5, X20 // 62c1d50816a40bf1ffffff or 62c1d52816a40bf1ffffff or 62c1d54816a40bf1ffffff + VMOVHPD (SP)(AX*2), X5, X20 // 62e1d508162444 or 62e1d528162444 or 62e1d548162444 + VMOVHPD (AX), X8, X20 // 62e1bd081620 or 62e1bd281620 or 62e1bd481620 + VMOVHPD 7(DX), X8, X20 // 62e1bd0816a207000000 or 62e1bd2816a207000000 or 62e1bd4816a207000000 + VMOVHPD -15(R11)(CX*1), X8, X20 // 62c1bd0816a40bf1ffffff or 62c1bd2816a40bf1ffffff or 62c1bd4816a40bf1ffffff + VMOVHPD (SP)(AX*2), X8, X20 // 62e1bd08162444 or 62e1bd28162444 or 62e1bd48162444 + VMOVHPD (AX), X20, X20 // 62e1dd001620 or 62e1dd201620 or 62e1dd401620 + VMOVHPD 7(DX), X20, X20 // 62e1dd0016a207000000 or 62e1dd2016a207000000 or 62e1dd4016a207000000 + VMOVHPD -15(R11)(CX*1), X20, X20 // 62c1dd0016a40bf1ffffff or 62c1dd2016a40bf1ffffff or 62c1dd4016a40bf1ffffff + VMOVHPD (SP)(AX*2), X20, X20 // 62e1dd00162444 or 62e1dd20162444 or 62e1dd40162444 + VMOVHPD X5, (AX) // c5f91728 or 62f1fd281728 or 62f1fd481728 + VMOVHPD X8, (AX) // c5791700 or 6271fd281700 or 6271fd481700 + VMOVHPD X20, (AX) // 62e1fd081720 or 62e1fd281720 or 62e1fd481720 + VMOVHPD X5, 7(DX) // c5f9176a07 or 62f1fd2817aa07000000 or 62f1fd4817aa07000000 + VMOVHPD X8, 7(DX) // c579174207 or 6271fd28178207000000 or 6271fd48178207000000 + VMOVHPD X20, 7(DX) // 62e1fd0817a207000000 or 62e1fd2817a207000000 or 62e1fd4817a207000000 + VMOVHPD X5, -15(R11)(CX*1) // c4c179176c0bf1 or 62d1fd2817ac0bf1ffffff or 62d1fd4817ac0bf1ffffff + VMOVHPD X8, -15(R11)(CX*1) // c4417917440bf1 or 6251fd2817840bf1ffffff or 6251fd4817840bf1ffffff + VMOVHPD X20, -15(R11)(CX*1) // 62c1fd0817a40bf1ffffff or 62c1fd2817a40bf1ffffff or 62c1fd4817a40bf1ffffff + VMOVHPD X5, (SP)(AX*2) // c5f9172c44 or 62f1fd28172c44 or 62f1fd48172c44 + VMOVHPD X8, (SP)(AX*2) // c579170444 or 6271fd28170444 or 6271fd48170444 + VMOVHPD X20, (SP)(AX*2) // 62e1fd08172444 or 62e1fd28172444 or 62e1fd48172444 + // VMOVLPD: overlapping VEX and EVEX variants. + VMOVLPD (AX), X5, X5 // c5d11228 or 62f1d5281228 or 62f1d5481228 + VMOVLPD 7(DX), X5, X5 // c5d1126a07 or 62f1d52812aa07000000 or 62f1d54812aa07000000 + VMOVLPD -15(R11)(CX*1), X5, X5 // c4c151126c0bf1 or 62d1d52812ac0bf1ffffff or 62d1d54812ac0bf1ffffff + VMOVLPD (SP)(AX*2), X5, X5 // c5d1122c44 or 62f1d528122c44 or 62f1d548122c44 + VMOVLPD (AX), X8, X5 // c5b91228 or 62f1bd281228 or 62f1bd481228 + VMOVLPD 7(DX), X8, X5 // c5b9126a07 or 62f1bd2812aa07000000 or 62f1bd4812aa07000000 + VMOVLPD -15(R11)(CX*1), X8, X5 // c4c139126c0bf1 or 62d1bd2812ac0bf1ffffff or 62d1bd4812ac0bf1ffffff + VMOVLPD (SP)(AX*2), X8, X5 // c5b9122c44 or 62f1bd28122c44 or 62f1bd48122c44 + VMOVLPD (AX), X20, X5 // 62f1dd001228 or 62f1dd201228 or 62f1dd401228 + VMOVLPD 7(DX), X20, X5 // 62f1dd0012aa07000000 or 62f1dd2012aa07000000 or 62f1dd4012aa07000000 + VMOVLPD -15(R11)(CX*1), X20, X5 // 62d1dd0012ac0bf1ffffff or 62d1dd2012ac0bf1ffffff or 62d1dd4012ac0bf1ffffff + VMOVLPD (SP)(AX*2), X20, X5 // 62f1dd00122c44 or 62f1dd20122c44 or 62f1dd40122c44 + VMOVLPD (AX), X5, X8 // c5511200 or 6271d5281200 or 6271d5481200 + VMOVLPD 7(DX), X5, X8 // c551124207 or 6271d528128207000000 or 6271d548128207000000 + VMOVLPD -15(R11)(CX*1), X5, X8 // c4415112440bf1 or 6251d52812840bf1ffffff or 6251d54812840bf1ffffff + VMOVLPD (SP)(AX*2), X5, X8 // c551120444 or 6271d528120444 or 6271d548120444 + VMOVLPD (AX), X8, X8 // c5391200 or 6271bd281200 or 6271bd481200 + VMOVLPD 7(DX), X8, X8 // c539124207 or 6271bd28128207000000 or 6271bd48128207000000 + VMOVLPD -15(R11)(CX*1), X8, X8 // c4413912440bf1 or 6251bd2812840bf1ffffff or 6251bd4812840bf1ffffff + VMOVLPD (SP)(AX*2), X8, X8 // c539120444 or 6271bd28120444 or 6271bd48120444 + VMOVLPD (AX), X20, X8 // 6271dd001200 or 6271dd201200 or 6271dd401200 + VMOVLPD 7(DX), X20, X8 // 6271dd00128207000000 or 6271dd20128207000000 or 6271dd40128207000000 + VMOVLPD -15(R11)(CX*1), X20, X8 // 6251dd0012840bf1ffffff or 6251dd2012840bf1ffffff or 6251dd4012840bf1ffffff + VMOVLPD (SP)(AX*2), X20, X8 // 6271dd00120444 or 6271dd20120444 or 6271dd40120444 + VMOVLPD (AX), X5, X20 // 62e1d5081220 or 62e1d5281220 or 62e1d5481220 + VMOVLPD 7(DX), X5, X20 // 62e1d50812a207000000 or 62e1d52812a207000000 or 62e1d54812a207000000 + VMOVLPD -15(R11)(CX*1), X5, X20 // 62c1d50812a40bf1ffffff or 62c1d52812a40bf1ffffff or 62c1d54812a40bf1ffffff + VMOVLPD (SP)(AX*2), X5, X20 // 62e1d508122444 or 62e1d528122444 or 62e1d548122444 + VMOVLPD (AX), X8, X20 // 62e1bd081220 or 62e1bd281220 or 62e1bd481220 + VMOVLPD 7(DX), X8, X20 // 62e1bd0812a207000000 or 62e1bd2812a207000000 or 62e1bd4812a207000000 + VMOVLPD -15(R11)(CX*1), X8, X20 // 62c1bd0812a40bf1ffffff or 62c1bd2812a40bf1ffffff or 62c1bd4812a40bf1ffffff + VMOVLPD (SP)(AX*2), X8, X20 // 62e1bd08122444 or 62e1bd28122444 or 62e1bd48122444 + VMOVLPD (AX), X20, X20 // 62e1dd001220 or 62e1dd201220 or 62e1dd401220 + VMOVLPD 7(DX), X20, X20 // 62e1dd0012a207000000 or 62e1dd2012a207000000 or 62e1dd4012a207000000 + VMOVLPD -15(R11)(CX*1), X20, X20 // 62c1dd0012a40bf1ffffff or 62c1dd2012a40bf1ffffff or 62c1dd4012a40bf1ffffff + VMOVLPD (SP)(AX*2), X20, X20 // 62e1dd00122444 or 62e1dd20122444 or 62e1dd40122444 + VMOVLPD X5, (AX) // c5f91328 or 62f1fd281328 or 62f1fd481328 + VMOVLPD X8, (AX) // c5791300 or 6271fd281300 or 6271fd481300 + VMOVLPD X20, (AX) // 62e1fd081320 or 62e1fd281320 or 62e1fd481320 + VMOVLPD X5, 7(DX) // c5f9136a07 or 62f1fd2813aa07000000 or 62f1fd4813aa07000000 + VMOVLPD X8, 7(DX) // c579134207 or 6271fd28138207000000 or 6271fd48138207000000 + VMOVLPD X20, 7(DX) // 62e1fd0813a207000000 or 62e1fd2813a207000000 or 62e1fd4813a207000000 + VMOVLPD X5, -15(R11)(CX*1) // c4c179136c0bf1 or 62d1fd2813ac0bf1ffffff or 62d1fd4813ac0bf1ffffff + VMOVLPD X8, -15(R11)(CX*1) // c4417913440bf1 or 6251fd2813840bf1ffffff or 6251fd4813840bf1ffffff + VMOVLPD X20, -15(R11)(CX*1) // 62c1fd0813a40bf1ffffff or 62c1fd2813a40bf1ffffff or 62c1fd4813a40bf1ffffff + VMOVLPD X5, (SP)(AX*2) // c5f9132c44 or 62f1fd28132c44 or 62f1fd48132c44 + VMOVLPD X8, (SP)(AX*2) // c579130444 or 6271fd28130444 or 6271fd48130444 + VMOVLPD X20, (SP)(AX*2) // 62e1fd08132444 or 62e1fd28132444 or 62e1fd48132444 + // "VPEXTRW imm8u, xmm1, r32/m16"/15 vs "VPEXTRW imm8u, xmm2, r32"/C5. + VPEXTRW $17, X20, AX // 62b17d08c5c411 or 62e37d0815e011 or 62e3fd0815e011 + VPEXTRW $127, X20, AX // 62b17d08c5c47f or 62e37d0815e07f or 62e3fd0815e07f + VPEXTRW $17, X20, SP // 62b17d08c5e411 or 62e37d0815e411 or 62e3fd0815e411 + VPEXTRW $127, X20, SP // 62b17d08c5e47f or 62e37d0815e47f or 62e3fd0815e47f + VPEXTRW $17, X20, BP // 62b17d08c5ec11 or 62e37d0815e511 or 62e3fd0815e511 + VPEXTRW $127, X20, BP // 62b17d08c5ec7f or 62e37d0815e57f or 62e3fd0815e57f + VPEXTRW $17, X20, R14 // 62317d08c5f411 or 62c37d0815e611 or 62c3fd0815e611 + VPEXTRW $127, X20, R14 // 62317d08c5f47f or 62c37d0815e67f or 62c3fd0815e67f + VPEXTRW $17, X20, (AX) // 62e37d08152011 or 62e3fd08152011 + VPEXTRW $127, X20, (AX) // 62e37d0815207f or 62e3fd0815207f + VPEXTRW $17, X20, 7(DX) // 62e37d0815a20700000011 or 62e3fd0815a20700000011 + VPEXTRW $127, X20, 7(DX) // 62e37d0815a2070000007f or 62e3fd0815a2070000007f + VPEXTRW $17, X20, -15(R11)(CX*1) // 62c37d0815a40bf1ffffff11 or 62c3fd0815a40bf1ffffff11 + VPEXTRW $127, X20, -15(R11)(CX*1) // 62c37d0815a40bf1ffffff7f or 62c3fd0815a40bf1ffffff7f + VPEXTRW $17, X20, (SP)(AX*2) // 62e37d0815244411 or 62e3fd0815244411 + VPEXTRW $127, X20, (SP)(AX*2) // 62e37d081524447f or 62e3fd081524447f + // EVEX: embedded zeroing. + VADDPD.Z X30, X1, X0 // 6291f58858c6 + VMAXPD.Z (AX), Z2, K1, Z1 // 62f1edc95f08 + // EVEX: embedded rounding. + VADDPD.RU_SAE Z3, Z2, K1, Z1 // 62f1ed5958cb + VADDPD.RD_SAE Z3, Z2, K1, Z1 // 62f1ed3958cb + VADDPD.RZ_SAE Z3, Z2, K1, Z1 // 62f1ed7958cb + VADDPD.RN_SAE Z3, Z2, K1, Z1 // 62f1ed1958cb + VADDPD.RU_SAE.Z Z3, Z2, K1, Z1 // 62f1edd958cb + VADDPD.RD_SAE.Z Z3, Z2, K1, Z1 // 62f1edb958cb + VADDPD.RZ_SAE.Z Z3, Z2, K1, Z1 // 62f1edf958cb + VADDPD.RN_SAE.Z Z3, Z2, K1, Z1 // 62f1ed9958cb + // EVEX: embedded broadcasting. + VADDPD.BCST (AX), X2, K1, X1 // 62f1ed195808 + VADDPD.BCST.Z (AX), X2, K1, X1 // 62f1ed995808 + VADDPD.BCST (AX), Y2, K1, Y1 // 62f1ed395808 + VADDPD.BCST.Z (AX), Y2, K1, Y1 // 62f1edb95808 + VADDPD.BCST (AX), Z2, K1, Z1 // 62f1ed595808 + VADDPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95808 + VMAXPD.BCST (AX), Z2, K1, Z1 // 62f1ed595f08 + VMAXPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95f08 + // EVEX: surpress all exceptions (SAE). + VMAXPD.SAE Z3, Z2, K1, Z1 // 62f1ed595fcb or 62f1ed195fcb + VMAXPD.SAE.Z Z3, Z2, K1, Z1 // 62f1edd95fcb or 62f1ed995fcb + VMAXPD (AX), Z2, K1, Z1 // 62f1ed495f08 + VCMPSD.SAE $0, X0, X2, K0 // 62f1ef18c2c000 + VCMPSD.SAE $0, X0, X2, K1, K0 // 62f1ef19c2c000 + // EVEX: broadcast-affected compressed displacement (Disp8). + VADDPD.BCST 1016(DX), X0, X29 // 6261fd18586a7f + VADDPD.BCST 1016(DX), X29, X1 // 62f19510584a7f + VADDPD.BCST 1016(DX), X28, X29 // 62619d10586a7f + VADDPD.BCST 1016(DX)(AX*2), X0, X29 // 6261fd18586c427f + VADDPD.BCST 1016(DX)(AX*2), X29, X1 // 62f19510584c427f + VADDPD.BCST 1016(DX), Y0, Y29 // 6261fd38586a7f + VADDPD.BCST 1016(DX), Y29, Y1 // 62f19530584a7f + VADDPD.BCST 1016(DX), Y28, Y29 // 62619d30586a7f + VADDPD.BCST 1016(DX)(AX*2), Y0, Y29 // 6261fd38586c427f + VADDPD.BCST 1016(DX)(AX*2), Y29, Y1 // 62f19530584c427f + VADDPD.BCST 1016(DX), Z0, Z29 // 6261fd58586a7f + VADDPD.BCST 1016(DX), Z29, Z1 // 62f19550584a7f + VADDPD.BCST 1016(DX), Z28, Z29 // 62619d50586a7f + VADDPD.BCST 1016(DX)(AX*2), Z0, Z29 // 6261fd58586c427f + VADDPD.BCST 1016(DX)(AX*2), Z29, Z1 // 62f19550584c427f + VADDPS.BCST 508(DX), Z0, Z29 // 62617c58586a7f + VADDPS.BCST 508(DX), Z1, Z29 // 62617458586a7f + VADDPS.BCST 508(DX), Z28, Z29 // 62611c50586a7f + VADDPS.BCST 508(DX)(AX*2), Z0, Z29 // 62617c58586c427f + VADDPS.BCST 508(DX)(AX*2), Z1, Z29 // 62617458586c427f + // EVEX: broadcast-affected compressed displacement that does not fit into 8bits. + VADDPD.BCST 2032(DX), X0, X29 // 6261fd1858aaf0070000 + VADDPD.BCST 2032(DX), X29, X1 // 62f19510588af0070000 + VADDPD.BCST 2032(DX), X28, X29 // 62619d1058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), X0, X29 // 6261fd1858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), X29, X1 // 62f19510588c42f0070000 + VADDPD.BCST 2032(DX), Y0, Y29 // 6261fd3858aaf0070000 + VADDPD.BCST 2032(DX), Y29, Y1 // 62f19530588af0070000 + VADDPD.BCST 2032(DX), Y28, Y29 // 62619d3058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), Y0, Y29 // 6261fd3858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), Y29, Y1 // 62f19530588c42f0070000 + VADDPD.BCST 2032(DX), Z0, Z29 // 6261fd5858aaf0070000 + VADDPD.BCST 2032(DX), Z29, Z1 // 62f19550588af0070000 + VADDPD.BCST 2032(DX), Z28, Z29 // 62619d5058aaf0070000 + VADDPD.BCST 2032(DX)(AX*2), Z0, Z29 // 6261fd5858ac42f0070000 + VADDPD.BCST 2032(DX)(AX*2), Z29, Z1 // 62f19550588c42f0070000 + VADDPS.BCST 2032(DX), Z0, Z29 // 62617c5858aaf0070000 + VADDPS.BCST 2032(DX), Z1, Z29 // 6261745858aaf0070000 + VADDPS.BCST 2032(DX), Z28, Z29 // 62611c5058aaf0070000 + VADDPS.BCST 2032(DX)(AX*2), Z0, Z29 // 62617c5858ac42f0070000 + VADDPS.BCST 2032(DX)(AX*2), Z1, Z29 // 6261745858ac42f0070000 + // Forced EVEX encoding due to suffixes. + VADDPD.BCST 2032(DX), X0, X0 // 62f1fd185882f0070000 + VADDPD.BCST 2032(DX), Y0, Y0 // 62f1fd385882f0070000 + // Test new Z-cases one-by-one. + // + // Zevex_i_r_k_rm. + VCVTPS2PH $1, Z2, K5, Y21 // 62b37d4d1dd501 + VCVTPS2PH $2, Z21, K4, Y2 // 62e37d4c1dea02 + // Zevex_i_r_rm. + VCVTPS2PH $1, Z2, Y21 // 62b37d481dd501 + VCVTPS2PH $2, Z21, Y2 // 62e37d481dea02 + // Zevex_i_rm_k_r. + VFPCLASSPDX $1, X2, K5, K3 // 62f3fd0d66da01 + VFPCLASSPDX $2, X21, K4, K1 // 62b3fd0c66cd02 + VFPCLASSPDX $1, (AX), K5, K3 // 62f3fd0d661801 + VFPCLASSPDX $2, (CX), K4, K1 // 62f3fd0c660902 + // Zevex_i_rm_k_vo. + VPROLD $1, X2, K5, X21 // 62f1550572ca01 + VPROLD $2, Y21, K5, Y2 // 62b16d2d72cd02 + VPROLD $1, (AX), K5, X21 // 62f15505720801 + VPROLD $2, (CX), K5, Y2 // 62f16d2d720902 + // Zevex_i_rm_r. + VFPCLASSPDX $1, X2, K3 // 62f3fd0866da01 + VFPCLASSPDX $2, X21, K1 // 62b3fd0866cd02 + VFPCLASSPDX $1, (AX), K3 // 62f3fd08661801 + VFPCLASSPDX $2, (CX), K1 // 62f3fd08660902 + // Zevex_i_rm_v_k_r. + VALIGND $1, X2, X9, K5, X21 // 62e3350d03ea01 + VALIGND $2, Y21, Y2, K5, Y9 // 62336d2d03cd02 + VALIGND $3, Z9, Z21, K5, Z2 // 62d3554503d103 + VALIGND $1, (AX), X9, K5, X21 // 62e3350d032801 + VALIGND $2, (CX), Y2, K5, Y9 // 62736d2d030902 + VALIGND $3, (AX), Z21, K5, Z2 // 62f35545031003 + // Zevex_i_rm_v_r. + VALIGND $1, X2, X9, X21 // 62e3350803ea01 + VALIGND $2, Y21, Y2, Y9 // 62336d2803cd02 + VALIGND $3, Z9, Z21, Z2 // 62d3554003d103 + VALIGND $1, (AX), X9, X21 // 62e33508032801 + VALIGND $2, (CX), Y2, Y9 // 62736d28030902 + VALIGND $3, (AX), Z21, Z2 // 62f35540031003 + // Zevex_i_rm_vo. + VPROLD $1, X2, X21 // 62f1550072ca01 + VPROLD $2, Y21, Y2 // 62b16d2872cd02 + VPROLD $1, (AX), X21 // 62f15500720801 + VPROLD $2, (CX), Y2 // 62f16d28720902 + // Zevex_k_rmo. + VGATHERPF0DPD K5, (AX)(Y2*2) // 62f2fd4dc60c50 + VGATHERPF0DPD K3, (CX)(Y21*2) // 62f2fd43c60c69 + VSCATTERPF1DPD K5, (AX)(Y2*2) // 62f2fd4dc63450 + VSCATTERPF1DPD K3, (CX)(Y21*2) // 62f2fd43c63469 + // Zevex_r_k_rm. + VPSCATTERDD X2, K5, (AX)(X21*2) // 62f27d05a01468 + VPSCATTERDD X21, K5, (AX)(X2*2) // 62e27d0da02c50 + VPSCATTERDD Y2, K5, (AX)(Y21*2) // 62f27d25a01468 + VPSCATTERDD Y21, K5, (AX)(Y2*2) // 62e27d2da02c50 + VPSCATTERDD Z2, K5, (AX)(Z21*2) // 62f27d45a01468 + VPSCATTERDD Z21, K5, (AX)(Z2*2) // 62e27d4da02c50 + // Zevex_r_v_k_rm. + VMOVSD X2, X9, K5, X21 // 62b1b70d11d5 or 62e1b70d10ea + VMOVSD X21, X2, K5, X9 // 62c1ef0d11e9 or 6231ef0d10cd + VMOVSD X9, X21, K5, X2 // 6271d70511ca or 62d1d70510d1 + // Zevex_r_v_rm. + VMOVSD X2, X9, X21 // 62b1b70811d5 or 62e1b70810ea + VMOVSD X21, X2, X9 // 62c1ef0811e9 or 6231ef0810cd + VMOVSD X9, X21, X2 // 6271d70011ca or 62d1d70010d1 + VPMOVDB X2, X21 // 62b27e0831d5 + VPMOVDB X21, X2 // 62e27e0831ea + VPMOVDB X2, (AX) // 62f27e083110 + VPMOVDB X21, (AX) // 62e27e083128 + // Zevex_rm_k_r. + VMOVDDUP X2, K5, X21 // 62e1ff0d12ea + VMOVDDUP X21, K5, X2 // 62b1ff0d12d5 + VMOVDDUP (AX), K5, X21 // 62e1ff0d1228 + VMOVDDUP (CX), K5, X2 // 62f1ff0d1211 + VMOVDDUP Y2, K5, Y21 // 62e1ff2d12ea + VMOVDDUP Y21, K5, Y2 // 62b1ff2d12d5 + VMOVDDUP (AX), K5, Y21 // 62e1ff2d1228 + VMOVDDUP (CX), K5, Y2 // 62f1ff2d1211 + VMOVDDUP Z2, K5, Z21 // 62e1ff4d12ea + VMOVDDUP Z21, K5, Z2 // 62b1ff4d12d5 + VMOVDDUP (AX), K5, Z21 // 62e1ff4d1228 + VMOVDDUP (CX), K5, Z2 // 62f1ff4d1211 + // Zevex_rm_v_k_r. + VADDPD Z2, Z9, K5, Z21 // 62e1b54d58ea + VADDPD Z21, Z2, K5, Z9 // 6231ed4d58cd + VADDPD Z9, Z21, K5, Z2 // 62d1d54558d1 + // Zevex_rm_v_r. + VADDPD Z2, Z9, Z21 // 62e1b54858ea + VADDPD Z21, Z2, Z9 // 6231ed4858cd + VADDPD Z9, Z21, Z2 // 62d1d54058d1 // End of tests. RET diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index ce6282f0ddb9a..54be761c543ce 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -190,6 +190,15 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2 EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2 + AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a + ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa + EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca + BIC $0x22220000, R3, R4 // BIC $572653568, R3, R4 // 5b44a4d264003b8a + ORN $0x22220000, R3, R4 // ORN $572653568, R3, R4 // 5b44a4d264003baa + EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca + ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea + BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea + AND $8, R0, RSP // 1f007d92 ORR $8, R0, RSP // 1f007db2 EOR $8, R0, RSP // 1f007dd2 @@ -390,6 +399,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 CMP R1>>22, R2 CMP R1<<33, R2 CMP R22.SXTX, RSP // ffe336eb + + CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb + CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a4d2ff633b6b + +// TST + TST $15, R2 // 5f0c40f2 + TST R1, R2 // 5f0001ea + TST R1->11, R2 // 5f2c81ea + TST R1>>22, R2 // 5f5841ea + TST R1<<33, R2 // 5f8401ea + TST $0x22220000, R3 // TST $572653568, R3 // 5b44a4d27f001bea + // // CBZ // diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 36829686f6231..be2251e442e0c 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -87,4 +87,6 @@ TEXT errors(SB),$0 MADD R1, R2, R3 // ERROR "illegal combination" CINC CS, R2, R3, R4 // ERROR "illegal combination" CSEL LT, R1, R2 // ERROR "illegal combination" + AND $0x22220000, R2, RSP // ERROR "illegal combination" + ANDS $0x22220000, R2, RSP // ERROR "illegal combination" RET diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go index 6d638f064422a..6720945cdddba 100644 --- a/src/cmd/cgo/godefs.go +++ b/src/cmd/cgo/godefs.go @@ -19,7 +19,7 @@ import ( func (p *Package) godefs(f *File, srcfile string) string { var buf bytes.Buffer - fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n") + fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n") fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " ")) fmt.Fprintf(&buf, "\n") diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 399e96d01e0e7..e9b79865650f1 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -73,7 +73,7 @@ func (p *Package) writeDefs() { // Write second Go output: definitions of _C_xxx. // In a separate file so that the import of "unsafe" does not // pollute the original file. - fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") + fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n") fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") if !*gccgo && *importRuntimeCgo { @@ -536,7 +536,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { p.GccFiles = append(p.GccFiles, base+".cgo2.c") // Write Go output: Go input with rewrites of C.xxx to _C_xxx. - fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") + fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n") fmt.Fprintf(fgo1, "//line %s:1\n", srcfile) fgo1.Write(f.Edit.Bytes()) @@ -725,7 +725,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { // packedAttribute returns host compiler struct attribute that will be // used to match gc's struct layout. For example, on 386 Windows, // gcc wants to 8-align int64s, but gc does not. -// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, +// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86, // and https://golang.org/issue/5603. func (p *Package) packedAttribute() string { s := "__attribute__((__packed__" @@ -740,7 +740,7 @@ func (p *Package) packedAttribute() string { func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { p.writeExportHeader(fgcch) - fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") fmt.Fprintf(fgcc, "#include \n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n") @@ -981,7 +981,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { p.writeExportHeader(fgcch) - fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog) @@ -1147,7 +1147,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { // writeExportHeader writes out the start of the _cgo_export.h file. func (p *Package) writeExportHeader(fgcch io.Writer) { - fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n") + fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n") pkg := *importPath if pkg == "" { pkg = p.PackagePath diff --git a/src/cmd/compile/README.md b/src/cmd/compile/README.md index c8369c7c8cc54..b78786e5f252f 100644 --- a/src/cmd/compile/README.md +++ b/src/cmd/compile/README.md @@ -26,7 +26,7 @@ little to do with uppercase GC, which stands for garbage collection. * `cmd/compile/internal/syntax` (lexer, parser, syntax tree) In the first phase of compilation, source code is tokenized (lexical analysis), -parsed (syntactic analyses), and a syntax tree is constructed for each source +parsed (syntax analysis), and a syntax tree is constructed for each source file. Each syntax tree is an exact representation of the respective source file, with diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 4459596e24354..501eafe03f20c 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -603,25 +603,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.Patch(p2, p5) case ssa.OpARM64LoweredAtomicAnd8, ssa.OpARM64LoweredAtomicOr8: - // LDAXRB (Rarg0), Rtmp - // AND/OR Rarg1, Rtmp - // STLXRB Rtmp, (Rarg0), Rtmp + // LDAXRB (Rarg0), Rout + // AND/OR Rarg1, Rout + // STLXRB Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) r0 := v.Args[0].Reg() r1 := v.Args[1].Reg() + out := v.Reg0() p := s.Prog(arm64.ALDAXRB) p.From.Type = obj.TYPE_MEM p.From.Reg = r0 p.To.Type = obj.TYPE_REG - p.To.Reg = arm64.REGTMP + p.To.Reg = out p1 := s.Prog(v.Op.Asm()) p1.From.Type = obj.TYPE_REG p1.From.Reg = r1 p1.To.Type = obj.TYPE_REG - p1.To.Reg = arm64.REGTMP + p1.To.Reg = out p2 := s.Prog(arm64.ASTLXRB) p2.From.Type = obj.TYPE_REG - p2.From.Reg = arm64.REGTMP + p2.From.Reg = out p2.To.Type = obj.TYPE_MEM p2.To.Reg = r0 p2.RegTo2 = arm64.REGTMP diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 6b416c8a5c99e..ec8f1093b6f5a 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -141,6 +141,7 @@ var runtimeDecls = [...]struct { {"uint32tofloat64", funcTag, 109}, {"complex128div", funcTag, 110}, {"racefuncenter", funcTag, 111}, + {"racefuncenterfp", funcTag, 5}, {"racefuncexit", funcTag, 5}, {"raceread", funcTag, 111}, {"racewrite", funcTag, 111}, diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index d459c07cbeca8..140b7f3b2d0dc 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128) // race detection func racefuncenter(uintptr) +func racefuncenterfp() func racefuncexit() func raceread(uintptr) func racewrite(uintptr) diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index d88c5e5c5e542..736ea0a018380 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -778,15 +778,26 @@ func functypefield0(t *types.Type, this *types.Field, in, out []*types.Field) { // origSym returns the original symbol written by the user. func origSym(s *types.Sym) *types.Sym { - if s != nil && s.Name[0] == '~' { + if s == nil { + return nil + } + + if len(s.Name) > 1 && s.Name[0] == '~' { switch s.Name[1] { case 'r': // originally an unnamed result - s = nil + return nil case 'b': // originally the blank identifier _ // TODO(mdempsky): Does s.Pkg matter here? - s = nblank.Sym + return nblank.Sym } + return s } + + if strings.HasPrefix(s.Name, ".anon") { + // originally an unnamed or _ name (see subr.go: structargs) + return nil + } + return s } diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 4e92f5421b0e5..75194ca6f034d 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1268,7 +1268,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { case OTARRAY: if n.Left != nil { - mode.Fprintf(s, "[]%v", n.Left) + mode.Fprintf(s, "[%v]%v", n.Left, n.Right) return } mode.Fprintf(s, "[]%v", n.Right) // happens before typecheck @@ -1599,7 +1599,7 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) { case OTYPE: mode.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type) - if recur && n.Type == nil && n.Name.Param.Ntype != nil { + if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil { indent(s) mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype) } diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 46fe87e8c3dda..25452911eb868 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -352,7 +352,7 @@ func (v *hairyVisitor) visit(n *Node) bool { v.budget -= v.extraCallCost case OPANIC: - v.budget -= v.extraCallCost + v.budget -= inlineExtraPanicCost case ORECOVER: // recover matches the argument frame pointer to find diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 74590ccc39264..9f1ea2ab4bf77 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -481,15 +481,13 @@ func Main(archInit func(*Arch)) { // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. - // We also defer type alias declarations until phase 2 - // to avoid cycles like #18640. defercheckwidth() // Don't use range--typecheck can add closures to xtop. timings.Start("fe", "typecheck", "top1") for i := 0; i < len(xtop); i++ { n := xtop[i] - if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) { + if op := n.Op; op != ODCL && op != OAS && op != OAS2 { xtop[i] = typecheck(n, Etop) } } @@ -501,7 +499,7 @@ func Main(archInit func(*Arch)) { timings.Start("fe", "typecheck", "top2") for i := 0; i < len(xtop); i++ { n := xtop[i] - if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias { + if op := n.Op; op == ODCL || op == OAS || op == OAS2 { xtop[i] = typecheck(n, Etop) } } @@ -532,6 +530,10 @@ func Main(archInit func(*Arch)) { checkMapKeys() timings.AddEvent(fcount, "funcs") + if nsavederrors+nerrors != 0 { + errorexit() + } + // Phase 4: Decide how to capture closed variables. // This needs to run before escape analysis, // because variables captured by value do not escape. @@ -659,14 +661,6 @@ func Main(archInit func(*Arch)) { Ctxt.DwFixups = nil genDwarfInline = 0 } - - // Check whether any of the functions we have compiled have gigantic stack frames. - obj.SortSlice(largeStackFrames, func(i, j int) bool { - return largeStackFrames[i].Before(largeStackFrames[j]) - }) - for _, largePos := range largeStackFrames { - yyerrorl(largePos, "stack frame too large (>1GB)") - } } // Phase 9: Check external declarations. @@ -688,6 +682,14 @@ func Main(archInit func(*Arch)) { dumpasmhdr() } + // Check whether any of the functions we have compiled have gigantic stack frames. + obj.SortSlice(largeStackFrames, func(i, j int) bool { + return largeStackFrames[i].Before(largeStackFrames[j]) + }) + for _, largePos := range largeStackFrames { + yyerrorl(largePos, "stack frame too large (>1GB)") + } + if len(compilequeue) != 0 { Fatalf("%d uncompiled functions", len(compilequeue)) } diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index ec1654b83f652..8a42fcefd1f2e 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -19,6 +19,10 @@ import ( "cmd/internal/src" ) +// parseFiles concurrently parses files into *syntax.File structures. +// Each declaration in every *syntax.File is converted to a syntax tree +// and its root represented by *Node is appended to xtop. +// Returns the total count of parsed lines. func parseFiles(filenames []string) uint { var noders []*noder // Limit the number of simultaneously open files. diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 9747a0299e672..cf1164772b0fc 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -257,18 +257,32 @@ const maxStackSize = 1 << 30 // worker indicates which of the backend workers is doing the processing. func compileSSA(fn *Node, worker int) { f := buildssa(fn, worker) - if f.Frontend().(*ssafn).stksize >= maxStackSize { + // Note: check arg size to fix issue 25507. + if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize { largeStackFramesMu.Lock() largeStackFrames = append(largeStackFrames, fn.Pos) largeStackFramesMu.Unlock() return } pp := newProgs(fn, worker) + defer pp.Free() genssa(f, pp) + // Check frame size again. + // The check above included only the space needed for local variables. + // After genssa, the space needed includes local variables and the callee arg region. + // We must do this check prior to calling pp.Flush. + // If there are any oversized stack frames, + // the assembler may emit inscrutable complaints about invalid instructions. + if pp.Text.To.Offset >= maxStackSize { + largeStackFramesMu.Lock() + largeStackFrames = append(largeStackFrames, fn.Pos) + largeStackFramesMu.Unlock() + return + } + pp.Flush() // assemble, fill in boilerplate, etc. // fieldtrack must be called after pp.Flush. See issue 20014. fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack) - pp.Free() } func init() { diff --git a/src/cmd/compile/internal/gc/phi.go b/src/cmd/compile/internal/gc/phi.go index bd66568eed025..5218cd0ef3d14 100644 --- a/src/cmd/compile/internal/gc/phi.go +++ b/src/cmd/compile/internal/gc/phi.go @@ -14,7 +14,7 @@ import ( // This file contains the algorithm to place phi nodes in a function. // For small functions, we use Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau. -// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf +// https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf // For large functions, we use Sreedhar & Gao: A Linear Time Algorithm for Placing Φ-Nodes. // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.1979&rep=rep1&type=pdf diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index f3f1ca3d397e6..88b4380637092 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -461,17 +461,6 @@ func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) { for _, reg := range regs[:nreg] { if reg.GCNum() == -1 { if ptrOnly { - if reg.String() == "g" { - // Issue #25504: Sometimes we - // spill and reload the g - // register, which this sees - // as a pointer load into the - // g register. The g register - // isn't a GP register and - // can't appear in register - // maps. Ignore it. - continue - } v.Fatalf("pointer in non-pointer register %v", reg) } else { continue diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 8ae080ab40861..df0e5f4059035 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/types" "cmd/internal/src" + "cmd/internal/sys" ) // The racewalk pass is currently handled in two parts. @@ -58,17 +59,23 @@ func instrument(fn *Node) { lno := lineno lineno = src.NoXPos - // nodpc is the PC of the caller as extracted by - // getcallerpc. We use -widthptr(FP) for x86. - // BUG: this will not work on arm. - nodpc := nodfp.copy() - nodpc.Type = types.Types[TUINTPTR] - nodpc.Xoffset = int64(-Widthptr) - fn.Func.Dcl = append(fn.Func.Dcl, nodpc) - - fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) - fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + if thearch.LinkArch.Arch == sys.ArchPPC64LE { + fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil)) + fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + } else { + // nodpc is the PC of the caller as extracted by + // getcallerpc. We use -widthptr(FP) for x86. + // BUG: This only works for amd64. This will not + // work on arm or others that might support + // race in the future. + nodpc := nodfp.copy() + nodpc.Type = types.Types[TUINTPTR] + nodpc.Xoffset = int64(-Widthptr) + fn.Func.Dcl = append(fn.Func.Dcl, nodpc) + fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) + fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + } lineno = lno } } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 483be32d6e9cc..fd134e9f12060 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -110,19 +110,35 @@ func typekind(t *types.Type) string { return fmt.Sprintf("etype=%d", et) } -// sprint_depchain prints a dependency chain of nodes into trace. -// It is used by typecheck in the case of OLITERAL nodes -// to print constant definition loops. -func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) { - for i := len(stack) - 1; i >= 0; i-- { - if n := stack[i]; n.Op == cur.Op { - if n != first { - sprint_depchain(trace, stack[:i], n, first) - } - *trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur) - return +func cycleFor(start *Node) []*Node { + // Find the start node in typecheck_tcstack. + // We know that it must exist because each time we mark + // a node with n.SetTypecheck(2) we push it on the stack, + // and each time we mark a node with n.SetTypecheck(2) we + // pop it from the stack. We hit a cycle when we encounter + // a node marked 2 in which case is must be on the stack. + i := len(typecheck_tcstack) - 1 + for i > 0 && typecheck_tcstack[i] != start { + i-- + } + + // collect all nodes with same Op + var cycle []*Node + for _, n := range typecheck_tcstack[i:] { + if n.Op == start.Op { + cycle = append(cycle, n) } } + + return cycle +} + +func cycleTrace(cycle []*Node) string { + var s string + for i, n := range cycle { + s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)]) + } + return s } var typecheck_tcstack []*Node @@ -174,10 +190,20 @@ func typecheck(n *Node, top int) *Node { } case OTYPE: + // Only report a type cycle if we are expecting a type. + // Otherwise let other code report an error. if top&Etype == Etype { - var trace string - sprint_depchain(&trace, typecheck_tcstack, n, n) - yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace) + // A cycle containing only alias types is an error + // since it would expand indefinitely when aliases + // are substituted. + cycle := cycleFor(n) + for _, n := range cycle { + if n.Name != nil && !n.Name.Param.Alias { + lineno = lno + return n + } + } + yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle)) } case OLITERAL: @@ -185,9 +211,7 @@ func typecheck(n *Node, top int) *Node { yyerror("%v is not a type", n) break } - var trace string - sprint_depchain(&trace, typecheck_tcstack, n, n) - yyerrorl(n.Pos, "constant definition loop%s", trace) + yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n))) } if nsavederrors+nerrors == 0 { diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index f42d1e43db6ea..591c8f3bfecbc 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -4078,7 +4078,7 @@ func canMergeLoads() bool { } // isRuneCount reports whether n is of the form len([]rune(string)). -// These are optimized into a call to runtime.runecount. +// These are optimized into a call to runtime.countrunes. func isRuneCount(n *Node) bool { return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTRARRAYRUNE } diff --git a/src/cmd/compile/internal/ssa/branchelim.go b/src/cmd/compile/internal/ssa/branchelim.go index 1967fb93febfd..d9dcaf844430d 100644 --- a/src/cmd/compile/internal/ssa/branchelim.go +++ b/src/cmd/compile/internal/ssa/branchelim.go @@ -4,7 +4,7 @@ package ssa -// branchelim tries to elminiate branches by +// branchelim tries to eliminate branches by // generating CondSelect instructions. // // Search for basic blocks that look like diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 322ea82c8d603..13b7d7e1e84a6 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -252,6 +252,19 @@ func deadcode(f *Func) { b.Values = b.Values[:i] } + // Remove dead blocks from WBLoads list. + i = 0 + for _, b := range f.WBLoads { + if reachable[b.ID] { + f.WBLoads[i] = b + i++ + } + } + for j := i; j < len(f.WBLoads); j++ { + f.WBLoads[j] = nil + } + f.WBLoads = f.WBLoads[:i] + // Remove unreachable blocks. Return dead blocks to allocator. i = 0 for _, b := range f.Blocks { diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index be9f19b51cbc1..5832050a8a608 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -28,6 +28,7 @@ var testCtxts = map[string]*obj.Link{ func testConfig(tb testing.TB) *Conf { return testConfigArch(tb, "amd64") } func testConfigS390X(tb testing.TB) *Conf { return testConfigArch(tb, "s390x") } +func testConfigARM64(tb testing.TB) *Conf { return testConfigArch(tb, "arm64") } func testConfigArch(tb testing.TB, arch string) *Conf { ctxt, ok := testCtxts[arch] diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 2f0364fb003b0..28694e435e58a 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -349,10 +349,10 @@ func init() { // result is undefined if the input is zero. // flags are set to "equal" if the input is zero, "not equal" otherwise. // BS{F,R}L returns only the result. - {name: "BSFQ", argLength: 1, reg: gp11flags, asm: "BSFQ", typ: "(UInt64,Flags)"}, // # of low-order zeroes in 64-bit arg - {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", typ: "UInt32"}, // # of low-order zeroes in 32-bit arg - {name: "BSRQ", argLength: 1, reg: gp11flags, asm: "BSRQ", typ: "(UInt64,Flags)"}, // # of high-order zeroes in 64-bit arg - {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", typ: "UInt32"}, // # of high-order zeroes in 32-bit arg + {name: "BSFQ", argLength: 1, reg: gp11flags, asm: "BSFQ", typ: "(UInt64,Flags)"}, // # of low-order zeroes in 64-bit arg + {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", typ: "UInt32", clobberFlags: true}, // # of low-order zeroes in 32-bit arg + {name: "BSRQ", argLength: 1, reg: gp11flags, asm: "BSRQ", typ: "(UInt64,Flags)"}, // # of high-order zeroes in 64-bit arg + {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", typ: "UInt32", clobberFlags: true}, // # of high-order zeroes in 32-bit arg // CMOV instructions: 64, 32 and 16-bit sizes. // if arg2 encodes a true result, return arg1, else arg0 diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index b5eeb96468367..a1a3cccf3c252 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -540,8 +540,9 @@ (AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem) (AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem) -(AtomicAnd8 ptr val mem) -> (LoweredAtomicAnd8 ptr val mem) -(AtomicOr8 ptr val mem) -> (LoweredAtomicOr8 ptr val mem) +// Currently the updated value is not used, but we need a register to temporarily hold it. +(AtomicAnd8 ptr val mem) -> (Select1 (LoweredAtomicAnd8 ptr val mem)) +(AtomicOr8 ptr val mem) -> (Select1 (LoweredAtomicOr8 ptr val mem)) // Write barrier. (WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index b54de53f59334..9e8b07ec4b3ef 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -596,13 +596,13 @@ func init() { {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, // atomic and/or. - // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero. - // LDAXRB (Rarg0), Rtmp - // AND/OR Rarg1, Rtmp - // STLXRB Rtmp, (Rarg0), Rtmp + // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. + // LDAXRB (Rarg0), Rout + // AND/OR Rarg1, Rout + // STLXRB Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) - {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true}, // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier // It saves all GP registers if necessary, diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index 01f3f5a670a10..18c208cccb6c1 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -46,8 +46,7 @@ (Not x) -> (I64Eqz x) // Lowering pointer arithmetic -(OffPtr [0] ptr) -> ptr -(OffPtr [off] ptr) && off > 0 -> (I64AddConst [off] ptr) +(OffPtr [off] ptr) -> (I64AddConst [off] ptr) // Lowering extension // It is unnecessary to extend loads @@ -388,6 +387,7 @@ (I64Ne x (I64Const [0])) -> (I64Eqz (I64Eqz x)) (I64Add x (I64Const [y])) -> (I64AddConst [y] x) +(I64AddConst [0] x) -> x (I64Eqz (I64Eqz (I64Eqz x))) -> (I64Eqz x) ((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 76212c0866853..7931aa7f06d2f 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -212,7 +212,7 @@ // (Mod64u x y) is always between 0 (inclusive) and y (exclusive). (IsInBounds (Mod32u _ y) y) -> (ConstBool [1]) (IsInBounds (Mod64u _ y) y) -> (ConstBool [1]) -// Right shifting a unsigned number limits its value. +// Right shifting an unsigned number limits its value. (IsInBounds (ZeroExt8to64 (Rsh8Ux64 _ (Const64 [c]))) (Const64 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) (IsInBounds (ZeroExt8to32 (Rsh8Ux64 _ (Const64 [c]))) (Const32 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) (IsInBounds (ZeroExt8to16 (Rsh8Ux64 _ (Const64 [c]))) (Const16 [d])) && 0 < c && c < 8 && 1< (ConstBool [1]) diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index e85a988d14ebc..eec5b027139ec 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -7393,9 +7393,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSFL", - argLen: 1, - asm: x86.ABSFL, + name: "BSFL", + argLen: 1, + clobberFlags: true, + asm: x86.ABSFL, reg: regInfo{ inputs: []inputInfo{ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 @@ -7420,9 +7421,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSRL", - argLen: 1, - asm: x86.ABSRL, + name: "BSRL", + argLen: 1, + clobberFlags: true, + asm: x86.ABSRL, reg: regInfo{ inputs: []inputInfo{ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 @@ -16757,29 +16759,37 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LoweredAtomicAnd8", - argLen: 3, - faultOnNilArg0: true, - hasSideEffects: true, - asm: arm64.AAND, + name: "LoweredAtomicAnd8", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + asm: arm64.AAND, reg: regInfo{ inputs: []inputInfo{ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, }, }, { - name: "LoweredAtomicOr8", - argLen: 3, - faultOnNilArg0: true, - hasSideEffects: true, - asm: arm64.AORR, + name: "LoweredAtomicOr8", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + asm: arm64.AORR, reg: regInfo{ inputs: []inputInfo{ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, }, }, { diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 080ad0fda11ca..bbf1932981458 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -532,6 +532,9 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos } s.assignReg(r, v, c) + if c.Op == OpLoadReg && s.isGReg(r) { + s.f.Fatalf("allocValToReg.OpLoadReg targeting g: " + c.LongString()) + } if nospill { s.nospill |= regMask(1) << r } @@ -809,6 +812,10 @@ func (s *regAllocState) regspec(op Op) regInfo { return opcodeTable[op].reg } +func (s *regAllocState) isGReg(r register) bool { + return s.f.Config.hasGReg && s.GReg == r +} + func (s *regAllocState) regalloc(f *Func) { regValLiveSet := f.newSparseSet(f.NumValues()) // set of values that may be live in register defer f.retSparseSet(regValLiveSet) @@ -951,6 +958,7 @@ func (s *regAllocState) regalloc(f *Func) { // Majority vote? Deepest nesting level? phiRegs = phiRegs[:0] var phiUsed regMask + for _, v := range phis { if !s.values[v.ID].needReg { phiRegs = append(phiRegs, noRegister) @@ -1516,6 +1524,9 @@ func (s *regAllocState) regalloc(f *Func) { // predecessor of it, find live values that we use soon after // the merge point and promote them to registers now. if len(b.Succs) == 1 { + if s.f.Config.hasGReg && s.regs[s.GReg].v != nil { + s.freeReg(s.GReg) // Spill value in G register before any merge. + } // For this to be worthwhile, the loop must have no calls in it. top := b.Succs[0].b loop := s.loopnest.b2l[top.ID] @@ -1996,6 +2007,9 @@ func (e *edgeState) process() { c = e.p.NewValue1(pos, OpLoadReg, c.Type, c) } e.set(r, vid, c, false, pos) + if c.Op == OpLoadReg && e.s.isGReg(register(r.(*Register).num)) { + e.s.f.Fatalf("process.OpLoadReg targeting g: " + c.LongString()) + } } } @@ -2110,6 +2124,9 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP } } e.set(loc, vid, x, true, pos) + if x.Op == OpLoadReg && e.s.isGReg(register(loc.(*Register).num)) { + e.s.f.Fatalf("processDest.OpLoadReg targeting g: " + x.LongString()) + } if splice != nil { (*splice).Uses-- *splice = x diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go index 02751a9349aae..bb8be5e7ac6f6 100644 --- a/src/cmd/compile/internal/ssa/regalloc_test.go +++ b/src/cmd/compile/internal/ssa/regalloc_test.go @@ -36,6 +36,55 @@ func TestLiveControlOps(t *testing.T) { checkFunc(f.f) } +// Test to make sure G register is never reloaded from spill (spill of G is okay) +// See #25504 +func TestNoGetgLoadReg(t *testing.T) { + /* + Original: + func fff3(i int) *g { + gee := getg() + if i == 0 { + fff() + } + return gee // here + } + */ + c := testConfigARM64(t) + f := c.Fun("b1", + Bloc("b1", + Valu("v1", OpInitMem, types.TypeMem, 0, nil), + Valu("v6", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)), + Valu("v8", OpGetG, c.config.Types.Int64.PtrTo(), 0, nil, "v1"), + Valu("v11", OpARM64CMPconst, types.TypeFlags, 0, nil, "v6"), + Eq("v11", "b2", "b4"), + ), + Bloc("b4", + Goto("b3"), + ), + Bloc("b3", + Valu("v14", OpPhi, types.TypeMem, 0, nil, "v1", "v12"), + Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil), + Valu("v16", OpARM64MOVDstore, types.TypeMem, 0, nil, "v8", "sb", "v14"), + Exit("v16"), + ), + Bloc("b2", + Valu("v12", OpARM64CALLstatic, types.TypeMem, 0, nil, "v1"), + Goto("b3"), + ), + ) + regalloc(f.f) + checkFunc(f.f) + // Double-check that we never restore to the G register. Regalloc should catch it, but check again anyway. + r := f.f.RegAlloc + for _, b := range f.blocks { + for _, v := range b.Values { + if v.Op == OpLoadReg && r[v.ID].String() == "g" { + t.Errorf("Saw OpLoadReg targeting g register: %s", v.LongString()) + } + } + } +} + // Test to make sure we don't push spills into loops. // See issue #19595. func TestSpillWithLoop(t *testing.T) { diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index f5380111983a4..60121038e4bdb 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -25925,18 +25925,24 @@ func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool { } } func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (AtomicAnd8 ptr val mem) // cond: - // result: (LoweredAtomicAnd8 ptr val mem) + // result: (Select1 (LoweredAtomicAnd8 ptr val mem)) for { _ = v.Args[2] ptr := v.Args[0] val := v.Args[1] mem := v.Args[2] - v.reset(OpARM64LoweredAtomicAnd8) - v.AddArg(ptr) - v.AddArg(val) - v.AddArg(mem) + v.reset(OpSelect1) + v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicAnd8, types.NewTuple(typ.UInt8, types.TypeMem)) + v0.AddArg(ptr) + v0.AddArg(val) + v0.AddArg(mem) + v.AddArg(v0) return true } } @@ -26051,18 +26057,24 @@ func rewriteValueARM64_OpAtomicLoadPtr_0(v *Value) bool { } } func rewriteValueARM64_OpAtomicOr8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (AtomicOr8 ptr val mem) // cond: - // result: (LoweredAtomicOr8 ptr val mem) + // result: (Select1 (LoweredAtomicOr8 ptr val mem)) for { _ = v.Args[2] ptr := v.Args[0] val := v.Args[1] mem := v.Args[2] - v.reset(OpARM64LoweredAtomicOr8) - v.AddArg(ptr) - v.AddArg(val) - v.AddArg(mem) + v.reset(OpSelect1) + v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicOr8, types.NewTuple(typ.UInt8, types.TypeMem)) + v0.AddArg(ptr) + v0.AddArg(val) + v0.AddArg(mem) + v.AddArg(v0) return true } } diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 38822a746687f..f3648ebca1d5f 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -463,6 +463,8 @@ func rewriteValueWasm(v *Value) bool { return rewriteValueWasm_OpWasmF64Mul_0(v) case OpWasmI64Add: return rewriteValueWasm_OpWasmI64Add_0(v) + case OpWasmI64AddConst: + return rewriteValueWasm_OpWasmI64AddConst_0(v) case OpWasmI64And: return rewriteValueWasm_OpWasmI64And_0(v) case OpWasmI64Eq: @@ -3688,34 +3690,17 @@ func rewriteValueWasm_OpNot_0(v *Value) bool { } } func rewriteValueWasm_OpOffPtr_0(v *Value) bool { - // match: (OffPtr [0] ptr) - // cond: - // result: ptr - for { - if v.AuxInt != 0 { - break - } - ptr := v.Args[0] - v.reset(OpCopy) - v.Type = ptr.Type - v.AddArg(ptr) - return true - } // match: (OffPtr [off] ptr) - // cond: off > 0 + // cond: // result: (I64AddConst [off] ptr) for { off := v.AuxInt ptr := v.Args[0] - if !(off > 0) { - break - } v.reset(OpWasmI64AddConst) v.AuxInt = off v.AddArg(ptr) return true } - return false } func rewriteValueWasm_OpOr16_0(v *Value) bool { // match: (Or16 x y) @@ -5211,6 +5196,22 @@ func rewriteValueWasm_OpWasmI64Add_0(v *Value) bool { } return false } +func rewriteValueWasm_OpWasmI64AddConst_0(v *Value) bool { + // match: (I64AddConst [0] x) + // cond: + // result: x + for { + if v.AuxInt != 0 { + break + } + x := v.Args[0] + v.reset(OpCopy) + v.Type = x.Type + v.AddArg(x) + return true + } + return false +} func rewriteValueWasm_OpWasmI64And_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go index c42fb99c7af8c..f55db54b1c0bf 100644 --- a/src/cmd/compile/internal/ssa/sparsemap.go +++ b/src/cmd/compile/internal/ssa/sparsemap.go @@ -6,7 +6,7 @@ package ssa import "cmd/internal/src" -// from http://research.swtch.com/sparse +// from https://research.swtch.com/sparse // in turn, from Briggs and Torczon type sparseEntry struct { diff --git a/src/cmd/compile/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go index b5cabfb0cdf08..395931d1ff148 100644 --- a/src/cmd/compile/internal/ssa/sparseset.go +++ b/src/cmd/compile/internal/ssa/sparseset.go @@ -4,7 +4,7 @@ package ssa -// from http://research.swtch.com/sparse +// from https://research.swtch.com/sparse // in turn, from Briggs and Torczon type sparseSet struct { diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index f20fbb4b71218..ec80f94e59d93 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -5,6 +5,7 @@ package main_test import ( + "bufio" "bytes" "flag" "fmt" @@ -17,6 +18,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strings" "testing" ) @@ -36,6 +38,12 @@ var ( coverInput = filepath.Join(testdata, "test_line.go") coverOutput = filepath.Join(testdata, "test_cover.go") coverProfile = filepath.Join(testdata, "profile.cov") + + // The HTML test files are in a separate directory + // so they are a complete package. + htmlProfile = filepath.Join(testdata, "html", "html.cov") + htmlHTML = filepath.Join(testdata, "html", "html.html") + htmlGolden = filepath.Join(testdata, "html", "html.golden") ) var debug = flag.Bool("debug", false, "keep rewritten files for debugging") @@ -256,6 +264,61 @@ func TestCoverFunc(t *testing.T) { } } +// Check that cover produces correct HTML. +// Issue #25767. +func TestCoverHTML(t *testing.T) { + if _, err := exec.LookPath("diff"); err != nil { + t.Skipf("skip test on %s: diff command is required", runtime.GOOS) + } + testenv.MustHaveGoBuild(t) + if !*debug { + defer os.Remove(testcover) + defer os.Remove(htmlProfile) + defer os.Remove(htmlHTML) + } + // go build -o testcover + cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover) + run(cmd, t) + // go test -coverprofile testdata/html/html.cov cmd/cover/testdata/html + cmd = exec.Command(testenv.GoToolPath(t), "test", "-coverprofile", htmlProfile, "cmd/cover/testdata/html") + run(cmd, t) + // ./testcover -html testdata/html/html.cov -o testdata/html/html.html + cmd = exec.Command(testcover, "-html", htmlProfile, "-o", htmlHTML) + run(cmd, t) + + // Extract the parts of the HTML with comment markers, + // and compare against a golden file. + entireHTML, err := ioutil.ReadFile(htmlHTML) + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + scan := bufio.NewScanner(bytes.NewReader(entireHTML)) + in := false + for scan.Scan() { + line := scan.Text() + if strings.Contains(line, "// START") { + in = true + } + if in { + fmt.Fprintln(&out, line) + } + if strings.Contains(line, "// END") { + in = false + } + } + if err := ioutil.WriteFile(htmlHTML, out.Bytes(), 0644); err != nil { + t.Fatal(err) + } + diff := "diff" + if runtime.GOOS == "plan9" { + diff = "/bin/ape/diff" + } + // diff -uw testdata/html/html.html testdata/html/html.golden + cmd = exec.Command(diff, "-u", "-w", htmlHTML, htmlGolden) + run(cmd, t) +} + func run(c *exec.Cmd, t *testing.T) { t.Helper() c.Stdout = os.Stdout diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go index 5628b91f51990..656c862740274 100644 --- a/src/cmd/cover/profile.go +++ b/src/cmd/cover/profile.go @@ -153,6 +153,7 @@ type Boundary struct { Start bool // Is this the start of a block? Count int // Event count from the cover profile. Norm float64 // Count normalized to [0..1]. + Index int // Order in input file. } // Boundaries returns a Profile as a set of Boundary objects within the provided src. @@ -168,13 +169,15 @@ func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { divisor := math.Log(float64(max)) // boundary returns a Boundary, populating the Norm field with a normalized Count. + index := 0 boundary := func(offset int, start bool, count int) Boundary { - b := Boundary{Offset: offset, Start: start, Count: count} + b := Boundary{Offset: offset, Start: start, Count: count, Index: index} + index++ if !start || count == 0 { return b } if max <= 1 { - b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. + b.Norm = 0.8 // Profile is in "set" mode; we want a heat map. Use cov8 in the CSS. } else if count > 0 { b.Norm = math.Log(float64(count)) / divisor } @@ -209,7 +212,9 @@ func (b boundariesByPos) Len() int { return len(b) } func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b boundariesByPos) Less(i, j int) bool { if b[i].Offset == b[j].Offset { - return !b[i].Start && b[j].Start + // Boundaries at the same offset should be ordered according to + // their original position. + return b[i].Index < b[j].Index } return b[i].Offset < b[j].Offset } diff --git a/src/cmd/cover/testdata/html/html.go b/src/cmd/cover/testdata/html/html.go new file mode 100644 index 0000000000000..20578259a5c82 --- /dev/null +++ b/src/cmd/cover/testdata/html/html.go @@ -0,0 +1,30 @@ +package html + +import "fmt" + +// This file is tested by html_test.go. +// The comments below are markers for extracting the annotated source +// from the HTML output. + +// This is a regression test for incorrect sorting of boundaries +// that coincide, specifically for empty select clauses. +// START f +func f() { + ch := make(chan int) + select { + case <-ch: + default: + } +} + +// END f + +// https://golang.org/issue/25767 +// START g +func g() { + if false { + fmt.Printf("Hello") + } +} + +// END g diff --git a/src/cmd/cover/testdata/html/html.golden b/src/cmd/cover/testdata/html/html.golden new file mode 100644 index 0000000000000..84377d1e2035a --- /dev/null +++ b/src/cmd/cover/testdata/html/html.golden @@ -0,0 +1,18 @@ +// START f +func f() { + ch := make(chan int) + select { + case <-ch: + default: + } +} + +// END f +// START g +func g() { + if false { + fmt.Printf("Hello") + } +} + +// END g diff --git a/src/cmd/cover/testdata/html/html_test.go b/src/cmd/cover/testdata/html/html_test.go new file mode 100644 index 0000000000000..c15561fe4a92f --- /dev/null +++ b/src/cmd/cover/testdata/html/html_test.go @@ -0,0 +1,8 @@ +package html + +import "testing" + +func TestAll(t *testing.T) { + f() + g() +} diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 99d1db5909590..616e76dfe7fc4 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -67,6 +67,7 @@ var okgoarch = []string{ "mips64le", "ppc64", "ppc64le", + "riscv64", "s390x", "wasm", } @@ -1393,6 +1394,7 @@ var cgoEnabled = map[string]bool{ "linux/mipsle": true, "linux/mips64": true, "linux/mips64le": true, + "linux/riscv64": true, "linux/s390x": true, "android/386": true, "android/amd64": true, @@ -1438,7 +1440,7 @@ func checkCC() { fatalf("cannot invoke C compiler %q: %v\n\n"+ "Go needs a system C compiler for use with cgo.\n"+ "To set a C compiler, set CC=the-compiler.\n"+ - "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) + "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output) } } diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go index a72a2607f9f59..37e37e2733566 100644 --- a/src/cmd/dist/main.go +++ b/src/cmd/dist/main.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "runtime" - "strconv" "strings" ) @@ -61,6 +60,8 @@ func main() { // Even on 64-bit platform, darwin uname -m prints i386. // We don't support any of the OS X versions that run on 32-bit-only hardware anymore. gohostarch = "amd64" + // macOS 10.9 and later require clang + defaultclang = true case "freebsd": // Since FreeBSD 10 gcc is no longer part of the base system. defaultclang = true @@ -126,29 +127,6 @@ func main() { } bginit() - // The OS X 10.6 linker does not support external linking mode. - // See golang.org/issue/5130. - // - // OS X 10.6 does not work with clang either, but OS X 10.9 requires it. - // It seems to work with OS X 10.8, so we default to clang for 10.8 and later. - // See golang.org/issue/5822. - // - // Roughly, OS X 10.N shows up as uname release (N+4), - // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12. - if gohostos == "darwin" { - rel := run("", CheckExit, "uname", "-r") - if i := strings.Index(rel, "."); i >= 0 { - rel = rel[:i] - } - osx, _ := strconv.Atoi(rel) - if osx <= 6+4 { - goextlinkenabled = "0" - } - if osx >= 8+4 { - defaultclang = true - } - } - if len(os.Args) > 1 && os.Args[1] == "-check-goarm" { useVFPv1() // might fail with SIGILL println("VFPv1 OK.") diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go index 6d1f82e0936b6..216dc017982fe 100644 --- a/src/cmd/dist/sys_windows.go +++ b/src/cmd/dist/sys_windows.go @@ -14,7 +14,7 @@ var ( procGetSystemInfo = modkernel32.NewProc("GetSystemInfo") ) -// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx +// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx type systeminfo struct { wProcessorArchitecture uint16 wReserved uint16 diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 5bd5b424afbd6..ac43701d888ab 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -312,7 +312,6 @@ func (t *tester) registerStdTest(pkg string) { break } } - args := []string{ "test", short(), @@ -355,7 +354,8 @@ func (t *tester) registerRaceBenchTest(pkg string) { "test", short(), "-race", - "-run=^$", // nothing. only benchmarks. + t.timeout(1200), // longer timeout for race with benchmarks + "-run=^$", // nothing. only benchmarks. "-benchtime=.1s", "-cpu=4", } @@ -889,7 +889,7 @@ func (t *tester) extLink() bool { pair := gohostos + "-" + goarch switch pair { case "android-arm", - "darwin-arm", "darwin-arm64", + "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", "dragonfly-amd64", "freebsd-386", "freebsd-amd64", "freebsd-arm", "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x", @@ -897,15 +897,6 @@ func (t *tester) extLink() bool { "openbsd-386", "openbsd-amd64", "windows-386", "windows-amd64": return true - case "darwin-386", "darwin-amd64": - // linkmode=external fails on OS X 10.6 and earlier == Darwin - // 10.8 and earlier. - unameR, err := exec.Command("uname", "-r").Output() - if err != nil { - log.Fatalf("uname -r: %v", err) - } - major, _ := strconv.Atoi(string(unameR[:bytes.IndexByte(unameR, '.')])) - return major > 10 } return false } @@ -1327,7 +1318,7 @@ func (t *tester) raceDetectorSupported() bool { case "linux", "darwin", "freebsd", "windows": // The race detector doesn't work on Alpine Linux: // golang.org/issue/14481 - return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux() + return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux() } return false } diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index f1072b5e41fb7..e68e95f3fb511 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -26,7 +26,7 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } - dirsInit(testdataDir) + dirsInit(testdataDir, filepath.Join(testdataDir, "nested"), filepath.Join(testdataDir, "nested", "nested")) os.Exit(m.Run()) } @@ -510,6 +510,24 @@ var tests = []test{ "\\)\n+const", // This will appear if the const decl appears twice. }, }, + { + "non-imported: pkg.sym", + []string{"nested.Foo"}, + []string{"Foo struct"}, + nil, + }, + { + "non-imported: pkg only", + []string{"nested"}, + []string{"Foo struct"}, + nil, + }, + { + "non-imported: pkg sym", + []string{"nested", "Foo"}, + []string{"Foo struct"}, + nil, + }, } func TestDoc(t *testing.T) { diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index 9f947146a494a..bf0c7723f8e02 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -189,11 +189,16 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo // Done below. case 2: // Package must be findable and importable. - packagePath, ok := findPackage(arg) - if !ok { - return nil, args[0], args[1], false + for { + packagePath, ok := findNextPackage(arg) + if !ok { + break + } + if pkg, err := build.ImportDir(packagePath, build.ImportComment); err == nil { + return pkg, arg, args[1], true + } } - return importDir(packagePath), arg, args[1], true + return nil, args[0], args[1], false } // Usual case: one argument. // If it contains slashes, it begins with a package path. @@ -241,9 +246,15 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo } // See if we have the basename or tail of a package, as in json for encoding/json // or ivy/value for robpike.io/ivy/value. - path, ok := findPackage(arg[0:period]) - if ok { - return importDir(path), arg[0:period], symbol, true + pkgName := arg[:period] + for { + path, ok := findNextPackage(pkgName) + if !ok { + break + } + if pkg, err = build.ImportDir(path, build.ImportComment); err == nil { + return pkg, arg[0:period], symbol, true + } } dirs.Reset() // Next iteration of for loop must scan all the directories again. } @@ -338,9 +349,9 @@ func isUpper(name string) bool { return unicode.IsUpper(ch) } -// findPackage returns the full file name path that first matches the +// findNextPackage returns the next full file name path that matches the // (perhaps partial) package path pkg. The boolean reports if any match was found. -func findPackage(pkg string) (string, bool) { +func findNextPackage(pkg string) (string, bool) { if pkg == "" || isUpper(pkg) { // Upper case symbol cannot be a package name. return "", false } diff --git a/src/cmd/doc/testdata/nested/ignore.go b/src/cmd/doc/testdata/nested/ignore.go new file mode 100644 index 0000000000000..c497f1b5bc410 --- /dev/null +++ b/src/cmd/doc/testdata/nested/ignore.go @@ -0,0 +1,4 @@ +// +build ignore + +// Ignored package +package nested diff --git a/src/cmd/doc/testdata/nested/nested/real.go b/src/cmd/doc/testdata/nested/nested/real.go new file mode 100644 index 0000000000000..1e5546081ce03 --- /dev/null +++ b/src/cmd/doc/testdata/nested/nested/real.go @@ -0,0 +1,4 @@ +package nested + +type Foo struct { +} diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 8cccbf4de00ea..d37942b738f34 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -579,7 +579,7 @@ // // Usage: // -// go list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages] +// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages] // // List lists the packages named by the import paths, one per line. // @@ -609,6 +609,9 @@ // Root string // Go root or Go path dir containing this package // ConflictDir string // this directory shadows Dir in $GOPATH // BinaryOnly bool // binary-only package: cannot be recompiled from sources +// ForTest string // package is only for use in named test +// DepOnly bool // package is only a dependency, not explicitly listed +// Export string // file containing export data (when using -export) // // // Source files // GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -683,9 +686,15 @@ // The -json flag causes the package data to be printed in JSON format // instead of using the template format. // +// The -cgo flag causes list to set CgoFiles not to the original *.go files +// importing "C" but instead to the translated files generated by the cgo +// command. +// // The -deps flag causes list to iterate over not just the named packages // but also all their dependencies. It visits them in a depth-first post-order // traversal, so that a package is listed only after all its dependencies. +// Packages not explicitly listed on the command line will have the DepOnly +// field set to true. // // The -e flag changes the handling of erroneous packages, those that // cannot be found or are malformed. By default, the list command @@ -697,6 +706,9 @@ // a non-nil Error field; other information may or may not be missing // (zeroed). // +// The -export flag causes list to set the Export field to the name of a +// file containing up-to-date export information for the given package. +// // The -test flag causes list to report not only the named packages // but also their test binaries (for packages with tests), to convey to // source code analysis tools exactly how test binaries are constructed. @@ -707,7 +719,18 @@ // package itself). The reported import path of a package recompiled // for a particular test binary is followed by a space and the name of // the test binary in brackets, as in "math/rand [math/rand.test]" -// or "regexp [sort.test]". +// or "regexp [sort.test]". The ForTest field is also set to the name +// of the package being tested ("math/rand" or "sort" in the previous +// examples). +// +// The Dir, Target, Shlib, Root, ConflictDir, and Export file paths +// are all absolute paths. +// +// By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir +// (that is, paths relative to Dir, not absolute paths). +// The extra entries added by the -cgo and -test flags are absolute paths +// referring to cached copies of generated Go source files. +// Although they are Go source files, the paths may not end in ".go". // // For more about build flags, see 'go help build'. // diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index fb8846c710dc9..21dc9607d55d6 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -99,6 +99,7 @@ func init() { var testGOROOT string var testCC string +var testGOCACHE string // The TestMain function creates a go command for testing purposes and // deletes it after the tests have been run. @@ -175,6 +176,13 @@ func TestMain(m *testing.M) { } } + out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out) + os.Exit(2) + } + testGOCACHE = strings.TrimSpace(string(out)) + // As of Sept 2017, MSan is only supported on linux/amd64. // https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64" @@ -198,7 +206,7 @@ func TestMain(m *testing.M) { } os.Setenv("HOME", "/test-go-home-does-not-exist") if os.Getenv("GOCACHE") == "" { - os.Setenv("GOCACHE", "off") // because $HOME is gone + os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone } r := m.Run() @@ -1975,6 +1983,59 @@ func TestGoListTest(t *testing.T) { tg.run("list", "-test", "runtime/cgo") tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo") + + tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort") + tg.grepStdout(`^reflect$`, "missing reflect") + tg.grepStdoutNot(`^sort`, "unexpected sort") +} + +func TestGoListCgo(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net") + if tg.stdout.String() == "" { + t.Skip("net does not use cgo") + } + if strings.Contains(tg.stdout.String(), tg.tempdir) { + t.Fatalf(".CgoFiles without -cgo unexpectedly mentioned cache %s", tg.tempdir) + } + tg.run("list", "-cgo", "-f", `{{join .CgoFiles "\n"}}`, "net") + if !strings.Contains(tg.stdout.String(), tg.tempdir) { + t.Fatalf(".CgoFiles with -cgo did not mention cache %s", tg.tempdir) + } + for _, file := range strings.Split(tg.stdout.String(), "\n") { + if file == "" { + continue + } + if _, err := os.Stat(file); err != nil { + t.Fatalf("cannot find .CgoFiles result %s: %v", file, err) + } + } +} + +func TestGoListExport(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.tempdir) + + tg.run("list", "-f", "{{.Export}}", "strings") + if tg.stdout.String() != "" { + t.Fatalf(".Export without -export unexpectedly set") + } + tg.run("list", "-export", "-f", "{{.Export}}", "strings") + file := strings.TrimSpace(tg.stdout.String()) + if file == "" { + t.Fatalf(".Export with -export was empty") + } + if _, err := os.Stat(file); err != nil { + t.Fatalf("cannot find .Export result %s: %v", file, err) + } } // Issue 4096. Validate the output of unsuccessful go install foo/quxx. @@ -2925,7 +2986,7 @@ func TestCgoPkgConfig(t *testing.T) { // OpenBSD's pkg-config is strict about whitespace and only // supports backslash-escaped whitespace. It does not support // quotes, which the normal freedesktop.org pkg-config does - // support. See http://man.openbsd.org/pkg-config.1 + // support. See https://man.openbsd.org/pkg-config.1 tg.tempFile("foo.pc", ` Name: foo Description: The foo library @@ -3203,6 +3264,43 @@ func TestGoTestBuildsAnXtestContainingOnlyNonRunnableExamples(t *testing.T) { tg.grepStdout("File with non-runnable example was built.", "file with non-runnable example was not built") } +// issue 24570 +func TestGoTestCoverMultiPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-cover", "./testdata/testcover/...") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") +} + +// issue 24570 +func TestGoTestCoverprofileMultiPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/cover.out") + tg.run("test", "-coverprofile=testdata/cover.out", "./testdata/testcover/...") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") + if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { + t.Error(err) + } else { + if !bytes.Contains(out, []byte("mode: set")) { + t.Errorf(`missing "mode: set" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg1/a.go:5.10,7.2 1 0`)) && !bytes.Contains(out, []byte(`pkg1\a.go:5.10,7.2 1 0`)) { + t.Errorf(`missing "pkg1/a.go:5.10,7.2 1 0" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg2/a.go:5.10,7.2 1 0`)) && !bytes.Contains(out, []byte(`pkg2\a.go:5.10,7.2 1 0`)) { + t.Errorf(`missing "pkg2/a.go:5.10,7.2 1 0" in %s`, out) + } + if !bytes.Contains(out, []byte(`pkg3/a.go:5.10,7.2 1 1`)) && !bytes.Contains(out, []byte(`pkg3\a.go:5.10,7.2 1 1`)) { + t.Errorf(`missing "pkg3/a.go:5.10,7.2 1 1" in %s`, out) + } + } +} + func TestGoGenerateHandlesSimpleCommand(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping because windows has no echo command") @@ -3690,6 +3788,40 @@ func TestGoGetUpdateInsecure(t *testing.T) { tg.run("get", "-d", "-u", "-f", "-insecure", pkg) } +func TestGoGetUpdateUnknownProtocol(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + const repo = "github.com/golang/example" + + // Clone the repo via HTTPS manually. + repoDir := tg.path("src/" + repo) + cmd := exec.Command("git", "clone", "-q", "https://"+repo, repoDir) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("cloning %v repo: %v\n%s", repo, err, out) + } + + // Configure the repo to use a protocol unknown to cmd/go + // that still actually works. + cmd = exec.Command("git", "remote", "set-url", "origin", "xyz://"+repo) + cmd.Dir = repoDir + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("git remote set-url: %v\n%s", err, out) + } + cmd = exec.Command("git", "config", "--local", "url.https://github.com/.insteadOf", "xyz://github.com/") + cmd.Dir = repoDir + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("git config: %v\n%s", err, out) + } + + // We need -f to ignore import comments. + tg.run("get", "-d", "-u", "-f", repo+"/hello") +} + func TestGoGetInsecureCustomDomain(t *testing.T) { testenv.MustHaveExternalNetwork(t) @@ -4892,30 +5024,34 @@ func TestTestRegexps(t *testing.T) { // BenchmarkX/Y is run in full, twice want := `=== RUN TestX === RUN TestX/Y - x_test.go:6: LOG: X running - x_test.go:8: LOG: Y running + x_test.go:6: LOG: X running + x_test.go:8: LOG: Y running === RUN TestXX - z_test.go:10: LOG: XX running + z_test.go:10: LOG: XX running === RUN TestX === RUN TestX/Y - x_test.go:6: LOG: X running - x_test.go:8: LOG: Y running + x_test.go:6: LOG: X running + x_test.go:8: LOG: Y running === RUN TestXX - z_test.go:10: LOG: XX running + z_test.go:10: LOG: XX running --- BENCH: BenchmarkX/Y - x_test.go:15: LOG: Y running N=1 - x_test.go:15: LOG: Y running N=100 - x_test.go:15: LOG: Y running N=10000 - x_test.go:15: LOG: Y running N=1000000 - x_test.go:15: LOG: Y running N=100000000 - x_test.go:15: LOG: Y running N=2000000000 + x_test.go:15: LOG: Y running N=1 + x_test.go:15: LOG: Y running N=100 + x_test.go:15: LOG: Y running N=10000 + x_test.go:15: LOG: Y running N=1000000 + x_test.go:15: LOG: Y running N=100000000 + x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX/Y - x_test.go:15: LOG: Y running N=1 - x_test.go:15: LOG: Y running N=2000000000 + x_test.go:15: LOG: Y running N=1 + x_test.go:15: LOG: Y running N=100 + x_test.go:15: LOG: Y running N=10000 + x_test.go:15: LOG: Y running N=1000000 + x_test.go:15: LOG: Y running N=100000000 + x_test.go:15: LOG: Y running N=2000000000 --- BENCH: BenchmarkX - x_test.go:13: LOG: X running N=1 + x_test.go:13: LOG: X running N=1 --- BENCH: BenchmarkXX - z_test.go:18: LOG: XX running N=1 + z_test.go:18: LOG: XX running N=1 ` have := strings.Join(lines, "") @@ -6325,3 +6461,14 @@ func TestCDAndGOPATHAreDifferent(t *testing.T) { testCDAndGOPATHAreDifferent(tg, cd, strings.ToLower(gopath)) } } + +// Issue 25579. +func TestGoBuildDashODevNull(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("build", "-o", os.DevNull, filepath.Join(tg.pwd(), "testdata", "src", "hello", "hello.go")) + tg.mustNotExist("hello") + tg.mustNotExist("hello.exe") +} diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index edb58826f1704..0cf01550ff90d 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -189,6 +189,21 @@ func (c *Cache) get(id ActionID) (Entry, error) { return Entry{buf, size, time.Unix(0, tm)}, nil } +// GetFile looks up the action ID in the cache and returns +// the name of the corresponding data file. +func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) { + entry, err = c.Get(id) + if err != nil { + return "", Entry{}, err + } + file = c.OutputFile(entry.OutputID) + info, err := os.Stat(file) + if err != nil || info.Size() != entry.Size { + return "", Entry{}, errMissing + } + return file, entry, nil +} + // GetBytes looks up the action ID in the cache and returns // the corresponding output bytes. // GetBytes should only be used for data that can be expected to fit in memory. diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index 3df5905d02691..b7906bb1dbb32 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -103,6 +103,16 @@ func init() { } } +// There is a copy of findGOROOT, isSameDir, and isGOROOT in +// x/tools/cmd/godoc/goroot.go. +// Try to keep them in sync for now. + +// findGOROOT returns the GOROOT value, using either an explicitly +// provided environment variable, a GOROOT that contains the current +// os.Executable value, or else the GOROOT that the binary was built +// with from runtime.GOROOT(). +// +// There is a copy of this code in x/tools/cmd/godoc/goroot.go. func findGOROOT() string { if env := os.Getenv("GOROOT"); env != "" { return filepath.Clean(env) @@ -162,6 +172,8 @@ func isSameDir(dir1, dir2 string) bool { // It does this by looking for the path/pkg/tool directory, // which is necessary for useful operation of the cmd/go tool, // and is not typically present in a GOPATH. +// +// There is a copy of this code in x/tools/cmd/godoc/goroot.go. func isGOROOT(path string) bool { stat, err := os.Stat(filepath.Join(path, "pkg", "tool")) if err != nil { diff --git a/src/cmd/go/internal/get/discovery.go b/src/cmd/go/internal/get/discovery.go index b2918dbb4f31a..97aa1d7e8d634 100644 --- a/src/cmd/go/internal/get/discovery.go +++ b/src/cmd/go/internal/get/discovery.go @@ -55,6 +55,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { continue } if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { + // Ignore VCS type "mod", which is new Go modules. + // This code is for old go get and must ignore the new mod lines. + // Otherwise matchGoImport will complain about two + // different metaImport lines for the same Prefix. + if f[1] == "mod" { + continue + } imports = append(imports, metaImport{ Prefix: f[0], VCS: f[1], diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 733116eca04d8..ffa15c5ba48e4 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -209,7 +209,7 @@ var downloadRootCache = map[string]bool{} // download runs the download half of the get command // for the package named by the argument. func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) { - if mode&load.UseVendor != 0 { + if mode&load.ResolveImport != 0 { // Caller is responsible for expanding vendor paths. panic("internal error: download mode has useVendor set") } @@ -217,7 +217,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) if parent == nil { return load.LoadPackage(path, stk) } - return load.LoadImport(path, parent.Dir, parent, stk, nil, mode) + return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) } p := load1(arg, mode) @@ -346,12 +346,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) base.Errorf("%s", err) continue } - // If this is a test import, apply vendor lookup now. - // We cannot pass useVendor to download, because + // If this is a test import, apply module and vendor lookup now. + // We cannot pass ResolveImport to download, because // download does caching based on the value of path, // so it must be the fully qualified path already. if i >= len(p.Imports) { - path = load.VendoredImportPath(p, path) + path = load.ResolveImportPath(p, path) } download(path, p, stk, 0) } @@ -369,6 +369,7 @@ func downloadPackage(p *load.Package) error { vcs *vcsCmd repo, rootPath string err error + blindRepo bool // set if the repo has unusual configuration ) security := web.Secure @@ -389,10 +390,12 @@ func downloadPackage(p *load.Package) error { dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) remote, err := vcs.remoteRepo(vcs, dir) if err != nil { - return err + // Proceed anyway. The package is present; we likely just don't understand + // the repo configuration (e.g. unusual remote protocol). + blindRepo = true } repo = remote - if !*getF { + if !*getF && err == nil { if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil { repo := rr.repo if rr.vcs.resolveRepo != nil { @@ -416,7 +419,7 @@ func downloadPackage(p *load.Package) error { } vcs, repo, rootPath = rr.vcs, rr.repo, rr.root } - if !vcs.isSecure(repo) && !*getInsecure { + if !blindRepo && !vcs.isSecure(repo) && !*getInsecure { return fmt.Errorf("cannot download, %v uses insecure protocol", repo) } diff --git a/src/cmd/go/internal/get/pkg_test.go b/src/cmd/go/internal/get/pkg_test.go index b8937a57ec912..1179d86693ace 100644 --- a/src/cmd/go/internal/get/pkg_test.go +++ b/src/cmd/go/internal/get/pkg_test.go @@ -47,6 +47,20 @@ var parseMetaGoImportsTests = []struct { {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, }, }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, { ` diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 5b242a887a2d8..218999c7e8e52 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -23,7 +23,7 @@ import ( ) var CmdList = &base.Command{ - UsageLine: "list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages]", + UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages]", Short: "list packages", Long: ` List lists the packages named by the import paths, one per line. @@ -54,6 +54,9 @@ syntax of package template. The default output is equivalent to -f Root string // Go root or Go path dir containing this package ConflictDir string // this directory shadows Dir in $GOPATH BinaryOnly bool // binary-only package: cannot be recompiled from sources + ForTest string // package is only for use in named test + DepOnly bool // package is only a dependency, not explicitly listed + Export string // file containing export data (when using -export) // Source files GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -128,9 +131,15 @@ for the go/build package's Context type. The -json flag causes the package data to be printed in JSON format instead of using the template format. +The -cgo flag causes list to set CgoFiles not to the original *.go files +importing "C" but instead to the translated files generated by the cgo +command. + The -deps flag causes list to iterate over not just the named packages but also all their dependencies. It visits them in a depth-first post-order traversal, so that a package is listed only after all its dependencies. +Packages not explicitly listed on the command line will have the DepOnly +field set to true. The -e flag changes the handling of erroneous packages, those that cannot be found or are malformed. By default, the list command @@ -142,6 +151,9 @@ printing. Erroneous packages will have a non-empty ImportPath and a non-nil Error field; other information may or may not be missing (zeroed). +The -export flag causes list to set the Export field to the name of a +file containing up-to-date export information for the given package. + The -test flag causes list to report not only the named packages but also their test binaries (for packages with tests), to convey to source code analysis tools exactly how test binaries are constructed. @@ -152,7 +164,18 @@ dependencies specially for that test (most commonly the tested package itself). The reported import path of a package recompiled for a particular test binary is followed by a space and the name of the test binary in brackets, as in "math/rand [math/rand.test]" -or "regexp [sort.test]". +or "regexp [sort.test]". The ForTest field is also set to the name +of the package being tested ("math/rand" or "sort" in the previous +examples). + +The Dir, Target, Shlib, Root, ConflictDir, and Export file paths +are all absolute paths. + +By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir +(that is, paths relative to Dir, not absolute paths). +The extra entries added by the -cgo and -test flags are absolute paths +referring to cached copies of generated Go source files. +Although they are Go source files, the paths may not end in ".go". For more about build flags, see 'go help build'. @@ -165,8 +188,10 @@ func init() { work.AddBuildFlags(CmdList) } +var listCgo = CmdList.Flag.Bool("cgo", false, "") var listDeps = CmdList.Flag.Bool("deps", false, "") var listE = CmdList.Flag.Bool("e", false, "") +var listExport = CmdList.Flag.Bool("export", false, "") var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "") var listJson = CmdList.Flag.Bool("json", false, "") var listTest = CmdList.Flag.Bool("test", false, "") @@ -222,11 +247,22 @@ func runList(cmd *base.Command, args []string) { pkgs = load.Packages(args) } - if *listTest { - c := cache.Default() - if c == nil { + if cache.Default() == nil { + // These flags return file names pointing into the build cache, + // so the build cache must exist. + if *listCgo { + base.Fatalf("go list -cgo requires build cache") + } + if *listExport { + base.Fatalf("go list -export requires build cache") + } + if *listTest { base.Fatalf("go list -test requires build cache") } + } + + if *listTest { + c := cache.Default() // Add test binaries to packages to be listed. for _, p := range pkgs { if p.Error != nil { @@ -279,13 +315,14 @@ func runList(cmd *base.Command, args []string) { pkgs = load.PackageList(pkgs) } - // Estimate whether staleness information is needed, - // since it's a little bit of work to compute. + // Do we need to run a build to gather information? needStale := *listJson || strings.Contains(*listFmt, ".Stale") - if needStale { + if needStale || *listExport || *listCgo { var b work.Builder b.Init() - b.ComputeStaleOnly = true + b.IsCmdList = true + b.NeedExport = *listExport + b.NeedCgoFiles = *listCgo a := &work.Action{} // TODO: Use pkgsFilter? for _, p := range pkgs { @@ -296,8 +333,9 @@ func runList(cmd *base.Command, args []string) { for _, p := range pkgs { // Show vendor-expanded paths in listing - p.TestImports = p.Vendored(p.TestImports) - p.XTestImports = p.Vendored(p.XTestImports) + p.TestImports = p.Resolve(p.TestImports) + p.XTestImports = p.Resolve(p.XTestImports) + p.DepOnly = !cmdline[p] } if *listTest { diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 5a26ca7892a23..693d862214345 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -6,6 +6,7 @@ package load import ( + "bytes" "fmt" "go/build" "go/token" @@ -14,6 +15,7 @@ import ( pathpkg "path" "path/filepath" "sort" + "strconv" "strings" "unicode" "unicode/utf8" @@ -49,6 +51,7 @@ type PackagePublic struct { BinaryOnly bool `json:",omitempty"` // package cannot be recompiled ForTest string `json:",omitempty"` // package is only for use in named test DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed + Export string `json:",omitempty"` // file containing export data (set by go list -export) // Stale and StaleReason remain here *only* for the list command. // They are only initialized in preparation for list execution. @@ -179,7 +182,7 @@ func (e *NoGoError) Error() string { return "no Go files in " + e.Package.Dir } -// Vendored returns the vendor-resolved version of imports, +// Resolve returns the resolved version of imports, // which should be p.TestImports or p.XTestImports, NOT p.Imports. // The imports in p.TestImports and p.XTestImports are not recursively // loaded during the initial load of p, so they list the imports found in @@ -189,14 +192,14 @@ func (e *NoGoError) Error() string { // can produce better error messages if it starts with the original paths. // The initial load of p loads all the non-test imports and rewrites // the vendored paths, so nothing should ever call p.vendored(p.Imports). -func (p *Package) Vendored(imports []string) []string { +func (p *Package) Resolve(imports []string) []string { if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { - panic("internal error: p.vendored(p.Imports) called") + panic("internal error: p.Resolve(p.Imports) called") } seen := make(map[string]bool) var all []string for _, path := range imports { - path = VendoredImportPath(p, path) + path = ResolveImportPath(p, path) if !seen[path] { seen[path] = true all = append(all, path) @@ -391,16 +394,20 @@ func makeImportValid(r rune) rune { // Mode flags for loadImport and download (in get.go). const ( - // UseVendor means that loadImport should do vendor expansion - // (provided the vendoring experiment is enabled). - // That is, useVendor means that the import path came from - // a source file and has not been vendor-expanded yet. - // Every import path should be loaded initially with useVendor, - // and then the expanded version (with the /vendor/ in it) gets - // recorded as the canonical import path. At that point, future loads - // of that package must not pass useVendor, because + // ResolveImport means that loadImport should do import path expansion. + // That is, ResolveImport means that the import path came from + // a source file and has not been expanded yet to account for + // vendoring or possible module adjustment. + // Every import path should be loaded initially with ResolveImport, + // and then the expanded version (for example with the /vendor/ in it) + // gets recorded as the canonical import path. At that point, future loads + // of that package must not pass ResolveImport, because // disallowVendor will reject direct use of paths containing /vendor/. - UseVendor = 1 << iota + ResolveImport = 1 << iota + + // ResolveModule is for download (part of "go get") and indicates + // that the module adjustment should be done, but not vendor adjustment. + ResolveModule // GetTestDeps is for download (part of "go get") and indicates // that test dependencies should be fetched too. @@ -425,12 +432,15 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo isLocal := build.IsLocalImport(path) if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) - } else if mode&UseVendor != 0 { - // We do our own vendor resolution, because we want to + } else if mode&ResolveImport != 0 { + // We do our own path resolution, because we want to // find out the key to use in packageCache without the // overhead of repeated calls to buildContext.Import. // The code is also needed in a few other places anyway. - path = VendoredImportPath(parent, path) + path = ResolveImportPath(parent, path) + importPath = path + } else if mode&ResolveModule != 0 { + path = ModuleImportPath(parent, path) importPath = path } @@ -447,7 +457,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo // Import always returns bp != nil, even if an error occurs, // in order to return partial information. buildMode := build.ImportComment - if mode&UseVendor == 0 || path != origPath { + if mode&ResolveImport == 0 || path != origPath { // Not vendoring, or we already found the vendored path. buildMode |= build.IgnoreVendor } @@ -478,7 +488,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo if perr := disallowInternal(srcDir, p, stk); perr != p { return setErrorPos(perr, importPos) } - if mode&UseVendor != 0 { + if mode&ResolveImport != 0 { if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { return setErrorPos(perr, importPos) } @@ -537,24 +547,31 @@ func isDir(path string) bool { return result } -// VendoredImportPath returns the expansion of path when it appears in parent. -// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, -// x/vendor/path, vendor/path, or else stay path if none of those exist. -// VendoredImportPath returns the expanded path or, if no expansion is found, the original. -func VendoredImportPath(parent *Package, path string) (found string) { - if parent == nil || parent.Root == "" { - return path - } +// ResolveImportPath returns the true meaning of path when it appears in parent. +// There are two different resolutions applied. +// First, there is Go 1.5 vendoring (golang.org/s/go15vendor). +// If vendor expansion doesn't trigger, then the path is also subject to +// Go 1.11 vgo legacy conversion (golang.org/issue/25069). +func ResolveImportPath(parent *Package, path string) (found string) { + found = VendoredImportPath(parent, path) + if found != path { + return found + } + return ModuleImportPath(parent, path) +} - dir := filepath.Clean(parent.Dir) - root := filepath.Join(parent.Root, "src") - if !str.HasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir { +// dirAndRoot returns the source directory and workspace root +// for the package p, guaranteeing that root is a path prefix of dir. +func dirAndRoot(p *Package) (dir, root string) { + dir = filepath.Clean(p.Dir) + root = filepath.Join(p.Root, "src") + if !str.HasFilePathPrefix(dir, root) || p.ImportPath != "command-line-arguments" && filepath.Join(root, p.ImportPath) != dir { // Look for symlinks before reporting error. dir = expandPath(dir) root = expandPath(root) } - if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir { + if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || p.ImportPath != "command-line-arguments" && !p.Internal.Local && filepath.Join(root, p.ImportPath) != dir { base.Fatalf("unexpected directory layout:\n"+ " import path: %s\n"+ " root: %s\n"+ @@ -562,14 +579,28 @@ func VendoredImportPath(parent *Package, path string) (found string) { " expand root: %s\n"+ " expand dir: %s\n"+ " separator: %s", - parent.ImportPath, - filepath.Join(parent.Root, "src"), - filepath.Clean(parent.Dir), + p.ImportPath, + filepath.Join(p.Root, "src"), + filepath.Clean(p.Dir), root, dir, string(filepath.Separator)) } + return dir, root +} + +// VendoredImportPath returns the vendor-expansion of path when it appears in parent. +// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, +// x/vendor/path, vendor/path, or else stay path if none of those exist. +// VendoredImportPath returns the expanded path or, if no expansion is found, the original. +func VendoredImportPath(parent *Package, path string) (found string) { + if parent == nil || parent.Root == "" { + return path + } + + dir, root := dirAndRoot(parent) + vpath := "vendor/" + path for i := len(dir); i >= len(root); i-- { if i < len(dir) && dir[i] != filepath.Separator { @@ -612,6 +643,164 @@ func VendoredImportPath(parent *Package, path string) (found string) { return path } +var ( + modulePrefix = []byte("\nmodule ") + goModPathCache = make(map[string]string) +) + +// goModPath returns the module path in the go.mod in dir, if any. +func goModPath(dir string) (path string) { + path, ok := goModPathCache[dir] + if ok { + return path + } + defer func() { + goModPathCache[dir] = path + }() + + data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod")) + if err != nil { + return "" + } + var i int + if bytes.HasPrefix(data, modulePrefix[1:]) { + i = 0 + } else { + i = bytes.Index(data, modulePrefix) + if i < 0 { + return "" + } + i++ + } + line := data[i:] + + // Cut line at \n, drop trailing \r if present. + if j := bytes.IndexByte(line, '\n'); j >= 0 { + line = line[:j] + } + if line[len(line)-1] == '\r' { + line = line[:len(line)-1] + } + line = line[len("module "):] + + // If quoted, unquote. + path = strings.TrimSpace(string(line)) + if path != "" && path[0] == '"' { + s, err := strconv.Unquote(path) + if err != nil { + return "" + } + path = s + } + return path +} + +// findVersionElement returns the slice indices of the final version element /vN in path. +// If there is no such element, it returns -1, -1. +func findVersionElement(path string) (i, j int) { + j = len(path) + for i = len(path) - 1; i >= 0; i-- { + if path[i] == '/' { + if isVersionElement(path[i:j]) { + return i, j + } + j = i + } + } + return -1, -1 +} + +// isVersionElement reports whether s is a well-formed path version element: +// v2, v3, v10, etc, but not v0, v05, v1. +func isVersionElement(s string) bool { + if len(s) < 3 || s[0] != '/' || s[1] != 'v' || s[2] == '0' || s[2] == '1' && len(s) == 3 { + return false + } + for i := 2; i < len(s); i++ { + if s[i] < '0' || '9' < s[i] { + return false + } + } + return true +} + +// ModuleImportPath translates import paths found in go modules +// back down to paths that can be resolved in ordinary builds. +// +// Define “new” code as code with a go.mod file in the same directory +// or a parent directory. If an import in new code says x/y/v2/z but +// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”, +// then go build will read the import as x/y/z instead. +// See golang.org/issue/25069. +func ModuleImportPath(parent *Package, path string) (found string) { + if parent == nil || parent.Root == "" { + return path + } + + // If there are no vN elements in path, leave it alone. + // (The code below would do the same, but only after + // some other file system accesses that we can avoid + // here by returning early.) + if i, _ := findVersionElement(path); i < 0 { + return path + } + + dir, root := dirAndRoot(parent) + + // Consider dir and parents, up to and including root. + for i := len(dir); i >= len(root); i-- { + if i < len(dir) && dir[i] != filepath.Separator { + continue + } + if goModPath(dir[:i]) != "" { + goto HaveGoMod + } + } + // This code is not in a tree with a go.mod, + // so apply no changes to the path. + return path + +HaveGoMod: + // This import is in a tree with a go.mod. + // Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z + // if GOPATH/src/x/y/go.mod says module "x/y/v2", + + // If x/y/v2/z exists, use it unmodified. + if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" { + return path + } + + // Otherwise look for a go.mod supplying a version element. + // Some version-like elements may appear in paths but not + // be module versions; we skip over those to look for module + // versions. For example the module m/v2 might have a + // package m/v2/api/v1/foo. + limit := len(path) + for limit > 0 { + i, j := findVersionElement(path[:limit]) + if i < 0 { + return path + } + if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" { + if mpath := goModPath(bp.Dir); mpath != "" { + // Found a valid go.mod file, so we're stopping the search. + // If the path is m/v2/p and we found m/go.mod that says + // "module m/v2", then we return "m/p". + if mpath == path[:j] { + return path[:i] + path[j:] + } + // Otherwise just return the original path. + // We didn't find anything worth rewriting, + // and the go.mod indicates that we should + // not consider parent directories. + return path + } + } + limit = i + } + return path +} + // hasGoFiles reports whether dir contains any files with names ending in .go. // For a vendor check we must exclude directories that contain no .go files. // Otherwise it is not possible to vendor just a/b/c and still import the @@ -1076,7 +1265,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { if path == "C" { continue } - p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport) if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { p.Error = &PackageError{ ImportStack: stk.Copy(), diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index a9b47ce72dc40..0a13dfc1b7a9c 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -49,16 +49,13 @@ type TestCover struct { // (for example, if there are no "package p" test files and // package p need not be instrumented for coverage or any other reason), // then the returned ptest == p. -// -// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0, -// or else there's no point in any of this. func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) { var imports, ximports []*Package var stk ImportStack stk.Push(p.ImportPath + " (test)") rawTestImports := str.StringList(p.TestImports) for i, path := range p.TestImports { - p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) if p1.Error != nil { return nil, nil, nil, p1.Error } @@ -86,7 +83,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag pxtestNeedsPtest := false rawXTestImports := str.StringList(p.XTestImports) for i, path := range p.XTestImports { - p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor) + p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport) if p1.Error != nil { return nil, nil, nil, p1.Error } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index bcff5ff3b164d..aff5ff2c9d3ed 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -600,10 +600,10 @@ func runTest(cmd *base.Command, args []string) { for _, path := range p.Imports { deps[path] = true } - for _, path := range p.Vendored(p.TestImports) { + for _, path := range p.Resolve(p.TestImports) { deps[path] = true } - for _, path := range p.Vendored(p.XTestImports) { + for _, path := range p.Resolve(p.XTestImports) { deps[path] = true } } @@ -781,14 +781,6 @@ var windowsBadWords = []string{ } func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { - if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := b.CompileAction(work.ModeBuild, work.ModeBuild, p) - run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}} - addTestVet(b, p, run, nil) - print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}} - return build, run, print, nil - } - // Build Package structs describing: // pmain - pkg.test binary // ptest - package + test files @@ -1176,13 +1168,17 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error { if err == nil { norun := "" + res := "ok" if !testShowPass && !testJSON { buf.Reset() } - if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { + if len(a.Package.TestGoFiles)+len(a.Package.XTestGoFiles) == 0 { + res = "? " + norun = " [no test files]" + } else if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { norun = " [no tests to run]" } - fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) + fmt.Fprintf(cmd.Stdout, "%s \t%s\t%s%s%s\n", res, a.Package.ImportPath, t, coveragePercentage(out), norun) c.saveOutput(a) } else { base.SetExitStatus(1) @@ -1596,15 +1592,3 @@ func builderPrintTest(b *work.Builder, a *work.Action) error { } return nil } - -// builderNoTest is the action for testing a package with no test files. -func builderNoTest(b *work.Builder, a *work.Action) error { - var stdout io.Writer = os.Stdout - if testJSON { - json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) - defer json.Close() - stdout = json - } - fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath) - return nil -} diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index 03770ea920eb6..bdfe033018909 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -90,7 +90,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) { } switch f.Name { // Flags known to the build but not to vet, so must be dropped. - case "x", "n", "vettool", "compiler": + case "a", "x", "n", "vettool", "compiler": if extraWord { args = append(args[:i], args[i+2:]...) extraWord = false diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index c83fe4e58d282..8edf55ffa1ef4 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -36,7 +36,10 @@ type Builder struct { flagCache map[[2]string]bool // a cache of supported compiler flags Print func(args ...interface{}) (int, error) - ComputeStaleOnly bool // compute staleness for go list; no actual build + IsCmdList bool // running as part of go list; set p.Stale and additional fields below + NeedError bool // list needs p.Error + NeedExport bool // list needs p.Export + NeedCgoFiles bool // list needs p.CgoFiles to cgo-generated files, not originals objdirSeq int // counter for NewObjdir pkgSeq int @@ -79,9 +82,10 @@ type Action struct { actionID cache.ActionID // cache ID of action input buildID string // build ID of action output - needVet bool // Mode=="build": need to fill in vet config - vetCfg *vetConfig // vet config - output []byte // output redirect buffer (nil means use b.Print) + VetxOnly bool // Mode=="vet": only being called to supply info about dependencies + needVet bool // Mode=="build": need to fill in vet config + vetCfg *vetConfig // vet config + output []byte // output redirect buffer (nil means use b.Print) // Execution state. pending int // number of deps yet to complete @@ -138,6 +142,7 @@ type actionJSON struct { Priority int `json:",omitempty"` Failed bool `json:",omitempty"` Built string `json:",omitempty"` + VetxOnly bool `json:",omitempty"` } // cacheKey is the key for the action cache. @@ -177,6 +182,7 @@ func actionGraphJSON(a *Action) string { Failed: a.Failed, Priority: a.priority, Built: a.built, + VetxOnly: a.VetxOnly, } if a.Package != nil { // TODO(rsc): Make this a unique key for a.Package somehow. @@ -380,6 +386,12 @@ func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Actio // If the caller may be causing p to be installed, it is up to the caller // to make sure that the install depends on (runs after) vet. func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { + a := b.vetAction(mode, depMode, p) + a.VetxOnly = false + return a +} + +func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { // Construct vet action. a := b.cacheAction("vet", p, func() *Action { a1 := b.CompileAction(mode, depMode, p) @@ -391,11 +403,18 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { stk.Pop() aFmt := b.CompileAction(ModeBuild, depMode, p1) + deps := []*Action{a1, aFmt} + for _, p1 := range load.PackageList(p.Internal.Imports) { + deps = append(deps, b.vetAction(mode, depMode, p1)) + } + a := &Action{ - Mode: "vet", - Package: p, - Deps: []*Action{a1, aFmt}, - Objdir: a1.Objdir, + Mode: "vet", + Package: p, + Deps: deps, + Objdir: a1.Objdir, + VetxOnly: true, + IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems) } if a1.Func == nil { // Built-in packages like unsafe. @@ -403,7 +422,6 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { } a1.needVet = true a.Func = (*Builder).vet - return a }) return a diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index e5f0e624c3ef9..5cb0c2431f2a8 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -284,11 +284,6 @@ func runBuild(cmd *base.Command, args []string) { cfg.BuildO += cfg.ExeSuffix } - // Special case -o /dev/null by not writing at all. - if cfg.BuildO == os.DevNull { - cfg.BuildO = "" - } - // sanity check some often mis-used options switch cfg.BuildContext.Compiler { case "gccgo": @@ -311,6 +306,11 @@ func runBuild(cmd *base.Command, args []string) { pkgs = pkgsFilter(load.Packages(args)) + // Special case -o /dev/null by not writing at all. + if cfg.BuildO == os.DevNull { + cfg.BuildO = "" + } + if cfg.BuildO != "" { if len(pkgs) > 1 { base.Fatalf("go build: cannot use -o with multiple packages") diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 94a06ff68fabb..9a2528b914167 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -174,20 +174,29 @@ func (b *Builder) toolID(name string) string { return id } - cmdline := str.StringList(cfg.BuildToolexec, base.Tool(name), "-V=full") + path := base.Tool(name) + desc := "go tool " + name + + // Special case: undocumented -vettool overrides usual vet, for testing vet. + if name == "vet" && VetTool != "" { + path = VetTool + desc = VetTool + } + + cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full") cmd := exec.Command(cmdline[0], cmdline[1:]...) cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - base.Fatalf("go tool %s: %v\n%s%s", name, err, stdout.Bytes(), stderr.Bytes()) + base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes()) } line := stdout.String() f := strings.Fields(line) - if len(f) < 3 || f[0] != name || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { - base.Fatalf("go tool %s -V=full: unexpected output:\n\t%s", name, line) + if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { + base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line) } if f[2] == "devel" { // On the development branch, use the content ID part of the build ID. @@ -294,13 +303,32 @@ func (b *Builder) gccgoToolID(name, language string) (string, error) { return id, nil } +// Check if assembler used by gccgo is GNU as. +func assemblerIsGas() bool { + cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as") + assembler, err := cmd.Output() + if err == nil { + cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version") + out, err := cmd.Output() + return err == nil && strings.Contains(string(out), "GNU") + } else { + return false + } +} + // gccgoBuildIDELFFile creates an assembler file that records the // action's build ID in an SHF_EXCLUDE section. func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { sfile := a.Objdir + "_buildid.s" var buf bytes.Buffer - fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + if cfg.Goos != "solaris" || assemblerIsGas() { + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" { + fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n") + } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64" + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n") + } fmt.Fprintf(&buf, "\t.byte ") for i := 0; i < len(a.buildID); i++ { if i > 0 { @@ -313,8 +341,10 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { fmt.Fprintf(&buf, "%#02x", a.buildID[i]) } fmt.Fprintf(&buf, "\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + if cfg.Goos != "solaris" { + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + } if cfg.BuildN || cfg.BuildX { for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { @@ -414,7 +444,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // already up-to-date, then to avoid a rebuild, report the package // as up-to-date as well. See "Build IDs" comment above. // TODO(rsc): Rewrite this code to use a TryCache func on the link action. - if target != "" && !cfg.BuildA && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { + if target != "" && !cfg.BuildA && !b.NeedExport && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { buildID, err := buildid.ReadFile(target) if err == nil { id := strings.Split(buildID, buildIDSeparator) @@ -455,8 +485,8 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID return true } - if b.ComputeStaleOnly { - // Invoked during go list only to compute and record staleness. + if b.IsCmdList { + // Invoked during go list to compute and record staleness. if p := a.Package; p != nil && !p.Stale { p.Stale = true if cfg.BuildA { @@ -488,14 +518,9 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // but we're still happy to use results from the build artifact cache. if c := cache.Default(); c != nil { if !cfg.BuildA { - entry, err := c.Get(actionHash) - if err == nil { - file := c.OutputFile(entry.OutputID) - info, err1 := os.Stat(file) - buildID, err2 := buildid.ReadFile(file) - if err1 == nil && err2 == nil && info.Size() == entry.Size { - stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")) - if err == nil { + if file, _, err := c.GetFile(actionHash); err == nil { + if buildID, err := buildid.ReadFile(file); err == nil { + if stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")); err == nil { if len(stdout) > 0 { if cfg.BuildX || cfg.BuildN { b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) @@ -521,10 +546,6 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID a.output = []byte{} } - if b.ComputeStaleOnly { - return true - } - return false } @@ -609,11 +630,17 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { panic("internal error: a.output not set") } outputID, _, err := c.Put(a.actionID, r) + r.Close() if err == nil && cfg.BuildX { b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID)))) } + if b.NeedExport { + if err != nil { + return err + } + a.Package.Export = c.OutputFile(outputID) + } c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) - r.Close() } } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 072e2904c1467..1013e1a11f24f 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -54,7 +54,7 @@ func actionList(root *Action) []*Action { // do runs the action graph rooted at root. func (b *Builder) Do(root *Action) { - if c := cache.Default(); c != nil && !b.ComputeStaleOnly { + if c := cache.Default(); c != nil && !b.IsCmdList { // If we're doing real work, take time at the end to trim the cache. defer c.Trim() } @@ -296,11 +296,11 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { return h.Sum() } -// needCgoHeader reports whether the actions triggered by this one +// needCgoHdr reports whether the actions triggered by this one // expect to be able to access the cgo-generated header file. -func needCgoHeader(a *Action) bool { +func (b *Builder) needCgoHdr(a *Action) bool { // If this build triggers a header install, run cgo to get the header. - if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { + if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { for _, t1 := range a.triggers { if t1.Mode == "install header" { return true @@ -317,19 +317,54 @@ func needCgoHeader(a *Action) bool { return false } +const ( + needBuild uint32 = 1 << iota + needCgoHdr + needVet + needCgoFiles + needStale +) + // build is the action for building a single package. // Note that any new influence on this logic must be reported in b.buildActionID above as well. func (b *Builder) build(a *Action) (err error) { p := a.Package + + bit := func(x uint32, b bool) uint32 { + if b { + return x + } + return 0 + } + cached := false - needCgo := needCgoHeader(a) + need := bit(needBuild, !b.IsCmdList || b.NeedExport) | + bit(needCgoHdr, b.needCgoHdr(a)) | + bit(needVet, a.needVet) | + bit(needCgoFiles, b.NeedCgoFiles && (p.UsesCgo() || p.UsesSwig())) + + // Save p.CgoFiles now, because we may modify it for go list. + cgofiles := append([]string{}, p.CgoFiles...) if !p.BinaryOnly { if b.useCache(a, p, b.buildActionID(a), p.Target) { - if b.ComputeStaleOnly || !needCgo && !a.needVet { - return nil + // We found the main output in the cache. + // If we don't need any other outputs, we can stop. + need &^= needBuild + if b.NeedExport { + p.Export = a.built + } + if need&needCgoFiles != 0 && b.loadCachedCgoFiles(a) { + need &^= needCgoFiles } + // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr). + // Remember that we might have them in cache + // and check again after we create a.Objdir. cached = true + a.output = []byte{} // start saving output in case we miss any cache results + } + if need == 0 { + return nil } defer b.flushOutput(a) } @@ -338,6 +373,9 @@ func (b *Builder) build(a *Action) (err error) { if err != nil && err != errPrintedOutput { err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err) } + if err != nil && b.IsCmdList && b.NeedError && p.Error == nil { + p.Error = &load.PackageError{Err: err.Error()} + } }() if cfg.BuildN { // In -n mode, print a banner between packages. @@ -357,14 +395,17 @@ func (b *Builder) build(a *Action) (err error) { if err == nil { a.built = a.Package.Target a.Target = a.Package.Target + if b.NeedExport { + a.Package.Export = a.Package.Target + } a.buildID = b.fileHash(a.Package.Target) a.Package.Stale = false a.Package.StaleReason = "binary-only package" return nil } - if b.ComputeStaleOnly { - a.Package.Stale = true - a.Package.StaleReason = "missing or invalid binary-only package" + a.Package.Stale = true + a.Package.StaleReason = "missing or invalid binary-only package" + if b.IsCmdList { return nil } return fmt.Errorf("missing or invalid binary-only package") @@ -375,8 +416,21 @@ func (b *Builder) build(a *Action) (err error) { } objdir := a.Objdir - if cached && (!needCgo || b.loadCachedCgo(a)) && (!a.needVet || b.loadCachedVet(a)) { - return nil + if cached { + if need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) { + need &^= needCgoHdr + } + + // Load cached vet config, but only if that's all we have left + // (need == needVet, not testing just the one bit). + // If we are going to do a full build anyway, + // we're going to regenerate the files below anyway. + if need == needVet && b.loadCachedVet(a) { + need &^= needVet + } + if need == 0 { + return nil + } } // make target directory @@ -387,9 +441,8 @@ func (b *Builder) build(a *Action) (err error) { } } - var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string + var gofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.Package.GoFiles...) - cgofiles = append(cgofiles, a.Package.CgoFiles...) cfiles = append(cfiles, a.Package.CFiles...) sfiles = append(sfiles, a.Package.SFiles...) cxxfiles = append(cxxfiles, a.Package.CXXFiles...) @@ -500,19 +553,27 @@ func (b *Builder) build(a *Action) (err error) { } b.cacheGofiles(a, gofiles) + // Running cgo generated the cgo header. + need &^= needCgoHdr + // Sanity check only, since Package.load already checked as well. if len(gofiles) == 0 { return &load.NoGoError{Package: a.Package} } // Prepare Go vet config if needed. - if a.needVet { + if need&needVet != 0 { buildVetConfig(a, gofiles) + need &^= needVet } - if cached { - // The cached package file is OK, so we don't need to run the compile. - // We've only gone this far in order to prepare the vet configuration - // or cgo header, and now we have. + if need&needCgoFiles != 0 { + if !b.loadCachedCgoFiles(a) { + return fmt.Errorf("failed to cache translated CgoFiles") + } + need &^= needCgoFiles + } + if need == 0 { + // Nothing left to do. return nil } @@ -656,17 +717,20 @@ func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error return err } +func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) { + file, _, err := c.GetFile(cache.Subkey(a.actionID, name)) + if err != nil { + return "", err + } + return file, nil +} + func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error { - entry, err := c.Get(cache.Subkey(a.actionID, name)) + cached, err := b.findCachedObjdirFile(a, c, name) if err != nil { return err } - out := c.OutputFile(entry.OutputID) - info, err := os.Stat(out) - if err != nil || info.Size() != entry.Size { - return fmt.Errorf("not in cache") - } - return b.copyFile(a.Objdir+name, out, 0666, true) + return b.copyFile(a.Objdir+name, cached, 0666, true) } func (b *Builder) cacheCgoHdr(a *Action) { @@ -677,7 +741,7 @@ func (b *Builder) cacheCgoHdr(a *Action) { b.cacheObjdirFile(a, c, "_cgo_install.h") } -func (b *Builder) loadCachedCgo(a *Action) bool { +func (b *Builder) loadCachedCgoHdr(a *Action) bool { c := cache.Default() if c == nil { return false @@ -737,16 +801,48 @@ func (b *Builder) loadCachedVet(a *Action) bool { return true } +func (b *Builder) loadCachedCgoFiles(a *Action) bool { + c := cache.Default() + if c == nil { + return false + } + list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles")) + if err != nil { + return false + } + var files []string + for _, name := range strings.Split(string(list), "\n") { + if name == "" { // end of list + continue + } + if strings.HasPrefix(name, "./") { + continue + } + file, err := b.findCachedObjdirFile(a, c, name) + if err != nil { + return false + } + files = append(files, file) + } + a.Package.CgoFiles = files + return true +} + +// vetConfig is the configuration passed to vet describing a single package. type vetConfig struct { - Compiler string - Dir string - GoFiles []string - ImportMap map[string]string - PackageFile map[string]string - Standard map[string]bool - ImportPath string + Compiler string // compiler name (gc, gccgo) + Dir string // directory containing package + ImportPath string // canonical import path ("package path") + GoFiles []string // absolute paths to package source files + + ImportMap map[string]string // map import path in source code to package path + PackageFile map[string]string // map package path to .a file with export data + Standard map[string]bool // map package path to whether it's in the standard library + PackageVetx map[string]string // map package path to vetx data from earlier vet run + VetxOnly bool // only compute vetx data; don't report detected problems + VetxOutput string // write vetx data to this output file - SucceedOnTypecheckFailure bool + SucceedOnTypecheckFailure bool // awful hack; see #18395 and below } func buildVetConfig(a *Action, gofiles []string) { @@ -807,6 +903,8 @@ func (b *Builder) vet(a *Action) error { // a.Deps[0] is the build of the package being vetted. // a.Deps[1] is the build of the "fmt" package. + a.Failed = false // vet of dependency may have failed but we can still succeed + vcfg := a.Deps[0].vetCfg if vcfg == nil { // Vet config should only be missing if the build failed. @@ -816,6 +914,38 @@ func (b *Builder) vet(a *Action) error { return nil } + vcfg.VetxOnly = a.VetxOnly + vcfg.VetxOutput = a.Objdir + "vet.out" + vcfg.PackageVetx = make(map[string]string) + + h := cache.NewHash("vet " + a.Package.ImportPath) + fmt.Fprintf(h, "vet %q\n", b.toolID("vet")) + + // Note: We could decide that vet should compute export data for + // all analyses, in which case we don't need to include the flags here. + // But that would mean that if an analysis causes problems like + // unexpected crashes there would be no way to turn it off. + // It seems better to let the flags disable export analysis too. + fmt.Fprintf(h, "vetflags %q\n", VetFlags) + + fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID) + for _, a1 := range a.Deps { + if a1.Mode == "vet" && a1.built != "" { + fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built)) + vcfg.PackageVetx[a1.Package.ImportPath] = a1.built + } + } + key := cache.ActionID(h.Sum()) + + if vcfg.VetxOnly { + if c := cache.Default(); c != nil && !cfg.BuildA { + if file, _, err := c.GetFile(key); err == nil { + a.built = file + return nil + } + } + } + if vcfg.ImportMap["fmt"] == "" { a1 := a.Deps[1] vcfg.ImportMap["fmt"] = "fmt" @@ -853,7 +983,18 @@ func (b *Builder) vet(a *Action) error { if tool == "" { tool = base.Tool("vet") } - return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg") + runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg") + + // If vet wrote export data, save it for input to future vets. + if f, err := os.Open(vcfg.VetxOutput); err == nil { + a.built = vcfg.VetxOutput + if c := cache.Default(); c != nil { + c.Put(key, f) + } + f.Close() + } + + return runErr } // linkActionID computes the action ID for a link action. @@ -939,7 +1080,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { // link is the action for linking a single command. // Note that any new influence on this logic must be reported in b.linkActionID above as well. func (b *Builder) link(a *Action) (err error) { - if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) { + if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList { return nil } defer b.flushOutput(a) @@ -1172,7 +1313,7 @@ func (b *Builder) linkSharedActionID(a *Action) cache.ActionID { } func (b *Builder) linkShared(a *Action) (err error) { - if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) { + if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList { return nil } defer b.flushOutput(a) @@ -1236,13 +1377,17 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { // We want to hide that awful detail as much as possible, so don't // advertise it by touching the mtimes (usually the libraries are up // to date). - if !a.buggyInstall && !b.ComputeStaleOnly { + if !a.buggyInstall && !b.IsCmdList { now := time.Now() os.Chtimes(a.Target, now, now) } return nil } - if b.ComputeStaleOnly { + + // If we're building for go list -export, + // never install anything; just keep the cache reference. + if b.IsCmdList { + a.built = a1.built return nil } @@ -1468,6 +1613,7 @@ var objectMagic = [][]byte{ {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm + {0x00, 0x61, 0x73, 0x6D}, // WASM } func isObject(s string) bool { diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go index 4d3c5cbd17a01..1081e5147e06d 100644 --- a/src/cmd/go/internal/work/init.go +++ b/src/cmd/go/internal/work/init.go @@ -43,11 +43,16 @@ func instrumentInit() { fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) os.Exit(2) } - if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") { - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) - os.Exit(2) + if cfg.BuildRace { + platform := cfg.Goos + "/" + cfg.Goarch + switch platform { + default: + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + os.Exit(2) + case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "darwin/amd64", "windows/amd64": + // race supported on these platforms + } } - mode := "race" if cfg.BuildMSan { mode = "msan" diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 5c67aa945eff7..cd39a8f79181f 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -41,43 +41,57 @@ var re = regexp.MustCompile var validCompilerFlags = []*regexp.Regexp{ re(`-D([A-Za-z_].*)`), + re(`-F([^@\-].*)`), re(`-I([^@\-].*)`), re(`-O`), re(`-O([^@\-].*)`), re(`-W`), re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. re(`-Wa,-mbig-obj`), + re(`-Wp,-D([A-Za-z_].*)`), re(`-ansi`), + re(`-f(no-)?asynchronous-unwind-tables`), re(`-f(no-)?blocks`), + re(`-f(no-)builtin-[a-zA-Z0-9_]*`), re(`-f(no-)?common`), re(`-f(no-)?constant-cfstrings`), re(`-fdiagnostics-show-note-include-stack`), + re(`-f(no-)?eliminate-unused-debug-types`), re(`-f(no-)?exceptions`), + re(`-f(no-)?fast-math`), re(`-f(no-)?inline-functions`), re(`-finput-charset=([^@\-].*)`), re(`-f(no-)?fat-lto-objects`), + re(`-f(no-)?keep-inline-dllexport`), re(`-f(no-)?lto`), re(`-fmacro-backtrace-limit=(.+)`), re(`-fmessage-length=(.+)`), re(`-f(no-)?modules`), re(`-f(no-)?objc-arc`), + re(`-f(no-)?objc-nonfragile-abi`), + re(`-f(no-)?objc-legacy-dispatch`), re(`-f(no-)?omit-frame-pointer`), re(`-f(no-)?openmp(-simd)?`), re(`-f(no-)?permissive`), re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?plt`), re(`-f(no-)?rtti`), re(`-f(no-)?split-stack`), re(`-f(no-)?stack-(.+)`), re(`-f(no-)?strict-aliasing`), re(`-f(un)signed-char`), re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B + re(`-f(no-)?visibility-inlines-hidden`), re(`-fsanitize=(.+)`), re(`-ftemplate-depth-(.+)`), re(`-fvisibility=(.+)`), re(`-g([^@\-].*)?`), re(`-m32`), re(`-m64`), - re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-marm`), + re(`-mfloat-abi=([^@\-].*)`), + re(`-mfpmath=[0-9a-z,+]*`), re(`-m(no-)?avx[0-9a-z.]*`), re(`-m(no-)?ms-bitfields`), re(`-m(no-)?stack-(.+)`), @@ -86,14 +100,19 @@ var validCompilerFlags = []*regexp.Regexp{ re(`-miphoneos-version-min=(.+)`), re(`-mnop-fun-dllimport`), re(`-m(no-)?sse[0-9.]*`), + re(`-mthumb(-interwork)?`), + re(`-mthreads`), re(`-mwindows`), + re(`--param=ssp-buffer-size=[0-9]*`), re(`-pedantic(-errors)?`), re(`-pipe`), re(`-pthread`), re(`-?-std=([^@\-].*)`), re(`-?-stdlib=([^@\-].*)`), + re(`--sysroot=([^@\-].*)`), re(`-w`), re(`-x([^@\-].*)`), + re(`-v`), } var validCompilerFlagsWithNextArg = []string{ @@ -115,18 +134,24 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-O`), re(`-O([^@\-].*)`), re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?openmp(-simd)?`), re(`-fsanitize=([^@\-].*)`), re(`-g([^@\-].*)?`), - re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-headerpad_max_install_names`), + re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-mfloat-abi=([^@\-].*)`), re(`-mmacosx-(.+)`), re(`-mios-simulator-version-min=(.+)`), re(`-miphoneos-version-min=(.+)`), + re(`-mthreads`), re(`-mwindows`), re(`-(pic|PIC|pie|PIE)`), re(`-pthread`), + re(`-rdynamic`), re(`-shared`), re(`-?-static([-a-z0-9+]*)`), re(`-?-stdlib=([^@\-].*)`), + re(`-v`), // Note that any wildcards in -Wl need to exclude comma, // since -Wl splits its argument at commas and passes @@ -134,22 +159,27 @@ var validLinkerFlags = []*regexp.Regexp{ // in a wildcard would allow tunnelling arbitrary additional // linker arguments through one of these. re(`-Wl,--(no-)?allow-multiple-definition`), + re(`-Wl,--(no-)?allow-shlib-undefined`), re(`-Wl,--(no-)?as-needed`), re(`-Wl,-Bdynamic`), re(`-Wl,-Bstatic`), + re(`-WL,-O([^@,\-][^,]*)?`), re(`-Wl,-d[ny]`), re(`-Wl,--disable-new-dtags`), + re(`-Wl,-e[=,][a-zA-Z0-9]*`), re(`-Wl,--enable-new-dtags`), re(`-Wl,--end-group`), re(`-Wl,-framework,[^,@\-][^,]+`), re(`-Wl,-headerpad_max_install_names`), re(`-Wl,--no-undefined`), - re(`-Wl,-rpath[=,]([^,@\-][^,]+)`), + re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`), + re(`-Wl,-s`), re(`-Wl,-search_paths_first`), re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`), re(`-Wl,--start-group`), re(`-Wl,-?-static`), - re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`), re(`-Wl,-undefined[=,]([^,@\-][^,]+)`), re(`-Wl,-?-unresolved-symbols=[^,]+`), re(`-Wl,--(no-)?warn-([^,]+)`), @@ -157,6 +187,7 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-Wl,-z,relro`), re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) + re(`\./.*\.(a|o|obj|dll|dylib|so)`), } var validLinkerFlagsWithNextArg = []string{ diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index bd898c9de6c17..d23b6eadff50e 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -12,6 +12,7 @@ import ( var goodCompilerFlags = [][]string{ {"-DFOO"}, {"-Dfoo=bar"}, + {"-F/Qt"}, {"-I/"}, {"-I/etc/passwd"}, {"-I."}, @@ -57,11 +58,14 @@ var goodCompilerFlags = [][]string{ {"-I", "世界"}, {"-framework", "Chocolate"}, {"-x", "c"}, + {"-v"}, } var badCompilerFlags = [][]string{ {"-D@X"}, {"-D-X"}, + {"-F@dir"}, + {"-F-dir"}, {"-I@dir"}, {"-I-dir"}, {"-O@1"}, @@ -125,6 +129,7 @@ var goodLinkerFlags = [][]string{ {"-Wl,--no-warn-error"}, {"foo.so"}, {"_世界.dll"}, + {"./x.o"}, {"libcgosotest.dylib"}, {"-F", "framework"}, {"-l", "."}, @@ -132,6 +137,7 @@ var goodLinkerFlags = [][]string{ {"-l", "世界"}, {"-L", "framework"}, {"-framework", "Chocolate"}, + {"-v"}, {"-Wl,-framework", "-Wl,Chocolate"}, {"-Wl,-framework,Chocolate"}, {"-Wl,-unresolved-symbols=ignore-all"}, @@ -191,6 +197,7 @@ var badLinkerFlags = [][]string{ {"-x", "--c"}, {"-x", "@obj"}, {"-Wl,-rpath,@foo"}, + {"../x.o"}, } func TestCheckLinkerFlags(t *testing.T) { diff --git a/src/cmd/go/testdata/modlegacy/src/new/go.mod b/src/cmd/go/testdata/modlegacy/src/new/go.mod new file mode 100644 index 0000000000000..d0dd46d314c6a --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/go.mod @@ -0,0 +1 @@ +module "new/v2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/new.go b/src/cmd/go/testdata/modlegacy/src/new/new.go new file mode 100644 index 0000000000000..e99c47a6a8411 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/new.go @@ -0,0 +1,3 @@ +package new + +import _ "new/v2/p2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go new file mode 100644 index 0000000000000..4539f40919653 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import _ "old/p2" +import _ "new/v2" +import _ "new/v2/p2" +import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module +import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod diff --git a/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go new file mode 100644 index 0000000000000..9b9052f54197e --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod new file mode 100644 index 0000000000000..484d20c6b2ea5 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod @@ -0,0 +1 @@ +module new/sub/v2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod new file mode 100644 index 0000000000000..ba3934541f745 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod @@ -0,0 +1 @@ +module new/sub/inner diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go new file mode 100644 index 0000000000000..823aafd0712b6 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go @@ -0,0 +1 @@ +package x diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go new file mode 100644 index 0000000000000..789ca715ec460 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go @@ -0,0 +1 @@ +package y diff --git a/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go new file mode 100644 index 0000000000000..90527483abf2c --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go @@ -0,0 +1,5 @@ +package p1 + +import _ "old/p2" +import _ "new/p1" +import _ "new" diff --git a/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go new file mode 100644 index 0000000000000..9b9052f54197e --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/testcover/pkg1/a.go b/src/cmd/go/testdata/testcover/pkg1/a.go new file mode 100644 index 0000000000000..e2916119d4f1f --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg1/a.go @@ -0,0 +1,7 @@ +package pkg1 + +import "fmt" + +func F() { + fmt.Println("pkg1") +} diff --git a/src/cmd/go/testdata/testcover/pkg2/a.go b/src/cmd/go/testdata/testcover/pkg2/a.go new file mode 100644 index 0000000000000..7bd9bd44ee913 --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg2/a.go @@ -0,0 +1,7 @@ +package pkg2 + +import "fmt" + +func F() { + fmt.Println("pkg2") +} diff --git a/src/cmd/go/testdata/testcover/pkg2/a_test.go b/src/cmd/go/testdata/testcover/pkg2/a_test.go new file mode 100644 index 0000000000000..4f791ad6ab038 --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg2/a_test.go @@ -0,0 +1 @@ +package pkg2 diff --git a/src/cmd/go/testdata/testcover/pkg3/a.go b/src/cmd/go/testdata/testcover/pkg3/a.go new file mode 100644 index 0000000000000..bf86ed8dc0e06 --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg3/a.go @@ -0,0 +1,7 @@ +package pkg3 + +import "fmt" + +func F() { + fmt.Println("pkg3") +} diff --git a/src/cmd/go/testdata/testcover/pkg3/a_test.go b/src/cmd/go/testdata/testcover/pkg3/a_test.go new file mode 100644 index 0000000000000..39c2c5a6fc59d --- /dev/null +++ b/src/cmd/go/testdata/testcover/pkg3/a_test.go @@ -0,0 +1,7 @@ +package pkg3 + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go index 4f21a510a3cff..0e7a633240b72 100644 --- a/src/cmd/go/vendor_test.go +++ b/src/cmd/go/vendor_test.go @@ -10,6 +10,7 @@ import ( "bytes" "fmt" "internal/testenv" + "os" "path/filepath" "regexp" "strings" @@ -328,3 +329,75 @@ func TestVendor12156(t *testing.T) { tg.grepStderrNot("panic", "panicked") tg.grepStderr(`cannot find package "x"`, "wrong error") } + +// Module legacy support does path rewriting very similar to vendoring. + +func TestModLegacy(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy")) + tg.run("list", "-f", "{{.Imports}}", "old/p1") + tg.grepStdout("new/p1", "old/p1 should import new/p1") + tg.run("list", "-f", "{{.Imports}}", "new/p1") + tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)") + tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*") + tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)") + tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*") + tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)") + tg.run("build", "old/p1", "new/p1") +} + +func TestModLegacyGet(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path("d1")) + tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1") + tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1") + tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2") + tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2") + tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1") + + tg.setenv("GOPATH", tg.path("d2")) + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest5") + tg.run("get", "github.com/rsc/vgotest4") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + if testing.Short() { + return + } + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest4") + tg.run("get", "github.com/rsc/vgotest5") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4") + tg.run("get", "github.com/myitcv/vgo_example_compat") + + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", "github.com/myitcv/vgo_example_compat") + tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5") + + pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"} + for i := 0; i < 3; i++ { + for j := 0; j < 3; j++ { + for k := 0; k < 3; k++ { + if i == j || i == k || k == j { + continue + } + tg.must(os.RemoveAll(tg.path("d2"))) + tg.run("get", pkgs[i], pkgs[j], pkgs[k]) + } + } + } +} diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index bf96bb58a6abb..e7271437573ef 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -245,12 +245,12 @@ var optab = []Optab{ {AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0}, {AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0}, {ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0}, - {AAND, C_MOVCON, C_REG, C_NONE, C_RSP, 62, 8, 0, 0, 0}, + {AAND, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AAND, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0}, {AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0}, {ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0}, - {AAND, C_VCON, C_REG, C_NONE, C_RSP, 28, 8, 0, LFROM, 0}, + {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, @@ -3548,7 +3548,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { if r == 0 { r = rt } - if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) { + if p.To.Reg == REGSP || r == REGSP { o2 = c.opxrrr(p, p.As, false) o2 |= REGTMP & 31 << 16 o2 |= LSL0_64 diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index 7bb21ab439363..f42d6758050ba 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q = c.stacksplit(q, autosize) // emit split check } - if autosize != 0 { + // Special handling of the racecall thunk. Assume that its asm code will + // save the link register and update the stack, since that code is + // called directly from C/C++ and can't clobber REGTMP (R31). + if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" { // Save the link register and update the SP. MOVDU is used unless // the frame size is too large. The link register must be saved // even for non-empty leaf functions so that traceback works. @@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { retTarget := p.To.Sym if c.cursym.Func.Text.Mark&LEAF != 0 { - if autosize == 0 { + if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" { p.As = ABR p.From = obj.Addr{} if retTarget == nil { @@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.Link = q p = q } - - if autosize != 0 { + prev := p + if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" { q = c.newprog() q.As = AADD q.Pos = p.Pos @@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q.Spadj = -autosize q.Link = p.Link - p.Link = q + prev.Link = q + prev = q } q1 = c.newprog() @@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q1.Spadj = +autosize q1.Link = q.Link - q.Link = q1 + prev.Link = q1 case AADD: if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { p.Spadj = int32(-p.From.Offset) diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go index ec959c40909fe..babcd2af010b2 100644 --- a/src/cmd/internal/obj/s390x/a.out.go +++ b/src/cmd/internal/obj/s390x/a.out.go @@ -150,7 +150,7 @@ const ( ) // LINUX for zSeries ELF Application Binary Interface Supplement -// http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x1472.html +// https://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries/x1472.html var S390XDWARFRegisters = map[int16]int16{} func init() { diff --git a/src/cmd/internal/obj/wasm/a.out.go b/src/cmd/internal/obj/wasm/a.out.go index 9c04be2609a0a..6f882215ff4e1 100644 --- a/src/cmd/internal/obj/wasm/a.out.go +++ b/src/cmd/internal/obj/wasm/a.out.go @@ -219,6 +219,8 @@ const ( // However, it is not allowed to switch goroutines while inside of an ACALLNORESUME call. ACALLNORESUME + ARETUNWIND + AMOVB AMOVH AMOVW @@ -244,6 +246,7 @@ const ( REG_RET1 REG_RET2 REG_RET3 + REG_RUN // locals REG_R0 diff --git a/src/cmd/internal/obj/wasm/anames.go b/src/cmd/internal/obj/wasm/anames.go index 20d04446d08d2..745f0d773a94d 100644 --- a/src/cmd/internal/obj/wasm/anames.go +++ b/src/cmd/internal/obj/wasm/anames.go @@ -180,6 +180,7 @@ var Anames = []string{ "F64ReinterpretI64", "RESUMEPOINT", "CALLNORESUME", + "RETUNWIND", "MOVB", "MOVH", "MOVW", diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index ca09b3fa0b23e..8498b407245f0 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -25,6 +25,7 @@ var Register = map[string]int16{ "RET1": REG_RET1, "RET2": REG_RET2, "RET3": REG_RET3, + "RUN": REG_RUN, "R0": REG_R0, "R1": REG_R1, @@ -487,7 +488,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { p = appendp(p, AEnd) // end of Loop } - case obj.ARET: + case obj.ARET, ARETUNWIND: ret := *p p.As = obj.ANOP @@ -528,7 +529,14 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { p = appendp(p, AI32Add) p = appendp(p, ASet, regAddr(REG_SP)) - // not switching goroutine, return 0 + if ret.As == ARETUNWIND { + // function needs to unwind the WebAssembly stack, return 1 + p = appendp(p, AI32Const, constAddr(1)) + p = appendp(p, AReturn) + break + } + + // not unwinding the WebAssembly stack, return 0 p = appendp(p, AI32Const, constAddr(0)) p = appendp(p, AReturn) } @@ -726,7 +734,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { } reg := p.From.Reg switch { - case reg >= REG_PC_F && reg <= REG_RET3: + case reg >= REG_PC_F && reg <= REG_RUN: w.WriteByte(0x23) // get_global writeUleb128(w, uint64(reg-REG_PC_F)) case reg >= REG_R0 && reg <= REG_F15: @@ -743,7 +751,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { } reg := p.To.Reg switch { - case reg >= REG_PC_F && reg <= REG_RET3: + case reg >= REG_PC_F && reg <= REG_RUN: w.WriteByte(0x24) // set_global writeUleb128(w, uint64(reg-REG_PC_F)) case reg >= REG_R0 && reg <= REG_F15: diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index b3dbaa39eb27c..2cd3a9404546a 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -4,9 +4,9 @@ package objabi import "strconv" -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFF" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORT" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478, 490} func (i RelocType) String() string { i -= 1 diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go index f8052136be625..1a54a1c3bb4b5 100644 --- a/src/cmd/internal/test2json/test2json.go +++ b/src/cmd/internal/test2json/test2json.go @@ -147,7 +147,7 @@ var ( fourSpace = []byte(" ") skipLinePrefix = []byte("? \t") - skipLineSuffix = []byte("\t[no test files]\n") + skipLineSuffix = []byte(" [no test files]\n") ) // handleInputLine handles a single whole test output line. @@ -166,7 +166,7 @@ func (c *converter) handleInputLine(line []byte) { return } - // Special case for entirely skipped test binary: "? \tpkgname\t[no test files]\n" is only line. + // Special case for entirely skipped test binary: "? \tpkgname\t0.001s [no test files]\n" is only line. // Report it as plain output but remember to say skip in the final summary. if bytes.HasPrefix(line, skipLinePrefix) && bytes.HasSuffix(line, skipLineSuffix) && len(c.report) == 0 { c.result = "skip" diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 6897ae21fe57f..af274444f36ae 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -617,7 +617,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { // so for now we'll just use non-lazy pointers, // which don't need to be told which library to use. // - // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html + // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html // has details about what we're avoiding. addgotsym(ctxt, s) diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 6685ad50ac052..18fbea62eef98 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { return true, objabi.GOARCH + " does not support internal cgo" } + // When the race flag is set, the LLVM tsan relocatable file is linked + // into the final binary, which means external linking is required because + // internal linking does not support it. + if *flagRace && ctxt.Arch.InFamily(sys.PPC64) { + return true, "race on ppc64le" + } + // Some build modes require work the internal linker cannot do (yet). switch ctxt.BuildMode { case BuildModeCArchive: diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 6cc5c544f5a01..184e8158fdc75 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -95,7 +95,7 @@ func trampoline(ctxt *Link, s *sym.Symbol) { if Symaddr(r.Sym) == 0 && r.Sym.Type != sym.SDYNIMPORT { if r.Sym.File != s.File { if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) { - Errorf(s, "unresolved inter-package jump to %s(%s)", r.Sym, r.Sym.File) + ctxt.ErrorUnresolved(s, r) } // runtime and its dependent packages may call to each other. // they are fine, as they will be laid down together. @@ -128,7 +128,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { continue } - if r.Sym != nil && ((r.Sym.Type == 0 && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { + if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { // When putting the runtime but not main into a shared library // these symbols are undefined and that's OK. if ctxt.BuildMode == BuildModeShared { @@ -140,7 +140,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) { continue } } else { - Errorf(s, "relocation target %s not defined", r.Sym.Name) + ctxt.ErrorUnresolved(s, r) continue } } @@ -1352,9 +1352,8 @@ func (ctxt *Link) dodata() { /* * We finished data, begin read-only data. * Not all systems support a separate read-only non-executable data section. - * ELF systems do. + * ELF and Windows PE systems do. * OS X and Plan 9 do not. - * Windows PE may, but if so we have not implemented it. * And if we're using external linking mode, the point is moot, * since it's not our decision; that code expects the sections in * segtext. @@ -1362,6 +1361,8 @@ func (ctxt *Link) dodata() { var segro *sym.Segment if ctxt.IsELF && ctxt.LinkMode == LinkInternal { segro = &Segrodata + } else if ctxt.HeadType == objabi.Hwindows { + segro = &Segrodata } else { segro = &Segtext } @@ -1902,12 +1903,15 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6 return sect, n, va } -// assign addresses -func (ctxt *Link) address() { +// address assigns virtual addresses to all segments and sections and +// returns all segments in file order. +func (ctxt *Link) address() []*sym.Segment { + var order []*sym.Segment // Layout order + va := uint64(*FlagTextAddr) + order = append(order, &Segtext) Segtext.Rwx = 05 Segtext.Vaddr = va - Segtext.Fileoff = uint64(HEADR) for _, s := range Segtext.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1915,7 +1919,6 @@ func (ctxt *Link) address() { } Segtext.Length = va - uint64(*FlagTextAddr) - Segtext.Filelen = Segtext.Length if ctxt.HeadType == objabi.Hnacl { va += 32 // room for the "halt sled" } @@ -1936,10 +1939,9 @@ func (ctxt *Link) address() { // writable even for this short period. va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segrodata) Segrodata.Rwx = 04 Segrodata.Vaddr = va - Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff - Segrodata.Filelen = 0 for _, s := range Segrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1947,17 +1949,15 @@ func (ctxt *Link) address() { } Segrodata.Length = va - Segrodata.Vaddr - Segrodata.Filelen = Segrodata.Length } if len(Segrelrodata.Sections) > 0 { // align to page boundary so as not to mix // rodata, rel-ro data, and executable text. va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segrelrodata) Segrelrodata.Rwx = 06 Segrelrodata.Vaddr = va - Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff - Segrelrodata.Filelen = 0 for _, s := range Segrelrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1965,20 +1965,12 @@ func (ctxt *Link) address() { } Segrelrodata.Length = va - Segrelrodata.Vaddr - Segrelrodata.Filelen = Segrelrodata.Length } va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segdata) Segdata.Rwx = 06 Segdata.Vaddr = va - Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff - Segdata.Filelen = 0 - if ctxt.HeadType == objabi.Hwindows { - Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) - } - if ctxt.HeadType == objabi.Hplan9 { - Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen - } var data *sym.Section var noptr *sym.Section var bss *sym.Section @@ -2008,16 +2000,14 @@ func (ctxt *Link) address() { } } + // Assign Segdata's Filelen omitting the BSS. We do this here + // simply because right now we know where the BSS starts. Segdata.Filelen = bss.Vaddr - Segdata.Vaddr va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segdwarf) Segdwarf.Rwx = 06 Segdwarf.Vaddr = va - Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound))) - Segdwarf.Filelen = 0 - if ctxt.HeadType == objabi.Hwindows { - Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN)) - } for i, s := range Segdwarf.Sections { vlen := int64(s.Length) if i+1 < len(Segdwarf.Sections) { @@ -2031,8 +2021,6 @@ func (ctxt *Link) address() { Segdwarf.Length = va - Segdwarf.Vaddr } - Segdwarf.Filelen = va - Segdwarf.Vaddr - var ( text = Segtext.Sections[0] rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect @@ -2119,6 +2107,34 @@ func (ctxt *Link) address() { ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr)) ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length)) ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length)) + + return order +} + +// layout assigns file offsets and lengths to the segments in order. +func (ctxt *Link) layout(order []*sym.Segment) { + var prev *sym.Segment + for _, seg := range order { + if prev == nil { + seg.Fileoff = uint64(HEADR) + } else { + switch ctxt.HeadType { + default: + seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), int64(*FlagRound))) + case objabi.Hwindows: + seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN)) + case objabi.Hplan9: + seg.Fileoff = prev.Fileoff + prev.Filelen + } + } + if seg != &Segdata { + // Link.address already set Segdata.Filelen to + // account for BSS. + seg.Filelen = seg.Length + } + prev = seg + } + } // add a trampoline with symbol s (to be laid down after the current function) diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go new file mode 100644 index 0000000000000..4884a07d05a93 --- /dev/null +++ b/src/cmd/link/internal/ld/ld_test.go @@ -0,0 +1,70 @@ +// Copyright 2018 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 ld + +import ( + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "strings" + "testing" +) + +func TestUndefinedRelocErrors(t *testing.T) { + testenv.MustHaveGoBuild(t) + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + out, err := exec.Command(testenv.GoToolPath(t), "build", "./testdata/issue10978").CombinedOutput() + if err == nil { + t.Fatal("expected build to fail") + } + + wantErrors := map[string]int{ + // Main function has dedicated error message. + "function main is undeclared in the main package": 1, + + // Single error reporting per each symbol. + // This way, duplicated messages are not reported for + // multiple relocations with a same name. + "main.defined1: relocation target main.undefined not defined": 1, + "main.defined2: relocation target main.undefined not defined": 1, + } + unexpectedErrors := map[string]int{} + + for _, l := range strings.Split(string(out), "\n") { + if strings.HasPrefix(l, "#") || l == "" { + continue + } + matched := "" + for want := range wantErrors { + if strings.Contains(l, want) { + matched = want + break + } + } + if matched != "" { + wantErrors[matched]-- + } else { + unexpectedErrors[l]++ + } + } + + for want, n := range wantErrors { + switch { + case n > 0: + t.Errorf("unmatched error: %s (x%d)", want, n) + case n < 0: + t.Errorf("extra errors: %s (x%d)", want, -n) + } + } + for unexpected, n := range unexpectedErrors { + t.Errorf("unexpected error: %s (x%d)", unexpected, n) + } +} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index edf3922980698..e6682606b62ed 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1962,7 +1962,7 @@ func usage() { type SymbolType int8 const ( - // see also http://9p.io/magic/man2html/1/nm + // see also https://9p.io/magic/man2html/1/nm TextSym SymbolType = 'T' DataSym SymbolType = 'D' BSSSym SymbolType = 'B' @@ -2199,6 +2199,18 @@ func undefsym(ctxt *Link, s *sym.Symbol) { } func (ctxt *Link) undef() { + // undefsym performs checks (almost) identical to checks + // that report undefined relocations in relocsym. + // Both undefsym and relocsym can report same symbol as undefined, + // which results in error message duplication (see #10978). + // + // The undef is run after Arch.Asmb and could detect some + // programming errors there, but if object being linked is already + // failed with errors, it is better to avoid duplicated errors. + if nerrors > 0 { + return + } + for _, s := range ctxt.Textp { undefsym(ctxt, s) } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index a413353b9fb56..a790fd084b578 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -81,6 +81,33 @@ type Link struct { PackageShlib map[string]string tramps []*sym.Symbol // trampolines + + // unresolvedSymSet is a set of erroneous unresolved references. + // Used to avoid duplicated error messages. + unresolvedSymSet map[unresolvedSymKey]bool +} + +type unresolvedSymKey struct { + from *sym.Symbol // Symbol that referenced unresolved "to" + to *sym.Symbol // Unresolved symbol referenced by "from" +} + +// ErrorUnresolved prints unresolved symbol error for r.Sym that is referenced from s. +func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) { + if ctxt.unresolvedSymSet == nil { + ctxt.unresolvedSymSet = make(map[unresolvedSymKey]bool) + } + + k := unresolvedSymKey{from: s, to: r.Sym} + if !ctxt.unresolvedSymSet[k] { + ctxt.unresolvedSymSet[k] = true + // Give a special error message for main symbol (see #24809). + if r.Sym.Name == "main.main" { + Errorf(s, "function main is undeclared in the main package") + } else { + Errorf(s, "relocation target %s not defined", r.Sym.Name) + } + } } // The smallest possible offset from the hardware stack pointer to a local diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 8643fef043cae..d804dc83b3428 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -142,12 +142,8 @@ const ( S_ATTR_SOME_INSTRUCTIONS = 0x00000400 ) -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - // Mach-O file writing -// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html +// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html var machohdr MachoHdr diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index bfa3f70a9eefa..23dfa277d0eaa 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -224,8 +224,9 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.typelink() ctxt.symtab() ctxt.dodata() - ctxt.address() + order := ctxt.address() ctxt.reloc() + ctxt.layout(order) thearch.Asmb(ctxt) ctxt.undef() ctxt.hostlink() diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 50ac6d0743996..7b7f7068e7411 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -11,6 +11,7 @@ import ( "log" "os" "path/filepath" + "strings" ) // iteration over encoded pcdata tables. @@ -159,13 +160,15 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) { *d = out } -// onlycsymbol reports whether this is a cgo symbol provided by the -// runtime and only used from C code. +// onlycsymbol reports whether this is a symbol that is referenced by C code. func onlycsymbol(s *sym.Symbol) bool { switch s.Name { case "_cgo_topofstack", "_cgo_panic", "crosscall2": return true } + if strings.HasPrefix(s.Name, "_cgoexp_") { + return true + } return false } diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 66b1463086d73..85acb7a11b0b4 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -116,7 +116,7 @@ const ( // license that can be found in the LICENSE file. // PE (Portable Executable) file writing -// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx +// https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx // DOS stub that prints out // "This program cannot be run in DOS mode." @@ -395,6 +395,7 @@ type peFile struct { sections []*peSection stringTable peStringTable textSect *peSection + rdataSect *peSection dataSect *peSection bssSect *peSection ctorsSect *peSection @@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) { return relocs } - f.textSect.emitRelocations(ctxt.Out, func() int { - n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr) - for _, sect := range Segtext.Sections[1:] { - n += relocsect(sect, datap, Segtext.Vaddr) - } - return n - }) - - f.dataSect.emitRelocations(ctxt.Out, func() int { - var n int - for _, sect := range Segdata.Sections { - n += relocsect(sect, datap, Segdata.Vaddr) - } - return n - }) + sects := []struct { + peSect *peSection + seg *sym.Segment + syms []*sym.Symbol + }{ + {f.textSect, &Segtext, ctxt.Textp}, + {f.rdataSect, &Segrodata, datap}, + {f.dataSect, &Segdata, datap}, + } + for _, s := range sects { + s.peSect.emitRelocations(ctxt.Out, func() int { + var n int + for _, sect := range s.seg.Sections { + n += relocsect(sect, s.syms, s.seg.Vaddr) + } + return n + }) + } dwarfLoop: for _, sect := range Segdwarf.Sections { @@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int if s.Sect.Seg == &Segtext { return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil } + if s.Sect.Seg == &Segrodata { + return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil + } if s.Sect.Seg != &Segdata { - return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .data section", s.Name) + return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name) } v := uint64(s.Value) - Segdata.Vaddr if linkmode != LinkExternal { @@ -904,7 +911,11 @@ func Peinit(ctxt *Link) { } if ctxt.LinkMode == LinkExternal { - PESECTALIGN = 0 + // .rdata section will contain "masks" and "shifts" symbols, and they + // need to be aligned to 16-bytes. So make all sections aligned + // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external + // linker will honour that requirement. + PESECTALIGN = 32 PEFILEALIGN = 0 } @@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) { t.checkSegment(&Segtext) pefile.textSect = t + ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length)) + ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ + if ctxt.LinkMode == LinkExternal { + // some data symbols (e.g. masks) end up in the .rdata section, and they normally + // expect larger alignment requirement than the default text section alignment. + ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES + } else { + // TODO(brainman): should not need IMAGE_SCN_MEM_EXECUTE, but I do not know why it carshes without it + ro.characteristics |= IMAGE_SCN_MEM_EXECUTE + } + ro.checkSegment(&Segrodata) + pefile.rdataSect = ro + var d *peSection if ctxt.LinkMode != LinkExternal { d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) diff --git a/src/cmd/link/internal/ld/testdata/issue10978/main.go b/src/cmd/link/internal/ld/testdata/issue10978/main.go new file mode 100644 index 0000000000000..5e8c09749f128 --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue10978/main.go @@ -0,0 +1,27 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func undefined() + +func defined1() int { + // To check multiple errors for a single symbol, + // reference undefined more than once. + undefined() + undefined() + return 0 +} + +func defined2() { + undefined() + undefined() +} + +func init() { + _ = defined1() + defined2() +} + +// The "main" function remains undeclared. diff --git a/src/cmd/link/internal/ld/testdata/issue10978/main.s b/src/cmd/link/internal/ld/testdata/issue10978/main.s new file mode 100644 index 0000000000000..1d00e76c1dd31 --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue10978/main.s @@ -0,0 +1 @@ +// This file is needed to make "go build" work for package with external functions. diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 7fb9a38a9fdfd..301c2ce1168e1 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -1048,7 +1048,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym // __i686.get_pc_thunk.bx is allowed to be duplicated, to // workaround that we set dupok. // TODO(minux): correctly handle __i686.get_pc_thunk.bx without - // set dupok generally. See http://codereview.appspot.com/5823055/ + // set dupok generally. See https://golang.org/cl/5823055 // comment #5 for details. if s != nil && elfsym.other == 2 { s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 235a5a25d1453..96d9cbd71efb1 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -88,7 +88,7 @@ func assignAddress(ctxt *ld.Link, sect *sym.Section, n int, s *sym.Symbol, va ui } // asmb writes the final WebAssembly module binary. -// Spec: http://webassembly.github.io/spec/core/binary/modules.html +// Spec: https://webassembly.github.io/spec/core/binary/modules.html func asmb(ctxt *ld.Link) { if ctxt.Debugvlog != 0 { ctxt.Logf("%5.2f asmb\n", ld.Cputime()) @@ -177,7 +177,7 @@ func asmb(ctxt *ld.Link) { writeCodeSec(ctxt, fns) writeDataSec(ctxt) if !*ld.FlagS { - writeNameSec(ctxt, append(hostImports, fns...)) + writeNameSec(ctxt, len(hostImports), fns) } ctxt.Out.Flush() @@ -304,6 +304,7 @@ func writeGlobalSec(ctxt *ld.Link) { I64, // 6: RET1 I64, // 7: RET2 I64, // 8: RET3 + I32, // 9: RUN } writeUleb128(ctxt.Out, uint64(len(globalRegs))) // number of globals @@ -408,14 +409,14 @@ var nameRegexp = regexp.MustCompile(`[^\w\.]`) // writeNameSec writes an optional section that assigns names to the functions declared by the "func" section. // The names are only used by WebAssembly stack traces, debuggers and decompilers. // TODO(neelance): add symbol table of DATA symbols -func writeNameSec(ctxt *ld.Link, fns []*wasmFunc) { +func writeNameSec(ctxt *ld.Link, firstFnIndex int, fns []*wasmFunc) { sizeOffset := writeSecHeader(ctxt, sectionCustom) writeName(ctxt.Out, "name") sizeOffset2 := writeSecHeader(ctxt, 0x01) // function names writeUleb128(ctxt.Out, uint64(len(fns))) for i, fn := range fns { - writeUleb128(ctxt.Out, uint64(i)) + writeUleb128(ctxt.Out, uint64(firstFnIndex+i)) writeName(ctxt.Out, fn.Name) } writeSecSize(ctxt, sizeOffset2) diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 4be5d0e74e2da..ccf5682d695ae 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { names["main."+f[0]] = f[1] } + runtimeSyms := map[string]string{ + "runtime.text": "T", + "runtime.etext": "T", + "runtime.rodata": "R", + "runtime.erodata": "R", + "runtime.epclntab": "R", + "runtime.noptrdata": "D", + } + out, err = exec.Command(testnmpath, exe).CombinedOutput() if err != nil { t.Fatalf("go tool nm: %v\n%s", err, string(out)) @@ -147,6 +156,16 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { if _, found := dups[name]; found { t.Errorf("duplicate name of %q is found", name) } + if stype, found := runtimeSyms[name]; found { + if runtime.GOOS == "plan9" && stype == "R" { + // no read-only data segment symbol on Plan 9 + stype = "D" + } + if want, have := stype, strings.ToUpper(f[1]); have != want { + t.Errorf("want %s type for %s symbol, but have %s", want, name, have) + } + delete(runtimeSyms, name) + } } err = scanner.Err() if err != nil { @@ -155,6 +174,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { if len(names) > 0 { t.Errorf("executable is missing %v symbols", names) } + if len(runtimeSyms) > 0 { + t.Errorf("executable is missing %v symbols", runtimeSyms) + } } func TestGoExec(t *testing.T) { diff --git a/src/cmd/pprof/readlineui.go b/src/cmd/pprof/readlineui.go index 67fb7aa49ca91..6e91816f9be1b 100644 --- a/src/cmd/pprof/readlineui.go +++ b/src/cmd/pprof/readlineui.go @@ -86,7 +86,7 @@ func (r *readlineUI) print(withColor bool, args ...interface{}) { if withColor { text = colorize(text) } - fmt.Fprintf(r.term, text) + fmt.Fprint(r.term, text) } // colorize prints the msg in red using ANSI color escapes. diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go index c91f18ef6f2b9..96c109e0f251a 100644 --- a/src/cmd/trace/annotations.go +++ b/src/cmd/trace/annotations.go @@ -1,3 +1,7 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package main import ( diff --git a/src/cmd/trace/annotations_test.go b/src/cmd/trace/annotations_test.go index 5d2b226b3520f..a9068d53c1ba2 100644 --- a/src/cmd/trace/annotations_test.go +++ b/src/cmd/trace/annotations_test.go @@ -1,3 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !js + package main import ( diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go index 852d745b29002..9e90f50d4ba91 100644 --- a/src/cmd/trace/trace_test.go +++ b/src/cmd/trace/trace_test.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !js + package main import ( diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go index c3c22e7c96b43..a5153e151132b 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go @@ -15,6 +15,7 @@ package driver import ( + "errors" "fmt" "os" "strings" @@ -28,6 +29,7 @@ type source struct { ExecName string BuildID string Base []string + DiffBase bool Normalize bool Seconds int @@ -43,7 +45,8 @@ type source struct { func parseFlags(o *plugin.Options) (*source, []string, error) { flag := o.Flagset // Comparisons. - flagBase := flag.StringList("base", "", "Source for base profile for comparison") + flagBase := flag.StringList("base", "", "Source for base profile for profile subtraction") + flagDiffBase := flag.StringList("diff_base", "", "Source for diff base profile for comparison") // Source options. flagSymbolize := flag.String("symbolize", "", "Options for profile symbolization") flagBuildID := flag.String("buildid", "", "Override build id for first mapping") @@ -85,7 +88,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { usageMsgVars) }) if len(args) == 0 { - return nil, nil, fmt.Errorf("no profile source specified") + return nil, nil, errors.New("no profile source specified") } var execName string @@ -112,7 +115,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { return nil, nil, err } if cmd != nil && *flagHTTP != "" { - return nil, nil, fmt.Errorf("-http is not compatible with an output format on the command line") + return nil, nil, errors.New("-http is not compatible with an output format on the command line") } si := pprofVariables["sample_index"].value @@ -140,15 +143,13 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { Comment: *flagAddComment, } - for _, s := range *flagBase { - if *s != "" { - source.Base = append(source.Base, *s) - } + if err := source.addBaseProfiles(*flagBase, *flagDiffBase); err != nil { + return nil, nil, err } normalize := pprofVariables["normalize"].boolValue() if normalize && len(source.Base) == 0 { - return nil, nil, fmt.Errorf("Must have base profile to normalize by") + return nil, nil, errors.New("must have base profile to normalize by") } source.Normalize = normalize @@ -158,6 +159,34 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { return source, cmd, nil } +// addBaseProfiles adds the list of base profiles or diff base profiles to +// the source. This function will return an error if both base and diff base +// profiles are specified. +func (source *source) addBaseProfiles(flagBase, flagDiffBase []*string) error { + base, diffBase := dropEmpty(flagBase), dropEmpty(flagDiffBase) + if len(base) > 0 && len(diffBase) > 0 { + return errors.New("-base and -diff_base flags cannot both be specified") + } + + source.Base = base + if len(diffBase) > 0 { + source.Base, source.DiffBase = diffBase, true + } + return nil +} + +// dropEmpty list takes a slice of string pointers, and outputs a slice of +// non-empty strings associated with the flag. +func dropEmpty(list []*string) []string { + var l []string + for _, s := range list { + if *s != "" { + l = append(l, *s) + } + } + return l +} + // installFlags creates command line flags for pprof variables. func installFlags(flag plugin.FlagSet) flagsInstalled { f := flagsInstalled{ @@ -240,7 +269,7 @@ func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, for n, b := range bcmd { if *b { if cmd != nil { - return nil, fmt.Errorf("must set at most one output format") + return nil, errors.New("must set at most one output format") } cmd = []string{n} } @@ -248,7 +277,7 @@ func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, for n, s := range acmd { if *s != "" { if cmd != nil { - return nil, fmt.Errorf("must set at most one output format") + return nil, errors.New("must set at most one output format") } cmd = []string{n, *s} } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go index acc0b4ad8ac99..2dabc3017b57e 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go @@ -65,7 +65,13 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug // Identify units of numeric tags in profile. numLabelUnits := identifyNumLabelUnits(p, o.UI) - vars = applyCommandOverrides(cmd, vars) + // Get report output format + c := pprofCommands[cmd[0]] + if c == nil { + panic("unexpected nil command") + } + + vars = applyCommandOverrides(cmd[0], c.format, vars) // Delay focus after configuring report to get percentages on all samples. relative := vars["relative_percentages"].boolValue() @@ -78,10 +84,6 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug if err != nil { return nil, nil, err } - c := pprofCommands[cmd[0]] - if c == nil { - panic("unexpected nil command") - } ropt.OutputFormat = c.format if len(cmd) == 2 { s, err := regexp.Compile(cmd[1]) @@ -149,13 +151,10 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin. return out.Close() } -func applyCommandOverrides(cmd []string, v variables) variables { +func applyCommandOverrides(cmd string, outputFormat int, v variables) variables { trim, tagfilter, filter := v["trim"].boolValue(), true, true - switch cmd[0] { - case "proto", "raw": - trim, tagfilter, filter = false, false, false - v.set("addresses", "t") + switch cmd { case "callgrind", "kcachegrind": trim = false v.set("addresses", "t") @@ -163,7 +162,7 @@ func applyCommandOverrides(cmd []string, v variables) variables { trim = false v.set("addressnoinlines", "t") case "peek": - trim, filter = false, false + trim, tagfilter, filter = false, false, false case "list": v.set("nodecount", "0") v.set("lines", "t") @@ -176,6 +175,12 @@ func applyCommandOverrides(cmd []string, v variables) variables { v.set("nodecount", "80") } } + + if outputFormat == report.Proto || outputFormat == report.Raw { + trim, tagfilter, filter = false, false, false + v.set("addresses", "t") + } + if !trim { v.set("nodecount", "0") v.set("nodefraction", "0") diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go index 309e9950b667a..ff6afe9cff7e5 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go @@ -288,7 +288,7 @@ type testFlags struct { floats map[string]float64 strings map[string]string args []string - stringLists map[string][]*string + stringLists map[string][]string } func (testFlags) ExtraUsage() string { return "" } @@ -355,7 +355,12 @@ func (f testFlags) StringVar(p *string, s, d, c string) { func (f testFlags) StringList(s, d, c string) *[]*string { if t, ok := f.stringLists[s]; ok { - return &t + // convert slice of strings to slice of string pointers before returning. + tp := make([]*string, len(t)) + for i, v := range t { + tp[i] = &v + } + return &tp } return &[]*string{} } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go index 7c576de61498b..7a7a1a20f2a2e 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go @@ -63,6 +63,9 @@ func fetchProfiles(s *source, o *plugin.Options) (*profile.Profile, error) { } if pbase != nil { + if s.DiffBase { + pbase.SetLabel("pprof::base", []string{"true"}) + } if s.Normalize { err := p.Normalize(pbase) if err != nil { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go index afb135b7cdda1..e67b2e9f87108 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go @@ -210,13 +210,20 @@ func TestFetchWithBase(t *testing.T) { baseVars := pprofVariables defer func() { pprofVariables = baseVars }() + type WantSample struct { + values []int64 + labels map[string][]string + } + const path = "testdata/" type testcase struct { - desc string - sources []string - bases []string - normalize bool - expectedSamples [][]int64 + desc string + sources []string + bases []string + diffBases []string + normalize bool + wantSamples []WantSample + wantErrorMsg string } testcases := []testcase{ @@ -224,58 +231,216 @@ func TestFetchWithBase(t *testing.T) { "not normalized base is same as source", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention"}, + nil, + false, + nil, + "", + }, + { + "not normalized base is same as source", + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + nil, false, - [][]int64{}, + nil, + "", }, { "not normalized single source, multiple base (all profiles same)", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention", path + "cppbench.contention"}, + nil, false, - [][]int64{{-2700, -608881724}, {-100, -23992}, {-200, -179943}, {-100, -17778444}, {-100, -75976}, {-300, -63568134}}, + []WantSample{ + { + values: []int64{-2700, -608881724}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -23992}, + labels: map[string][]string{}, + }, + { + values: []int64{-200, -179943}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{-100, -75976}, + labels: map[string][]string{}, + }, + { + values: []int64{-300, -63568134}, + labels: map[string][]string{}, + }, + }, + "", }, { "not normalized, different base and source", []string{path + "cppbench.contention"}, []string{path + "cppbench.small.contention"}, + nil, false, - [][]int64{{1700, 608878600}, {100, 23992}, {200, 179943}, {100, 17778444}, {100, 75976}, {300, 63568134}}, + []WantSample{ + { + values: []int64{1700, 608878600}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 23992}, + labels: map[string][]string{}, + }, + { + values: []int64{200, 179943}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 75976}, + labels: map[string][]string{}, + }, + { + values: []int64{300, 63568134}, + labels: map[string][]string{}, + }, + }, + "", }, { "normalized base is same as source", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention"}, + nil, true, - [][]int64{}, + nil, + "", }, { "normalized single source, multiple base (all profiles same)", []string{path + "cppbench.contention"}, []string{path + "cppbench.contention", path + "cppbench.contention"}, + nil, true, - [][]int64{}, + nil, + "", }, { "normalized different base and source", []string{path + "cppbench.contention"}, []string{path + "cppbench.small.contention"}, + nil, true, - [][]int64{{-229, -370}, {28, 0}, {57, 0}, {28, 80}, {28, 0}, {85, 287}}, + []WantSample{ + { + values: []int64{-229, -370}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{57, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 80}, + labels: map[string][]string{}, + }, + { + values: []int64{28, 0}, + labels: map[string][]string{}, + }, + { + values: []int64{85, 287}, + labels: map[string][]string{}, + }, + }, + "", + }, + { + "not normalized diff base is same as source", + []string{path + "cppbench.contention"}, + nil, + []string{path + "cppbench.contention"}, + false, + []WantSample{ + { + values: []int64{2700, 608881724}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 23992}, + labels: map[string][]string{}, + }, + { + values: []int64{200, 179943}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 17778444}, + labels: map[string][]string{}, + }, + { + values: []int64{100, 75976}, + labels: map[string][]string{}, + }, + { + values: []int64{300, 63568134}, + labels: map[string][]string{}, + }, + { + values: []int64{-2700, -608881724}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -23992}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-200, -179943}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -17778444}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-100, -75976}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + { + values: []int64{-300, -63568134}, + labels: map[string][]string{"pprof::base": {"true"}}, + }, + }, + "", + }, + { + "diff_base and base both specified", + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + []string{path + "cppbench.contention"}, + false, + nil, + "-base and -diff_base flags cannot both be specified", }, } for _, tc := range testcases { t.Run(tc.desc, func(t *testing.T) { pprofVariables = baseVars.makeCopy() - - base := make([]*string, len(tc.bases)) - for i, s := range tc.bases { - base[i] = &s - } - f := testFlags{ - stringLists: map[string][]*string{ - "base": base, + stringLists: map[string][]string{ + "base": tc.bases, + "diff_base": tc.diffBases, }, bools: map[string]bool{ "normalize": tc.normalize, @@ -289,30 +454,37 @@ func TestFetchWithBase(t *testing.T) { }) src, _, err := parseFlags(o) + if tc.wantErrorMsg != "" { + if err == nil { + t.Fatalf("got nil, want error %q", tc.wantErrorMsg) + } + + if gotErrMsg := err.Error(); gotErrMsg != tc.wantErrorMsg { + t.Fatalf("got error %q, want error %q", gotErrMsg, tc.wantErrorMsg) + } + return + } + if err != nil { - t.Fatalf("%s: %v", tc.desc, err) + t.Fatalf("got error %q, want no error", err) } p, err := fetchProfiles(src, o) - pprofVariables = baseVars + if err != nil { - t.Fatal(err) + t.Fatalf("got error %q, want no error", err) } - if want, got := len(tc.expectedSamples), len(p.Sample); want != got { - t.Fatalf("want %d samples got %d", want, got) + if got, want := len(p.Sample), len(tc.wantSamples); got != want { + t.Fatalf("got %d samples want %d", got, want) } - if len(p.Sample) > 0 { - for i, sample := range p.Sample { - if want, got := len(tc.expectedSamples[i]), len(sample.Value); want != got { - t.Errorf("want %d values for sample %d, got %d", want, i, got) - } - for j, value := range sample.Value { - if want, got := tc.expectedSamples[i][j], value; want != got { - t.Errorf("want value of %d for value %d of sample %d, got %d", want, j, i, got) - } - } + for i, sample := range p.Sample { + if !reflect.DeepEqual(tc.wantSamples[i].values, sample.Value) { + t.Errorf("for sample %d got values %v, want %v", i, sample.Value, tc.wantSamples[i]) + } + if !reflect.DeepEqual(tc.wantSamples[i].labels, sample.Label) { + t.Errorf("for sample %d got labels %v, want %v", i, sample.Label, tc.wantSamples[i].labels) } } }) diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go index db26862c7d1cc..8d775e16bdbc0 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go @@ -294,7 +294,13 @@ func TestInteractiveCommands(t *testing.T) { t.Errorf("failed on %q: %v", tc.input, err) continue } - vars = applyCommandOverrides(cmd, vars) + + // Get report output format + c := pprofCommands[cmd[0]] + if c == nil { + t.Errorf("unexpected nil command") + } + vars = applyCommandOverrides(cmd[0], c.format, vars) for n, want := range tc.want { if got := vars[n].stringValue(); got != want { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go index 15cadfb548069..76db9cbf991e5 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go @@ -264,6 +264,10 @@ func (rpt *Report) newGraph(nodes graph.NodeSet) *graph.Graph { s.NumUnit = numUnits } + // Remove label marking samples from the base profiles, so it does not appear + // as a nodelet in the graph view. + prof.RemoveLabel("pprof::base") + formatTag := func(v int64, key string) string { return measurement.ScaledLabel(v, key, o.OutputUnit) } @@ -1212,10 +1216,11 @@ func NewDefault(prof *profile.Profile, options Options) *Report { return New(prof, o) } -// computeTotal computes the sum of all sample values. This will be -// used to compute percentages. +// computeTotal computes the sum of the absolute value of all sample values. +// If any samples have the label "pprof::base" with value "true", then the total +// will only include samples with that label. func computeTotal(prof *profile.Profile, value, meanDiv func(v []int64) int64) int64 { - var div, ret int64 + var div, total, diffDiv, diffTotal int64 for _, sample := range prof.Sample { var d, v int64 v = value(sample.Value) @@ -1225,13 +1230,21 @@ func computeTotal(prof *profile.Profile, value, meanDiv func(v []int64) int64) i if v < 0 { v = -v } - ret += v + total += v div += d + if sample.HasLabel("pprof::base", "true") { + diffTotal += v + diffDiv += d + } + } + if diffTotal > 0 { + total = diffTotal + div = diffDiv } if div != 0 { - return ret / div + return total / div } - return ret + return total } // Report contains the data and associated routines to extract a diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go index 49c6e4934f5c2..9eb435bbb816d 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report_test.go @@ -287,3 +287,121 @@ func TestLegendActiveFilters(t *testing.T) { } } } + +func TestComputeTotal(t *testing.T) { + p1 := testProfile.Copy() + p1.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{1, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1, 10}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{1, 100}, + }, + } + + p2 := testProfile.Copy() + p2.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{1, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1, -10}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{1, 100}, + }, + } + + p3 := testProfile.Copy() + p3.Sample = []*profile.Sample{ + { + Location: []*profile.Location{testL[0]}, + Value: []int64{10000, 1}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-10, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{1000, -10}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-9000, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{-1, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + { + Location: []*profile.Location{testL[4], testL[2], testL[0]}, + Value: []int64{100, 100}, + }, + { + Location: []*profile.Location{testL[2], testL[1], testL[0]}, + Value: []int64{100, 3}, + Label: map[string][]string{"pprof::base": {"true"}}, + }, + } + + testcases := []struct { + desc string + prof *profile.Profile + value, meanDiv func(v []int64) int64 + wantTotal int64 + }{ + { + desc: "no diff base, all positive values, index 1", + prof: p1, + value: func(v []int64) int64 { + return v[0] + }, + wantTotal: 3, + }, + { + desc: "no diff base, all positive values, index 2", + prof: p1, + value: func(v []int64) int64 { + return v[1] + }, + wantTotal: 111, + }, + { + desc: "no diff base, some negative values", + prof: p2, + value: func(v []int64) int64 { + return v[1] + }, + wantTotal: 111, + }, + { + desc: "diff base, some negative values", + prof: p3, + value: func(v []int64) int64 { + return v[0] + }, + wantTotal: 9111, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + if gotTotal := computeTotal(tc.prof, tc.value, tc.meanDiv); gotTotal != tc.wantTotal { + t.Errorf("got total %d, want %v", gotTotal, tc.wantTotal) + } + }) + } +} diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go index 096890d9b4878..0c8f3bb5b71f4 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile.go @@ -1103,6 +1103,7 @@ var heapzSampleTypes = [][]string{ {"objects", "space"}, {"inuse_objects", "inuse_space"}, {"alloc_objects", "alloc_space"}, + {"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles } var contentionzSampleTypes = [][]string{ {"contentions", "delay"}, diff --git a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go index 5f63453e09d0f..6ba0e338c9bd4 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/legacy_profile_test.go @@ -39,10 +39,12 @@ func TestLegacyProfileType(t *testing.T) { {[]string{"objects", "space"}, heap, true, "heapzSampleTypes"}, {[]string{"inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"}, {[]string{"alloc_objects", "alloc_space"}, heap, true, "heapzSampleTypes"}, + {[]string{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"}, {[]string{"contentions", "delay"}, cont, true, "contentionzSampleTypes"}, // False cases {[]string{"objects"}, heap, false, "heapzSampleTypes"}, {[]string{"objects", "unknown"}, heap, false, "heapzSampleTypes"}, + {[]string{"inuse_objects", "inuse_space", "alloc_objects", "alloc_space"}, heap, false, "heapzSampleTypes"}, {[]string{"contentions", "delay"}, heap, false, "heapzSampleTypes"}, {[]string{"samples", "cpu"}, heap, false, "heapzSampleTypes"}, {[]string{"samples", "cpu"}, cont, false, "contentionzSampleTypes"}, diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go index 350538bf432b8..452194b12788a 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/profile.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go @@ -674,6 +674,36 @@ func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]strin return strings.Join(ls, " ") } +// SetLabel sets the specified key to the specified value for all samples in the +// profile. +func (p *Profile) SetLabel(key string, value []string) { + for _, sample := range p.Sample { + if sample.Label == nil { + sample.Label = map[string][]string{key: value} + } else { + sample.Label[key] = value + } + } +} + +// RemoveLabel removes all labels associated with the specified key for all +// samples in the profile. +func (p *Profile) RemoveLabel(key string) { + for _, sample := range p.Sample { + delete(sample.Label, key) + } +} + +// HasLabel returns true if a sample has a label with indicated key and value. +func (s *Sample) HasLabel(key, value string) bool { + for _, v := range s.Label[key] { + if v == value { + return true + } + } + return false +} + // Scale multiplies all sample values in a profile by a constant. func (p *Profile) Scale(ratio float64) { if ratio == 1 { diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go index 8ed67b1dd6c0e..5b299b1d55263 100644 --- a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go +++ b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go @@ -741,7 +741,7 @@ func TestNumLabelMerge(t *testing.T) { wantNumUnits []map[string][]string }{ { - name: "different tag units not merged", + name: "different label units not merged", profs: []*Profile{testProfile4.Copy(), testProfile5.Copy()}, wantNumLabels: []map[string][]int64{ { @@ -912,6 +912,271 @@ func locationHash(s *Sample) string { return tb } +func TestHasLabel(t *testing.T) { + var testcases = []struct { + desc string + labels map[string][]string + key string + value string + wantHasLabel bool + }{ + { + desc: "empty label does not have label", + labels: map[string][]string{}, + key: "key", + value: "value", + wantHasLabel: false, + }, + { + desc: "label with one key and value has label", + labels: map[string][]string{"key": {"value"}}, + key: "key", + value: "value", + wantHasLabel: true, + }, + { + desc: "label with one key and value does not have label", + labels: map[string][]string{"key": {"value"}}, + key: "key1", + value: "value1", + wantHasLabel: false, + }, + { + desc: "label with many keys and values has label", + labels: map[string][]string{ + "key1": {"value2", "value1"}, + "key2": {"value1", "value2", "value2"}, + "key3": {"value1", "value2", "value2"}, + }, + key: "key1", + value: "value1", + wantHasLabel: true, + }, + { + desc: "label with many keys and values does not have label", + labels: map[string][]string{ + "key1": {"value2", "value1"}, + "key2": {"value1", "value2", "value2"}, + "key3": {"value1", "value2", "value2"}, + }, + key: "key5", + value: "value5", + wantHasLabel: false, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + sample := &Sample{ + Label: tc.labels, + } + if gotHasLabel := sample.HasLabel(tc.key, tc.value); gotHasLabel != tc.wantHasLabel { + t.Errorf("sample.HasLabel(%q, %q) got %v, want %v", tc.key, tc.value, gotHasLabel, tc.wantHasLabel) + } + }) + } +} + +func TestRemove(t *testing.T) { + var testcases = []struct { + desc string + samples []*Sample + removeKey string + wantLabels []map[string][]string + }{ + { + desc: "some samples have label already", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1", "value2", "value3"}, + "key2": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value2"}, + }, + }, + }, + removeKey: "key1", + wantLabels: []map[string][]string{ + {}, + {"key2": {"value1"}}, + {}, + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + profile := testProfile1.Copy() + profile.Sample = tc.samples + profile.RemoveLabel(tc.removeKey) + if got, want := len(profile.Sample), len(tc.wantLabels); got != want { + t.Fatalf("got %v samples, want %v samples", got, want) + } + for i, sample := range profile.Sample { + wantLabels := tc.wantLabels[i] + if got, want := len(sample.Label), len(wantLabels); got != want { + t.Errorf("got %v label keys for sample %v, want %v", got, i, want) + continue + } + for wantKey, wantValues := range wantLabels { + if gotValues, ok := sample.Label[wantKey]; ok { + if !reflect.DeepEqual(gotValues, wantValues) { + t.Errorf("for key %s, got values %v, want values %v", wantKey, gotValues, wantValues) + } + } else { + t.Errorf("for key %s got no values, want %v", wantKey, wantValues) + } + } + } + }) + } +} + +func TestSetLabel(t *testing.T) { + var testcases = []struct { + desc string + samples []*Sample + setKey string + setVal []string + wantLabels []map[string][]string + }{ + { + desc: "some samples have label already", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1", "value2", "value3"}, + "key2": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value2"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + {"key1": {"value1"}, "key2": {"value1"}}, + {"key1": {"value1"}}, + }, + }, + { + desc: "no samples have labels", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + }, + }, + { + desc: "all samples have some labels, but not key being added", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key2": {"value2"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key3": {"value3"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}, "key2": {"value2"}}, + {"key1": {"value1"}, "key3": {"value3"}}, + }, + }, + { + desc: "all samples have key being added", + samples: []*Sample{ + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1"}, + }, + }, + { + Location: []*Location{cpuL[0]}, + Value: []int64{1000}, + Label: map[string][]string{ + "key1": {"value1"}, + }, + }, + }, + setKey: "key1", + setVal: []string{"value1"}, + wantLabels: []map[string][]string{ + {"key1": {"value1"}}, + {"key1": {"value1"}}, + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + profile := testProfile1.Copy() + profile.Sample = tc.samples + profile.SetLabel(tc.setKey, tc.setVal) + if got, want := len(profile.Sample), len(tc.wantLabels); got != want { + t.Fatalf("got %v samples, want %v samples", got, want) + } + for i, sample := range profile.Sample { + wantLabels := tc.wantLabels[i] + if got, want := len(sample.Label), len(wantLabels); got != want { + t.Errorf("got %v label keys for sample %v, want %v", got, i, want) + continue + } + for wantKey, wantValues := range wantLabels { + if gotValues, ok := sample.Label[wantKey]; ok { + if !reflect.DeepEqual(gotValues, wantValues) { + t.Errorf("for key %s, got values %v, want values %v", wantKey, gotValues, wantValues) + } + } else { + t.Errorf("for key %s got no values, want %v", wantKey, wantValues) + } + } + } + }) + } +} + func TestNumLabelUnits(t *testing.T) { var tagFilterTests = []struct { desc string diff --git a/src/cmd/vendor/vendor.json b/src/cmd/vendor/vendor.json index 89506e7fe1724..26b32692b28b1 100644 --- a/src/cmd/vendor/vendor.json +++ b/src/cmd/vendor/vendor.json @@ -5,98 +5,98 @@ { "checksumSHA1": "G9UsR+iruMWxwUefhy+ID+VIFNs=", "path": "github.com/google/pprof/driver", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LzGfApA19baVJIbQEqziWpRS3zE=", "path": "github.com/google/pprof/internal/binutils", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "f7aprpcWR7iZX1PJgKBZrpt++XY=", + "checksumSHA1": "uoKLYk9VTOx2kYV3hU3vOGm4BX8=", "path": "github.com/google/pprof/internal/driver", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "IhuyU2pFSHhQxzadDBw1nHbcsrY=", "path": "github.com/google/pprof/internal/elfexec", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "8vah+aXLGpbtn55JR8MkCAEOMrk=", "path": "github.com/google/pprof/internal/graph", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "QPWfnT5pEU2jOOb8l8hpiFzQJ7Q=", "path": "github.com/google/pprof/internal/measurement", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "PWZdFtGfGz/zbQTfvel9737NZdY=", "path": "github.com/google/pprof/internal/plugin", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LmDglu/S6vFmgqkxubKDZemFHaY=", "path": "github.com/google/pprof/internal/proftest", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "gdyWnzbjgwmqJ2EN/WAp+QPu7d0=", + "checksumSHA1": "qgsLCrPLve6es8A3bA3qv2LPoYk=", "path": "github.com/google/pprof/internal/report", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "rWdirHgJi1+TdRwv5v3zjgFKcJA=", "path": "github.com/google/pprof/internal/symbolizer", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "5lS2AF207MVYyjF+82qHkWK2V64=", "path": "github.com/google/pprof/internal/symbolz", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "RvwtpZ+NVtPRCo4EiFvLFFHpoBo=", + "checksumSHA1": "JMf63Fn5hz7JFgz6A2aT9DP/bL0=", "path": "github.com/google/pprof/profile", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "xmqfYca88U2c/I4642r3ps9uIRg=", "path": "github.com/google/pprof/third_party/d3", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "LzWzD56Trzpq+0hLR00Yw5Gpepw=", "path": "github.com/google/pprof/third_party/d3flamegraph", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { "checksumSHA1": "738v1E0v0qRW6oAKdCpBEtyVNnY=", "path": "github.com/google/pprof/third_party/svgpan", - "revision": "4d67f66d7c9469639518a80f378434bb7e9156b7", - "revisionTime": "2018-05-09T15:07:09Z" + "revision": "1ddc9e21322e23449cb6709652bf3583969ca167", + "revisionTime": "2018-05-30T14:24:47Z" }, { - "checksumSHA1": "UDJQBwUTuQYEHHJ/D7nPBv1qNqI=", + "checksumSHA1": "J5yI4NzHbondzccJmummyJR/kQQ=", "path": "github.com/ianlancetaylor/demangle", - "revision": "4883227f66371e02c4948937d3e2be1664d9be38", - "revisionTime": "2016-09-27T19:13:59Z" + "revision": "fc6590592b44fedfff586c5d94647c090fbd6bac", + "revisionTime": "2018-05-24T22:59:00Z" }, { "path": "golang.org/x/arch/arm/armasm", diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go index 6c56daff03b1b..09181f968950c 100644 --- a/src/cmd/vet/all/main.go +++ b/src/cmd/vet/all/main.go @@ -192,9 +192,9 @@ func vetPlatforms(pp []platform) { } func (p platform) vet() { - if p.os == "js" && p.arch == "wasm" { - // TODO(neelance): enable as soon as js/wasm has fully landed - fmt.Println("skipping js/wasm") + if p.os == "linux" && p.arch == "riscv64" { + // TODO(tklauser): enable as soon as the riscv64 port has fully landed + fmt.Println("skipping linux/riscv64") return } diff --git a/src/cmd/vet/all/whitelist/darwin_386.txt b/src/cmd/vet/all/whitelist/darwin_386.txt index f7645eff1a1e3..934b773f5081a 100644 --- a/src/cmd/vet/all/whitelist/darwin_386.txt +++ b/src/cmd/vet/all/whitelist/darwin_386.txt @@ -2,7 +2,5 @@ // Ok -runtime/sys_darwin_386.s: [386] now: function now missing Go declaration runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration -runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/all/whitelist/darwin_amd64.txt b/src/cmd/vet/all/whitelist/darwin_amd64.txt index 8423415aea801..fcdacb2dc1b61 100644 --- a/src/cmd/vet/all/whitelist/darwin_amd64.txt +++ b/src/cmd/vet/all/whitelist/darwin_amd64.txt @@ -1,4 +1,3 @@ // darwin/amd64-specific vet whitelist. See readme.txt for details. runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration -runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time diff --git a/src/cmd/vet/all/whitelist/darwin_arm.txt b/src/cmd/vet/all/whitelist/darwin_arm.txt index 8e935b6ff2dc2..1c25c6a939765 100644 --- a/src/cmd/vet/all/whitelist/darwin_arm.txt +++ b/src/cmd/vet/all/whitelist/darwin_arm.txt @@ -1,11 +1,5 @@ // darwin/arm-specific vet whitelist. See readme.txt for details. -// False positives due to comments in assembly. -// To be removed. See CL 27154. - -runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP) - - // Ok. runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration diff --git a/src/cmd/vet/all/whitelist/darwin_arm64.txt b/src/cmd/vet/all/whitelist/darwin_arm64.txt index 8cab997961a37..a1edb71383282 100644 --- a/src/cmd/vet/all/whitelist/darwin_arm64.txt +++ b/src/cmd/vet/all/whitelist/darwin_arm64.txt @@ -1,5 +1,3 @@ // darwin/arm64-specific vet whitelist. See readme.txt for details. -runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) -runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration diff --git a/src/cmd/vet/all/whitelist/s390x.txt b/src/cmd/vet/all/whitelist/s390x.txt index 9fa4949575281..5bc48e5afcfb1 100644 --- a/src/cmd/vet/all/whitelist/s390x.txt +++ b/src/cmd/vet/all/whitelist/s390x.txt @@ -5,3 +5,10 @@ runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration +internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value +internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value diff --git a/src/cmd/vet/all/whitelist/wasm.txt b/src/cmd/vet/all/whitelist/wasm.txt new file mode 100644 index 0000000000000..ade759026d8b0 --- /dev/null +++ b/src/cmd/vet/all/whitelist/wasm.txt @@ -0,0 +1,33 @@ +// wasm-specific vet whitelist. See readme.txt for details. + +// False positives. + +// Nothing much to do about cross-package assembly. Unfortunate. +internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: Compare is in package bytes +internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: cmpstring is in package runtime + +// morestack intentionally omits arg size. +runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame +runtime/asm_wasm.s: [wasm] morestack: use of 16(SP) points beyond argument frame +runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame + +// rt0_go does not allocate a stack frame. +runtime/asm_wasm.s: [wasm] rt0_go: use of 8(SP) points beyond argument frame + +// Calling WebAssembly import. No write from Go assembly. +runtime/sys_wasm.s: [wasm] nanotime: RET without writing to 8-byte ret+0(FP) +runtime/sys_wasm.s: [wasm] scheduleCallback: RET without writing to 4-byte ret+8(FP) +syscall/js/js_js.s: [wasm] boolVal: RET without writing to 4-byte ret+8(FP) +syscall/js/js_js.s: [wasm] intVal: RET without writing to 4-byte ret+8(FP) +syscall/js/js_js.s: [wasm] floatVal: RET without writing to 4-byte ret+8(FP) +syscall/js/js_js.s: [wasm] stringVal: RET without writing to 4-byte ret+16(FP) +syscall/js/js_js.s: [wasm] valueGet: RET without writing to 4-byte ret+24(FP) +syscall/js/js_js.s: [wasm] valueIndex: RET without writing to 4-byte ret+16(FP) +syscall/js/js_js.s: [wasm] valueCall: RET without writing to 4-byte ret+48(FP) +syscall/js/js_js.s: [wasm] valueInvoke: RET without writing to 4-byte ret+32(FP) +syscall/js/js_js.s: [wasm] valueNew: RET without writing to 4-byte ret+32(FP) +syscall/js/js_js.s: [wasm] valueFloat: RET without writing to 8-byte ret+8(FP) +syscall/js/js_js.s: [wasm] valueInt: RET without writing to 8-byte ret+8(FP) +syscall/js/js_js.s: [wasm] valueBool: RET without writing to 1-byte ret+8(FP) +syscall/js/js_js.s: [wasm] valueLength: RET without writing to 8-byte ret+8(FP) +syscall/js/js_js.s: [wasm] valuePrepareString: RET without writing to 4-byte ret+8(FP) diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go index d3335c69f561e..ccf6269f1db29 100644 --- a/src/cmd/vet/asmdecl.go +++ b/src/cmd/vet/asmdecl.go @@ -77,6 +77,7 @@ var ( asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true} asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true} asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true} + asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false} arches = []*asmArch{ &asmArch386, @@ -91,6 +92,7 @@ var ( &asmArchPpc64, &asmArchPpc64LE, &asmArchS390X, + &asmArchWasm, } ) @@ -104,6 +106,8 @@ func init() { arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer])) arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64])) } + + registerPkgCheck("asmdecl", asmCheck) } var ( @@ -119,7 +123,7 @@ var ( ) func asmCheck(pkg *Package) { - if !vet("asmdecl") { + if vcfg.VetxOnly { return } diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go index 80d8f819240c4..d1fedec554918 100644 --- a/src/cmd/vet/buildtag.go +++ b/src/cmd/vet/buildtag.go @@ -19,11 +19,39 @@ var ( ) // checkBuildTag checks that build tags are in the correct location and well-formed. -func checkBuildTag(name string, data []byte) { +func checkBuildTag(f *File) { if !vet("buildtags") { return } - lines := bytes.SplitAfter(data, nl) + // badf is like File.Badf, but it uses a line number instead of + // token.Pos. + badf := func(line int, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args) + fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg) + setExit(1) + } + + // we must look at the raw lines, as build tags may appear in non-Go + // files such as assembly files. + lines := bytes.SplitAfter(f.content, nl) + + // lineWithComment reports whether a line corresponds to a comment in + // the source file. If the source file wasn't Go, the function always + // returns true. + lineWithComment := func(line int) bool { + if f.file == nil { + // Current source file is not Go, so be conservative. + return true + } + for _, group := range f.file.Comments { + startLine := f.fset.Position(group.Pos()).Line + endLine := f.fset.Position(group.End()).Line + if startLine <= line && line <= endLine { + return true + } + } + return false + } // Determine cutpoint where +build comments are no longer valid. // They are valid in leading // comments in the file followed by @@ -46,18 +74,29 @@ func checkBuildTag(name string, data []byte) { if !bytes.HasPrefix(line, slashSlash) { continue } + if !bytes.Contains(line, plusBuild) { + // Check that the comment contains "+build" early, to + // avoid unnecessary lineWithComment calls that may + // incur linear searches. + continue + } + if !lineWithComment(i + 1) { + // This is a line in a Go source file that looks like a + // comment, but actually isn't - such as part of a raw + // string. + continue + } + text := bytes.TrimSpace(line[2:]) if bytes.HasPrefix(text, plusBuild) { fields := bytes.Fields(text) if !bytes.Equal(fields[0], plusBuild) { // Comment is something like +buildasdf not +build. - fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) - setExit(1) + badf(i+1, "possible malformed +build comment") continue } if i >= cutoff { - fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1) - setExit(1) + badf(i+1, "+build comment must appear before package clause and be followed by a blank line") continue } // Check arguments. @@ -65,15 +104,13 @@ func checkBuildTag(name string, data []byte) { for _, arg := range fields[1:] { for _, elem := range strings.Split(string(arg), ",") { if strings.HasPrefix(elem, "!!") { - fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg) - setExit(1) + badf(i+1, "invalid double negative in build constraint: %s", arg) break Args } elem = strings.TrimPrefix(elem, "!") for _, c := range elem { if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { - fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg) - setExit(1) + badf(i+1, "invalid non-alphanumeric build constraint: %s", arg) break Args } } @@ -82,9 +119,8 @@ func checkBuildTag(name string, data []byte) { continue } // Comment with +build but not at beginning. - if bytes.Contains(line, plusBuild) && i < cutoff { - fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1) - setExit(1) + if i < cutoff { + badf(i+1, "possible malformed +build comment") continue } } diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go index 3df975cacc435..d9af0a88759a3 100644 --- a/src/cmd/vet/doc.go +++ b/src/cmd/vet/doc.go @@ -119,22 +119,17 @@ Printf family Flag: -printf -Suspicious calls to functions in the Printf family, including any functions -with these names, disregarding case: - Print Printf Println - Fprint Fprintf Fprintln - Sprint Sprintf Sprintln - Error Errorf - Fatal Fatalf - Log Logf - Panic Panicf Panicln -The -printfuncs flag can be used to redefine this list. -If the function name ends with an 'f', the function is assumed to take -a format descriptor string in the manner of fmt.Printf. If not, vet -complains about arguments that look like format descriptor strings. - -It also checks for errors such as using a Writer as the first argument of -Printf. +Suspicious calls to fmt.Print, fmt.Printf, and related functions. +The check applies to known functions (for example, those in package fmt) +as well as any detected wrappers of known functions. + +The -printfuncs flag specifies a comma-separated list of names of +additional known formatting functions. Each name can be of the form +pkg.Name or pkg.Type.Name, where pkg is a complete import path, +or else can be a case-insensitive unqualified identifier like "errorf". +If a listed name ends in f, the function is assumed to be Printf-like, +taking a format string before the argument list. Otherwise it is +assumed to be Print-like, taking a list of arguments with no format string. Range loop variables diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 4422add72f242..959a536d257c1 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -4,10 +4,12 @@ // Vet is a simple checker for static errors in Go source code. // See doc.go for more information. + package main import ( "bytes" + "encoding/gob" "encoding/json" "flag" "fmt" @@ -24,6 +26,8 @@ import ( "path/filepath" "strconv" "strings" + + "cmd/internal/objabi" ) // Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go. @@ -154,9 +158,25 @@ var ( // checkers is a two-level map. // The outer level is keyed by a nil pointer, one of the AST vars above. // The inner level is keyed by checker name. - checkers = make(map[ast.Node]map[string]func(*File, ast.Node)) + checkers = make(map[ast.Node]map[string]func(*File, ast.Node)) + pkgCheckers = make(map[string]func(*Package)) + exporters = make(map[string]func() interface{}) ) +// Vet can provide its own "export information" +// about package A to future invocations of vet +// on packages importing A. If B imports A, +// then running "go vet B" actually invokes vet twice: +// first, it runs vet on A, in "vetx-only" mode, which +// skips most checks and only computes export data +// describing A. Then it runs vet on B, making A's vetx +// data available for consultation. The vet of B +// computes vetx data for B in addition to its +// usual vet checks. + +// register registers the named check function, +// to be called with AST nodes of the given types. +// The registered functions are not called in vetx-only mode. func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) { report[name] = triStateFlag(name, unset, usage) for _, typ := range types { @@ -169,6 +189,25 @@ func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) { } } +// registerPkgCheck registers a package-level checking function, +// to be invoked with the whole package being vetted +// before any of the per-node handlers. +// The registered function fn is called even in vetx-only mode +// (see comment above), so fn must take care not to report +// errors when vcfg.VetxOnly is true. +func registerPkgCheck(name string, fn func(*Package)) { + pkgCheckers[name] = fn +} + +// registerExport registers a function to return vetx export data +// that should be saved and provided to future invocations of vet +// when checking packages importing this one. +// The value returned by fn should be nil or else valid to encode using gob. +// Typically a registerExport call is paired with a call to gob.Register. +func registerExport(name string, fn func() interface{}) { + exporters[name] = fn +} + // Usage is a replacement usage function for the flags package. func Usage() { fmt.Fprintf(os.Stderr, "Usage of vet:\n") @@ -209,6 +248,7 @@ type File struct { } func main() { + objabi.AddVersionFlag() flag.Usage = Usage flag.Parse() @@ -295,6 +335,9 @@ type vetConfig struct { ImportMap map[string]string PackageFile map[string]string Standard map[string]bool + PackageVetx map[string]string // map from import path to vetx data file + VetxOnly bool // only compute vetx output; don't run ordinary checks + VetxOutput string // file where vetx output should be written SucceedOnTypecheckFailure bool @@ -355,6 +398,21 @@ func doPackageCfg(cfgFile string) { inittypes() mustTypecheck = true doPackage(vcfg.GoFiles, nil) + if vcfg.VetxOutput != "" { + out := make(map[string]interface{}) + for name, fn := range exporters { + out[name] = fn() + } + var buf bytes.Buffer + if err := gob.NewEncoder(&buf).Encode(out); err != nil { + errorf("encoding vet output: %v", err) + return + } + if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil { + errorf("saving vet output: %v", err) + return + } + } } // doPackageDir analyzes the single package found in the directory, if there is one, @@ -415,23 +473,24 @@ func doPackage(names []string, basePkg *Package) *Package { warnf("%s: %s", name, err) return nil } - checkBuildTag(name, data) var parsedFile *ast.File if strings.HasSuffix(name, ".go") { - parsedFile, err = parser.ParseFile(fs, name, data, 0) + parsedFile, err = parser.ParseFile(fs, name, data, parser.ParseComments) if err != nil { warnf("%s: %s", name, err) return nil } astFiles = append(astFiles, parsedFile) } - files = append(files, &File{ + file := &File{ fset: fs, content: data, name: name, file: parsedFile, dead: make(map[ast.Node]bool), - }) + } + checkBuildTag(file) + files = append(files, file) } if len(astFiles) == 0 { return nil @@ -460,6 +519,19 @@ func doPackage(names []string, basePkg *Package) *Package { } // Check. + for _, file := range files { + file.pkg = pkg + file.basePkg = basePkg + } + for name, fn := range pkgCheckers { + if vet(name) { + fn(pkg) + } + } + if vcfg.VetxOnly { + return pkg + } + chk := make(map[ast.Node][]func(*File, ast.Node)) for typ, set := range checkers { for name, fn := range set { @@ -469,14 +541,11 @@ func doPackage(names []string, basePkg *Package) *Package { } } for _, file := range files { - file.pkg = pkg - file.basePkg = basePkg file.checkers = chk if file.file != nil { file.walkFile(file.name, file.file) } } - asmCheck(pkg) return pkg } @@ -629,3 +698,35 @@ func (f *File) gofmt(x ast.Expr) string { printer.Fprint(&f.b, f.fset, x) return f.b.String() } + +// imported[path][key] is previously written export data. +var imported = make(map[string]map[string]interface{}) + +// readVetx reads export data written by a previous +// invocation of vet on an imported package (path). +// The key is the name passed to registerExport +// when the data was originally generated. +// readVetx returns nil if the data is unavailable. +func readVetx(path, key string) interface{} { + if path == "unsafe" || vcfg.ImportPath == "" { + return nil + } + m := imported[path] + if m == nil { + file := vcfg.PackageVetx[path] + if file == "" { + return nil + } + data, err := ioutil.ReadFile(file) + if err != nil { + return nil + } + m = make(map[string]interface{}) + err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m) + if err != nil { + return nil + } + imported[path] = m + } + return m[key] +} diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 6728d88d45d28..1edd3dd22881f 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -8,6 +8,7 @@ package main import ( "bytes" + "encoding/gob" "flag" "fmt" "go/ast" @@ -27,6 +28,9 @@ func init() { "check printf-like invocations", checkFmtPrintfCall, funcDecl, callExpr) + registerPkgCheck("printf", findPrintfLike) + registerExport("printf", exportPrintfLike) + gob.Register(map[string]int(nil)) } func initPrintFlags() { @@ -44,73 +48,244 @@ func initPrintFlags() { name = name[:colon] } - isPrint[strings.ToLower(name)] = true + if !strings.Contains(name, ".") { + name = strings.ToLower(name) + } + isPrint[name] = true } } -// TODO(rsc): Incorporate user-defined printf wrappers again. -// The general plan is to allow vet of one package P to output -// additional information to supply to later vets of packages -// importing P. Then vet of P can record a list of printf wrappers -// and the later vet using P.Printf will find it in the list and check it. -// That's not ready for Go 1.10. -// When that does happen, uncomment the user-defined printf -// wrapper tests in testdata/print.go. +var localPrintfLike = make(map[string]int) + +type printfWrapper struct { + name string + fn *ast.FuncDecl + format *ast.Field + args *ast.Field + callers []printfCaller + printfLike bool +} + +type printfCaller struct { + w *printfWrapper + call *ast.CallExpr +} + +// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper +// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper +// function describing the declaration. Later processing will analyze the +// graph of potential printf wrappers to pick out the ones that are true wrappers. +// A function may be a Printf or Print wrapper if its last argument is ...interface{}. +// If the next-to-last argument is a string, then this may be a Printf wrapper. +// Otherwise it may be a Print wrapper. +func maybePrintfWrapper(decl ast.Decl) *printfWrapper { + // Look for functions with final argument type ...interface{}. + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + return nil + } + name := fn.Name.Name + if fn.Recv != nil { + // For (*T).Name or T.name, use "T.name". + rcvr := fn.Recv.List[0].Type + if ptr, ok := rcvr.(*ast.StarExpr); ok { + rcvr = ptr.X + } + id, ok := rcvr.(*ast.Ident) + if !ok { + return nil + } + name = id.Name + "." + name + } + params := fn.Type.Params.List + if len(params) == 0 { + return nil + } + args := params[len(params)-1] + if len(args.Names) != 1 { + return nil + } + ddd, ok := args.Type.(*ast.Ellipsis) + if !ok { + return nil + } + iface, ok := ddd.Elt.(*ast.InterfaceType) + if !ok || len(iface.Methods.List) > 0 { + return nil + } + var format *ast.Field + if len(params) >= 2 { + p := params[len(params)-2] + if len(p.Names) == 1 { + if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" { + format = p + } + } + } + + return &printfWrapper{ + name: name, + fn: fn, + format: format, + args: args, + } +} + +// findPrintfLike scans the entire package to find printf-like functions. +func findPrintfLike(pkg *Package) { + if vcfg.ImportPath == "" { // no type or vetx information; don't bother + return + } + + // Gather potential wrappesr and call graph between them. + byName := make(map[string]*printfWrapper) + var wrappers []*printfWrapper + for _, file := range pkg.files { + if file.file == nil { + continue + } + for _, decl := range file.file.Decls { + w := maybePrintfWrapper(decl) + if w == nil { + continue + } + byName[w.name] = w + wrappers = append(wrappers, w) + } + } + + // Walk the graph to figure out which are really printf wrappers. + for _, w := range wrappers { + // Scan function for calls that could be to other printf-like functions. + ast.Inspect(w.fn.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) { + return true + } + + pkgpath, name, kind := printfNameAndKind(pkg, call.Fun) + if kind != 0 { + checkPrintfFwd(pkg, w, call, kind) + return true + } + + // If the call is to another function in this package, + // maybe we will find out it is printf-like later. + // Remember this call for later checking. + if pkgpath == "" && byName[name] != nil { + callee := byName[name] + callee.callers = append(callee.callers, printfCaller{w, call}) + } + + return true + }) + } +} + +func match(arg ast.Expr, param *ast.Field) bool { + id, ok := arg.(*ast.Ident) + return ok && id.Obj != nil && id.Obj.Decl == param +} + +const ( + kindPrintf = 1 + kindPrint = 2 +) + +// printfLike reports whether a call to fn should be considered a call to a printf-like function. +// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint. +func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int { + if id, ok := fn.(*ast.Ident); ok && id.Obj != nil { + if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn { + // Found call to function in same package. + return localPrintfLike[id.Name] + } + } + if sel, ok := fn.(*ast.SelectorExpr); ok { + if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") { + if strings.HasSuffix(sel.Sel.Name, "f") { + return kindPrintf + } + return kindPrint + } + } + return 0 +} + +// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly. +// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...). +func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) { + matched := kind == kindPrint || + kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format) + if !matched { + return + } + + if !call.Ellipsis.IsValid() { + if !vcfg.VetxOnly { + desc := "printf" + if kind == kindPrint { + desc = "print" + } + pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc) + } + return + } + name := w.name + if localPrintfLike[name] == 0 { + localPrintfLike[name] = kind + for _, caller := range w.callers { + checkPrintfFwd(pkg, caller.w, caller.call, kind) + } + } +} + +func exportPrintfLike() interface{} { + return localPrintfLike +} // isPrint records the print functions. // If a key ends in 'f' then it is assumed to be a formatted print. var isPrint = map[string]bool{ - "fmt.Errorf": true, - "fmt.Fprint": true, - "fmt.Fprintf": true, - "fmt.Fprintln": true, - "fmt.Print": true, - "fmt.Printf": true, - "fmt.Println": true, - "fmt.Sprint": true, - "fmt.Sprintf": true, - "fmt.Sprintln": true, - "log.Fatal": true, - "log.Fatalf": true, - "log.Fatalln": true, - "log.Logger.Fatal": true, - "log.Logger.Fatalf": true, - "log.Logger.Fatalln": true, - "log.Logger.Panic": true, - "log.Logger.Panicf": true, - "log.Logger.Panicln": true, - "log.Logger.Printf": true, - "log.Logger.Println": true, - "log.Panic": true, - "log.Panicf": true, - "log.Panicln": true, - "log.Print": true, - "log.Printf": true, - "log.Println": true, - "testing.B.Error": true, - "testing.B.Errorf": true, - "testing.B.Fatal": true, - "testing.B.Fatalf": true, - "testing.B.Log": true, - "testing.B.Logf": true, - "testing.B.Skip": true, - "testing.B.Skipf": true, - "testing.T.Error": true, - "testing.T.Errorf": true, - "testing.T.Fatal": true, - "testing.T.Fatalf": true, - "testing.T.Log": true, - "testing.T.Logf": true, - "testing.T.Skip": true, - "testing.T.Skipf": true, - "testing.TB.Error": true, - "testing.TB.Errorf": true, - "testing.TB.Fatal": true, - "testing.TB.Fatalf": true, - "testing.TB.Log": true, - "testing.TB.Logf": true, - "testing.TB.Skip": true, - "testing.TB.Skipf": true, + "fmt.Errorf": true, + "fmt.Fprint": true, + "fmt.Fprintf": true, + "fmt.Fprintln": true, + "fmt.Print": true, + "fmt.Printf": true, + "fmt.Println": true, + "fmt.Sprint": true, + "fmt.Sprintf": true, + "fmt.Sprintln": true, + + // testing.B, testing.T not auto-detected + // because the methods are picked up by embedding. + "testing.B.Error": true, + "testing.B.Errorf": true, + "testing.B.Fatal": true, + "testing.B.Fatalf": true, + "testing.B.Log": true, + "testing.B.Logf": true, + "testing.B.Skip": true, + "testing.B.Skipf": true, + "testing.T.Error": true, + "testing.T.Errorf": true, + "testing.T.Fatal": true, + "testing.T.Fatalf": true, + "testing.T.Log": true, + "testing.T.Logf": true, + "testing.T.Skip": true, + "testing.T.Skipf": true, + + // testing.TB is an interface, so can't detect wrapping. + "testing.TB.Error": true, + "testing.TB.Errorf": true, + "testing.TB.Fatal": true, + "testing.TB.Fatalf": true, + "testing.TB.Log": true, + "testing.TB.Logf": true, + "testing.TB.Skip": true, + "testing.TB.Skipf": true, } // formatString returns the format string argument and its index within @@ -206,66 +381,84 @@ func checkFmtPrintfCall(f *File, node ast.Node) { } // Construct name like pkg.Printf or pkg.Type.Printf for lookup. - var name string - switch x := call.Fun.(type) { + _, name, kind := printfNameAndKind(f.pkg, call.Fun) + if kind == kindPrintf { + f.checkPrintf(call, name) + } + if kind == kindPrint { + f.checkPrint(call, name) + } +} + +func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) { + switch x := called.(type) { case *ast.Ident: - if fn, ok := f.pkg.uses[x].(*types.Func); ok { - var pkg string - if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg { - pkg = vcfg.ImportPath + if fn, ok := pkg.uses[x].(*types.Func); ok { + if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg { + pkgpath = "" } else { - pkg = fn.Pkg().Path() + pkgpath = fn.Pkg().Path() } - name = pkg + "." + x.Name - break + return pkgpath, x.Name } case *ast.SelectorExpr: // Check for "fmt.Printf". if id, ok := x.X.(*ast.Ident); ok { - if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok { - name = pkgName.Imported().Path() + "." + x.Sel.Name - break + if pkgName, ok := pkg.uses[id].(*types.PkgName); ok { + return pkgName.Imported().Path(), x.Sel.Name } } // Check for t.Logf where t is a *testing.T. - if sel := f.pkg.selectors[x]; sel != nil { + if sel := pkg.selectors[x]; sel != nil { recv := sel.Recv() if p, ok := recv.(*types.Pointer); ok { recv = p.Elem() } if named, ok := recv.(*types.Named); ok { obj := named.Obj() - var pkg string - if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg { - pkg = vcfg.ImportPath + if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg { + pkgpath = "" } else { - pkg = obj.Pkg().Path() + pkgpath = obj.Pkg().Path() } - name = pkg + "." + obj.Name() + "." + x.Sel.Name - break + return pkgpath, obj.Name() + "." + x.Sel.Name } } } + return "", "" +} + +func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) { + pkgpath, name = printfName(pkg, called) if name == "" { - return + return pkgpath, name, 0 } - shortName := name[strings.LastIndex(name, ".")+1:] - - _, ok = isPrint[name] - if !ok { - // Next look up just "printf", for use with -printfuncs. - _, ok = isPrint[strings.ToLower(shortName)] + if pkgpath == "" { + kind = localPrintfLike[name] + } else { + printfLike, _ := readVetx(pkgpath, "printf").(map[string]int) + kind = printfLike[name] } - if ok { - if strings.HasSuffix(name, "f") { - f.checkPrintf(call, shortName) - } else { - f.checkPrint(call, shortName) + + if kind == 0 { + _, ok := isPrint[pkgpath+"."+name] + if !ok { + // Next look up just "printf", for use with -printfuncs. + short := name[strings.LastIndex(name, ".")+1:] + _, ok = isPrint[strings.ToLower(short)] + } + if ok { + if strings.HasSuffix(name, "f") { + kind = kindPrintf + } else { + kind = kindPrint + } } } + return pkgpath, name, kind } // isStringer returns true if the provided declaration is a "String() string" diff --git a/src/cmd/vet/testdata/atomic.go b/src/cmd/vet/testdata/atomic.go index 8b587567c75e0..69730b4e6f03f 100644 --- a/src/cmd/vet/testdata/atomic.go +++ b/src/cmd/vet/testdata/atomic.go @@ -43,7 +43,7 @@ func AtomicTests() { { // A variable declaration creates a new variable in the current scope. - x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16" + x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at atomic.go:16" // Re-declaration assigns a new value. x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value" diff --git a/src/cmd/vet/testdata/buildtag/buildtag.go b/src/cmd/vet/testdata/buildtag/buildtag.go index f12f895dfb19b..6ee08da638da8 100644 --- a/src/cmd/vet/testdata/buildtag/buildtag.go +++ b/src/cmd/vet/testdata/buildtag/buildtag.go @@ -12,3 +12,7 @@ package testdata // +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line" var _ = 3 + +var _ = ` +// +build notacomment +` diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 34f4e2865a142..16f46a4897ebc 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -14,6 +14,7 @@ package testdata import ( "fmt" . "fmt" + logpkg "log" // renamed to make it harder to see "math" "os" "testing" @@ -175,6 +176,18 @@ func PrintfTests() { f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args" f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r" f.Warnf(0, "%#s", "hello") // ERROR "Warnf format %#s has unrecognized flag #" + f.Warn2(0, "%s", "hello", 3) // ERROR "Warn2 call has possible formatting directive %s" + f.Warnf2(0, "%s", "hello", 3) // ERROR "Warnf2 call needs 1 arg but has 2 args" + f.Warnf2(0, "%r", "hello") // ERROR "Warnf2 format %r has unknown verb r" + f.Warnf2(0, "%#s", "hello") // ERROR "Warnf2 format %#s has unrecognized flag #" + f.Wrap(0, "%s", "hello", 3) // ERROR "Wrap call has possible formatting directive %s" + f.Wrapf(0, "%s", "hello", 3) // ERROR "Wrapf call needs 1 arg but has 2 args" + f.Wrapf(0, "%r", "hello") // ERROR "Wrapf format %r has unknown verb r" + f.Wrapf(0, "%#s", "hello") // ERROR "Wrapf format %#s has unrecognized flag #" + f.Wrap2(0, "%s", "hello", 3) // ERROR "Wrap2 call has possible formatting directive %s" + f.Wrapf2(0, "%s", "hello", 3) // ERROR "Wrapf2 call needs 1 arg but has 2 args" + f.Wrapf2(0, "%r", "hello") // ERROR "Wrapf2 format %r has unknown verb r" + f.Wrapf2(0, "%#s", "hello") // ERROR "Wrapf2 format %#s has unrecognized flag #" fmt.Printf("%#s", FormatterVal(true)) // correct (the type is responsible for formatting) Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string" Printf("%d", percentDV) @@ -283,6 +296,28 @@ func PrintfTests() { Printf(someString(), "hello") // OK + // Printf wrappers in package log should be detected automatically + logpkg.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d" + logpkg.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string" + logpkg.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d" + logpkg.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d" + logpkg.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string" + logpkg.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d" + logpkg.Print("%d", 1) // ERROR "Print call has possible formatting directive %d" + logpkg.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string" + logpkg.Println("%d", 1) // ERROR "Println call has possible formatting directive %d" + + // Methods too. + var l *logpkg.Logger + l.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d" + l.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string" + l.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d" + l.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d" + l.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string" + l.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d" + l.Print("%d", 1) // ERROR "Print call has possible formatting directive %d" + l.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string" + l.Println("%d", 1) // ERROR "Println call has possible formatting directive %d" } func someString() string { return "X" } @@ -368,14 +403,46 @@ func (*ptrStringer) String() string { return "string" } -func (*ptrStringer) Warn(int, ...interface{}) string { +func (p *ptrStringer) Warn2(x int, args ...interface{}) string { + return p.Warn(x, args...) +} + +func (p *ptrStringer) Warnf2(x int, format string, args ...interface{}) string { + return p.Warnf(x, format, args...) +} + +func (*ptrStringer) Warn(x int, args ...interface{}) string { return "warn" } -func (*ptrStringer) Warnf(int, string, ...interface{}) string { +func (*ptrStringer) Warnf(x int, format string, args ...interface{}) string { return "warnf" } +func (p *ptrStringer) Wrap2(x int, args ...interface{}) string { + return p.Wrap(x, args...) +} + +func (p *ptrStringer) Wrapf2(x int, format string, args ...interface{}) string { + return p.Wrapf(x, format, args...) +} + +func (*ptrStringer) Wrap(x int, args ...interface{}) string { + return fmt.Sprint(args...) +} + +func (*ptrStringer) Wrapf(x int, format string, args ...interface{}) string { + return fmt.Sprintf(format, args...) +} + +func (*ptrStringer) BadWrap(x int, args ...interface{}) string { + return fmt.Sprint(args) // ERROR "missing ... in args forwarded to print-like function" +} + +func (*ptrStringer) BadWrapf(x int, format string, args ...interface{}) string { + return fmt.Sprintf(format, args) // ERROR "missing ... in args forwarded to printf-like function" +} + type embeddedStringer struct { foo string ptrStringer diff --git a/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go index 3b61137b87c09..c55cb2772a9c6 100644 --- a/src/cmd/vet/testdata/shadow.go +++ b/src/cmd/vet/testdata/shadow.go @@ -17,7 +17,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) { _ = err } if f != nil { - _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13" if err != nil { return err } @@ -25,8 +25,8 @@ func ShadowRead(f *os.File, buf []byte) (err error) { _ = i } if f != nil { - x := one() // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" - var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13" + x := one() // ERROR "declaration of .x. shadows declaration at shadow.go:14" + var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13" if x == 1 && err != nil { return err } @@ -46,7 +46,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) { if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration var f *os.File // OK because f is not mentioned later in the function. // The declaration of x is a shadow because x is mentioned below. - var x int // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14" + var x int // ERROR "declaration of .x. shadows declaration at shadow.go:14" _, _, _ = x, f, shadowTemp } // Use a couple of variables to trigger shadowing errors. diff --git a/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go index c87e42f5d004b..ce21e803c802e 100644 --- a/src/cmd/vet/testdata/structtag.go +++ b/src/cmd/vet/testdata/structtag.go @@ -44,40 +44,40 @@ type AnonymousXML struct{} type DuplicateJSONFields struct { JSON int `json:"a"` - DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46" + DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:46" IgnoredJSON int `json:"-"` OtherIgnoredJSON int `json:"-"` OmitJSON int `json:",omitempty"` OtherOmitJSON int `json:",omitempty"` - DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46" + DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:46" NonJSON int `foo:"a"` DuplicateNonJSON int `foo:"a"` Embedded struct { DuplicateJSON int `json:"a"` // OK because its not in the same struct type } - AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46" + AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:46" XML int `xml:"a"` - DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60" + DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:60" IgnoredXML int `xml:"-"` OtherIgnoredXML int `xml:"-"` OmitXML int `xml:",omitempty"` OtherOmitXML int `xml:",omitempty"` - DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60" + DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:60" NonXML int `foo:"a"` DuplicateNonXML int `foo:"a"` Embedded struct { DuplicateXML int `xml:"a"` // OK because its not in the same struct type } - AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60" + AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:60" Attribute struct { XMLName xml.Name `xml:"b"` NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct. Attr int `xml:"b,attr"` // OK because 0 is valid. - DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" - DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76" + DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:76" + DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:76" - AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76" + AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:76" } } diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index f654d4679ec12..ecb4ce129566e 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -6,12 +6,17 @@ package main_test import ( "bytes" + "errors" "fmt" "internal/testenv" + "io/ioutil" + "log" "os" "os/exec" "path/filepath" + "regexp" "runtime" + "strconv" "strings" "sync" "testing" @@ -19,7 +24,7 @@ import ( const ( dataDir = "testdata" - binary = "testvet.exe" + binary = "./testvet.exe" ) // We implement TestMain so remove the test binary when all is done. @@ -29,16 +34,6 @@ func TestMain(m *testing.M) { os.Exit(result) } -func MustHavePerl(t *testing.T) { - switch runtime.GOOS { - case "plan9", "windows": - t.Skipf("skipping test: perl not available on %s", runtime.GOOS) - } - if _, err := exec.LookPath("perl"); err != nil { - t.Skipf("skipping test: perl not found in path") - } -} - var ( buildMu sync.Mutex // guards following built = false // We have built the binary. @@ -55,7 +50,6 @@ func Build(t *testing.T) { t.Skip("cannot run on this environment") } testenv.MustHaveGoBuild(t) - MustHavePerl(t) cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary) output, err := cmd.CombinedOutput() if err != nil { @@ -67,23 +61,19 @@ func Build(t *testing.T) { } func Vet(t *testing.T, files []string) { - errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") flags := []string{ - "./" + binary, "-printfuncs=Warn:1,Warnf:1", "-all", "-shadow", } - cmd := exec.Command(errchk, append(flags, files...)...) - if !run(cmd, t) { - t.Fatal("vet command failed") - } + cmd := exec.Command(binary, append(flags, files...)...) + errchk(cmd, files, t) } -// Run this shell script, but do it in Go so it can be run by "go test". -// go build -o testvet -// $(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s -// rm testvet +// TestVet is equivalent to running this: +// go build -o ./testvet +// errorCheck the output of ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s +// rm ./testvet // // TestVet tests self-contained files in testdata/*.go. @@ -95,7 +85,6 @@ func TestVet(t *testing.T) { Build(t) t.Parallel() - // errchk ./testvet gos, err := filepath.Glob(filepath.Join(dataDir, "*.go")) if err != nil { t.Fatal(err) @@ -128,17 +117,14 @@ func TestVet(t *testing.T) { func TestVetPrint(t *testing.T) { Build(t) - errchk := filepath.Join(runtime.GOROOT(), "test", "errchk") + file := filepath.Join("testdata", "print.go") cmd := exec.Command( - errchk, - "go", "vet", "-vettool=./"+binary, + "go", "vet", "-vettool="+binary, "-printf", "-printfuncs=Warn:1,Warnf:1", - "testdata/print.go", + file, ) - if !run(cmd, t) { - t.Fatal("vet command failed") - } + errchk(cmd, []string{file}, t) } func TestVetAsm(t *testing.T) { @@ -155,7 +141,6 @@ func TestVetAsm(t *testing.T) { } t.Parallel() - // errchk ./testvet Vet(t, append(gos, asms...)) } @@ -181,23 +166,20 @@ func TestVetDirs(t *testing.T) { } } -func run(c *exec.Cmd, t *testing.T) bool { +func errchk(c *exec.Cmd, files []string, t *testing.T) { output, err := c.CombinedOutput() - if err != nil { + if _, ok := err.(*exec.ExitError); !ok { t.Logf("vet output:\n%s", output) t.Fatal(err) } - // Errchk delights by not returning non-zero status if it finds errors, so we look at the output. - // It prints "BUG" if there is a failure. - if !c.ProcessState.Success() { - t.Logf("vet output:\n%s", output) - return false + fullshort := make([]string, 0, len(files)*2) + for _, f := range files { + fullshort = append(fullshort, f, filepath.Base(f)) } - ok := !bytes.Contains(output, []byte("BUG")) - if !ok { - t.Logf("vet output:\n%s", output) + err = errorCheck(string(output), false, fullshort...) + if err != nil { + t.Errorf("error check failed: %s", err) } - return ok } // TestTags verifies that the -tags argument controls which files to check. @@ -214,7 +196,7 @@ func TestTags(t *testing.T) { "-v", // We're going to look at the files it examines. "testdata/tagtest", } - cmd := exec.Command("./"+binary, args...) + cmd := exec.Command(binary, args...) output, err := cmd.CombinedOutput() if err != nil { t.Fatal(err) @@ -234,10 +216,225 @@ func TestTags(t *testing.T) { func TestVetVerbose(t *testing.T) { t.Parallel() Build(t) - cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go") + cmd := exec.Command(binary, "-v", "-all", "testdata/cgo/cgo3.go") out, err := cmd.CombinedOutput() if err != nil { t.Logf("%s", out) t.Error(err) } } + +// All declarations below were adapted from test/run.go. + +// errorCheck matches errors in outStr against comments in source files. +// For each line of the source files which should generate an error, +// there should be a comment of the form // ERROR "regexp". +// If outStr has an error for a line which has no such comment, +// this function will report an error. +// Likewise if outStr does not have an error for a line which has a comment, +// or if the error message does not match the . +// The syntax is Perl but its best to stick to egrep. +// +// Sources files are supplied as fullshort slice. +// It consists of pairs: full path to source file and it's base name. +func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) { + var errs []error + out := splitOutput(outStr, wantAuto) + // Cut directory name. + for i := range out { + for j := 0; j < len(fullshort); j += 2 { + full, short := fullshort[j], fullshort[j+1] + out[i] = strings.Replace(out[i], full, short, -1) + } + } + + var want []wantedError + for j := 0; j < len(fullshort); j += 2 { + full, short := fullshort[j], fullshort[j+1] + want = append(want, wantedErrors(full, short)...) + } + for _, we := range want { + var errmsgs []string + if we.auto { + errmsgs, out = partitionStrings("", out) + } else { + errmsgs, out = partitionStrings(we.prefix, out) + } + if len(errmsgs) == 0 { + errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr)) + continue + } + matched := false + n := len(out) + for _, errmsg := range errmsgs { + // Assume errmsg says "file:line: foo". + // Cut leading "file:line: " to avoid accidental matching of file name instead of message. + text := errmsg + if i := strings.Index(text, " "); i >= 0 { + text = text[i+1:] + } + if we.re.MatchString(text) { + matched = true + } else { + out = append(out, errmsg) + } + } + if !matched { + errs = append(errs, fmt.Errorf("%s:%d: no match for %#q in:\n\t%s", we.file, we.lineNum, we.reStr, strings.Join(out[n:], "\n\t"))) + continue + } + } + + if len(out) > 0 { + errs = append(errs, fmt.Errorf("Unmatched Errors:")) + for _, errLine := range out { + errs = append(errs, fmt.Errorf("%s", errLine)) + } + } + + if len(errs) == 0 { + return nil + } + if len(errs) == 1 { + return errs[0] + } + var buf bytes.Buffer + fmt.Fprintf(&buf, "\n") + for _, err := range errs { + fmt.Fprintf(&buf, "%s\n", err.Error()) + } + return errors.New(buf.String()) +} + +func splitOutput(out string, wantAuto bool) []string { + // gc error messages continue onto additional lines with leading tabs. + // Split the output at the beginning of each line that doesn't begin with a tab. + // lines are impossible to match so those are filtered out. + var res []string + for _, line := range strings.Split(out, "\n") { + line = strings.TrimSuffix(line, "\r") // normalize Windows output + if strings.HasPrefix(line, "\t") { + res[len(res)-1] += "\n" + line + } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "") { + continue + } else if strings.TrimSpace(line) != "" { + res = append(res, line) + } + } + return res +} + +// matchPrefix reports whether s starts with file name prefix followed by a :, +// and possibly preceded by a directory name. +func matchPrefix(s, prefix string) bool { + i := strings.Index(s, ":") + if i < 0 { + return false + } + j := strings.LastIndex(s[:i], "/") + s = s[j+1:] + if len(s) <= len(prefix) || s[:len(prefix)] != prefix { + return false + } + if s[len(prefix)] == ':' { + return true + } + return false +} + +func partitionStrings(prefix string, strs []string) (matched, unmatched []string) { + for _, s := range strs { + if matchPrefix(s, prefix) { + matched = append(matched, s) + } else { + unmatched = append(unmatched, s) + } + } + return +} + +type wantedError struct { + reStr string + re *regexp.Regexp + lineNum int + auto bool // match line + file string + prefix string +} + +var ( + errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`) + errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`) + errQuotesRx = regexp.MustCompile(`"([^"]*)"`) + lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`) +) + +// wantedErrors parses expected errors from comments in a file. +func wantedErrors(file, short string) (errs []wantedError) { + cache := make(map[string]*regexp.Regexp) + + src, err := ioutil.ReadFile(file) + if err != nil { + log.Fatal(err) + } + for i, line := range strings.Split(string(src), "\n") { + lineNum := i + 1 + if strings.Contains(line, "////") { + // double comment disables ERROR + continue + } + var auto bool + m := errAutoRx.FindStringSubmatch(line) + if m != nil { + auto = true + } else { + m = errRx.FindStringSubmatch(line) + } + if m == nil { + continue + } + all := m[1] + mm := errQuotesRx.FindAllStringSubmatch(all, -1) + if mm == nil { + log.Fatalf("%s:%d: invalid errchk line: %s", file, lineNum, line) + } + for _, m := range mm { + replacedOnce := false + rx := lineRx.ReplaceAllStringFunc(m[1], func(m string) string { + if replacedOnce { + return m + } + replacedOnce = true + n := lineNum + if strings.HasPrefix(m, "LINE+") { + delta, _ := strconv.Atoi(m[5:]) + n += delta + } else if strings.HasPrefix(m, "LINE-") { + delta, _ := strconv.Atoi(m[5:]) + n -= delta + } + return fmt.Sprintf("%s:%d", short, n) + }) + re := cache[rx] + if re == nil { + var err error + re, err = regexp.Compile(rx) + if err != nil { + log.Fatalf("%s:%d: invalid regexp \"%#q\" in ERROR line: %v", file, lineNum, rx, err) + } + cache[rx] = re + } + prefix := fmt.Sprintf("%s:%d", short, lineNum) + errs = append(errs, wantedError{ + reStr: rx, + re: re, + prefix: prefix, + auto: auto, + lineNum: lineNum, + file: short, + }) + } + } + + return +} diff --git a/src/compress/bzip2/bzip2.go b/src/compress/bzip2/bzip2.go index f07c7e81e876b..c40129b9820ee 100644 --- a/src/compress/bzip2/bzip2.go +++ b/src/compress/bzip2/bzip2.go @@ -8,7 +8,7 @@ package bzip2 import "io" // There's no RFC for bzip2. I used the Wikipedia page for reference and a lot -// of guessing: http://en.wikipedia.org/wiki/Bzip2 +// of guessing: https://en.wikipedia.org/wiki/Bzip2 // The source code to pyflate was useful for debugging: // http://www.paul.sladen.org/projects/pyflate diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go index 4d6a5357d881d..8b92f1586db2c 100644 --- a/src/compress/flate/deflate.go +++ b/src/compress/flate/deflate.go @@ -720,7 +720,7 @@ func (w *Writer) Write(data []byte) (n int, err error) { // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. func (w *Writer) Flush() error { // For more about flushing: - // http://www.bolet.org/~pornin/deflate-flush.html + // https://www.bolet.org/~pornin/deflate-flush.html return w.d.syncFlush() } diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go index f8974de28fc95..98bbfbb763e4c 100644 --- a/src/compress/lzw/reader_test.go +++ b/src/compress/lzw/reader_test.go @@ -66,7 +66,7 @@ var lzwTests = []lzwTest{ "\x54\x9e\x08\x29\xf2\x44\x8a\x93\x27\x54\x04", io.ErrUnexpectedEOF, }, - // This example comes from http://en.wikipedia.org/wiki/Graphics_Interchange_Format. + // This example comes from https://en.wikipedia.org/wiki/Graphics_Interchange_Format. { "gif;LSB;8", "\x28\xff\xff\xff\x28\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", diff --git a/src/compress/zlib/reader_test.go b/src/compress/zlib/reader_test.go index 7e27aecb47d1b..70e33babd1062 100644 --- a/src/compress/zlib/reader_test.go +++ b/src/compress/zlib/reader_test.go @@ -19,7 +19,7 @@ type zlibTest struct { } // Compare-to-golden test data was generated by the ZLIB example program at -// http://www.zlib.net/zpipe.c +// https://www.zlib.net/zpipe.c var zlibTests = []zlibTest{ { diff --git a/src/context/benchmark_test.go b/src/context/benchmark_test.go index 6dd8510ff4c43..5d56863050a9a 100644 --- a/src/context/benchmark_test.go +++ b/src/context/benchmark_test.go @@ -13,6 +13,30 @@ import ( "time" ) +func BenchmarkCommonParentCancel(b *testing.B) { + root := WithValue(Background(), "key", "value") + shared, sharedcancel := WithCancel(root) + defer sharedcancel() + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + x := 0 + for pb.Next() { + ctx, cancel := WithCancel(shared) + if ctx.Value("key").(string) != "value" { + b.Fatal("should not be reached") + } + for i := 0; i < 100; i++ { + x /= x + 1 + } + cancel() + for i := 0; i < 100; i++ { + x /= x + 1 + } + } + }) +} + func BenchmarkWithTimeout(b *testing.B) { for concurrency := 40; concurrency <= 4e5; concurrency *= 100 { name := fmt.Sprintf("concurrency=%d", concurrency) diff --git a/src/context/example_test.go b/src/context/example_test.go index b2c2aa921da35..2b28b577042d6 100644 --- a/src/context/example_test.go +++ b/src/context/example_test.go @@ -93,6 +93,8 @@ func ExampleWithTimeout() { // context deadline exceeded } +// This example demonstrates how a value can be passed to the context +// and also how to retrieve it if it exists. func ExampleWithValue() { type favContextKey string diff --git a/src/crypto/aes/aes_test.go b/src/crypto/aes/aes_test.go index 28144968fcfd2..bedc2da946593 100644 --- a/src/crypto/aes/aes_test.go +++ b/src/crypto/aes/aes_test.go @@ -122,7 +122,7 @@ func TestTd(t *testing.T) { } // Test vectors are from FIPS 197: -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf // Appendix A of FIPS 197: Key expansion examples type KeyTest struct { diff --git a/src/crypto/aes/block.go b/src/crypto/aes/block.go index 41ea9cf95ed7c..8647019d5809a 100644 --- a/src/crypto/aes/block.go +++ b/src/crypto/aes/block.go @@ -31,8 +31,8 @@ // // See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission // for implementation details. -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf -// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf +// https://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf package aes diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go index 93e3b929b941c..82f6f8f335c42 100644 --- a/src/crypto/aes/cipher_s390x.go +++ b/src/crypto/aes/cipher_s390x.go @@ -31,12 +31,11 @@ type aesCipherAsm struct { func cryptBlocks(c code, key, dst, src *byte, length int) func newCipher(key []byte) (cipher.Block, error) { - // Strictly speaking, this check should be for HasKM. - // The check for HasKMC and HasKMCTR provides compatibility - // with the existing optimized s390x CBC and CTR implementations - // in this package, which already assert that they meet the - // cbcEncAble, cbcDecAble, and ctrAble interfaces - if !(cpu.S390X.HasKM && cpu.S390X.HasKMC && cpu.S390X.HasKMCTR) { + // The aesCipherAsm type implements the cbcEncAble, cbcDecAble, + // ctrAble and gcmAble interfaces. We therefore need to check + // for all the features required to implement these modes. + // Keep in sync with crypto/tls/common.go. + if !(cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)) { return newCipherGeneric(key) } diff --git a/src/crypto/aes/const.go b/src/crypto/aes/const.go index cbac5ff0ea155..4eca4b9aff842 100644 --- a/src/crypto/aes/const.go +++ b/src/crypto/aes/const.go @@ -15,7 +15,7 @@ package aes // This file contains AES constants - 8720 bytes of initialized data. -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf // AES is based on the mathematical behavior of binary polynomials // (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x³ + x + 1. diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go index acac6ec7b64be..ca06ae52ac0bd 100644 --- a/src/crypto/aes/gcm_s390x.go +++ b/src/crypto/aes/gcm_s390x.go @@ -85,7 +85,7 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { nonceSize: nonceSize, tagSize: tagSize, } - if cpu.S390X.HasKMA { + if cpu.S390X.HasAESGCM { g := gcmKMA{g} return &g, nil } diff --git a/src/crypto/cipher/cfb_test.go b/src/crypto/cipher/cfb_test.go index 9b544bb2118b7..ecb716df01516 100644 --- a/src/crypto/cipher/cfb_test.go +++ b/src/crypto/cipher/cfb_test.go @@ -14,7 +14,7 @@ import ( ) // cfbTests contains the test vectors from -// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section +// https://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section // F.3.13. var cfbTests = []struct { key, iv, plaintext, ciphertext string diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go index 31c14d7f914a5..7e1a4de9a3778 100644 --- a/src/crypto/cipher/cipher.go +++ b/src/crypto/cipher/cipher.go @@ -4,7 +4,7 @@ // Package cipher implements standard block cipher modes that can be wrapped // around low-level block cipher implementations. -// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html +// See https://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html // and NIST Special Publication 800-38A. package cipher diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go index 0ea053428c009..28f8b2093e74e 100644 --- a/src/crypto/cipher/gcm.go +++ b/src/crypto/cipher/gcm.go @@ -63,7 +63,7 @@ type gcmFieldElement struct { } // gcm represents a Galois Counter Mode with a specific key. See -// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf +// https://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf type gcm struct { cipher Block nonceSize int @@ -80,7 +80,7 @@ type gcm struct { // An exception is when the underlying Block was created by aes.NewCipher // on systems with hardware support for AES. See the crypto/aes package documentation for details. func NewGCM(cipher Block) (AEAD, error) { - return NewGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize) + return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize) } // NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois @@ -90,18 +90,22 @@ func NewGCM(cipher Block) (AEAD, error) { // cryptosystem that uses non-standard nonce lengths. All other users should use // NewGCM, which is faster and more resistant to misuse. func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) { - return NewGCMWithNonceAndTagSize(cipher, size, gcmTagSize) + return newGCMWithNonceAndTagSize(cipher, size, gcmTagSize) } -// NewGCMWithNonceAndTagSize returns the given 128-bit, block cipher wrapped in Galois -// Counter Mode, which accepts nonces of the given length and generates tags with the given length. +// NewGCMWithTagSize returns the given 128-bit, block cipher wrapped in Galois +// Counter Mode, which generates tags with the given length. // // Tag sizes between 12 and 16 bytes are allowed. // // Only use this function if you require compatibility with an existing // cryptosystem that uses non-standard tag lengths. All other users should use // NewGCM, which is more resistant to misuse. -func NewGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) { +func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) { + return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, tagSize) +} + +func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) { if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize { return nil, errors.New("cipher: incorrect tag size given to GCM") } diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go index 31f4d953649a8..c48001db281e6 100644 --- a/src/crypto/cipher/gcm_test.go +++ b/src/crypto/cipher/gcm_test.go @@ -231,9 +231,28 @@ func TestAESGCM(t *testing.T) { plaintext, _ := hex.DecodeString(test.plaintext) ad, _ := hex.DecodeString(test.ad) tagSize := (len(test.result) - len(test.plaintext)) / 2 - aesgcm, err := cipher.NewGCMWithNonceAndTagSize(aes, len(nonce), tagSize) - if err != nil { - t.Fatal(err) + + var aesgcm cipher.AEAD + switch { + // Handle non-standard nonce sizes + case tagSize != 16: + aesgcm, err = cipher.NewGCMWithTagSize(aes, tagSize) + if err != nil { + t.Fatal(err) + } + + // Handle non-standard tag sizes + case len(nonce) != 12: + aesgcm, err = cipher.NewGCMWithNonceSize(aes, len(nonce)) + if err != nil { + t.Fatal(err) + } + + default: + aesgcm, err = cipher.NewGCM(aes) + if err != nil { + t.Fatal(err) + } } ct := aesgcm.Seal(nil, nonce, plaintext, ad) @@ -277,12 +296,11 @@ func TestAESGCM(t *testing.T) { func TestGCMInvalidTagSize(t *testing.T) { key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed") - nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db") aes, _ := aes.NewCipher(key) for _, tagSize := range []int{0, 1, aes.BlockSize() + 1} { - aesgcm, err := cipher.NewGCMWithNonceAndTagSize(aes, len(nonce), tagSize) + aesgcm, err := cipher.NewGCMWithTagSize(aes, tagSize) if aesgcm != nil || err == nil { t.Fatalf("NewGCMWithNonceAndTagSize was successful with an invalid %d-byte tag size", tagSize) } diff --git a/src/crypto/dsa/dsa.go b/src/crypto/dsa/dsa.go index e94585579eb2a..575314b1b4689 100644 --- a/src/crypto/dsa/dsa.go +++ b/src/crypto/dsa/dsa.go @@ -11,6 +11,8 @@ import ( "errors" "io" "math/big" + + "crypto/internal/randutil" ) // Parameters represents the domain parameters for a key. These parameters can @@ -195,6 +197,8 @@ func fermatInverse(k, P *big.Int) *big.Int { // Be aware that calling Sign with an attacker-controlled PrivateKey may // require an arbitrary amount of CPU. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + randutil.MaybeReadByte(rand) + // FIPS 186-3, section 4.6 n := priv.Q.BitLen() diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 755ed284a910b..2bab14cbb9e26 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -26,6 +26,8 @@ import ( "errors" "io" "math/big" + + "crypto/internal/randutil" ) // A invertible implements fast inverse mod Curve.Params().N @@ -152,6 +154,8 @@ var errZeroParam = errors.New("zero parameter") // returns the signature as a pair of integers. The security of the private key // depends on the entropy of rand. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + randutil.MaybeReadByte(rand) + // Get min(log2(q) / 2, 256) bits of entropy from rand. entropylen := (priv.Curve.Params().BitSize + 7) / 16 if entropylen > 32 { diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go index 9224a039f3feb..6284e06bd4390 100644 --- a/src/crypto/ecdsa/ecdsa_test.go +++ b/src/crypto/ecdsa/ecdsa_test.go @@ -213,7 +213,7 @@ func fromHex(s string) *big.Int { func TestVectors(t *testing.T) { // This test runs the full set of NIST test vectors from - // http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip + // https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip // // The SigVer.rsp file has been edited to remove test vectors for // unsupported algorithms and has been compressed. diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go index 35aacf24e5152..4fc2b5e5213af 100644 --- a/src/crypto/elliptic/elliptic.go +++ b/src/crypto/elliptic/elliptic.go @@ -20,7 +20,7 @@ import ( ) // A Curve represents a short-form Weierstrass curve with a=-3. -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html type Curve interface { // Params returns the parameters for the curve. Params() *CurveParams @@ -108,7 +108,7 @@ func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int) if z1.Sign() == 0 { x3.Set(x2) @@ -191,7 +191,7 @@ func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b delta := new(big.Int).Mul(z, z) delta.Mod(delta, curve.P) gamma := new(big.Int).Mul(y, y) diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go index 22d0e2429cdfb..2ea63f3f0c057 100644 --- a/src/crypto/elliptic/p224.go +++ b/src/crypto/elliptic/p224.go @@ -7,7 +7,7 @@ package elliptic // This is a constant-time, 32-bit implementation of P224. See FIPS 186-3, // section D.2.2. // -// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. +// See https://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. import ( "math/big" @@ -503,7 +503,7 @@ func p224Contract(out, in *p224FieldElement) { // p224AddJacobian computes *out = a+b where a != b. func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl var z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v p224FieldElement var c p224LargeFieldElement diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go index bbf0087e664dd..bb9757355ac59 100644 --- a/src/crypto/elliptic/p256.go +++ b/src/crypto/elliptic/p256.go @@ -817,7 +817,7 @@ func p256Scalar8(out *[p256Limbs]uint32) { // p256PointDouble sets {xOut,yOut,zOut} = 2*{x,y,z}. // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l func p256PointDouble(xOut, yOut, zOut, x, y, z *[p256Limbs]uint32) { var delta, gamma, alpha, beta, tmp, tmp2 [p256Limbs]uint32 @@ -850,7 +850,7 @@ func p256PointDouble(xOut, yOut, zOut, x, y, z *[p256Limbs]uint32) { // p256PointAddMixed sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,1}. // (i.e. the second point is affine.) // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. @@ -886,7 +886,7 @@ func p256PointAddMixed(xOut, yOut, zOut, x1, y1, z1, x2, y2 *[p256Limbs]uint32) // p256PointAdd sets {xOut,yOut,zOut} = {x1,y1,z1} + {x2,y2,z2}. // -// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl +// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // // Note that this function does not handle P+P, infinity+P nor P+infinity // correctly. diff --git a/src/crypto/elliptic/p256_amd64.go b/src/crypto/elliptic/p256_amd64.go index b4346d7484c01..30eb33a0d4119 100644 --- a/src/crypto/elliptic/p256_amd64.go +++ b/src/crypto/elliptic/p256_amd64.go @@ -7,7 +7,7 @@ // detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with // 256-bit primes" -// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x +// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf // +build amd64 diff --git a/src/crypto/elliptic/p256_asm_amd64.s b/src/crypto/elliptic/p256_asm_amd64.s index 4aebe37c8dd72..a4e375797718c 100644 --- a/src/crypto/elliptic/p256_asm_amd64.s +++ b/src/crypto/elliptic/p256_asm_amd64.s @@ -6,7 +6,7 @@ // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with // 256-bit primes" -// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x +// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf #include "textflag.h" diff --git a/src/crypto/elliptic/p256_asm_s390x.s b/src/crypto/elliptic/p256_asm_s390x.s index d0e6d09e2e326..2219b858b3b9b 100644 --- a/src/crypto/elliptic/p256_asm_s390x.s +++ b/src/crypto/elliptic/p256_asm_s390x.s @@ -991,7 +991,7 @@ TEXT ·p256OrdMul(SB), NOSPLIT, $0 * *Mi obra de arte de siglo XXI @vpaprots * * - * First group is special, doesnt get the two inputs: + * First group is special, doesn't get the two inputs: * +--------+--------+<-+ * +-------| ADD2 | ADD1 |--|-----+ * | +--------+--------+ | | @@ -1733,9 +1733,9 @@ TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0 #undef CAR2 // p256PointDoubleAsm(P3, P1 *p256Point) -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html #define P3ptr R1 #define P1ptr R2 #define CPOOL R4 @@ -1783,7 +1783,7 @@ TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0 #define CAR1 V28 #define CAR2 V29 /* - * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv + * https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3. * Source: 2004 Hankerson–Menezes–Vanstone, page 91. * A = 3(X₁-Z₁²)×(X₁+Z₁²) @@ -1995,7 +1995,7 @@ TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0 * Y₃ = D×(A×C² - X₃) - B×C³ * Z₃ = Z₁×Z₂×C * - * Three-operand formula (adopted): http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + * Three-operand formula (adopted): https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R * * T1 = Z1*Z1 diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go index 3c8e727bc8c3d..c8c0617c47f78 100644 --- a/src/crypto/hmac/hmac.go +++ b/src/crypto/hmac/hmac.go @@ -27,7 +27,7 @@ import ( ) // FIPS 198-1: -// http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf +// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf // key is zero padded to the block size of the hash function // ipad = 0x36 byte repeated for key length diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go index aac9aa96a8ece..eea345edb635b 100644 --- a/src/crypto/hmac/hmac_test.go +++ b/src/crypto/hmac/hmac_test.go @@ -25,7 +25,7 @@ type hmacTest struct { var hmacTests = []hmacTest{ // Tests from US FIPS 198 - // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf + // https://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf { sha1.New, []byte{ @@ -205,7 +205,7 @@ var hmacTests = []hmacTest{ sha256.BlockSize, }, - // Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html + // Tests from https://csrc.nist.gov/groups/ST/toolkit/examples.html // (truncated tag tests are left out) { sha1.New, diff --git a/src/crypto/internal/randutil/randutil.go b/src/crypto/internal/randutil/randutil.go new file mode 100644 index 0000000000000..84b1295a87706 --- /dev/null +++ b/src/crypto/internal/randutil/randutil.go @@ -0,0 +1,38 @@ +// Copyright 2018 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 randutil contains internal randomness utilities for various +// crypto packages. +package randutil + +import ( + "io" + "sync" +) + +var ( + closedChanOnce sync.Once + closedChan chan struct{} +) + +// MaybeReadByte reads a single byte from r with ~50% probability. This is used +// to ensure that callers do not depend on non-guaranteed behaviour, e.g. +// assuming that rsa.GenerateKey is deterministic w.r.t. a given random stream. +// +// This does not affect tests that pass a stream of fixed bytes as the random +// source (e.g. a zeroReader). +func MaybeReadByte(r io.Reader) { + closedChanOnce.Do(func() { + closedChan = make(chan struct{}) + close(closedChan) + }) + + select { + case <-closedChan: + return + case <-closedChan: + var buf [1]byte + r.Read(buf[:]) + } +} diff --git a/src/crypto/rc4/rc4_test.go b/src/crypto/rc4/rc4_test.go index af7988246329d..1fc08b859343a 100644 --- a/src/crypto/rc4/rc4_test.go +++ b/src/crypto/rc4/rc4_test.go @@ -16,7 +16,7 @@ type rc4Test struct { var golden = []rc4Test{ // Test vectors from the original cypherpunk posting of ARC4: - // http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1 + // https://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1 { []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79}, @@ -30,7 +30,7 @@ var golden = []rc4Test{ []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61}, }, - // Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4 + // Test vectors from the Wikipedia page: https://en.wikipedia.org/wiki/RC4 { []byte{0x4b, 0x65, 0x79}, []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19}, diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index cdd2071ab90b7..37790acb9860a 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -10,6 +10,8 @@ import ( "errors" "io" "math/big" + + "crypto/internal/randutil" ) // This file implements encryption and decryption using PKCS#1 v1.5 padding. @@ -35,6 +37,8 @@ type PKCS1v15DecryptOptions struct { // WARNING: use of this function to encrypt plaintexts other than // session keys is dangerous. Use RSA OAEP in new protocols. func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) { + randutil.MaybeReadByte(rand) + if err := checkPub(pub); err != nil { return nil, err } diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 83d74967aa6dd..ad32d3e3add0f 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -31,6 +31,8 @@ import ( "io" "math" "math/big" + + "crypto/internal/randutil" ) var bigZero = big.NewInt(0) @@ -68,7 +70,7 @@ var ( // We require pub.E to fit into a 32-bit integer so that we // do not have different behavior depending on whether // int is 32 or 64 bits. See also -// http://www.imperialviolet.org/2012/03/16/rsae.html. +// https://www.imperialviolet.org/2012/03/16/rsae.html. func checkPub(pub *PublicKey) error { if pub.N == nil { return errPublicModulus @@ -218,6 +220,8 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { // [1] US patent 4405829 (1972, expired) // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) { + randutil.MaybeReadByte(random) + priv := new(PrivateKey) priv.E = 65537 @@ -467,6 +471,8 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er var ir *big.Int if random != nil { + randutil.MaybeReadByte(random) + // Blinding enabled. Blinding involves multiplying c by r^e. // Then the decryption operation performs (m^e * r^e)^d mod n // which equals mr mod n. The factor of r can then be removed diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s index a0032c4544095..135f113898c43 100644 --- a/src/crypto/sha1/sha1block_amd64.s +++ b/src/crypto/sha1/sha1block_amd64.s @@ -395,7 +395,7 @@ end: PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260) -// Macros calculating individual rounds have general forn +// Macros calculating individual rounds have general form // CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST // CALC_ROUND_{PRE,POST} macros follow @@ -413,7 +413,7 @@ end: LEAL (REG_E)(R12*1), REG_E // E += A >>> 5 -// Registers are cycleickly rotated DX -> AX -> DI -> SI -> BX -> CX +// Registers are cyclically rotated DX -> AX -> DI -> SI -> BX -> CX #define CALC_0 \ MOVL SI, BX \ // Precalculating first round RORXL $2, SI, SI \ diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go index 340704aee2419..446bf5d36e594 100644 --- a/src/crypto/sha1/sha1block_s390x.go +++ b/src/crypto/sha1/sha1block_s390x.go @@ -4,9 +4,6 @@ package sha1 -// featureCheck reports whether the CPU supports the -// SHA-1 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA1 diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s index 3c71998645471..6ba6883cc38fc 100644 --- a/src/crypto/sha1/sha1block_s390x.s +++ b/src/crypto/sha1/sha1block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x40, R4 // bit 1 (big endian) for SHA-1 - CMPBEQ R4, $0, nosha1 - MOVB $1, ret+0(FP) - RET -nosha1: - MOVB $0, ret+0(FP) - RET - // func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $1, R0 // SHA-1 function code +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $1, R0 // SHA-1 function code + CMPBEQ R4, $0, generic + loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET + generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/sha256/sha256block_386.s b/src/crypto/sha256/sha256block_386.s index 33ed027e1fcfc..086a0ab25c88c 100644 --- a/src/crypto/sha256/sha256block_386.s +++ b/src/crypto/sha256/sha256block_386.s @@ -6,7 +6,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s index f30f4829a6c1b..f6af47c50e9f0 100644 --- a/src/crypto/sha256/sha256block_amd64.s +++ b/src/crypto/sha256/sha256block_amd64.s @@ -8,7 +8,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // The avx2-version is described in an Intel White-Paper: // "Fast SHA-256 Implementations on Intel Architecture Processors" @@ -755,7 +755,7 @@ avx2_loop1: // for w0 - w47 JB avx2_loop1 avx2_loop2: - // w48 - w63 processed with no scheduliung (last 16 rounds) + // w48 - w63 processed with no scheduling (last 16 rounds) VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1) DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h) diff --git a/src/crypto/sha256/sha256block_ppc64le.s b/src/crypto/sha256/sha256block_ppc64le.s index f5435602fe73b..77e63c073fd44 100644 --- a/src/crypto/sha256/sha256block_ppc64le.s +++ b/src/crypto/sha256/sha256block_ppc64le.s @@ -16,7 +16,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63 diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go index b7beefef0c61f..1a376c5f93531 100644 --- a/src/crypto/sha256/sha256block_s390x.go +++ b/src/crypto/sha256/sha256block_s390x.go @@ -4,9 +4,6 @@ package sha256 -// featureCheck reports whether the CPU supports the -// SHA256 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA256 diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s index ee35991f50cee..81b1b382c76a5 100644 --- a/src/crypto/sha256/sha256block_s390x.s +++ b/src/crypto/sha256/sha256block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x20, R4 // bit 2 (big endian) for SHA256 - CMPBEQ R4, $0, nosha256 - MOVB $1, ret+0(FP) - RET -nosha256: - MOVB $0, ret+0(FP) - RET - // func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $2, R0 // SHA256 function code +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $2, R0 // SHA-256 function code + CMPBEQ R4, $0, generic + loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET + generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/sha512/sha512block_amd64.s b/src/crypto/sha512/sha512block_amd64.s index a02356607ec9a..0fa0df2f60e8b 100644 --- a/src/crypto/sha512/sha512block_amd64.s +++ b/src/crypto/sha512/sha512block_amd64.s @@ -8,7 +8,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 @@ -274,7 +274,7 @@ end: // Version below is based on "Fast SHA512 Implementations on Intel // Architecture Processors" White-paper -// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf +// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf // AVX2 version by Intel, same algorithm in Linux kernel: // https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha512-avx2-asm.S diff --git a/src/crypto/sha512/sha512block_ppc64le.s b/src/crypto/sha512/sha512block_ppc64le.s index 170e3a645689e..55f0c06c7a056 100644 --- a/src/crypto/sha512/sha512block_ppc64le.s +++ b/src/crypto/sha512/sha512block_ppc64le.s @@ -16,7 +16,7 @@ // // The algorithm is detailed in FIPS 180-4: // -// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf // // Wt = Mt; for 0 <= t <= 15 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 diff --git a/src/crypto/sha512/sha512block_s390x.go b/src/crypto/sha512/sha512block_s390x.go index f05dc18e124a2..7df29fd29828c 100644 --- a/src/crypto/sha512/sha512block_s390x.go +++ b/src/crypto/sha512/sha512block_s390x.go @@ -4,9 +4,6 @@ package sha512 -// featureCheck reports whether the CPU supports the -// SHA512 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA512 diff --git a/src/crypto/sha512/sha512block_s390x.s b/src/crypto/sha512/sha512block_s390x.s index aab81e2bcf986..f221bd1399c93 100644 --- a/src/crypto/sha512/sha512block_s390x.s +++ b/src/crypto/sha512/sha512block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x10, R4 // bit 3 (big endian) for SHA512 - CMPBEQ R4, $0, nosha512 - MOVB $1, ret+0(FP) - RET -nosha512: - MOVB $0, ret+0(FP) - RET - // func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $3, R0 // SHA512 function code +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $3, R0 // SHA-512 function code + CMPBEQ R4, $0, generic + loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET + generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 32caa6233cbc0..14996e6835c2a 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -246,19 +246,19 @@ type ClientHelloInfo struct { // ServerName indicates the name of the server requested by the client // in order to support virtual hosting. ServerName is only set if the // client is using SNI (see - // http://tools.ietf.org/html/rfc4366#section-3.1). + // https://tools.ietf.org/html/rfc4366#section-3.1). ServerName string // SupportedCurves lists the elliptic curves supported by the client. // SupportedCurves is set only if the Supported Elliptic Curves // Extension is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.1). + // https://tools.ietf.org/html/rfc4492#section-5.1.1). SupportedCurves []CurveID // SupportedPoints lists the point formats supported by the client. // SupportedPoints is set only if the Supported Point Formats Extension // is being used (see - // http://tools.ietf.org/html/rfc4492#section-5.1.2). + // https://tools.ietf.org/html/rfc4492#section-5.1.2). SupportedPoints []uint8 // SignatureSchemes lists the signature and hash schemes that the client @@ -459,7 +459,8 @@ type Config struct { PreferServerCipherSuites bool // SessionTicketsDisabled may be set to true to disable session ticket - // (resumption) support. + // (resumption) support. Note that on clients, session ticket support is + // also disabled if ClientSessionCache is nil. SessionTicketsDisabled bool // SessionTicketKey is used by TLS servers to provide session @@ -473,7 +474,7 @@ type Config struct { SessionTicketKey [32]byte // ClientSessionCache is a cache of ClientSessionState entries for TLS - // session resumption. + // session resumption. It is only used by clients. ClientSessionCache ClientSessionCache // MinVersion contains the minimum SSL/TLS version that is acceptable. @@ -929,7 +930,8 @@ func initDefaultCipherSuites() { hasGCMAsmARM64 := false // hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - hasGCMAsmS390X := cpu.S390X.HasKM && (cpu.S390X.HasKMA || (cpu.S390X.HasKMCTR && cpu.S390X.HasKIMD)) + // Keep in sync with crypto/aes/cipher_s390x.go. + hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index dc3b8911c771d..cdaa7aba97c88 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -1061,9 +1061,9 @@ func (c *Conn) Write(b []byte) (int, error) { // This can be prevented by splitting each Application Data // record into two records, effectively randomizing the IV. // - // http://www.openssl.org/~bodo/tls-cbc.txt + // https://www.openssl.org/~bodo/tls-cbc.txt // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 - // http://www.imperialviolet.org/2012/01/15/beastfollowup.html + // https://www.imperialviolet.org/2012/01/15/beastfollowup.html var m int if len(b) > 1 && c.vers <= VersionTLS10 { diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go index f8c8d571ccde1..a5bf10efb8c6c 100644 --- a/src/crypto/tls/handshake_messages.go +++ b/src/crypto/tls/handshake_messages.go @@ -192,7 +192,7 @@ func (m *clientHelloMsg) marshal() []byte { z = z[9:] } if len(m.supportedCurves) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.1 + // https://tools.ietf.org/html/rfc4492#section-5.5.1 z[0] = byte(extensionSupportedCurves >> 8) z[1] = byte(extensionSupportedCurves) l := 2 + 2*len(m.supportedCurves) @@ -209,7 +209,7 @@ func (m *clientHelloMsg) marshal() []byte { } } if len(m.supportedPoints) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.5.2 + // https://tools.ietf.org/html/rfc4492#section-5.5.2 z[0] = byte(extensionSupportedPoints >> 8) z[1] = byte(extensionSupportedPoints) l := 1 + len(m.supportedPoints) @@ -224,7 +224,7 @@ func (m *clientHelloMsg) marshal() []byte { } } if m.ticketSupported { - // http://tools.ietf.org/html/rfc5077#section-3.2 + // https://tools.ietf.org/html/rfc5077#section-3.2 z[0] = byte(extensionSessionTicket >> 8) z[1] = byte(extensionSessionTicket) l := len(m.sessionTicket) @@ -414,7 +414,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { case extensionStatusRequest: m.ocspStapling = length > 0 && data[0] == statusTypeOCSP case extensionSupportedCurves: - // http://tools.ietf.org/html/rfc4492#section-5.5.1 + // https://tools.ietf.org/html/rfc4492#section-5.5.1 if length < 2 { return false } @@ -430,7 +430,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { d = d[2:] } case extensionSupportedPoints: - // http://tools.ietf.org/html/rfc4492#section-5.5.2 + // https://tools.ietf.org/html/rfc4492#section-5.5.2 if length < 1 { return false } @@ -441,7 +441,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.supportedPoints = make([]uint8, l) copy(m.supportedPoints, data[1:]) case extensionSessionTicket: - // http://tools.ietf.org/html/rfc5077#section-3.2 + // https://tools.ietf.org/html/rfc5077#section-3.2 m.ticketSupported = true m.sessionTicket = data[:length] case extensionSignatureAlgorithms: @@ -1224,7 +1224,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc4346#section-7.4.4 + // See https://tools.ietf.org/html/rfc4346#section-7.4.4 length := 1 + len(m.certificateTypes) + 2 casLength := 0 for _, ca := range m.certificateAuthorities { @@ -1374,7 +1374,7 @@ func (m *certificateVerifyMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc4346#section-7.4.8 + // See https://tools.ietf.org/html/rfc4346#section-7.4.8 siglength := len(m.signature) length := 2 + siglength if m.hasSignatureAndHash { @@ -1452,7 +1452,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) { return m.raw } - // See http://tools.ietf.org/html/rfc5077#section-3.3 + // See https://tools.ietf.org/html/rfc5077#section-3.3 ticketLen := len(m.ticket) length := 2 + 4 + ticketLen x = make([]byte, 4+length) diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go index 3f570b66c6927..6685b47584f37 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -141,7 +141,7 @@ func pickTLS12HashForSignature(sigType uint8, clientList []SignatureScheme) (Sig if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See - // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 switch sigType { case signatureRSA: return PKCS1WithSHA1, nil @@ -239,7 +239,7 @@ NextCandidate: ecdhePublic = elliptic.Marshal(curve, x, y) } - // http://tools.ietf.org/html/rfc4492#section-5.4 + // https://tools.ietf.org/html/rfc4492#section-5.4 serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) serverECDHParams[0] = 3 // named curve serverECDHParams[1] = byte(ka.curveid >> 8) diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go index 93a638819dc34..367e0842b01c3 100644 --- a/src/crypto/tls/prf.go +++ b/src/crypto/tls/prf.go @@ -140,7 +140,7 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe } // masterFromPreMasterSecret generates the master secret from the pre-master -// secret. See http://tools.ietf.org/html/rfc5246#section-8.1 +// secret. See https://tools.ietf.org/html/rfc5246#section-8.1 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) seed = append(seed, clientRandom...) diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go index 7b32220b74e17..3cc4d587e363c 100644 --- a/src/crypto/x509/pkix/pkix.go +++ b/src/crypto/x509/pkix/pkix.go @@ -95,7 +95,7 @@ func (r RDNSequence) String() string { type RelativeDistinguishedNameSET []AttributeTypeAndValue // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in -// http://tools.ietf.org/html/rfc5280#section-4.1.2.4 +// https://tools.ietf.org/html/rfc5280#section-4.1.2.4 type AttributeTypeAndValue struct { Type asn1.ObjectIdentifier Value interface{} diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go index 5c310bff09122..a02ac3cfe8364 100644 --- a/src/crypto/x509/root_cgo_darwin.go +++ b/src/crypto/x509/root_cgo_darwin.go @@ -7,7 +7,7 @@ package x509 /* -#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080 +#cgo CFLAGS: -mmacosx-version-min=10.10 -D__MAC_OS_X_VERSION_MAX_ALLOWED=101300 #cgo LDFLAGS: -framework CoreFoundation -framework Security #include @@ -16,59 +16,6 @@ package x509 #include #include -// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6 -// which still works on OS X 10.8 (Mountain Lion). -// It lacks support for admin & user cert domains. -// See golang.org/issue/16473 -int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) { - if (pemRoots == NULL) { - return -1; - } - CFArrayRef certs = NULL; - OSStatus err = SecTrustCopyAnchorCertificates(&certs); - if (err != noErr) { - return -1; - } - CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); - int i, ncerts = CFArrayGetCount(certs); - for (i = 0; i < ncerts; i++) { - CFDataRef data = NULL; - SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); - if (cert == NULL) { - continue; - } - // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. - // Once we support weak imports via cgo we should prefer that, and fall back to this - // for older systems. - err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); - if (err != noErr) { - continue; - } - if (data != NULL) { - CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); - CFRelease(data); - } - } - CFRelease(certs); - *pemRoots = combinedData; - return 0; -} - -// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion -// or older. We only support Mountain Lion and higher, but we'll at least try our -// best on older machines and continue to use the old code path. -// -// See golang.org/issue/16473 -int useOldCode() { - char str[256]; - size_t size = sizeof(str); - memset(str, 0, size); - sysctlbyname("kern.osrelease", str, &size, NULL, 0); - // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*. - // We never supported things before that. - return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0; -} - // FetchPEMRoots fetches the system's list of trusted X.509 root certificates. // // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root @@ -80,10 +27,6 @@ int useOldCode() { int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) { int i; - if (useOldCode()) { - return FetchPEMRoots_MountainLion(pemRoots); - } - // Get certificates from all domains, not just System, this lets // the user add CAs to their "login" keychain, and Admins to add // to the "System" keychain @@ -193,10 +136,7 @@ int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) { } } - // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. - // Once we support weak imports via cgo we should prefer that, and fall back to this - // for older systems. - err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); + err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); if (err != noErr) { continue; } diff --git a/src/crypto/x509/sha2_windows_test.go b/src/crypto/x509/sha2_windows_test.go index 79dc685c5b55b..620b7b9e77cb6 100644 --- a/src/crypto/x509/sha2_windows_test.go +++ b/src/crypto/x509/sha2_windows_test.go @@ -13,7 +13,7 @@ func init() { } if major := byte(v); major < 6 { // Windows XP SP2 and Windows 2003 do not support SHA2. - // http://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx + // https://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx supportSHA2 = false } } diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 96d7742a3ccca..1e7a989089b87 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -340,8 +340,8 @@ var ErrNoRows = errors.New("sql: no rows in result set") // // The sql package creates and frees connections automatically; it // also maintains a free pool of idle connections. If the database has -// a concept of per-connection state, such state can only be reliably -// observed within a transaction. Once DB.Begin is called, the +// a concept of per-connection state, such state can be reliably observed +// within a transaction (Tx) or connection (Conn). Once DB.Begin is called, the // returned Tx is bound to a single connection. Once Commit or // Rollback is called on the transaction, that transaction's // connection is returned to DB's idle connection pool. The pool size diff --git a/src/debug/macho/reloctype_string.go b/src/debug/macho/reloctype_string.go index 6d5c5d87e82c5..9c2b13186e7d6 100644 --- a/src/debug/macho/reloctype_string.go +++ b/src/debug/macho/reloctype_string.go @@ -2,7 +2,7 @@ package macho -import "fmt" +import "strconv" const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV" @@ -10,7 +10,7 @@ var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129} func (i RelocTypeGeneric) String() string { if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) { - return fmt.Sprintf("RelocTypeGeneric(%d)", i) + return "RelocTypeGeneric(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]] } @@ -21,7 +21,7 @@ var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 18 func (i RelocTypeX86_64) String() string { if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) { - return fmt.Sprintf("RelocTypeX86_64(%d)", i) + return "RelocTypeX86_64(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]] } @@ -32,7 +32,7 @@ var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, func (i RelocTypeARM) String() string { if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) { - return fmt.Sprintf("RelocTypeARM(%d)", i) + return "RelocTypeARM(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]] } @@ -43,7 +43,7 @@ var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 2 func (i RelocTypeARM64) String() string { if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) { - return fmt.Sprintf("RelocTypeARM64(%d)", i) + return "RelocTypeARM64(" + strconv.FormatInt(int64(i), 10) + ")" } return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]] } diff --git a/src/debug/pe/pe.go b/src/debug/pe/pe.go index 872c977fe3880..e933ae1c2aa66 100644 --- a/src/debug/pe/pe.go +++ b/src/debug/pe/pe.go @@ -91,6 +91,7 @@ const ( IMAGE_FILE_MACHINE_AM33 = 0x1d3 IMAGE_FILE_MACHINE_AMD64 = 0x8664 IMAGE_FILE_MACHINE_ARM = 0x1c0 + IMAGE_FILE_MACHINE_ARM64 = 0xaa64 IMAGE_FILE_MACHINE_EBC = 0xebc IMAGE_FILE_MACHINE_I386 = 0x14c IMAGE_FILE_MACHINE_IA64 = 0x200 diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index ae382ee6bf52e..1ed357adfffcc 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -250,7 +250,7 @@ func (oi ObjectIdentifier) String() string { // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and // returns it. An object identifier is a sequence of variable length integers // that are assigned in a hierarchy. -func parseObjectIdentifier(bytes []byte) (s []int, err error) { +func parseObjectIdentifier(bytes []byte) (s ObjectIdentifier, err error) { if len(bytes) == 0 { err = SyntaxError{"zero length OBJECT IDENTIFIER"} return diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index 185349773f593..f0a54e0cb2e69 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -227,7 +227,7 @@ func TestBitStringRightAlign(t *testing.T) { type objectIdentifierTest struct { in []byte ok bool - out []int + out ObjectIdentifier // has base type[]int } var objectIdentifierTestData = []objectIdentifierTest{ diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go index f20ccdc8e98c5..a77826a7b034f 100644 --- a/src/encoding/asn1/marshal_test.go +++ b/src/encoding/asn1/marshal_test.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/hex" "math/big" + "reflect" "strings" "testing" "time" @@ -253,6 +254,62 @@ func TestInvalidUTF8(t *testing.T) { } } +func TestMarshalOID(t *testing.T) { + var marshalTestsOID = []marshalTest{ + {[]byte("\x06\x01\x30"), "0403060130"}, // bytes format returns a byte sequence \x04 + // {ObjectIdentifier([]int{0}), "060100"}, // returns an error as OID 0.0 has the same encoding + {[]byte("\x06\x010"), "0403060130"}, // same as above "\x06\x010" = "\x06\x01" + "0" + {ObjectIdentifier([]int{2, 999, 3}), "0603883703"}, // Example of ITU-T X.690 + {ObjectIdentifier([]int{0, 0}), "060100"}, // zero OID + } + for i, test := range marshalTestsOID { + data, err := Marshal(test.in) + if err != nil { + t.Errorf("#%d failed: %s", i, err) + } + out, _ := hex.DecodeString(test.out) + if !bytes.Equal(out, data) { + t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out) + } + } +} + +func TestIssue11130(t *testing.T) { + data := []byte("\x06\x010") // == \x06\x01\x30 == OID = 0 (the figure) + var v interface{} + // v has Zero value here and Elem() would panic + _, err := Unmarshal(data, &v) + if err != nil { + t.Errorf("%v", err) + return + } + if reflect.TypeOf(v).String() != reflect.TypeOf(ObjectIdentifier{}).String() { + t.Errorf("marshal OID returned an invalid type") + return + } + + data1, err := Marshal(v) + if err != nil { + t.Errorf("%v", err) + return + } + + if !bytes.Equal(data, data1) { + t.Errorf("got: %q, want: %q \n", data1, data) + return + } + + var v1 interface{} + _, err = Unmarshal(data1, &v1) + if err != nil { + t.Errorf("%v", err) + return + } + if !reflect.DeepEqual(v, v1) { + t.Errorf("got: %#v data=%q , want : %#v data=%q\n ", v1, data1, v, data) + } +} + func BenchmarkMarshal(b *testing.B) { b.ReportAllocs() diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go index 60f25b04b22f4..3fb6caceab485 100644 --- a/src/encoding/base32/base32.go +++ b/src/encoding/base32/base32.go @@ -21,7 +21,7 @@ import ( // introduced for SASL GSSAPI and standardized in RFC 4648. // The alternate "base32hex" encoding is used in DNSSEC. type Encoding struct { - encode string + encode [32]byte decodeMap [256]byte padChar rune } @@ -37,8 +37,12 @@ const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV" // NewEncoding returns a new Encoding defined by the given alphabet, // which must be a 32-byte string. func NewEncoding(encoder string) *Encoding { + if len(encoder) != 32 { + panic("encoding alphabet is not 32-bytes long") + } + e := new(Encoding) - e.encode = encoder + copy(e.encode[:], encoder) e.padChar = StdPadding for i := 0; i < len(e.decodeMap); i++ { @@ -129,17 +133,17 @@ func (enc *Encoding) Encode(dst, src []byte) { size := len(dst) if size >= 8 { // Common case, unrolled for extra performance - dst[0] = enc.encode[b[0]] - dst[1] = enc.encode[b[1]] - dst[2] = enc.encode[b[2]] - dst[3] = enc.encode[b[3]] - dst[4] = enc.encode[b[4]] - dst[5] = enc.encode[b[5]] - dst[6] = enc.encode[b[6]] - dst[7] = enc.encode[b[7]] + dst[0] = enc.encode[b[0]&31] + dst[1] = enc.encode[b[1]&31] + dst[2] = enc.encode[b[2]&31] + dst[3] = enc.encode[b[3]&31] + dst[4] = enc.encode[b[4]&31] + dst[5] = enc.encode[b[5]&31] + dst[6] = enc.encode[b[6]&31] + dst[7] = enc.encode[b[7]&31] } else { for i := 0; i < size; i++ { - dst[i] = enc.encode[b[i]] + dst[i] = enc.encode[b[i]&31] } } diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index a41fc9e889787..dc9bbcf35d8b5 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -1015,7 +1015,7 @@ type Bug4Secret struct { } // Test that a failed compilation doesn't leave around an executable encoder. -// Issue 3273. +// Issue 3723. func TestMutipleEncodingsOfBadType(t *testing.T) { x := Bug4Public{ Name: "name", diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go index 4cb26b6673442..aee5aecb1a757 100644 --- a/src/encoding/hex/hex.go +++ b/src/encoding/hex/hex.go @@ -50,8 +50,8 @@ func DecodedLen(x int) int { return x / 2 } // Decode decodes src into DecodedLen(len(src)) bytes, // returning the actual number of bytes written to dst. // -// Decode expects that src contain only hexadecimal -// characters and that src should have an even length. +// Decode expects that src contains only hexadecimal +// characters and that src has even length. // If the input is malformed, Decode returns the number // of bytes decoded before the error. func Decode(dst, src []byte) (int, error) { @@ -101,10 +101,10 @@ func EncodeToString(src []byte) string { // DecodeString returns the bytes represented by the hexadecimal string s. // -// DecodeString expects that src contain only hexadecimal -// characters and that src should have an even length. -// If the input is malformed, DecodeString returns a string -// containing the bytes decoded before the error. +// DecodeString expects that src contains only hexadecimal +// characters and that src has even length. +// If the input is malformed, DecodeString returns +// the bytes decoded before the error. func DecodeString(s string) ([]byte, error) { src := []byte(s) // We can use the source slice itself as the destination diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 6a66940034645..0b29249218a32 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -204,7 +204,7 @@ func (n Number) Int64() (int64, error) { func isValidNumber(s string) bool { // This function implements the JSON numbers grammar. // See https://tools.ietf.org/html/rfc7159#section-6 - // and http://json.org/number.gif + // and https://json.org/number.gif if s == "" { return false diff --git a/src/encoding/json/number_test.go b/src/encoding/json/number_test.go index 4b8699963886e..cc6701814fb72 100644 --- a/src/encoding/json/number_test.go +++ b/src/encoding/json/number_test.go @@ -10,7 +10,7 @@ import ( ) func TestNumberIsValid(t *testing.T) { - // From: http://stackoverflow.com/a/13340826 + // From: https://stackoverflow.com/a/13340826 var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`) validTests := []string{ diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 7d2ff01ee946a..452caefab4da4 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -7,8 +7,8 @@ package xml // References: -// Annotated XML spec: http://www.xml.com/axml/testaxml.htm -// XML name spaces: http://www.w3.org/TR/REC-xml-names/ +// Annotated XML spec: https://www.xml.com/axml/testaxml.htm +// XML name spaces: https://www.w3.org/TR/REC-xml-names/ // TODO(rsc): // Test error handling. @@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { // it will return an error. // // Token implements XML name spaces as described by -// http://www.w3.org/TR/REC-xml-names/. Each of the +// https://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, @@ -863,7 +863,7 @@ func (d *Decoder) attrval() []byte { if !ok { return nil } - // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 + // https://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' { d.buf.WriteByte(b) @@ -1134,7 +1134,7 @@ Input: } // Decide whether the given rune is in the XML Character Range, per -// the Char production of http://www.xml.com/axml/testaxml.htm, +// the Char production of https://www.xml.com/axml/testaxml.htm, // Section 2.2 Characters. func isInCharacterRange(r rune) (inrange bool) { return r == 0x09 || @@ -1263,7 +1263,7 @@ func isNameString(s string) bool { } // These tables were generated by cut and paste from Appendix B of -// the XML spec at http://www.xml.com/axml/testaxml.htm +// the XML spec at https://www.xml.com/axml/testaxml.htm // and then reformatting. First corresponds to (Letter | '_' | ':') // and second corresponds to NameChar. diff --git a/src/flag/flag.go b/src/flag/flag.go index f613144a7e35b..188adb285f4a9 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -5,7 +5,7 @@ /* Package flag implements command-line flag parsing. - Usage: + Usage Define flags using flag.String(), Bool(), Int(), etc. @@ -35,7 +35,7 @@ slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. - Command line flag syntax: + Command line flag syntax -flag -flag=x -flag x // non-boolean flags only diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 9aebd7327a9da..663d5246f89c3 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -139,7 +139,7 @@ var pkgDeps = map[string][]string{ // Operating system access. "syscall": {"L0", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"}, - "syscall/js": {"unsafe"}, + "syscall/js": {"L0"}, "internal/syscall/unix": {"L0", "syscall"}, "internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"}, "internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"}, @@ -330,19 +330,21 @@ var pkgDeps = map[string][]string{ "net/textproto": {"L4", "OS", "net"}, // Core crypto. - "crypto/aes": {"L3"}, - "crypto/des": {"L3"}, - "crypto/hmac": {"L3"}, - "crypto/md5": {"L3"}, - "crypto/rc4": {"L3"}, - "crypto/sha1": {"L3"}, - "crypto/sha256": {"L3"}, - "crypto/sha512": {"L3"}, + "crypto/aes": {"L3"}, + "crypto/des": {"L3"}, + "crypto/hmac": {"L3"}, + "crypto/internal/randutil": {"io", "sync"}, + "crypto/md5": {"L3"}, + "crypto/rc4": {"L3"}, + "crypto/sha1": {"L3"}, + "crypto/sha256": {"L3"}, + "crypto/sha512": {"L3"}, "CRYPTO": { "crypto/aes", "crypto/des", "crypto/hmac", + "crypto/internal/randutil", "crypto/md5", "crypto/rc4", "crypto/sha1", @@ -401,6 +403,7 @@ var pkgDeps = map[string][]string{ "crypto/rand", "crypto/tls", "golang_org/x/net/http/httpguts", + "golang_org/x/net/http/httpproxy", "golang_org/x/net/http2/hpack", "golang_org/x/net/idna", "golang_org/x/text/unicode/norm", @@ -410,9 +413,10 @@ var pkgDeps = map[string][]string{ "net/http/httptrace", "net/http/internal", "runtime/debug", + "syscall/js", }, "net/http/internal": {"L4"}, - "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"}, + "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "net/textproto", "reflect", "time"}, // HTTP-using packages. "expvar": {"L4", "OS", "encoding/json", "net/http"}, diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go index 5ec4f4c418534..e6fca76e182bc 100644 --- a/src/go/constant/value_test.go +++ b/src/go/constant/value_test.go @@ -431,6 +431,7 @@ func TestUnknown(t *testing.T) { MakeBool(false), // token.ADD ok below, operation is never considered MakeString(""), MakeInt64(1), + MakeFromLiteral("''", token.CHAR, 0), MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0), MakeFloat64(1.2), MakeImag(MakeFloat64(1.2)), diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go index 5d6f6e8fb00cc..05c3786ef605f 100644 --- a/src/go/doc/reader.go +++ b/src/go/doc/reader.go @@ -399,9 +399,9 @@ func (r *reader) readFunc(fun *ast.FuncDecl) { // with the first type in result signature (there may // be more than one result) factoryType := res.Type - if t, ok := factoryType.(*ast.ArrayType); ok && t.Len == nil { - // We consider functions that return slices of type T (or - // pointers to T) as factory functions of T. + if t, ok := factoryType.(*ast.ArrayType); ok { + // We consider functions that return slices or arrays of type + // T (or pointers to T) as factory functions of T. factoryType = t.Elt } if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) { diff --git a/src/go/doc/testdata/issue18063.0.golden b/src/go/doc/testdata/issue22856.0.golden similarity index 73% rename from src/go/doc/testdata/issue18063.0.golden rename to src/go/doc/testdata/issue22856.0.golden index 0afbc169c2c33..a88f43f4bd7e2 100644 --- a/src/go/doc/testdata/issue18063.0.golden +++ b/src/go/doc/testdata/issue22856.0.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.1.golden b/src/go/doc/testdata/issue22856.1.golden similarity index 73% rename from src/go/doc/testdata/issue18063.1.golden rename to src/go/doc/testdata/issue22856.1.golden index 0afbc169c2c33..a88f43f4bd7e2 100644 --- a/src/go/doc/testdata/issue18063.1.golden +++ b/src/go/doc/testdata/issue22856.1.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.2.golden b/src/go/doc/testdata/issue22856.2.golden similarity index 73% rename from src/go/doc/testdata/issue18063.2.golden rename to src/go/doc/testdata/issue22856.2.golden index 0afbc169c2c33..a88f43f4bd7e2 100644 --- a/src/go/doc/testdata/issue18063.2.golden +++ b/src/go/doc/testdata/issue22856.2.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.go b/src/go/doc/testdata/issue22856.go similarity index 74% rename from src/go/doc/testdata/issue18063.go rename to src/go/doc/testdata/issue22856.go index 1193af51e7c12..f4569981aaac6 100644 --- a/src/go/doc/testdata/issue18063.go +++ b/src/go/doc/testdata/issue22856.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package issue18063 +package issue22856 type T struct{} @@ -11,14 +11,8 @@ func NewPointer() *T { return &T{} } func NewPointerSlice() []*T { return []*T{&T{}} } func NewSlice() []T { return []T{T{}} } func NewPointerOfPointer() **T { x := &T{}; return &x } - -// NewArray is not a factory function because arrays of type T are not -// factory functions of type T. -func NewArray() [1]T { return [1]T{T{}} } - -// NewPointerArray is not a factory function because arrays of type *T are not -// factory functions of type T. -func NewPointerArray() [1]*T { return [1]*T{&T{}} } +func NewArray() [1]T { return [1]T{T{}} } +func NewPointerArray() [1]*T { return [1]*T{&T{}} } // NewSliceOfSlice is not a factory function because slices of a slice of // type *T are not factory functions of type T. diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index 73ce465eabb6b..503845e31cbab 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -50,24 +50,24 @@ type importer struct { // compromised, an error is returned. func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { // catch panics and return them as errors + const currentVersion = 6 + version := -1 // unknown version defer func() { if e := recover(); e != nil { - // The package (filename) causing the problem is added to this - // error by a wrapper in the caller (Import in gcimporter.go). // Return a (possibly nil or incomplete) package unchanged (see #16088). - err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e) + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } } }() - if len(data) > 0 && data[0] == 'i' { - return iImportData(fset, imports, data[1:], path) - } - p := importer{ imports: imports, data: data, importpath: path, - version: -1, // unknown version + version: version, strList: []string{""}, // empty string is mapped to 0 pathList: []string{""}, // empty string is mapped to 0 fake: fakeFileSet{ @@ -92,7 +92,7 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data [] p.posInfoFormat = p.int() != 0 versionstr = p.string() if versionstr == "v1" { - p.version = 0 + version = 0 } } else { // Go1.8 extensible encoding @@ -100,24 +100,25 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data [] versionstr = p.rawStringln(b) if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { - p.version = v + version = v } } } + p.version = version // read version specific flags - extend as necessary switch p.version { - // case 7: + // case currentVersion: // ... // fallthrough - case 6, 5, 4, 3, 2, 1: + case currentVersion, 5, 4, 3, 2, 1: p.debugFormat = p.rawStringln(p.rawByte()) == "debug" p.trackAllTypes = p.int() != 0 p.posInfoFormat = p.int() != 0 case 0: // Go1.7 encoding format - nothing to do here default: - errorf("unknown export format version %d (%q)", p.version, versionstr) + errorf("unknown bexport format version %d (%q)", p.version, versionstr) } // --- generic export data --- diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index cf89fcd1b4f6b..d117f6fe4d3f4 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -144,16 +144,27 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func switch hdr { case "$$\n": err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path) + case "$$B\n": var data []byte data, err = ioutil.ReadAll(buf) - if err == nil { - // TODO(gri): allow clients of go/importer to provide a FileSet. - // Or, define a new standard go/types/gcexportdata package. - fset := token.NewFileSet() + if err != nil { + break + } + + // TODO(gri): allow clients of go/importer to provide a FileSet. + // Or, define a new standard go/types/gcexportdata package. + fset := token.NewFileSet() + + // The indexed export format starts with an 'i'; the older + // binary export format starts with a 'c', 'd', or 'v' + // (from "version"). Select appropriate importer. + if len(data) > 0 && data[0] == 'i' { + _, pkg, err = iImportData(fset, packages, data[1:], id) + } else { _, pkg, err = BImportData(fset, packages, data, id) - return } + default: err = fmt.Errorf("unknown export data header: %q", hdr) } diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index a8745eea3e385..d496f2e57d384 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -141,9 +141,21 @@ func TestVersionHandling(t *testing.T) { } pkgpath := "./" + name[:len(name)-2] + if testing.Verbose() { + t.Logf("importing %s", name) + } + // test that export data can be imported _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil) if err != nil { + // ok to fail if it fails with a newer version error for select files + if strings.Contains(err.Error(), "newer version") { + switch name { + case "test_go1.11_999b.a", "test_go1.11_999i.a": + continue + } + // fall through + } t.Errorf("import %q failed: %v", pkgpath, err) continue } @@ -530,6 +542,27 @@ func TestIssue25301(t *testing.T) { importPkg(t, "./testdata/issue25301") } +func TestIssue25596(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + } + + // On windows, we have to set the -D option for the compiler to avoid having a drive + // letter and an illegal ':' in the import path - just skip it (see also issue #3483). + if runtime.GOOS == "windows" { + t.Skip("avoid dealing with relative paths/drive letters on windows") + } + + if f := compile(t, "testdata", "issue25596.go"); f != "" { + defer os.Remove(f) + } + + importPkg(t, "./testdata/issue25596") +} + func importPkg(t *testing.T, path string) *types.Package { pkg, err := Import(make(map[string]*types.Package), path, ".", nil) if err != nil { diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index 1d13449ef6b0e..a333f98f3a04f 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -10,6 +10,7 @@ package gcimporter import ( "bytes" "encoding/binary" + "fmt" "go/constant" "go/token" "go/types" @@ -60,13 +61,25 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { + const currentVersion = 0 + version := -1 + defer func() { + if e := recover(); e != nil { + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } + } + }() + r := &intReader{bytes.NewReader(data), path} - version := r.uint64() + version = int(r.uint64()) switch version { - case 0: + case currentVersion: default: - errorf("cannot import %q: unknown iexport format version %d", path, version) + errorf("unknown iexport format version %d", version) } sLen := int64(r.uint64()) diff --git a/src/syscall/time_js_wasm.s b/src/go/internal/gcimporter/testdata/issue25596.go similarity index 54% rename from src/syscall/time_js_wasm.s rename to src/go/internal/gcimporter/testdata/issue25596.go index f08b17006db45..8923373e5fa44 100644 --- a/src/syscall/time_js_wasm.s +++ b/src/go/internal/gcimporter/testdata/issue25596.go @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "textflag.h" +package issue25596 -TEXT ·startTimer(SB),NOSPLIT,$0 - JMP time·startTimer(SB) +type E interface { + M() T +} -TEXT ·stopTimer(SB),NOSPLIT,$0 - JMP time·stopTimer(SB) +type T interface { + E +} diff --git a/src/go/internal/gcimporter/testdata/versions/test.go b/src/go/internal/gcimporter/testdata/versions/test.go index ac9c968c2d088..227fc09251921 100644 --- a/src/go/internal/gcimporter/testdata/versions/test.go +++ b/src/go/internal/gcimporter/testdata/versions/test.go @@ -11,7 +11,10 @@ // // go build -o test_go1.$X_$Y.a test.go // -// with $X = Go version and $Y = export format version. +// with $X = Go version and $Y = export format version +// (add 'b' or 'i' to distinguish between binary and +// indexed format starting with 1.11 as long as both +// formats are supported). // // Make sure this source is extended such that it exercises // whatever export format change has taken place. diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a new file mode 100644 index 0000000000000..b00fefed04621 Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a differ diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a new file mode 100644 index 0000000000000..c0a211e917435 Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a differ diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a new file mode 100644 index 0000000000000..c35d22dce691e Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a differ diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a new file mode 100644 index 0000000000000..99401d7c37ca4 Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a differ diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index afe5f5d0fcb44..05e032423ca2c 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -174,7 +174,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } } - if mode == invalid { + if mode == invalid && typ != Typ[Invalid] { check.invalidArg(x.pos(), "%s for %s", x, bin.name) return } diff --git a/src/go/types/check.go b/src/go/types/check.go index 177065fded54e..286b1f36a9578 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -90,6 +90,7 @@ type Checker struct { interfaces map[*TypeName]*ifaceInfo // maps interface type names to corresponding interface infos untyped map[ast.Expr]exprInfo // map of expressions without final type delayed []func() // stack of delayed actions + objPath []Object // path of object dependencies during type inference (for cycle reporting) // context within which the current object is type-checked // (valid only for the duration of type-checking a specific object) @@ -144,6 +145,33 @@ func (check *Checker) later(f func()) { check.delayed = append(check.delayed, f) } +// push pushes obj onto the object path and returns its index in the path. +func (check *Checker) push(obj Object) int { + check.objPath = append(check.objPath, obj) + return len(check.objPath) - 1 +} + +// pop pops and returns the topmost object from the object path. +func (check *Checker) pop() Object { + i := len(check.objPath) - 1 + obj := check.objPath[i] + check.objPath[i] = nil + check.objPath = check.objPath[:i] + return obj +} + +// pathString returns a string of the form a->b-> ... ->g for an object path [a, b, ... g]. +func (check *Checker) pathString() string { + var s string + for i, p := range check.objPath { + if i > 0 { + s += "->" + } + s += p.Name() + } + return s +} + // NewChecker returns a new Checker instance for a given package. // Package files may be added incrementally via checker.Files. func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker { diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 288ba8e447916..e8e01541a3e95 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -49,15 +49,18 @@ func pathString(path []*TypeName) string { return s } +// useCycleMarking enables the new coloring-based cycle marking scheme +// for package-level objects. Set this flag to false to disable this +// code quickly and revert to the existing mechanism (and comment out +// some of the new tests in cycles5.src that will fail again). +// TODO(gri) remove this for Go 1.12 +const useCycleMarking = true + // objDecl type-checks the declaration of obj in its respective (file) context. // See check.typ for the details on def and path. func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { - if obj.Type() != nil { - return // already checked - nothing to do - } - if trace { - check.trace(obj.Pos(), "-- checking %s (path = %s)", obj, pathString(path)) + check.trace(obj.Pos(), "-- checking %s %s (path = %s, objPath = %s)", obj.color(), obj, pathString(path), check.pathString()) check.indent++ defer func() { check.indent-- @@ -65,6 +68,114 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { }() } + // Checking the declaration of obj means inferring its type + // (and possibly its value, for constants). + // An object's type (and thus the object) may be in one of + // three states which are expressed by colors: + // + // - an object whose type is not yet known is painted white (initial color) + // - an object whose type is in the process of being inferred is painted grey + // - an object whose type is fully inferred is painted black + // + // During type inference, an object's color changes from white to grey + // to black (pre-declared objects are painted black from the start). + // A black object (i.e., its type) can only depend on (refer to) other black + // ones. White and grey objects may depend on white and black objects. + // A dependency on a grey object indicates a cycle which may or may not be + // valid. + // + // When objects turn grey, they are pushed on the object path (a stack); + // they are popped again when they turn black. Thus, if a grey object (a + // cycle) is encountered, it is on the object path, and all the objects + // it depends on are the remaining objects on that path. Color encoding + // is such that the color value of a grey object indicates the index of + // that object in the object path. + + // During type-checking, white objects may be assigned a type without + // traversing through objDecl; e.g., when initializing constants and + // variables. Update the colors of those objects here (rather than + // everywhere where we set the type) to satisfy the color invariants. + if obj.color() == white && obj.Type() != nil { + obj.setColor(black) + return + } + + switch obj.color() { + case white: + assert(obj.Type() == nil) + // All color values other than white and black are considered grey. + // Because black and white are < grey, all values >= grey are grey. + // Use those values to encode the object's index into the object path. + obj.setColor(grey + color(check.push(obj))) + defer func() { + check.pop().setColor(black) + }() + + case black: + assert(obj.Type() != nil) + return + + default: + // Color values other than white or black are considered grey. + fallthrough + + case grey: + // We have a cycle. + // In the existing code, this is marked by a non-nil type + // for the object except for constants and variables whose + // type may be non-nil (known), or nil if it depends on the + // not-yet known initialization value. + // In the former case, set the type to Typ[Invalid] because + // we have an initialization cycle. The cycle error will be + // reported later, when determining initialization order. + // TODO(gri) Report cycle here and simplify initialization + // order code. + switch obj := obj.(type) { + case *Const: + if useCycleMarking && check.typeCycle(obj) { + obj.typ = Typ[Invalid] + break + } + if obj.typ == nil { + obj.typ = Typ[Invalid] + } + + case *Var: + if useCycleMarking && check.typeCycle(obj) { + obj.typ = Typ[Invalid] + break + } + if obj.typ == nil { + obj.typ = Typ[Invalid] + } + + case *TypeName: + if useCycleMarking && check.typeCycle(obj) { + // break cycle + // (without this, calling underlying() + // below may lead to an endless loop + // if we have a cycle for a defined + // (*Named) type) + obj.typ = Typ[Invalid] + } + + case *Func: + if useCycleMarking && check.typeCycle(obj) { + // Don't set obj.typ to Typ[Invalid] here + // because plenty of code type-asserts that + // functions have a *Signature type. Grey + // functions have their type set to an empty + // signature which makes it impossible to + // initialize a variable with the function. + } + + default: + unreachable() + } + assert(obj.Type() != nil) + return + } + d := check.objMap[obj] if d == nil { check.dump("%v: %s should have been declared", obj.Pos(), obj) @@ -102,14 +213,88 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { } } -func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { - assert(obj.typ == nil) +// indir is a sentinel type name that is pushed onto the object path +// to indicate an "indirection" in the dependency from one type name +// to the next. For instance, for "type p *p" the object path contains +// p followed by indir, indicating that there's an indirection *p. +// Indirections are used to break type cycles. +var indir = NewTypeName(token.NoPos, nil, "*", nil) + +// typeCycle checks if the cycle starting with obj is valid and +// reports an error if it is not. +// TODO(gri) rename s/typeCycle/cycle/ once we don't need the other +// cycle method anymore. +func (check *Checker) typeCycle(obj Object) bool { + d := check.objMap[obj] + if d == nil { + check.dump("%v: %s should have been declared", obj.Pos(), obj) + unreachable() + } - if obj.visited { - obj.typ = Typ[Invalid] - return + // We distinguish between cycles involving only constants and variables + // (nval = len(cycle)), cycles involving types (and functions) only + // (nval == 0), and mixed cycles (nval != 0 && nval != len(cycle)). + // We ignore functions at the moment (taking them into account correctly + // is complicated and it doesn't improve error reporting significantly). + // + // A cycle must have at least one indirection and one type definition + // to be permitted: If there is no indirection, the size of the type + // cannot be computed (it's either infinite or 0); if there is no type + // definition, we have a sequence of alias type names which will expand + // ad infinitum. + var nval int + var hasIndir, hasTDef bool + assert(obj.color() >= grey) + start := obj.color() - grey // index of obj in objPath + cycle := check.objPath[start:] + for _, obj := range cycle { + switch obj := obj.(type) { + case *Const, *Var: + nval++ + case *TypeName: + if obj == indir { + hasIndir = true + } else if !check.objMap[obj].alias { + hasTDef = true + } + case *Func: + // ignored for now + default: + unreachable() + } } - obj.visited = true + + // A cycle involving only constants and variables is invalid but we + // ignore them here because they are reported via the initialization + // cycle check. + if nval == len(cycle) { + return false + } + + // A cycle involving only types (and possibly functions) must have at + // least one indirection and one type definition to be permitted: If + // there is no indirection, the size of the type cannot be computed + // (it's either infinite or 0); if there is no type definition, we + // have a sequence of alias type names which will expand ad infinitum. + if nval == 0 && hasIndir && hasTDef { + return false // cycle is permitted + } + + // report cycle + check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name()) + for _, obj := range cycle { + if obj == indir { + continue // don't print indir sentinels + } + check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented + } + check.errorf(obj.Pos(), "\t%s", obj.Name()) + + return true +} + +func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { + assert(obj.typ == nil) // use the correct value of iota check.iota = obj.val @@ -144,12 +329,6 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { assert(obj.typ == nil) - if obj.visited { - obj.typ = Typ[Invalid] - return - } - obj.visited = true - // determine type, if any if typ != nil { obj.typ = check.typ(typ) @@ -279,7 +458,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) { return } delete(check.methods, obj) - assert(!obj.IsAlias()) + assert(!check.objMap[obj].alias) // don't use TypeName.IsAlias (requires fully set up object) // use an objset to check for name conflicts var mset objset diff --git a/src/go/types/errors.go b/src/go/types/errors.go index 0c0049b1f3e21..4c8d8537ee6a6 100644 --- a/src/go/types/errors.go +++ b/src/go/types/errors.go @@ -67,10 +67,20 @@ func (check *Checker) dump(format string, args ...interface{}) { } func (check *Checker) err(pos token.Pos, msg string, soft bool) { + // Cheap trick: Don't report errors with messages containing + // "invalid operand" or "invalid type" as those tend to be + // follow-on errors which don't add useful information. Only + // exclude them if these strings are not at the beginning, + // and only if we have at least one error already reported. + if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) { + return + } + err := Error{check.fset, pos, msg, soft} if check.firstErr == nil { check.firstErr = err } + f := check.conf.Error if f == nil { panic(bailout{}) // report only first error diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 0a2a811bd8898..3f3c4f83c6489 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1064,7 +1064,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { break } } - typ = check.typ(e.Type) + typ = check.typExpr(e.Type, nil, nil) base = typ case hint != nil: diff --git a/src/go/types/interfaces.go b/src/go/types/interfaces.go index b4efebae5d059..e4b42dc5a36b9 100644 --- a/src/go/types/interfaces.go +++ b/src/go/types/interfaces.go @@ -144,7 +144,7 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn } if trace { - check.trace(iface.Pos(), "-- collect methods for %v (path = %s)", iface, pathString(path)) + check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), check.pathString()) check.indent++ defer func() { check.indent-- diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 02af0cf51b12d..8560bb9b7dc8d 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -314,3 +314,44 @@ func TestIssue22525(t *testing.T) { t.Errorf("got: %swant: %s", got, want) } } + +func TestIssue25627(t *testing.T) { + const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T ` + // The src strings (without prefix) are constructed such that the number of semicolons + // plus one corresponds to the number of fields expected in the respective struct. + for _, src := range []string{ + `struct { x Missing }`, + `struct { Missing }`, + `struct { *Missing }`, + `struct { unsafe.Pointer }`, + `struct { P }`, + `struct { *I }`, + `struct { a int; b Missing; *Missing }`, + } { + f, err := parser.ParseFile(fset, "", prefix+src, 0) + if err != nil { + t.Fatal(err) + } + + cfg := Config{Importer: importer.Default(), Error: func(err error) {}} + info := &Info{Types: make(map[ast.Expr]TypeAndValue)} + _, err = cfg.Check(f.Name.Name, fset, []*ast.File{f}, info) + if err != nil { + if _, ok := err.(Error); !ok { + t.Fatal(err) + } + } + + ast.Inspect(f, func(n ast.Node) bool { + if spec, _ := n.(*ast.TypeSpec); spec != nil { + if tv, ok := info.Types[spec.Type]; ok && spec.Name.Name == "T" { + want := strings.Count(src, ";") + 1 + if got := tv.Type.(*Struct).NumFields(); got != want { + t.Errorf("%s: got %d fields; want %d", src, got, want) + } + } + } + return true + }) + } +} diff --git a/src/go/types/object.go b/src/go/types/object.go index f158e2733f337..07adfbc34c390 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -34,9 +34,15 @@ type Object interface { // 0 for all other objects (including objects in file scopes). order() uint32 + // color returns the object's color. + color() color + // setOrder sets the order number of the object. It must be > 0. setOrder(uint32) + // setColor sets the object's color. It must not be white. + setColor(color color) + // setParent sets the parent scope of the object. setParent(*Scope) @@ -78,9 +84,41 @@ type object struct { name string typ Type order_ uint32 + color_ color scopePos_ token.Pos } +// color encodes the color of an object (see Checker.objDecl for details). +type color uint32 + +// An object may be painted in one of three colors. +// Color values other than white or black are considered grey. +const ( + white color = iota + black + grey // must be > white and black +) + +func (c color) String() string { + switch c { + case white: + return "white" + case black: + return "black" + default: + return "grey" + } +} + +// colorFor returns the (initial) color for an object depending on +// whether its type t is known or not. +func colorFor(t Type) color { + if t != nil { + return black + } + return white +} + // Parent returns the scope in which the object is declared. // The result is nil for methods and struct fields. func (obj *object) Parent() *Scope { return obj.parent } @@ -108,10 +146,12 @@ func (obj *object) Id() string { return Id(obj.pkg, obj.name) } func (obj *object) String() string { panic("abstract") } func (obj *object) order() uint32 { return obj.order_ } +func (obj *object) color() color { return obj.color_ } func (obj *object) scopePos() token.Pos { return obj.scopePos_ } func (obj *object) setParent(parent *Scope) { obj.parent = parent } func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order } +func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color } func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } func (obj *object) sameId(pkg *Package, name string) bool { @@ -147,7 +187,7 @@ type PkgName struct { // NewPkgName returns a new PkgName object representing an imported package. // The remaining arguments set the attributes found with all Objects. func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName { - return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, token.NoPos}, imported, false} + return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, token.NoPos}, imported, false} } // Imported returns the package that was imported. @@ -157,14 +197,13 @@ func (obj *PkgName) Imported() *Package { return obj.imported } // A Const represents a declared constant. type Const struct { object - val constant.Value - visited bool // for initialization cycle detection + val constant.Value } // NewConst returns a new constant with value val. // The remaining arguments set the attributes found with all Objects. func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const { - return &Const{object{nil, pos, pkg, name, typ, 0, token.NoPos}, val, false} + return &Const{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, val} } // Val returns the constant's value. @@ -185,7 +224,7 @@ type TypeName struct { // argument for NewNamed, which will set the TypeName's type as a side- // effect. func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { - return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // IsAlias reports whether obj is an alias name for a type. @@ -216,7 +255,6 @@ func (obj *TypeName) IsAlias() bool { type Var struct { object embedded bool // if set, the variable is an embedded struct field, and name is the type name - visited bool // for initialization cycle detection isField bool // var is struct field used bool // set if the variable was used } @@ -224,19 +262,19 @@ type Var struct { // NewVar returns a new variable. // The arguments set the attributes found with all Objects. func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // NewParam returns a new variable representing a function parameter. func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, used: true} // parameters are always 'used' + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, used: true} // parameters are always 'used' } // NewField returns a new variable representing a struct field. // For embedded fields, the name is the unqualified type name /// under which the field is accessible. func NewField(pos token.Pos, pkg *Package, name string, typ Type, embedded bool) *Var { - return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, embedded: embedded, isField: true} + return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, embedded: embedded, isField: true} } // Anonymous reports whether the variable is an embedded field. @@ -266,7 +304,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { if sig != nil { typ = sig } - return &Func{object{nil, pos, pkg, name, typ, 0, token.NoPos}} + return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} } // FullName returns the package- or receiver-type-qualified name of @@ -291,7 +329,7 @@ type Label struct { // NewLabel returns a new label. func NewLabel(pos token.Pos, pkg *Package, name string) *Label { - return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false} + return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid], color_: black}, false} } // A Builtin represents a built-in function. @@ -302,7 +340,7 @@ type Builtin struct { } func newBuiltin(id builtinId) *Builtin { - return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id} + return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid], color_: black}, id} } // Nil represents the predeclared value nil. diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index fda0c954697ed..7b5410167f99b 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -167,6 +167,7 @@ var gcArchSizes = map[string]*StdSizes{ "mips64le": {8, 8}, "ppc64": {8, 8}, "ppc64le": {8, 8}, + "riscv64": {8, 8}, "s390x": {8, 8}, "wasm": {8, 8}, // When adding more architectures here, @@ -178,7 +179,7 @@ var gcArchSizes = map[string]*StdSizes{ // // Supported architectures for compiler "gc": // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle", -// "mips64", "mips64le", "ppc64", "ppc64le", "s390x", "wasm". +// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm". func SizesFor(compiler, arch string) Sizes { if compiler != "gc" { return nil diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index ad4c51f74def1..229d2030995b6 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -174,6 +174,8 @@ func TestStdFixed(t *testing.T) { "issue20529.go", // go/types does not have constraints on stack size "issue22200.go", // go/types does not have constraints on stack size "issue22200b.go", // go/types does not have constraints on stack size + "issue25507.go", // go/types does not have constraints on stack size + "issue20780.go", // go/types does not have constraints on stack size ) } diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src index 79e75e9316d7f..59f112dba1db7 100644 --- a/src/go/types/testdata/cycles.src +++ b/src/go/types/testdata/cycles.src @@ -147,7 +147,7 @@ type ( // test cases for issue 18643 // (type cycle detection when non-type expressions are involved) type ( - T14 [len(T14 /* ERROR cycle */ {})]int + T14 /* ERROR cycle */ [len(T14{})]int T15 [][len(T15 /* ERROR cycle */ {})]int T16 map[[len(T16 /* ERROR cycle */ {1:2})]int]int T17 map[int][len(T17 /* ERROR cycle */ {1:2})]int diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src index 345ab56ea690c..a7f4bc60f5b23 100644 --- a/src/go/types/testdata/cycles2.src +++ b/src/go/types/testdata/cycles2.src @@ -69,47 +69,38 @@ type T interface { // Variations of this test case. -type T1 interface { - m() [x1 /* ERROR no value */ .m()[0]]int +type T1 /* ERROR cycle */ interface { + m() [x1.m()[0]]int } var x1 T1 -type T2 interface { - m() [len(x2 /* ERROR no value */ .m())]int +type T2 /* ERROR cycle */ interface { + m() [len(x2.m())]int } var x2 T2 -type T3 interface { +type T3 /* ERROR cycle */ interface { m() [unsafe.Sizeof(x3.m)]int } var x3 T3 -// The test case below should also report an error for -// the cast inside the T4 interface (like it does for the -// variable initialization). The reason why it does not is -// that inside T4, the method x4.m depends on T4 which is not -// fully set up yet. The x4.m method happens to have an empty -// signature which is why the cast is permitted. -// TODO(gri) Consider marking methods as incomplete and provide -// a better error message in that case. - -type T4 interface { +type T4 /* ERROR cycle */ interface { m() [unsafe.Sizeof(cast4(x4.m))]int } var x4 T4 -var _ = cast4(x4 /* ERROR cannot convert */.m) +var _ = cast4(x4.m) type cast4 func() // This test is symmetric to the T4 case: Here the cast is // "correct", but it doesn't work inside the T5 interface. -type T5 interface { - m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int +type T5 /* ERROR cycle */ interface { + m() [unsafe.Sizeof(cast5(x5.m))]int } var x5 T5 diff --git a/src/go/types/testdata/cycles3.src b/src/go/types/testdata/cycles3.src index 3da4fb5761a66..5e89b627f00a7 100644 --- a/src/go/types/testdata/cycles3.src +++ b/src/go/types/testdata/cycles3.src @@ -48,7 +48,7 @@ type ( ) type ( - U interface { + U /* ERROR cycle */ interface { V } diff --git a/src/go/types/testdata/cycles5.src b/src/go/types/testdata/cycles5.src index aab9ee235ebfb..9c2822e738ac1 100644 --- a/src/go/types/testdata/cycles5.src +++ b/src/go/types/testdata/cycles5.src @@ -97,12 +97,12 @@ var _ = err.Error() // more esoteric cases type ( - T1 interface { T2 /* ERROR not an interface */ } + T1 interface { T2 } T2 /* ERROR cycle */ T2 ) type ( - T3 interface { T4 /* ERROR not an interface */ } + T3 interface { T4 } T4 /* ERROR cycle */ T5 T5 = T6 T6 = T7 @@ -117,3 +117,65 @@ const n = unsafe.Sizeof(func(){}) type I interface { m([unsafe.Sizeof(func() { I.m(nil, [n]byte{}) })]byte) } + + +// test cases for varias alias cycles + +type T10 /* ERROR cycle */ = *T10 // issue #25141 +type T11 /* ERROR cycle */ = interface{ f(T11) } // issue #23139 + +// issue #18640 +type ( + aa = bb + bb struct { + *aa + } +) + +type ( + a struct{ *b } + b = c + c struct{ *b } +) + +// issue #24939 +type ( + _ interface { + M(P) + } + + M interface { + F() P + } + + P = interface { + I() M + } +) + +// issue #8699 +type T12 /* ERROR cycle */ [len(a12)]int +var a12 = makeArray() +func makeArray() (res T12) { return } + +// issue #20770 +var r /* ERROR cycle */ = newReader() +func newReader() r + +// variations of the theme of #8699 amd #20770 +var arr /* ERROR cycle */ = f() +func f() [len(arr)]int + +// TODO(gri) here we should only get one error +func ff /* ERROR cycle */ (ff /* ERROR not a type */ ) + +type T13 /* ERROR cycle */ [len(b13)]int +var b13 T13 + +func g /* ERROR cycle */ () [unsafe.Sizeof(x)]int +var x = g + +func h /* ERROR cycle */ () [h /* ERROR no value */ ()[0]]int { panic(0) } + +var c14 /* ERROR cycle */ T14 +type T14 [uintptr(unsafe.Sizeof(&c14))]byte diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src index 75d442bc132ae..162dfeda04e3d 100644 --- a/src/go/types/testdata/decls0.src +++ b/src/go/types/testdata/decls0.src @@ -184,10 +184,10 @@ type ( // cycles in function/method declarations // (test cases for issue 5217 and variants) -func f1(x f1 /* ERROR "not a type" */ ) {} -func f2(x *f2 /* ERROR "not a type" */ ) {} -func f3() (x f3 /* ERROR "not a type" */ ) { return } -func f4() (x *f4 /* ERROR "not a type" */ ) { return } +func f1 /* ERROR cycle */ (x f1 /* ERROR "not a type" */ ) {} +func f2 /* ERROR cycle */ (x *f2 /* ERROR "not a type" */ ) {} +func f3 /* ERROR cycle */ () (x f3 /* ERROR "not a type" */ ) { return } +func f4 /* ERROR cycle */ () (x *f4 /* ERROR "not a type" */ ) { return } func (S0) m1(x S0.m1 /* ERROR "field or method" */ ) {} func (S0) m2(x *S0.m2 /* ERROR "field or method" */ ) {} diff --git a/src/go/types/testdata/decls3.src b/src/go/types/testdata/decls3.src index 3071fdae5eecc..18ddf5859c602 100644 --- a/src/go/types/testdata/decls3.src +++ b/src/go/types/testdata/decls3.src @@ -99,9 +99,9 @@ func _() { // unsafe.Pointers are treated like regular pointers when embedded type T2 struct { unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer - */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer + */* ERROR "cannot be unsafe.Pointer" */ /* ERROR "Pointer redeclared" */ unsafe.Pointer UP /* ERROR "cannot be unsafe.Pointer" */ - * /* ERROR "cannot be unsafe.Pointer" */ UP + * /* ERROR "cannot be unsafe.Pointer" */ /* ERROR "UP redeclared" */ UP } } diff --git a/src/go/types/testdata/errors.src b/src/go/types/testdata/errors.src index 29fcd8fe1da6d..ff929217c4c86 100644 --- a/src/go/types/testdata/errors.src +++ b/src/go/types/testdata/errors.src @@ -53,3 +53,8 @@ func _() { // Use unqualified names for package-local objects. type T struct{} var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T + +// Don't report errors containing "invalid type" (issue #24182). +func _(x *missing /* ERROR undeclared name: missing */ ) { + x.m() // there shouldn't be an error here referring to *invalid type +} diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index 9750bdc2e22b9..d727c3b3e23f1 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -97,7 +97,7 @@ func issue10979() { // issue11347 // These should not crash. -var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1 +var a1, b1 /* ERROR cycle */ /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1 var a2, b2 /* ERROR cycle */ = 0 /* ERROR cannot initialize */ /* ERROR cannot initialize */ > 0<<""[b2] var a3, b3 /* ERROR cycle */ = int /* ERROR cannot initialize */ /* ERROR cannot initialize */ (1<<""[b3]) diff --git a/src/go/types/type.go b/src/go/types/type.go index f274e30ab6b9b..60e3efaec314e 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -264,18 +264,17 @@ var markComplete = make([]*Func, 0) // to be embedded. This is necessary for interfaces that embed alias type names referring to // non-defined (literal) interface types. func NewInterface(methods []*Func, embeddeds []*Named) *Interface { - var tnames []Type - if len(embeddeds) > 0 { - tnames := make([]Type, len(embeddeds)) - for i, t := range embeddeds { - tnames[i] = t - } + tnames := make([]Type, len(embeddeds)) + for i, t := range embeddeds { + tnames[i] = t } return NewInterface2(methods, tnames) } // NewInterface2 returns a new (incomplete) interface for the given methods and embedded types. -// Each embedded type must have an underlying type of interface type. +// Each embedded type must have an underlying type of interface type (this property is not +// verified for defined types, which may be in the process of being set up and which don't +// have a valid underlying type yet). // NewInterface2 takes ownership of the provided methods and may modify their types by setting // missing receivers. To compute the method set of the interface, Complete must be called. func NewInterface2(methods []*Func, embeddeds []Type) *Interface { @@ -298,8 +297,12 @@ func NewInterface2(methods []*Func, embeddeds []Type) *Interface { sort.Sort(byUniqueMethodName(methods)) if len(embeddeds) > 0 { + // All embedded types should be interfaces; however, defined types + // may not yet be fully resolved. Only verify that non-defined types + // are interfaces. This matches the behavior of the code before the + // fix for #25301 (issue #25596). for _, t := range embeddeds { - if !IsInterface(t) { + if _, ok := t.(*Named); !ok && !IsInterface(t) { panic("embedded type is not an interface") } } @@ -350,27 +353,24 @@ func (t *Interface) Complete() *Interface { } var allMethods []*Func - if t.embeddeds == nil { - if t.methods == nil { - allMethods = make([]*Func, 0, 1) - } else { - allMethods = t.methods + allMethods = append(allMethods, t.methods...) + for _, et := range t.embeddeds { + it := et.Underlying().(*Interface) + it.Complete() + for _, tm := range it.allMethods { + // Make a copy of the method and adjust its receiver type. + newm := *tm + newmtyp := *tm.typ.(*Signature) + newm.typ = &newmtyp + newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t) + allMethods = append(allMethods, &newm) } - } else { - allMethods = append(allMethods, t.methods...) - for _, et := range t.embeddeds { - it := et.Underlying().(*Interface) - it.Complete() - for _, tm := range it.allMethods { - // Make a copy of the method and adjust its receiver type. - newm := *tm - newmtyp := *tm.typ.(*Signature) - newm.typ = &newmtyp - newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t) - allMethods = append(allMethods, &newm) - } - } - sort.Sort(byUniqueMethodName(allMethods)) + } + sort.Sort(byUniqueMethodName(allMethods)) + + // t.methods and/or t.embeddeds may have been empty + if allMethods == nil { + allMethods = markComplete } t.allMethods = allMethods diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go index 78f67d1f05002..6ed2d75dfe3f1 100644 --- a/src/go/types/typestring_test.go +++ b/src/go/types/typestring_test.go @@ -140,16 +140,41 @@ func TestTypeString(t *testing.T) { func TestIncompleteInterfaces(t *testing.T) { sig := NewSignature(nil, nil, nil, false) + m := NewFunc(token.NoPos, nil, "m", sig) for _, test := range []struct { typ *Interface want string }{ {new(Interface), "interface{/* incomplete */}"}, {new(Interface).Complete(), "interface{}"}, + + {NewInterface(nil, nil), "interface{/* incomplete */}"}, + {NewInterface(nil, nil).Complete(), "interface{}"}, + {NewInterface([]*Func{}, nil), "interface{/* incomplete */}"}, + {NewInterface([]*Func{}, nil).Complete(), "interface{}"}, + {NewInterface(nil, []*Named{}), "interface{/* incomplete */}"}, + {NewInterface(nil, []*Named{}).Complete(), "interface{}"}, + {NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"}, + {NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"}, + {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"}, + {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"}, + {NewInterface2(nil, nil), "interface{/* incomplete */}"}, {NewInterface2(nil, nil).Complete(), "interface{}"}, - {NewInterface2([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil), "interface{m() /* incomplete */}"}, - {NewInterface2([]*Func{NewFunc(token.NoPos, nil, "m", sig)}, nil).Complete(), "interface{m()}"}, + {NewInterface2([]*Func{}, nil), "interface{/* incomplete */}"}, + {NewInterface2([]*Func{}, nil).Complete(), "interface{}"}, + {NewInterface2(nil, []Type{}), "interface{/* incomplete */}"}, + {NewInterface2(nil, []Type{}).Complete(), "interface{}"}, + {NewInterface2([]*Func{m}, nil), "interface{m() /* incomplete */}"}, + {NewInterface2([]*Func{m}, nil).Complete(), "interface{m()}"}, + {NewInterface2(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"}, + {NewInterface2(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"}, + {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"}, } { got := test.typ.String() if got != test.want { @@ -158,6 +183,13 @@ func TestIncompleteInterfaces(t *testing.T) { } } +// newDefined creates a new defined type named T with the given underlying type. +// Helper function for use with TestIncompleteInterfaces only. +func newDefined(underlying Type) *Named { + tname := NewTypeName(token.NoPos, nil, "T", nil) + return NewNamed(tname, underlying, nil) +} + func TestQualifiedTypeString(t *testing.T) { p, _ := pkgFor("p.go", "package p; type T int", nil) q, _ := pkgFor("q.go", "package q", nil) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 999383ed275a7..45ada5874bc19 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -71,6 +71,12 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa case *TypeName: x.mode = typexpr + // package-level alias cycles are now checked by Checker.objDecl + if useCycleMarking { + if check.objMap[obj] != nil { + break + } + } if check.cycle(obj, path, true) { // maintain x.mode == typexpr despite error typ = Typ[Invalid] @@ -132,7 +138,11 @@ func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool { // If def != nil, e is the type specification for the named type def, declared // in a type declaration, and def.underlying will be set to the type of e before // any components of e are type-checked. Path contains the path of named types -// referring to this type. +// referring to this type; i.e. it is the path of named types directly containing +// each other and leading to the current type e. Indirect containment (e.g. via +// pointer indirection, function parameter, etc.) breaks the path (leads to a new +// path, and usually via calling Checker.typ below) and those types are not found +// in the path. // func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) { if trace { @@ -151,7 +161,18 @@ func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) return } +// typ is like typExpr (with a nil argument for the def parameter), +// but typ breaks type cycles. It should be called for components of +// types that break cycles, such as pointer base types, slice or map +// element types, etc. See the comment in typExpr for details. +// func (check *Checker) typ(e ast.Expr) Type { + // typExpr is called with a nil path indicating an indirection: + // push indir sentinel on object path + if useCycleMarking { + check.push(indir) + defer check.pop() + } return check.typExpr(e, nil, nil) } @@ -677,6 +698,16 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa } } + // addInvalid adds an embedded field of invalid type to the struct for + // fields with errors; this keeps the number of struct fields in sync + // with the source as long as the fields are _ or have different names + // (issue #25627). + addInvalid := func(ident *ast.Ident, pos token.Pos) { + typ = Typ[Invalid] + tag = "" + add(ident, true, pos) + } + for _, f := range list.List { typ = check.typExpr(f.Type, nil, path) tag = check.tag(f.Tag) @@ -693,6 +724,9 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa name := embeddedFieldIdent(f.Type) if name == nil { check.invalidAST(pos, "embedded field type %s has no name", f.Type) + name = ast.NewIdent("_") + name.NamePos = pos + addInvalid(name, pos) continue } t, isPtr := deref(typ) @@ -702,22 +736,26 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa case *Basic: if t == Typ[Invalid] { // error was reported before + addInvalid(name, pos) continue } // unsafe.Pointer is treated like a regular pointer if t.kind == UnsafePointer { check.errorf(pos, "embedded field type cannot be unsafe.Pointer") + addInvalid(name, pos) continue } case *Pointer: check.errorf(pos, "embedded field type cannot be a pointer") + addInvalid(name, pos) continue case *Interface: if isPtr { check.errorf(pos, "embedded field type cannot be a pointer to an interface") + addInvalid(name, pos) continue } } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 286ef7ba46854..2ae8a319707c4 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -102,7 +102,7 @@ func defPredeclaredConsts() { } func defPredeclaredNil() { - def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}}) + def(&Nil{object{name: "nil", typ: Typ[UntypedNil], color_: black}}) } // A builtinId is the id of a builtin function. @@ -207,6 +207,7 @@ func init() { // scope; other objects are inserted in the universe scope. // func def(obj Object) { + assert(obj.color() == black) name := obj.Name() if strings.Contains(name, " ") { return // nothing to do diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index 1912caa212ba1..908b84adcb290 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -3,12 +3,12 @@ // license that can be found in the LICENSE file. // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, -// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for +// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. // // Polynomials are represented in LSB-first form also known as reversed representation. // -// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials +// See https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials // for information. package crc32 @@ -29,12 +29,12 @@ const ( // Castagnoli's polynomial, used in iSCSI. // Has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/26.231911 + // https://dx.doi.org/10.1109/26.231911 Castagnoli = 0x82f63b78 // Koopman's polynomial. // Also has better error detection characteristics than IEEE. - // http://dx.doi.org/10.1109/DSN.2002.1028931 + // https://dx.doi.org/10.1109/DSN.2002.1028931 Koopman = 0xeb31d82e ) diff --git a/src/hash/crc32/crc32_amd64.s b/src/hash/crc32/crc32_amd64.s index a944ead9b2f2e..6af6c253a7900 100644 --- a/src/hash/crc32/crc32_amd64.s +++ b/src/hash/crc32/crc32_amd64.s @@ -149,7 +149,7 @@ GLOBL r4r3<>(SB),RODATA,$16 GLOBL rupoly<>(SB),RODATA,$16 GLOBL r5<>(SB),RODATA,$8 -// Based on http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf +// Based on https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf // len(p) must be at least 64, and must be a multiple of 16. // func ieeeCLMUL(crc uint32, p []byte) uint32 diff --git a/src/hash/crc64/crc64.go b/src/hash/crc64/crc64.go index 3b24c2440628a..a799a017c938c 100644 --- a/src/hash/crc64/crc64.go +++ b/src/hash/crc64/crc64.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64, -// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for +// checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. package crc64 diff --git a/src/html/template/attr.go b/src/html/template/attr.go index 92d2789e8041e..22922e6038b65 100644 --- a/src/html/template/attr.go +++ b/src/html/template/attr.go @@ -13,9 +13,9 @@ import ( // other content, or affects the contents, idempotency, or credentials of a // network message, then the value in this map is contentTypeUnsafe. // This map is derived from HTML5, specifically -// http://www.w3.org/TR/html5/Overview.html#attributes-1 +// https://www.w3.org/TR/html5/Overview.html#attributes-1 // as well as "%URI"-typed attributes from -// http://www.w3.org/TR/html4/index/attributes.html +// https://www.w3.org/TR/html4/index/attributes.html var attrTypeMap = map[string]contentType{ "accept": contentTypePlain, "accept-charset": contentTypeUnsafe, @@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{ "name": contentTypePlain, "novalidate": contentTypeUnsafe, // Skip handler names from - // http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects + // https://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects // since we have special handling in attrType. "open": contentTypePlain, "optimum": contentTypePlain, @@ -160,7 +160,7 @@ func attrType(name string) contentType { // Heuristics to prevent "javascript:..." injection in custom // data attributes and custom attributes like g:tweetUrl. - // http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes + // https://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes // "Custom data attributes are intended to store custom data // private to the page or application, for which there are no // more appropriate attributes or elements." diff --git a/src/html/template/content.go b/src/html/template/content.go index e7cdedc3b6209..4aadf64df252f 100644 --- a/src/html/template/content.go +++ b/src/html/template/content.go @@ -16,7 +16,7 @@ type ( // 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`. // 3. CSS3 declaration productions, such as `color: red; margin: 2px`. // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. - // See http://www.w3.org/TR/css3-syntax/#parsing and + // See https://www.w3.org/TR/css3-syntax/#parsing and // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style // // Use of this type presents a security risk: @@ -85,7 +85,7 @@ type ( URL string // Srcset encapsulates a known safe srcset attribute - // (see http://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset). + // (see https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset). // // Use of this type presents a security risk: // the encapsulated content should come from a trusted source, diff --git a/src/html/template/context.go b/src/html/template/context.go index fdbf7e25ee2df..45be3a6a9f94d 100644 --- a/src/html/template/context.go +++ b/src/html/template/context.go @@ -13,7 +13,7 @@ import ( // // The zero value of type context is the start context for a template that // produces an HTML fragment as defined at -// http://www.w3.org/TR/html5/syntax.html#the-end +// https://www.w3.org/TR/html5/syntax.html#the-end // where the context element is null. type context struct { state state @@ -98,7 +98,7 @@ const ( // stateHTMLCmt occurs inside an . stateHTMLCmt // stateRCDATA occurs inside an RCDATA element (