mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15da892a49 | ||
|
|
703c8ab7e5 | ||
|
|
d9242f7a8c | ||
|
|
489c148578 | ||
|
|
66c60f076c | ||
|
|
c25b12fb81 | ||
|
|
1ed3c127da | ||
|
|
cd54600b86 | ||
|
|
76f8b7304d | ||
|
|
8c1d8c8362 | ||
|
|
0117dee7dc | ||
|
|
ba8788ebce | ||
|
|
2678d0c957 | ||
|
|
58facfbe7d | ||
|
|
ed2f33e1a7 | ||
|
|
d13431c37a | ||
|
|
ae2dfcc1c8 | ||
|
|
fc07039e23 | ||
|
|
9ef614f5aa | ||
|
|
b1be664d64 | ||
|
|
77cc1c0def | ||
|
|
8d2935ab7c | ||
|
|
651a8d81ba | ||
|
|
26cdea3acc | ||
|
|
4c69fd51a9 | ||
|
|
909881db03 | ||
|
|
03c2e56f68 | ||
|
|
c15a8e2dbb | ||
|
|
590b53fac9 | ||
|
|
2be03d789d | ||
|
|
65701ad2b4 | ||
|
|
e846f3f2d6 | ||
|
|
a9003376d5 | ||
|
|
0e7138a102 | ||
|
|
085c61ae51 | ||
|
|
f7209f904d | ||
|
|
5b45e19a53 | ||
|
|
feec92c423 | ||
|
|
04781d14d2 | ||
|
|
4c5acd4b57 | ||
|
|
78992411de | ||
|
|
2150be1a9b | ||
|
|
9511f6deb6 | ||
|
|
0fdca725c7 | ||
|
|
346b18ee9d | ||
|
|
2116d60993 | ||
|
|
7139e8b024 | ||
|
|
eb75219438 | ||
|
|
4e69fddc64 | ||
|
|
efed283e79 | ||
|
|
88be85f18b | ||
|
|
7dd10d4ce2 | ||
|
|
7f04645b7a | ||
|
|
7d8fa65789 | ||
|
|
1ba25fa288 | ||
|
|
7d70adf3f5 | ||
|
|
ac071634c4 | ||
|
|
cd6e0d7cad | ||
|
|
6a70ee2873 | ||
|
|
1952c65f9a | ||
|
|
4a31565cc0 | ||
|
|
e163319023 | ||
|
|
fbcc30a2c9 | ||
|
|
acb1ce53f9 | ||
|
|
1651426f77 | ||
|
|
17e179e187 | ||
|
|
faa04090f8 | ||
|
|
1b867ce3ef | ||
|
|
539d430efb | ||
|
|
3a34273b8a | ||
|
|
9de1ac6ac2 | ||
|
|
dbdf055101 | ||
|
|
ab70d7c799 | ||
|
|
1242f430a9 | ||
|
|
59f1a26262 | ||
|
|
ebd1b4d97d | ||
|
|
0aa7f8fd4d | ||
|
|
4223f6eb23 | ||
|
|
de690c2ff8 | ||
|
|
48d948963c | ||
|
|
65633fee16 | ||
|
|
e46abcb816 | ||
|
|
61317ef99e | ||
|
|
0f2d0d0694 | ||
|
|
759a9211d4 | ||
|
|
01779135c0 | ||
|
|
66007e5cfc | ||
|
|
3c50f27391 | ||
|
|
ab175939e2 | ||
|
|
f0ee7c6f96 | ||
|
|
b7651e5046 | ||
|
|
4eaf0b7a58 | ||
|
|
4536558f16 | ||
|
|
e347c89598 | ||
|
|
1c05b9b024 | ||
|
|
364f15ff9f | ||
|
|
b954f58e9d | ||
|
|
f1935e2c43 | ||
|
|
f58c78a577 | ||
|
|
b212ba6829 | ||
|
|
f9cb33c7c9 | ||
|
|
4a842985bf | ||
|
|
f6f024f120 | ||
|
|
18b970277e | ||
|
|
91aa2f190a | ||
|
|
8bdb0b235a | ||
|
|
3a03ddf735 | ||
|
|
644555d34e | ||
|
|
11b64b428b | ||
|
|
2ac3bdf378 | ||
|
|
4925e0766f | ||
|
|
b18ba59aaf | ||
|
|
04242ac88f | ||
|
|
c5c1d069da | ||
|
|
abc4f092ac | ||
|
|
e79c297fa8 | ||
|
|
21a4e67ad5 | ||
|
|
328cf2e8b2 | ||
|
|
fcce86c4cf | ||
|
|
36c171763e | ||
|
|
678b07d5e5 | ||
|
|
14c9b1e00b | ||
|
|
c35f8a37d9 | ||
|
|
47a57bc4f0 | ||
|
|
2d97a87287 | ||
|
|
3969694203 | ||
|
|
1dd24caf08 | ||
|
|
ec5170397c | ||
|
|
fdd6dfd507 | ||
|
|
f7b9470992 | ||
|
|
4397d66bdd | ||
|
|
eb5a7b5050 | ||
|
|
72ab3ff68b | ||
|
|
c3ccb77d1e | ||
|
|
c3b47cb598 | ||
|
|
ddfd72f7d1 | ||
|
|
d6f4d9a2be |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.17
|
||||
parent-branch: master
|
||||
|
||||
@@ -753,9 +753,9 @@ func Foo() bool {
|
||||
|
||||
<p><!-- CL 311572 -->
|
||||
The new
|
||||
<a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a>
|
||||
and
|
||||
<a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a>
|
||||
<a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a>
|
||||
and
|
||||
<a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a>
|
||||
structs represent the int16 and byte values that may be null. These can be used as
|
||||
destinations of the <a href="/pkg/database/sql/#Scan"><code>Scan</code></a> method,
|
||||
similar to NullString.
|
||||
@@ -1205,11 +1205,11 @@ func Foo() bool {
|
||||
|
||||
<p><!-- CL 300996 -->
|
||||
The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time.
|
||||
The following time formats are now accepted:
|
||||
For example, the following time layouts are now accepted:
|
||||
<ul>
|
||||
<li>2006-01-02 14:06:03,999999999 -0700 MST</li>
|
||||
<li>Mon Jan _2 14:06:03,120007 2006</li>
|
||||
<li>Mon Jan 2 14:06:03,120007 2006</li>
|
||||
<li>2006-01-02 15:04:05,999999999 -0700 MST</li>
|
||||
<li>Mon Jan _2 15:04:05,000000 2006</li>
|
||||
<li>Monday, January 2 15:04:05,000 2006</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -10,12 +10,14 @@ import (
|
||||
"debug/elf"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
@@ -263,6 +265,173 @@ func checkLineComments(t *testing.T, hdrname string) {
|
||||
}
|
||||
}
|
||||
|
||||
// checkArchive verifies that the created library looks OK.
|
||||
// We just check a couple of things now, we can add more checks as needed.
|
||||
func checkArchive(t *testing.T, arname string) {
|
||||
t.Helper()
|
||||
|
||||
switch GOOS {
|
||||
case "aix", "darwin", "ios", "windows":
|
||||
// We don't have any checks for non-ELF libraries yet.
|
||||
if _, err := os.Stat(arname); err != nil {
|
||||
t.Errorf("archive %s does not exist: %v", arname, err)
|
||||
}
|
||||
default:
|
||||
checkELFArchive(t, arname)
|
||||
}
|
||||
}
|
||||
|
||||
// checkELFArchive checks an ELF archive.
|
||||
func checkELFArchive(t *testing.T, arname string) {
|
||||
t.Helper()
|
||||
|
||||
f, err := os.Open(arname)
|
||||
if err != nil {
|
||||
t.Errorf("archive %s does not exist: %v", arname, err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// TODO(iant): put these in a shared package? But where?
|
||||
const (
|
||||
magic = "!<arch>\n"
|
||||
fmag = "`\n"
|
||||
|
||||
namelen = 16
|
||||
datelen = 12
|
||||
uidlen = 6
|
||||
gidlen = 6
|
||||
modelen = 8
|
||||
sizelen = 10
|
||||
fmaglen = 2
|
||||
hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
|
||||
)
|
||||
|
||||
type arhdr struct {
|
||||
name string
|
||||
date string
|
||||
uid string
|
||||
gid string
|
||||
mode string
|
||||
size string
|
||||
fmag string
|
||||
}
|
||||
|
||||
var magbuf [len(magic)]byte
|
||||
if _, err := io.ReadFull(f, magbuf[:]); err != nil {
|
||||
t.Errorf("%s: archive too short", arname)
|
||||
return
|
||||
}
|
||||
if string(magbuf[:]) != magic {
|
||||
t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
|
||||
}
|
||||
|
||||
off := int64(len(magic))
|
||||
for {
|
||||
if off&1 != 0 {
|
||||
var b [1]byte
|
||||
if _, err := f.Read(b[:]); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
|
||||
}
|
||||
off++
|
||||
}
|
||||
|
||||
var hdrbuf [hdrlen]byte
|
||||
if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
|
||||
return
|
||||
}
|
||||
|
||||
var hdr arhdr
|
||||
hdrslice := hdrbuf[:]
|
||||
set := func(len int, ps *string) {
|
||||
*ps = string(bytes.TrimSpace(hdrslice[:len]))
|
||||
hdrslice = hdrslice[len:]
|
||||
}
|
||||
set(namelen, &hdr.name)
|
||||
set(datelen, &hdr.date)
|
||||
set(uidlen, &hdr.uid)
|
||||
set(gidlen, &hdr.gid)
|
||||
set(modelen, &hdr.mode)
|
||||
set(sizelen, &hdr.size)
|
||||
hdr.fmag = string(hdrslice[:fmaglen])
|
||||
hdrslice = hdrslice[fmaglen:]
|
||||
if len(hdrslice) != 0 {
|
||||
t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
|
||||
}
|
||||
|
||||
if hdr.fmag != fmag {
|
||||
t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
|
||||
return
|
||||
}
|
||||
|
||||
size, err := strconv.ParseInt(hdr.size, 10, 64)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
|
||||
return
|
||||
}
|
||||
|
||||
off += hdrlen
|
||||
|
||||
switch hdr.name {
|
||||
case "__.SYMDEF", "/", "/SYM64/":
|
||||
// The archive symbol map.
|
||||
case "//", "ARFILENAMES/":
|
||||
// The extended name table.
|
||||
default:
|
||||
// This should be an ELF object.
|
||||
checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
|
||||
}
|
||||
|
||||
off += size
|
||||
if _, err := f.Seek(off, os.SEEK_SET); err != nil {
|
||||
t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkELFArchiveObject checks an object in an ELF archive.
|
||||
func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
|
||||
t.Helper()
|
||||
|
||||
ef, err := elf.NewFile(obj)
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
|
||||
return
|
||||
}
|
||||
defer ef.Close()
|
||||
|
||||
// Verify section types.
|
||||
for _, sec := range ef.Sections {
|
||||
want := elf.SHT_NULL
|
||||
switch sec.Name {
|
||||
case ".text", ".data":
|
||||
want = elf.SHT_PROGBITS
|
||||
case ".bss":
|
||||
want = elf.SHT_NOBITS
|
||||
case ".symtab":
|
||||
want = elf.SHT_SYMTAB
|
||||
case ".strtab":
|
||||
want = elf.SHT_STRTAB
|
||||
case ".init_array":
|
||||
want = elf.SHT_INIT_ARRAY
|
||||
case ".fini_array":
|
||||
want = elf.SHT_FINI_ARRAY
|
||||
case ".preinit_array":
|
||||
want = elf.SHT_PREINIT_ARRAY
|
||||
}
|
||||
if want != elf.SHT_NULL && sec.Type != want {
|
||||
t.Errorf("%s: incorrect section type in elf file at %d for section %q: got %v want %v", arname, off, sec.Name, sec.Type, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
if !testWork {
|
||||
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
||||
@@ -321,6 +490,7 @@ func TestEarlySignalHandler(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo2.h")
|
||||
checkArchive(t, "libgo2.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -361,6 +531,7 @@ func TestSignalForwarding(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo2.h")
|
||||
checkArchive(t, "libgo2.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -411,6 +582,7 @@ func TestSignalForwardingExternal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo2.h")
|
||||
checkArchive(t, "libgo2.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -528,6 +700,7 @@ func TestOsSignal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo3.h")
|
||||
checkArchive(t, "libgo3.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -565,6 +738,7 @@ func TestSigaltstack(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo4.h")
|
||||
checkArchive(t, "libgo4.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -752,6 +926,7 @@ func TestSIGPROF(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo6.h")
|
||||
checkArchive(t, "libgo6.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
@@ -795,6 +970,7 @@ func TestCompileWithoutShared(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo2.h")
|
||||
checkArchive(t, "libgo2.a")
|
||||
|
||||
exe := "./testnoshared" + exeSuffix
|
||||
|
||||
@@ -899,6 +1075,7 @@ func TestManyCalls(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkLineComments(t, "libgo7.h")
|
||||
checkArchive(t, "libgo7.a")
|
||||
|
||||
ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
|
||||
if runtime.Compiler == "gccgo" {
|
||||
|
||||
@@ -265,7 +265,7 @@ func TestIssue25756(t *testing.T) {
|
||||
|
||||
// Test with main using -buildmode=pie with plugin for issue #43228
|
||||
func TestIssue25756pie(t *testing.T) {
|
||||
if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" {
|
||||
if os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-11_0-toothrot" || os.Getenv("GO_BUILDER_NAME") == "darwin-arm64-12_0-toothrot" {
|
||||
t.Skip("broken on darwin/arm64 builder in sharded mode; see issue 46239")
|
||||
}
|
||||
|
||||
@@ -287,9 +287,43 @@ func TestMethod2(t *testing.T) {
|
||||
run(t, "./method2.exe")
|
||||
}
|
||||
|
||||
func TestMethod3(t *testing.T) {
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "method3.so", "./method3/plugin.go")
|
||||
goCmd(t, "build", "-o", "method3.exe", "./method3/main.go")
|
||||
run(t, "./method3.exe")
|
||||
}
|
||||
|
||||
func TestIssue44956(t *testing.T) {
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p1.so", "./issue44956/plugin1.go")
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p2.so", "./issue44956/plugin2.go")
|
||||
goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
|
||||
run(t, "./issue44956.exe")
|
||||
}
|
||||
|
||||
func TestForkExec(t *testing.T) {
|
||||
// Issue 38824: importing the plugin package causes it hang in forkExec on darwin.
|
||||
|
||||
t.Parallel()
|
||||
goCmd(t, "build", "-o", "forkexec.exe", "./forkexec/main.go")
|
||||
|
||||
var cmd *exec.Cmd
|
||||
done := make(chan int, 1)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 100; i++ {
|
||||
cmd = exec.Command("./forkexec.exe", "1")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
t.Errorf("running command failed: %v", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
done <- 1
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Minute):
|
||||
cmd.Process.Kill()
|
||||
t.Fatalf("subprocess hang")
|
||||
}
|
||||
}
|
||||
|
||||
30
misc/cgo/testplugin/testdata/forkexec/main.go
vendored
Normal file
30
misc/cgo/testplugin/testdata/forkexec/main.go
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2021 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 (
|
||||
"os"
|
||||
"os/exec"
|
||||
_ "plugin"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if os.Args[1] != "1" {
|
||||
return
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 8; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// does not matter what we exec, just exec itself
|
||||
cmd := exec.Command("./forkexec.exe", "0")
|
||||
cmd.Run()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
32
misc/cgo/testplugin/testdata/method3/main.go
vendored
Normal file
32
misc/cgo/testplugin/testdata/method3/main.go
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
// An unexported method can be reachable from the plugin via interface
|
||||
// when a package is shared. So it need to be live.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"plugin"
|
||||
|
||||
"testplugin/method3/p"
|
||||
)
|
||||
|
||||
var i p.I
|
||||
|
||||
func main() {
|
||||
pl, err := plugin.Open("method3.so")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f, err := pl.Lookup("F")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f.(func())()
|
||||
|
||||
i = p.T(123)
|
||||
}
|
||||
17
misc/cgo/testplugin/testdata/method3/p/p.go
vendored
Normal file
17
misc/cgo/testplugin/testdata/method3/p/p.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type T int
|
||||
|
||||
func (T) m() { println("m") }
|
||||
|
||||
type I interface { m() }
|
||||
|
||||
func F() {
|
||||
i.m()
|
||||
}
|
||||
|
||||
var i I = T(123)
|
||||
11
misc/cgo/testplugin/testdata/method3/plugin.go
vendored
Normal file
11
misc/cgo/testplugin/testdata/method3/plugin.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2022 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 "testplugin/method3/p"
|
||||
|
||||
func main() {}
|
||||
|
||||
func F() { p.F() }
|
||||
2
misc/cgo/testsanitizers/testdata/tsan11.go
vendored
2
misc/cgo/testsanitizers/testdata/tsan11.go
vendored
@@ -45,7 +45,7 @@ static void register_handler(int signo) {
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
ch := make(chan os.Signal)
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR2)
|
||||
|
||||
C.register_handler(C.int(syscall.SIGUSR1))
|
||||
|
||||
2
misc/cgo/testsanitizers/testdata/tsan12.go
vendored
2
misc/cgo/testsanitizers/testdata/tsan12.go
vendored
@@ -22,7 +22,7 @@ import (
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
ch := make(chan os.Signal)
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
|
||||
if err := exec.Command("true").Run(); err != nil {
|
||||
|
||||
@@ -1070,3 +1070,11 @@ func TestIssue44031(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
|
||||
goCmd(t, "run", "-linkshared", "./issue44031/main")
|
||||
}
|
||||
|
||||
// Test that we use a variable from shared libraries (which implement an
|
||||
// interface in shared libraries.). A weak reference is used in the itab
|
||||
// in main process. It can cause unreacheble panic. See issue 47873.
|
||||
func TestIssue47873(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
|
||||
goCmd(t, "run", "-linkshared", "./issue47837/main")
|
||||
}
|
||||
|
||||
19
misc/cgo/testshared/testdata/issue47837/a/a.go
vendored
Normal file
19
misc/cgo/testshared/testdata/issue47837/a/a.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 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 a
|
||||
|
||||
type A interface {
|
||||
M()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func TheFuncWithArgA(a A) {
|
||||
a.M()
|
||||
}
|
||||
|
||||
type ImplA struct{}
|
||||
|
||||
//go:noinline
|
||||
func (A *ImplA) M() {}
|
||||
14
misc/cgo/testshared/testdata/issue47837/main/main.go
vendored
Normal file
14
misc/cgo/testshared/testdata/issue47837/main/main.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2021 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 (
|
||||
"testshared/issue47837/a"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var vara a.ImplA
|
||||
a.TheFuncWithArgA(&vara)
|
||||
}
|
||||
@@ -567,6 +567,13 @@
|
||||
offset += 8;
|
||||
});
|
||||
|
||||
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||
const wasmMinDataAddr = 4096 + 8192;
|
||||
if (offset >= wasmMinDataAddr) {
|
||||
throw new Error("total length of command line and environment variables exceeds limit");
|
||||
}
|
||||
|
||||
this._inst.exports.run(argc, argv);
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
|
||||
@@ -102,7 +102,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
||||
// indicate it contains up to 1 << 128 - 1 files. Since each file has a
|
||||
// header which will be _at least_ 30 bytes we can safely preallocate
|
||||
// if (data size / 30) >= end.directoryRecords.
|
||||
if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
|
||||
if end.directorySize < uint64(size) && (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
|
||||
z.File = make([]*File, 0, end.directoryRecords)
|
||||
}
|
||||
z.Comment = end.comment
|
||||
@@ -741,6 +741,9 @@ func (r *Reader) initFileList() {
|
||||
for _, file := range r.File {
|
||||
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
||||
name := toValidName(file.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||
dirs[dir] = true
|
||||
}
|
||||
@@ -782,8 +785,11 @@ func fileEntryLess(x, y string) bool {
|
||||
func (r *Reader) Open(name string) (fs.File, error) {
|
||||
r.initFileList()
|
||||
|
||||
if !fs.ValidPath(name) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
|
||||
}
|
||||
e := r.openLookup(name)
|
||||
if e == nil || !fs.ValidPath(name) {
|
||||
if e == nil {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||
}
|
||||
if e.isDir {
|
||||
@@ -797,7 +803,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
func split(name string) (dir, elem string, isDir bool) {
|
||||
if name[len(name)-1] == '/' {
|
||||
if len(name) > 0 && name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -1202,6 +1203,15 @@ func TestCVE202127919(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
if len(r.File) != 1 {
|
||||
t.Fatalf("No entries in the file list")
|
||||
}
|
||||
if r.File[0].Name != "../test.txt" {
|
||||
t.Errorf("Unexpected entry name: %s", r.File[0].Name)
|
||||
}
|
||||
if _, err := r.File[0].Open(); err != nil {
|
||||
t.Errorf("Error opening file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadDataDescriptor(t *testing.T) {
|
||||
@@ -1384,3 +1394,139 @@ func TestCVE202133196(t *testing.T) {
|
||||
t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202139293(t *testing.T) {
|
||||
// directory size is so large, that the check in Reader.init
|
||||
// overflows when subtracting from the archive size, causing
|
||||
// the pre-allocation check to be bypassed.
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
|
||||
0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
|
||||
0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff,
|
||||
}
|
||||
_, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != ErrFormat {
|
||||
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202141772(t *testing.T) {
|
||||
// Archive contains a file whose name is exclusively made up of '/', '\'
|
||||
// characters, or "../", "..\" paths, which would previously cause a panic.
|
||||
//
|
||||
// Length Method Size Cmpr Date Time CRC-32 Name
|
||||
// -------- ------ ------- ---- ---------- ----- -------- ----
|
||||
// 0 Stored 0 0% 08-05-2021 18:32 00000000 /
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 //
|
||||
// 0 Stored 0 0% 09-14-2021 12:59 00000000 \
|
||||
// 11 Stored 11 0% 09-14-2021 13:04 0d4a1185 /test.txt
|
||||
// -------- ------- --- -------
|
||||
// 11 11 0% 4 files
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
|
||||
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
|
||||
0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
|
||||
0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
|
||||
0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
|
||||
0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
|
||||
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
|
||||
0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
|
||||
0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
|
||||
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
|
||||
0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
|
||||
0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
|
||||
0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
|
||||
0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
|
||||
0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
|
||||
0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
|
||||
0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
|
||||
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the archive: %v", err)
|
||||
}
|
||||
entryNames := []string{`/`, `//`, `\`, `/test.txt`}
|
||||
var names []string
|
||||
for _, f := range r.File {
|
||||
names = append(names, f.Name)
|
||||
if _, err := f.Open(); err != nil {
|
||||
t.Errorf("Error opening %q: %v", f.Name, err)
|
||||
}
|
||||
if _, err := r.Open(f.Name); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(names, entryNames) {
|
||||
t.Errorf("Unexpected file entries: %q", names)
|
||||
}
|
||||
if _, err := r.Open(""); err == nil {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", "")
|
||||
}
|
||||
if _, err := r.Open("test.txt"); err != nil {
|
||||
t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
|
||||
}
|
||||
dirEntries, err := fs.ReadDir(r, ".")
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading the root directory: %v", err)
|
||||
}
|
||||
if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
|
||||
t.Errorf("Unexpected directory entries")
|
||||
for _, dirEntry := range dirEntries {
|
||||
_, err := r.Open(dirEntry.Name())
|
||||
t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
info, err := dirEntries[0].Info()
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading info entry: %v", err)
|
||||
}
|
||||
if name := info.Name(); name != "test.txt" {
|
||||
t.Errorf("Inconsistent name in info entry: %v", name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,8 @@ func storeByType(t *types.Type) obj.As {
|
||||
return x86.AMOVL
|
||||
case 8:
|
||||
return x86.AMOVQ
|
||||
case 16:
|
||||
return x86.AMOVUPS
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("bad store type %v", t))
|
||||
|
||||
@@ -91,6 +91,11 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
|
||||
continue
|
||||
}
|
||||
apdecls = append(apdecls, n)
|
||||
if n.Type().Kind() == types.TSSA {
|
||||
// Can happen for TypeInt128 types. This only happens for
|
||||
// spill locations, so not a huge deal.
|
||||
continue
|
||||
}
|
||||
fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +320,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
|
||||
a = a.Args[0]
|
||||
}
|
||||
if a.Op == ssa.OpLoadReg {
|
||||
if a.Op == ssa.OpLoadReg && mips.REG_R0 <= a.Reg() && a.Reg() <= mips.REG_R31 {
|
||||
// LoadReg from a narrower type does an extension, except loading
|
||||
// to a floating point register. So only eliminate the extension
|
||||
// if it is loaded to an integer register.
|
||||
t := a.Type
|
||||
switch {
|
||||
case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
|
||||
|
||||
@@ -495,10 +495,11 @@ func transformSelect(sel *ir.SelectStmt) {
|
||||
if ncase.Comm != nil {
|
||||
n := ncase.Comm
|
||||
oselrecv2 := func(dst, recv ir.Node, def bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
n.Def = def
|
||||
n.SetTypecheck(1)
|
||||
ncase.Comm = n
|
||||
selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
selrecv.Def = def
|
||||
selrecv.SetTypecheck(1)
|
||||
selrecv.SetInit(n.Init())
|
||||
ncase.Comm = selrecv
|
||||
}
|
||||
switch n.Op() {
|
||||
case ir.OAS:
|
||||
|
||||
@@ -952,6 +952,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
||||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
eltRO := x.regWidth(elt)
|
||||
source.Type = t
|
||||
for i := int64(0); i < t.NumElem(); i++ {
|
||||
sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
|
||||
mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Width, loadRegOffset, storeRc.at(t, 0))
|
||||
@@ -985,6 +986,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
|
||||
return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
|
||||
}
|
||||
|
||||
source.Type = t
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
fld := t.Field(i)
|
||||
sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
|
||||
|
||||
@@ -78,7 +78,11 @@ func fuseBranchRedirect(f *Func) bool {
|
||||
if v.Op != OpPhi {
|
||||
continue
|
||||
}
|
||||
v.RemoveArg(k)
|
||||
n := len(v.Args)
|
||||
v.Args[k].Uses--
|
||||
v.Args[k] = v.Args[n-1]
|
||||
v.Args[n-1] = nil
|
||||
v.Args = v.Args[:n-1]
|
||||
phielimValue(v)
|
||||
}
|
||||
// Fix up child to have one more predecessor.
|
||||
|
||||
@@ -497,9 +497,9 @@
|
||||
(XOR x (MOVWconst [c])) => (XORconst [c] x)
|
||||
(BIC x (MOVWconst [c])) => (BICconst [c] x)
|
||||
|
||||
(SLL x (MOVWconst [c])) => (SLLconst x [c&31]) // Note: I don't think we ever generate bad constant shifts (i.e. c>=32)
|
||||
(SRL x (MOVWconst [c])) => (SRLconst x [c&31])
|
||||
(SRA x (MOVWconst [c])) => (SRAconst x [c&31])
|
||||
(SLL x (MOVWconst [c])) && 0 <= c && c < 32 => (SLLconst x [c])
|
||||
(SRL x (MOVWconst [c])) && 0 <= c && c < 32 => (SRLconst x [c])
|
||||
(SRA x (MOVWconst [c])) && 0 <= c && c < 32 => (SRAconst x [c])
|
||||
|
||||
(CMP x (MOVWconst [c])) => (CMPconst [c] x)
|
||||
(CMP (MOVWconst [c]) x) => (InvertFlags (CMPconst [c] x))
|
||||
@@ -1072,60 +1072,60 @@
|
||||
(CMNshiftRL x (MOVWconst [c]) [d]) => (CMNconst x [int32(uint32(c)>>uint64(d))])
|
||||
(CMNshiftRA x (MOVWconst [c]) [d]) => (CMNconst x [c>>uint64(d)])
|
||||
|
||||
(ADDshiftLLreg x y (MOVWconst [c])) => (ADDshiftLL x y [c])
|
||||
(ADDshiftRLreg x y (MOVWconst [c])) => (ADDshiftRL x y [c])
|
||||
(ADDshiftRAreg x y (MOVWconst [c])) => (ADDshiftRA x y [c])
|
||||
(ADCshiftLLreg x y (MOVWconst [c]) flags) => (ADCshiftLL x y [c] flags)
|
||||
(ADCshiftRLreg x y (MOVWconst [c]) flags) => (ADCshiftRL x y [c] flags)
|
||||
(ADCshiftRAreg x y (MOVWconst [c]) flags) => (ADCshiftRA x y [c] flags)
|
||||
(ADDSshiftLLreg x y (MOVWconst [c])) => (ADDSshiftLL x y [c])
|
||||
(ADDSshiftRLreg x y (MOVWconst [c])) => (ADDSshiftRL x y [c])
|
||||
(ADDSshiftRAreg x y (MOVWconst [c])) => (ADDSshiftRA x y [c])
|
||||
(SUBshiftLLreg x y (MOVWconst [c])) => (SUBshiftLL x y [c])
|
||||
(SUBshiftRLreg x y (MOVWconst [c])) => (SUBshiftRL x y [c])
|
||||
(SUBshiftRAreg x y (MOVWconst [c])) => (SUBshiftRA x y [c])
|
||||
(SBCshiftLLreg x y (MOVWconst [c]) flags) => (SBCshiftLL x y [c] flags)
|
||||
(SBCshiftRLreg x y (MOVWconst [c]) flags) => (SBCshiftRL x y [c] flags)
|
||||
(SBCshiftRAreg x y (MOVWconst [c]) flags) => (SBCshiftRA x y [c] flags)
|
||||
(SUBSshiftLLreg x y (MOVWconst [c])) => (SUBSshiftLL x y [c])
|
||||
(SUBSshiftRLreg x y (MOVWconst [c])) => (SUBSshiftRL x y [c])
|
||||
(SUBSshiftRAreg x y (MOVWconst [c])) => (SUBSshiftRA x y [c])
|
||||
(RSBshiftLLreg x y (MOVWconst [c])) => (RSBshiftLL x y [c])
|
||||
(RSBshiftRLreg x y (MOVWconst [c])) => (RSBshiftRL x y [c])
|
||||
(RSBshiftRAreg x y (MOVWconst [c])) => (RSBshiftRA x y [c])
|
||||
(RSCshiftLLreg x y (MOVWconst [c]) flags) => (RSCshiftLL x y [c] flags)
|
||||
(RSCshiftRLreg x y (MOVWconst [c]) flags) => (RSCshiftRL x y [c] flags)
|
||||
(RSCshiftRAreg x y (MOVWconst [c]) flags) => (RSCshiftRA x y [c] flags)
|
||||
(RSBSshiftLLreg x y (MOVWconst [c])) => (RSBSshiftLL x y [c])
|
||||
(RSBSshiftRLreg x y (MOVWconst [c])) => (RSBSshiftRL x y [c])
|
||||
(RSBSshiftRAreg x y (MOVWconst [c])) => (RSBSshiftRA x y [c])
|
||||
(ANDshiftLLreg x y (MOVWconst [c])) => (ANDshiftLL x y [c])
|
||||
(ANDshiftRLreg x y (MOVWconst [c])) => (ANDshiftRL x y [c])
|
||||
(ANDshiftRAreg x y (MOVWconst [c])) => (ANDshiftRA x y [c])
|
||||
(ORshiftLLreg x y (MOVWconst [c])) => (ORshiftLL x y [c])
|
||||
(ORshiftRLreg x y (MOVWconst [c])) => (ORshiftRL x y [c])
|
||||
(ORshiftRAreg x y (MOVWconst [c])) => (ORshiftRA x y [c])
|
||||
(XORshiftLLreg x y (MOVWconst [c])) => (XORshiftLL x y [c])
|
||||
(XORshiftRLreg x y (MOVWconst [c])) => (XORshiftRL x y [c])
|
||||
(XORshiftRAreg x y (MOVWconst [c])) => (XORshiftRA x y [c])
|
||||
(BICshiftLLreg x y (MOVWconst [c])) => (BICshiftLL x y [c])
|
||||
(BICshiftRLreg x y (MOVWconst [c])) => (BICshiftRL x y [c])
|
||||
(BICshiftRAreg x y (MOVWconst [c])) => (BICshiftRA x y [c])
|
||||
(MVNshiftLLreg x (MOVWconst [c])) => (MVNshiftLL x [c])
|
||||
(MVNshiftRLreg x (MOVWconst [c])) => (MVNshiftRL x [c])
|
||||
(MVNshiftRAreg x (MOVWconst [c])) => (MVNshiftRA x [c])
|
||||
(CMPshiftLLreg x y (MOVWconst [c])) => (CMPshiftLL x y [c])
|
||||
(CMPshiftRLreg x y (MOVWconst [c])) => (CMPshiftRL x y [c])
|
||||
(CMPshiftRAreg x y (MOVWconst [c])) => (CMPshiftRA x y [c])
|
||||
(TSTshiftLLreg x y (MOVWconst [c])) => (TSTshiftLL x y [c])
|
||||
(TSTshiftRLreg x y (MOVWconst [c])) => (TSTshiftRL x y [c])
|
||||
(TSTshiftRAreg x y (MOVWconst [c])) => (TSTshiftRA x y [c])
|
||||
(TEQshiftLLreg x y (MOVWconst [c])) => (TEQshiftLL x y [c])
|
||||
(TEQshiftRLreg x y (MOVWconst [c])) => (TEQshiftRL x y [c])
|
||||
(TEQshiftRAreg x y (MOVWconst [c])) => (TEQshiftRA x y [c])
|
||||
(CMNshiftLLreg x y (MOVWconst [c])) => (CMNshiftLL x y [c])
|
||||
(CMNshiftRLreg x y (MOVWconst [c])) => (CMNshiftRL x y [c])
|
||||
(CMNshiftRAreg x y (MOVWconst [c])) => (CMNshiftRA x y [c])
|
||||
(ADDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftLL x y [c])
|
||||
(ADDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRL x y [c])
|
||||
(ADDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRA x y [c])
|
||||
(ADCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftLL x y [c] flags)
|
||||
(ADCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRL x y [c] flags)
|
||||
(ADCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRA x y [c] flags)
|
||||
(ADDSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftLL x y [c])
|
||||
(ADDSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRL x y [c])
|
||||
(ADDSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRA x y [c])
|
||||
(SUBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftLL x y [c])
|
||||
(SUBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRL x y [c])
|
||||
(SUBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRA x y [c])
|
||||
(SBCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftLL x y [c] flags)
|
||||
(SBCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRL x y [c] flags)
|
||||
(SBCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRA x y [c] flags)
|
||||
(SUBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftLL x y [c])
|
||||
(SUBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRL x y [c])
|
||||
(SUBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRA x y [c])
|
||||
(RSBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftLL x y [c])
|
||||
(RSBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRL x y [c])
|
||||
(RSBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRA x y [c])
|
||||
(RSCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftLL x y [c] flags)
|
||||
(RSCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRL x y [c] flags)
|
||||
(RSCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRA x y [c] flags)
|
||||
(RSBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftLL x y [c])
|
||||
(RSBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRL x y [c])
|
||||
(RSBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRA x y [c])
|
||||
(ANDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftLL x y [c])
|
||||
(ANDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRL x y [c])
|
||||
(ANDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRA x y [c])
|
||||
(ORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftLL x y [c])
|
||||
(ORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRL x y [c])
|
||||
(ORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRA x y [c])
|
||||
(XORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftLL x y [c])
|
||||
(XORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRL x y [c])
|
||||
(XORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRA x y [c])
|
||||
(BICshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftLL x y [c])
|
||||
(BICshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRL x y [c])
|
||||
(BICshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRA x y [c])
|
||||
(MVNshiftLLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftLL x [c])
|
||||
(MVNshiftRLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRL x [c])
|
||||
(MVNshiftRAreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRA x [c])
|
||||
(CMPshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftLL x y [c])
|
||||
(CMPshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRL x y [c])
|
||||
(CMPshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRA x y [c])
|
||||
(TSTshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftLL x y [c])
|
||||
(TSTshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRL x y [c])
|
||||
(TSTshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRA x y [c])
|
||||
(TEQshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftLL x y [c])
|
||||
(TEQshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRL x y [c])
|
||||
(TEQshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRA x y [c])
|
||||
(CMNshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftLL x y [c])
|
||||
(CMNshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRL x y [c])
|
||||
(CMNshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRA x y [c])
|
||||
|
||||
// Generate rotates
|
||||
(ADDshiftLL [c] (SRLconst x [32-c]) x) => (SRRconst [32-c] x)
|
||||
@@ -1237,24 +1237,24 @@
|
||||
(AND x (MVN y)) => (BIC x y)
|
||||
|
||||
// simplification with *shift ops
|
||||
(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(RSBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
|
||||
(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(RSBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(ORshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ORshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ORshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(XORshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(XORshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(XORshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(BICshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
|
||||
(AND x (MVNshiftLL y [c])) => (BICshiftLL x y [c])
|
||||
(AND x (MVNshiftRL y [c])) => (BICshiftRL x y [c])
|
||||
(AND x (MVNshiftRA y [c])) => (BICshiftRA x y [c])
|
||||
@@ -1268,8 +1268,8 @@
|
||||
(SRLconst (SLLconst x [c]) [d]) && buildcfg.GOARM==7 && uint64(d)>=uint64(c) && uint64(d)<=31 => (BFXU [(d-c)|(32-d)<<8] x)
|
||||
|
||||
// comparison simplification
|
||||
((LT|LE|EQ|NE|GE|GT) (CMP x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMN x y)) // sense of carry bit not preserved
|
||||
((LT|LE|EQ|NE|GE|GT) (CMN x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMP x y)) // sense of carry bit not preserved
|
||||
((EQ|NE) (CMP x (RSBconst [0] y))) => ((EQ|NE) (CMN x y)) // sense of carry bit not preserved; see also #50854
|
||||
((EQ|NE) (CMN x (RSBconst [0] y))) => ((EQ|NE) (CMP x y)) // sense of carry bit not preserved; see also #50864
|
||||
(EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (EQ (CMP x y) yes no)
|
||||
(EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (EQ (CMPconst [c] x) yes no)
|
||||
|
||||
@@ -645,19 +645,13 @@
|
||||
(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMNW x y) yes no)
|
||||
(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMNW x y) yes no)
|
||||
|
||||
// CMP(x,-y) -> CMN(x,y) is only valid for unordered comparison, if y can be -1<<63
|
||||
(EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
|
||||
(NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
|
||||
(LT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMN x y) yes no)
|
||||
(LE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMN x y) yes no)
|
||||
(GT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMN x y) yes no)
|
||||
(GE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMN x y) yes no)
|
||||
|
||||
// CMPW(x,-y) -> CMNW(x,y) is only valid for unordered comparison, if y can be -1<<31
|
||||
(EQ (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
|
||||
(NE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
|
||||
(LT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMNW x y) yes no)
|
||||
(LE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMNW x y) yes no)
|
||||
(GT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMNW x y) yes no)
|
||||
(GE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMNW x y) yes no)
|
||||
|
||||
(EQ (CMPconst [0] x) yes no) => (Z x yes no)
|
||||
(NE (CMPconst [0] x) yes no) => (NZ x yes no)
|
||||
@@ -1698,27 +1692,27 @@
|
||||
(TSTshiftRA x (MOVDconst [c]) [d]) => (TSTconst x [c>>uint64(d)])
|
||||
|
||||
// simplification with *shift ops
|
||||
(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
|
||||
(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
|
||||
(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
|
||||
(EONshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(EONshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(EONshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(ORNshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
|
||||
(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(ORshiftLL y:(SLLconst x [c]) x [c]) => y
|
||||
(ORshiftRL y:(SRLconst x [c]) x [c]) => y
|
||||
(ORshiftRA y:(SRAconst x [c]) x [c]) => y
|
||||
(XORshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(XORshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(XORshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(BICshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
|
||||
(EONshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(EONshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(EONshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
(ORNshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
|
||||
|
||||
// Generate rotates with const shift
|
||||
(ADDshiftLL [c] (SRLconst x [64-c]) x) => (RORconst [64-c] x)
|
||||
|
||||
@@ -284,9 +284,9 @@ func init() {
|
||||
{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt
|
||||
{name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit
|
||||
{name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit
|
||||
{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1
|
||||
{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1, provided arg1 is not 1<<63
|
||||
{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt
|
||||
{name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit
|
||||
{name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit, provided arg1 is not 1<<31
|
||||
{name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit
|
||||
{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
|
||||
{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int64", typ: "Flags"}, // arg0 & auxInt compare to 0
|
||||
|
||||
@@ -228,14 +228,15 @@ func init() {
|
||||
|
||||
// shifts
|
||||
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
|
||||
{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
|
||||
{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, 0 <= auxInt < 32
|
||||
{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 256
|
||||
{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
|
||||
{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned, 0 <= auxInt < 32
|
||||
{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 256
|
||||
{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
|
||||
{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, 0 <= auxInt < 32
|
||||
{name: "SRR", argLength: 2, reg: gp21}, // arg0 right rotate by arg1 bits
|
||||
{name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits
|
||||
{name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits, 0 <= auxInt < 32
|
||||
|
||||
// auxInt for all of these satisfy 0 <= auxInt < 32
|
||||
{name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt
|
||||
{name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift
|
||||
{name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift
|
||||
@@ -330,7 +331,7 @@ func init() {
|
||||
// comparisons
|
||||
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
|
||||
{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt
|
||||
{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1
|
||||
{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1, provided arg1 is not 1<<63
|
||||
{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt
|
||||
{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
|
||||
{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
(Leq64F ...) => (FLED ...)
|
||||
(Leq32F ...) => (FLES ...)
|
||||
|
||||
(EqPtr x y) => (SEQZ (SUB <x.Type> x y))
|
||||
(EqPtr x y) => (SEQZ (SUB <typ.Uintptr> x y))
|
||||
(Eq64 x y) => (SEQZ (SUB <x.Type> x y))
|
||||
(Eq32 x y) => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
|
||||
(Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
|
||||
@@ -258,7 +258,7 @@
|
||||
(Eq64F ...) => (FEQD ...)
|
||||
(Eq32F ...) => (FEQS ...)
|
||||
|
||||
(NeqPtr x y) => (SNEZ (SUB <x.Type> x y))
|
||||
(NeqPtr x y) => (SNEZ (SUB <typ.Uintptr> x y))
|
||||
(Neq64 x y) => (SNEZ (SUB <x.Type> x y))
|
||||
(Neq32 x y) => (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
|
||||
(Neq16 x y) => (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
|
||||
|
||||
@@ -106,7 +106,7 @@ var genericOps = []opData{
|
||||
|
||||
// For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
|
||||
// Shift amounts are considered unsigned.
|
||||
// If arg1 is known to be less than the number of bits in arg0,
|
||||
// If arg1 is known to be nonnegative and less than the number of bits in arg0,
|
||||
// then auxInt may be set to 1.
|
||||
// This enables better code generation on some platforms.
|
||||
{name: "Lsh8x8", argLength: 2, aux: "Bool"}, // arg0 << arg1
|
||||
|
||||
@@ -159,6 +159,13 @@ func findIndVar(f *Func) []indVar {
|
||||
step = -step
|
||||
}
|
||||
|
||||
if flags&indVarMaxInc != 0 && max.Op == OpConst64 && max.AuxInt+step < max.AuxInt {
|
||||
// For a <= comparison, we need to make sure that a value equal to
|
||||
// max can be incremented without overflowing.
|
||||
// (For a < comparison, the %step check below ensures no overflow.)
|
||||
continue
|
||||
}
|
||||
|
||||
// Up to now we extracted the induction variable (ind),
|
||||
// the increment delta (inc), the temporary sum (nxt),
|
||||
// the mininum value (min) and the maximum value (max).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2265,18 +2265,16 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftLL x y:(SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftLL y:(SLLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2319,18 +2317,16 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftRA x y:(SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftRA y:(SRAconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2373,18 +2369,16 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ANDshiftRL x y:(SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ANDshiftRL y:(SRLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -2495,17 +2489,15 @@ func rewriteValueARM64_OpARM64BICshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -2531,17 +2523,15 @@ func rewriteValueARM64_OpARM64BICshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -2567,17 +2557,15 @@ func rewriteValueARM64_OpARM64BICshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (BICshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (BICshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -3945,17 +3933,15 @@ func rewriteValueARM64_OpARM64EONshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -3981,17 +3967,15 @@ func rewriteValueARM64_OpARM64EONshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -4017,17 +4001,15 @@ func rewriteValueARM64_OpARM64EONshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (EONshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (EONshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17819,17 +17801,15 @@ func rewriteValueARM64_OpARM64ORNshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17855,17 +17835,15 @@ func rewriteValueARM64_OpARM64ORNshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -17891,17 +17869,15 @@ func rewriteValueARM64_OpARM64ORNshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORNshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORNshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [-1])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -18014,18 +17990,16 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftLL x y:(SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftLL y:(SLLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -19694,18 +19668,16 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftRA x y:(SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftRA y:(SRAconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -19748,18 +19720,16 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ORshiftRL x y:(SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (ORshiftRL y:(SRLconst x [c]) x [c])
|
||||
// result: y
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
y := v_1
|
||||
if y.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
y := v_0
|
||||
if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(y.AuxInt)
|
||||
if x != y.Args[0] || !(c == d) {
|
||||
x := y.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(y)
|
||||
@@ -20836,17 +20806,15 @@ func rewriteValueARM64_OpARM64SUBshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -20872,17 +20840,15 @@ func rewriteValueARM64_OpARM64SUBshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -20908,17 +20874,15 @@ func rewriteValueARM64_OpARM64SUBshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (SUBshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (SUBshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22007,17 +21971,15 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftLL x (SLLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftLL (SLLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SLLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22219,17 +22181,15 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftRA x (SRAconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftRA (SRAconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRAconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -22273,17 +22233,15 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value) bool {
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (XORshiftRL x (SRLconst x [c]) [d])
|
||||
// cond: c==d
|
||||
// match: (XORshiftRL (SRLconst x [c]) x [c])
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
d := auxIntToInt64(v.AuxInt)
|
||||
x := v_0
|
||||
if v_1.Op != OpARM64SRLconst {
|
||||
c := auxIntToInt64(v.AuxInt)
|
||||
if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
|
||||
break
|
||||
}
|
||||
c := auxIntToInt64(v_1.AuxInt)
|
||||
if x != v_1.Args[0] || !(c == d) {
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDconst)
|
||||
@@ -27247,46 +27205,6 @@ func rewriteBlockARM64(b *Block) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GE (CMP x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (GE (CMN x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMP {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64GE, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPW x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (GE (CMNW x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMPW {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64GE, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GE (CMPconst [0] z:(MADD a x y)) yes no)
|
||||
// cond: z.Uses==1
|
||||
// result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
@@ -27683,46 +27601,6 @@ func rewriteBlockARM64(b *Block) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (GT (CMP x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (GT (CMN x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMP {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64GT, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPW x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (GT (CMNW x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMPW {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64GT, v0)
|
||||
return true
|
||||
}
|
||||
// match: (GT (CMPconst [0] z:(MADD a x y)) yes no)
|
||||
// cond: z.Uses==1
|
||||
// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
@@ -28215,46 +28093,6 @@ func rewriteBlockARM64(b *Block) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LE (CMP x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (LE (CMN x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMP {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64LE, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPW x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (LE (CMNW x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMPW {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64LE, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LE (CMPconst [0] z:(MADD a x y)) yes no)
|
||||
// cond: z.Uses==1
|
||||
// result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
@@ -28627,46 +28465,6 @@ func rewriteBlockARM64(b *Block) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (LT (CMP x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (LT (CMN x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMP {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64LT, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPW x z:(NEG y)) yes no)
|
||||
// cond: z.Uses == 1
|
||||
// result: (LT (CMNW x y) yes no)
|
||||
for b.Controls[0].Op == OpARM64CMPW {
|
||||
v_0 := b.Controls[0]
|
||||
_ = v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
z := v_0.Args[1]
|
||||
if z.Op != OpARM64NEG {
|
||||
break
|
||||
}
|
||||
y := z.Args[0]
|
||||
if !(z.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
|
||||
v0.AddArg2(x, y)
|
||||
b.resetWithControl(BlockARM64LT, v0)
|
||||
return true
|
||||
}
|
||||
// match: (LT (CMPconst [0] z:(MADD a x y)) yes no)
|
||||
// cond: z.Uses==1
|
||||
// result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
|
||||
@@ -1080,13 +1080,14 @@ func rewriteValueRISCV64_OpEqPtr(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (EqPtr x y)
|
||||
// result: (SEQZ (SUB <x.Type> x y))
|
||||
// result: (SEQZ (SUB <typ.Uintptr> x y))
|
||||
for {
|
||||
x := v_0
|
||||
y := v_1
|
||||
v.reset(OpRISCV64SEQZ)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
@@ -2629,13 +2630,14 @@ func rewriteValueRISCV64_OpNeqPtr(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (NeqPtr x y)
|
||||
// result: (SNEZ (SUB <x.Type> x y))
|
||||
// result: (SNEZ (SUB <typ.Uintptr> x y))
|
||||
for {
|
||||
x := v_0
|
||||
y := v_1
|
||||
v.reset(OpRISCV64SNEZ)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
|
||||
@@ -2387,6 +2387,175 @@ func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op {
|
||||
return x
|
||||
}
|
||||
|
||||
func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value {
|
||||
if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
|
||||
// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
|
||||
return s.newValue1(ssa.OpCopy, tt, v)
|
||||
}
|
||||
if ft.IsInteger() && tt.IsInteger() {
|
||||
var op ssa.Op
|
||||
if tt.Size() == ft.Size() {
|
||||
op = ssa.OpCopy
|
||||
} else if tt.Size() < ft.Size() {
|
||||
// truncation
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 21:
|
||||
op = ssa.OpTrunc16to8
|
||||
case 41:
|
||||
op = ssa.OpTrunc32to8
|
||||
case 42:
|
||||
op = ssa.OpTrunc32to16
|
||||
case 81:
|
||||
op = ssa.OpTrunc64to8
|
||||
case 82:
|
||||
op = ssa.OpTrunc64to16
|
||||
case 84:
|
||||
op = ssa.OpTrunc64to32
|
||||
default:
|
||||
s.Fatalf("weird integer truncation %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.IsSigned() {
|
||||
// sign extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpSignExt8to16
|
||||
case 14:
|
||||
op = ssa.OpSignExt8to32
|
||||
case 18:
|
||||
op = ssa.OpSignExt8to64
|
||||
case 24:
|
||||
op = ssa.OpSignExt16to32
|
||||
case 28:
|
||||
op = ssa.OpSignExt16to64
|
||||
case 48:
|
||||
op = ssa.OpSignExt32to64
|
||||
default:
|
||||
s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
} else {
|
||||
// zero extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpZeroExt8to16
|
||||
case 14:
|
||||
op = ssa.OpZeroExt8to32
|
||||
case 18:
|
||||
op = ssa.OpZeroExt8to64
|
||||
case 24:
|
||||
op = ssa.OpZeroExt16to32
|
||||
case 28:
|
||||
op = ssa.OpZeroExt16to64
|
||||
case 48:
|
||||
op = ssa.OpZeroExt32to64
|
||||
default:
|
||||
s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
}
|
||||
return s.newValue1(op, tt, v)
|
||||
}
|
||||
|
||||
if ft.IsFloat() || tt.IsFloat() {
|
||||
conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
|
||||
if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
|
||||
if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
|
||||
if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
|
||||
if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
|
||||
if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint32Tofloat32(n, v, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint32Tofloat64(n, v, ft, tt)
|
||||
}
|
||||
} else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint32(n, v, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint32(n, v, ft, tt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
s.Fatalf("weird float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
op1, op2, it := conv.op1, conv.op2, conv.intermediateType
|
||||
|
||||
if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
|
||||
// normal case, not tripping over unsigned 64
|
||||
if op1 == ssa.OpCopy {
|
||||
if op2 == ssa.OpCopy {
|
||||
return v
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, tt, v)
|
||||
}
|
||||
if op2 == ssa.OpCopy {
|
||||
return s.newValueOrSfCall1(op1, tt, v)
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, tt, s.newValueOrSfCall1(op1, types.Types[it], v))
|
||||
}
|
||||
// Tricky 64-bit unsigned cases.
|
||||
if ft.IsInteger() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint64Tofloat32(n, v, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint64Tofloat64(n, v, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint64(n, v, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint64(n, v, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ft.IsComplex() && tt.IsComplex() {
|
||||
var op ssa.Op
|
||||
if ft.Size() == tt.Size() {
|
||||
switch ft.Size() {
|
||||
case 8:
|
||||
op = ssa.OpRound32F
|
||||
case 16:
|
||||
op = ssa.OpRound64F
|
||||
default:
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.Size() == 8 && tt.Size() == 16 {
|
||||
op = ssa.OpCvt32Fto64F
|
||||
} else if ft.Size() == 16 && tt.Size() == 8 {
|
||||
op = ssa.OpCvt64Fto32F
|
||||
} else {
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
ftp := types.FloatForComplex(ft)
|
||||
ttp := types.FloatForComplex(tt)
|
||||
return s.newValue2(ssa.OpComplexMake, tt,
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, v)),
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, v)))
|
||||
}
|
||||
|
||||
s.Fatalf("unhandled OCONV %s -> %s", ft.Kind(), tt.Kind())
|
||||
return nil
|
||||
}
|
||||
|
||||
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
|
||||
func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
if ir.HasUniquePos(n) {
|
||||
@@ -2574,174 +2743,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
case ir.OCONV:
|
||||
n := n.(*ir.ConvExpr)
|
||||
x := s.expr(n.X)
|
||||
ft := n.X.Type() // from type
|
||||
tt := n.Type() // to type
|
||||
if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
|
||||
// Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
|
||||
return s.newValue1(ssa.OpCopy, n.Type(), x)
|
||||
}
|
||||
if ft.IsInteger() && tt.IsInteger() {
|
||||
var op ssa.Op
|
||||
if tt.Size() == ft.Size() {
|
||||
op = ssa.OpCopy
|
||||
} else if tt.Size() < ft.Size() {
|
||||
// truncation
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 21:
|
||||
op = ssa.OpTrunc16to8
|
||||
case 41:
|
||||
op = ssa.OpTrunc32to8
|
||||
case 42:
|
||||
op = ssa.OpTrunc32to16
|
||||
case 81:
|
||||
op = ssa.OpTrunc64to8
|
||||
case 82:
|
||||
op = ssa.OpTrunc64to16
|
||||
case 84:
|
||||
op = ssa.OpTrunc64to32
|
||||
default:
|
||||
s.Fatalf("weird integer truncation %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.IsSigned() {
|
||||
// sign extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpSignExt8to16
|
||||
case 14:
|
||||
op = ssa.OpSignExt8to32
|
||||
case 18:
|
||||
op = ssa.OpSignExt8to64
|
||||
case 24:
|
||||
op = ssa.OpSignExt16to32
|
||||
case 28:
|
||||
op = ssa.OpSignExt16to64
|
||||
case 48:
|
||||
op = ssa.OpSignExt32to64
|
||||
default:
|
||||
s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
} else {
|
||||
// zero extension
|
||||
switch 10*ft.Size() + tt.Size() {
|
||||
case 12:
|
||||
op = ssa.OpZeroExt8to16
|
||||
case 14:
|
||||
op = ssa.OpZeroExt8to32
|
||||
case 18:
|
||||
op = ssa.OpZeroExt8to64
|
||||
case 24:
|
||||
op = ssa.OpZeroExt16to32
|
||||
case 28:
|
||||
op = ssa.OpZeroExt16to64
|
||||
case 48:
|
||||
op = ssa.OpZeroExt32to64
|
||||
default:
|
||||
s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
|
||||
}
|
||||
}
|
||||
return s.newValue1(op, n.Type(), x)
|
||||
}
|
||||
|
||||
if ft.IsFloat() || tt.IsFloat() {
|
||||
conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
|
||||
if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
|
||||
if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
|
||||
if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
|
||||
conv = conv1
|
||||
}
|
||||
}
|
||||
|
||||
if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
|
||||
if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint32Tofloat32(n, x, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint32Tofloat64(n, x, ft, tt)
|
||||
}
|
||||
} else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint32(n, x, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint32(n, x, ft, tt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
s.Fatalf("weird float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
op1, op2, it := conv.op1, conv.op2, conv.intermediateType
|
||||
|
||||
if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
|
||||
// normal case, not tripping over unsigned 64
|
||||
if op1 == ssa.OpCopy {
|
||||
if op2 == ssa.OpCopy {
|
||||
return x
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, n.Type(), x)
|
||||
}
|
||||
if op2 == ssa.OpCopy {
|
||||
return s.newValueOrSfCall1(op1, n.Type(), x)
|
||||
}
|
||||
return s.newValueOrSfCall1(op2, n.Type(), s.newValueOrSfCall1(op1, types.Types[it], x))
|
||||
}
|
||||
// Tricky 64-bit unsigned cases.
|
||||
if ft.IsInteger() {
|
||||
// tt is float32 or float64, and ft is also unsigned
|
||||
if tt.Size() == 4 {
|
||||
return s.uint64Tofloat32(n, x, ft, tt)
|
||||
}
|
||||
if tt.Size() == 8 {
|
||||
return s.uint64Tofloat64(n, x, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
|
||||
}
|
||||
// ft is float32 or float64, and tt is unsigned integer
|
||||
if ft.Size() == 4 {
|
||||
return s.float32ToUint64(n, x, ft, tt)
|
||||
}
|
||||
if ft.Size() == 8 {
|
||||
return s.float64ToUint64(n, x, ft, tt)
|
||||
}
|
||||
s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
|
||||
return nil
|
||||
}
|
||||
|
||||
if ft.IsComplex() && tt.IsComplex() {
|
||||
var op ssa.Op
|
||||
if ft.Size() == tt.Size() {
|
||||
switch ft.Size() {
|
||||
case 8:
|
||||
op = ssa.OpRound32F
|
||||
case 16:
|
||||
op = ssa.OpRound64F
|
||||
default:
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
} else if ft.Size() == 8 && tt.Size() == 16 {
|
||||
op = ssa.OpCvt32Fto64F
|
||||
} else if ft.Size() == 16 && tt.Size() == 8 {
|
||||
op = ssa.OpCvt64Fto32F
|
||||
} else {
|
||||
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
|
||||
}
|
||||
ftp := types.FloatForComplex(ft)
|
||||
ttp := types.FloatForComplex(tt)
|
||||
return s.newValue2(ssa.OpComplexMake, tt,
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
|
||||
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
|
||||
}
|
||||
|
||||
s.Fatalf("unhandled OCONV %s -> %s", n.X.Type().Kind(), n.Type().Kind())
|
||||
return nil
|
||||
return s.conv(n, x, n.X.Type(), n.Type())
|
||||
|
||||
case ir.ODOTTYPE:
|
||||
n := n.(*ir.TypeAssertExpr)
|
||||
@@ -5116,6 +5118,18 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
||||
for _, p := range params.InParams() { // includes receiver for interface calls
|
||||
ACArgs = append(ACArgs, p.Type)
|
||||
}
|
||||
|
||||
// Split the entry block if there are open defers, because later calls to
|
||||
// openDeferSave may cause a mismatch between the mem for an OpDereference
|
||||
// and the call site which uses it. See #49282.
|
||||
if s.curBlock.ID == s.f.Entry.ID && s.hasOpenDefers {
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockPlain
|
||||
curb := s.f.NewBlock(ssa.BlockPlain)
|
||||
b.AddEdgeTo(curb)
|
||||
s.startBlock(curb)
|
||||
}
|
||||
|
||||
for i, n := range args {
|
||||
callArgs = append(callArgs, s.putArg(n, t.Params().Field(i).Type))
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func embedKind(typ *types.Type) int {
|
||||
if typ.Kind() == types.TSTRING {
|
||||
return embedString
|
||||
}
|
||||
if typ.Sym() == nil && typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
if typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
|
||||
@@ -1222,12 +1222,14 @@ func (r *importReader) node() ir.Node {
|
||||
switch op {
|
||||
case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER:
|
||||
n.Selection = r.exoticField()
|
||||
case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
|
||||
case ir.OMETHEXPR:
|
||||
n = typecheckMethodExpr(n).(*ir.SelectorExpr)
|
||||
case ir.ODOTMETH, ir.OCALLPART:
|
||||
// These require a Lookup to link to the correct declaration.
|
||||
rcvrType := expr.Type()
|
||||
typ := n.Type()
|
||||
n.Selection = Lookdot(n, rcvrType, 1)
|
||||
if op == ir.OCALLPART || op == ir.OMETHEXPR {
|
||||
if op == ir.OCALLPART {
|
||||
// Lookdot clobbers the opcode and type, undo that.
|
||||
n.SetOp(op)
|
||||
n.SetType(typ)
|
||||
|
||||
@@ -383,10 +383,11 @@ func tcSelect(sel *ir.SelectStmt) {
|
||||
n := Stmt(ncase.Comm)
|
||||
ncase.Comm = n
|
||||
oselrecv2 := func(dst, recv ir.Node, def bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
n.Def = def
|
||||
n.SetTypecheck(1)
|
||||
ncase.Comm = n
|
||||
selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
selrecv.Def = def
|
||||
selrecv.SetTypecheck(1)
|
||||
selrecv.SetInit(n.Init())
|
||||
ncase.Comm = selrecv
|
||||
}
|
||||
switch n.Op() {
|
||||
default:
|
||||
|
||||
@@ -625,6 +625,12 @@ func PtrDataSize(t *Type) int64 {
|
||||
}
|
||||
return lastPtrField.Offset + PtrDataSize(lastPtrField.Type)
|
||||
|
||||
case TSSA:
|
||||
if t != TypeInt128 {
|
||||
base.Fatalf("PtrDataSize: unexpected ssa type %v", t)
|
||||
}
|
||||
return 0
|
||||
|
||||
default:
|
||||
base.Fatalf("PtrDataSize: unexpected type, %v", t)
|
||||
return 0
|
||||
|
||||
@@ -1661,6 +1661,11 @@ var (
|
||||
TypeResultMem = newResults([]*Type{TypeMem})
|
||||
)
|
||||
|
||||
func init() {
|
||||
TypeInt128.Width = 16
|
||||
TypeInt128.Align = 8
|
||||
}
|
||||
|
||||
// NewNamed returns a new named type for the given type name. obj should be an
|
||||
// ir.Name. The new type is incomplete (marked as TFORW kind), and the underlying
|
||||
// type should be set later via SetUnderlying(). References to the type are
|
||||
|
||||
@@ -621,6 +621,12 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
|
||||
// not a special composite literal assignment
|
||||
return false
|
||||
}
|
||||
if x.Addrtaken() {
|
||||
// If x is address-taken, the RHS may (implicitly) uses LHS.
|
||||
// Not safe to do a special composite literal assignment
|
||||
// (which may expand to multiple assignments).
|
||||
return false
|
||||
}
|
||||
|
||||
switch n.Y.Op() {
|
||||
default:
|
||||
@@ -629,7 +635,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
|
||||
|
||||
case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
|
||||
if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
|
||||
// not a special composite literal assignment
|
||||
// not safe to do a special composite literal assignment if RHS uses LHS.
|
||||
return false
|
||||
}
|
||||
anylit(n.Y, n.X, init)
|
||||
|
||||
53
src/cmd/dist/exec.go
vendored
Normal file
53
src/cmd/dist/exec.go
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2021 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 (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// setDir sets cmd.Dir to dir, and also adds PWD=dir to cmd's environment.
|
||||
func setDir(cmd *exec.Cmd, dir string) {
|
||||
cmd.Dir = dir
|
||||
setEnv(cmd, "PWD", dir)
|
||||
}
|
||||
|
||||
// setEnv sets cmd.Env so that key = value.
|
||||
//
|
||||
// It first removes any existing values for key, so it is safe to call
|
||||
// even from within cmdbootstrap.
|
||||
func setEnv(cmd *exec.Cmd, key, value string) {
|
||||
kv := key + "=" + value
|
||||
if cmd.Env == nil {
|
||||
cmd.Env = os.Environ()
|
||||
}
|
||||
|
||||
prefix := kv[:len(key)+1]
|
||||
for i, entry := range cmd.Env {
|
||||
if strings.HasPrefix(entry, prefix) {
|
||||
cmd.Env[i] = kv
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cmd.Env = append(cmd.Env, kv)
|
||||
}
|
||||
|
||||
// unsetEnv sets cmd.Env so that key is not present in the environment.
|
||||
func unsetEnv(cmd *exec.Cmd, key string) {
|
||||
if cmd.Env == nil {
|
||||
cmd.Env = os.Environ()
|
||||
}
|
||||
|
||||
prefix := key + "="
|
||||
for i, entry := range cmd.Env {
|
||||
if strings.HasPrefix(entry, prefix) {
|
||||
cmd.Env = append(cmd.Env[:i], cmd.Env[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/cmd/dist/test.go
vendored
58
src/cmd/dist/test.go
vendored
@@ -522,7 +522,8 @@ func (t *tester) registerTests() {
|
||||
heading: "GOOS=ios on darwin/amd64",
|
||||
fn: func(dt *distTest) error {
|
||||
cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
|
||||
cmd.Env = append(os.Environ(), "GOOS=ios", "CGO_ENABLED=1")
|
||||
setEnv(cmd, "GOOS", "ios")
|
||||
setEnv(cmd, "CGO_ENABLED", "1")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
@@ -542,7 +543,7 @@ func (t *tester) registerTests() {
|
||||
cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
|
||||
// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
|
||||
// creation of first goroutines and first garbage collections in the parallel setting.
|
||||
cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
|
||||
setEnv(cmd, "GOMAXPROCS", "2")
|
||||
return nil
|
||||
},
|
||||
})
|
||||
@@ -563,7 +564,7 @@ func (t *tester) registerTests() {
|
||||
return nil
|
||||
}
|
||||
cmd := exec.Command("go", "test")
|
||||
cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
|
||||
setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
@@ -600,16 +601,13 @@ func (t *tester) registerTests() {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run `go test fmt` in the moved GOROOT.
|
||||
// Run `go test fmt` in the moved GOROOT, without explicitly setting
|
||||
// GOROOT in the environment. The 'go' command should find itself.
|
||||
cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
// Don't set GOROOT in the environment.
|
||||
for _, e := range os.Environ() {
|
||||
if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") {
|
||||
cmd.Env = append(cmd.Env, e)
|
||||
}
|
||||
}
|
||||
unsetEnv(cmd, "GOROOT")
|
||||
unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
|
||||
err := cmd.Run()
|
||||
|
||||
if rerr := os.Rename(moved, goroot); rerr != nil {
|
||||
@@ -736,11 +734,9 @@ func (t *tester) registerTests() {
|
||||
heading: "../misc/swig/callback",
|
||||
fn: func(dt *distTest) error {
|
||||
cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
|
||||
cmd.Env = append(os.Environ(),
|
||||
"CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
|
||||
"CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
|
||||
"CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
|
||||
)
|
||||
setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
|
||||
setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
|
||||
setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -892,9 +888,9 @@ func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{})
|
||||
func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
|
||||
cmd := exec.Command(bin, args...)
|
||||
if filepath.IsAbs(dir) {
|
||||
cmd.Dir = dir
|
||||
setDir(cmd, dir)
|
||||
} else {
|
||||
cmd.Dir = filepath.Join(goroot, dir)
|
||||
setDir(cmd, filepath.Join(goroot, dir))
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
@@ -1132,7 +1128,8 @@ func (t *tester) runHostTest(dir, pkg string) error {
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
|
||||
cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos)
|
||||
setEnv(cmd, "GOARCH", gohostarch)
|
||||
setEnv(cmd, "GOOS", gohostos)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1141,15 +1138,15 @@ func (t *tester) runHostTest(dir, pkg string) error {
|
||||
|
||||
func (t *tester) cgoTest(dt *distTest) error {
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
|
||||
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=auto")
|
||||
setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
|
||||
|
||||
// Skip internal linking cases on linux/arm64 to support GCC-9.4 and above.
|
||||
// Skip internal linking cases on arm64 to support GCC-9.4 and above.
|
||||
// See issue #39466.
|
||||
skipInternalLink := goarch == "arm64" && goos == "linux"
|
||||
skipInternalLink := goarch == "arm64" && goos != "darwin"
|
||||
|
||||
if t.internalLink() && !skipInternalLink {
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
|
||||
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=internal")
|
||||
setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
|
||||
}
|
||||
|
||||
pair := gohostos + "-" + goarch
|
||||
@@ -1161,9 +1158,9 @@ func (t *tester) cgoTest(dt *distTest) error {
|
||||
break
|
||||
}
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
|
||||
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
|
||||
setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
|
||||
|
||||
cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
|
||||
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
|
||||
|
||||
if t.supportedBuildmode("pie") {
|
||||
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
|
||||
@@ -1181,10 +1178,10 @@ func (t *tester) cgoTest(dt *distTest) error {
|
||||
"openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
|
||||
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
|
||||
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
|
||||
setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
|
||||
// cgo should be able to cope with both -g arguments and colored
|
||||
// diagnostics.
|
||||
cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
|
||||
setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
|
||||
|
||||
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
|
||||
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
|
||||
@@ -1217,7 +1214,7 @@ func (t *tester) cgoTest(dt *distTest) error {
|
||||
// than -static in -extldflags, so test both.
|
||||
// See issue #16651.
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
|
||||
cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread")
|
||||
setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1456,7 +1453,7 @@ func (t *tester) raceTest(dt *distTest) error {
|
||||
// We shouldn't need to redo all of misc/cgo/test too.
|
||||
// The race buildler will take care of this.
|
||||
// cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
|
||||
// cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
|
||||
// setEnv(cmd, "GOTRACEBACK", "2")
|
||||
}
|
||||
if t.extLink() {
|
||||
// Test with external linking; see issue 9133.
|
||||
@@ -1486,7 +1483,8 @@ func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
|
||||
})
|
||||
|
||||
cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
|
||||
cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
|
||||
setEnv(cmd, "GOOS", gohostos)
|
||||
setEnv(cmd, "GOARCH", gohostarch)
|
||||
runtest.err = cmd.Run()
|
||||
})
|
||||
if runtest.err != nil {
|
||||
@@ -1650,7 +1648,7 @@ func (t *tester) runPrecompiledStdTest(timeout time.Duration) error {
|
||||
bin := t.prebuiltGoPackageTestBinary()
|
||||
fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
|
||||
cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String())
|
||||
cmd.Dir = filepath.Dir(bin)
|
||||
setDir(cmd, filepath.Dir(bin))
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
|
||||
2
src/cmd/dist/util.go
vendored
2
src/cmd/dist/util.go
vendored
@@ -72,7 +72,7 @@ func run(dir string, mode int, cmd ...string) string {
|
||||
}
|
||||
|
||||
xcmd := exec.Command(cmd[0], cmd[1:]...)
|
||||
xcmd.Dir = dir
|
||||
setDir(xcmd, dir)
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
|
||||
@@ -4,12 +4,15 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||
golang.org/x/mod v0.5.1
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect
|
||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
)
|
||||
|
||||
@@ -10,11 +10,11 @@ golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjc
|
||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU=
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
|
||||
@@ -2,17 +2,51 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copied from Go distribution src/go/build/build.go, syslist.go
|
||||
// Copied from Go distribution src/go/build/build.go, syslist.go.
|
||||
// That package does not export the ability to process raw file data,
|
||||
// although we could fake it with an appropriate build.Context
|
||||
// and a lot of unwrapping.
|
||||
// More importantly, that package does not implement the tags["*"]
|
||||
// special case, in which both tag and !tag are considered to be true
|
||||
// for essentially all tags (except "ignore").
|
||||
//
|
||||
// If we added this API to go/build directly, we wouldn't need this
|
||||
// file anymore, but this API is not terribly general-purpose and we
|
||||
// don't really want to commit to any public form of it, nor do we
|
||||
// want to move the core parts of go/build into a top-level internal package.
|
||||
// These details change very infrequently, so the copy is fine.
|
||||
|
||||
package imports
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var slashslash = []byte("//")
|
||||
var (
|
||||
bSlashSlash = []byte("//")
|
||||
bStarSlash = []byte("*/")
|
||||
bSlashStar = []byte("/*")
|
||||
bPlusBuild = []byte("+build")
|
||||
|
||||
goBuildComment = []byte("//go:build")
|
||||
|
||||
errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
|
||||
errMultipleGoBuild = errors.New("multiple //go:build comments")
|
||||
)
|
||||
|
||||
func isGoBuildComment(line []byte) bool {
|
||||
if !bytes.HasPrefix(line, goBuildComment) {
|
||||
return false
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
rest := line[len(goBuildComment):]
|
||||
return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
|
||||
}
|
||||
|
||||
// ShouldBuild reports whether it is okay to use this file,
|
||||
// The rule is that in the file's leading run of // comments
|
||||
@@ -34,90 +68,124 @@ var slashslash = []byte("//")
|
||||
// in any build.
|
||||
//
|
||||
func ShouldBuild(content []byte, tags map[string]bool) bool {
|
||||
// Pass 1. Identify leading run of // comments and blank lines,
|
||||
// Identify leading run of // comments and blank lines,
|
||||
// which must be followed by a blank line.
|
||||
end := 0
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 { // Blank line
|
||||
end = len(content) - len(p)
|
||||
continue
|
||||
}
|
||||
if !bytes.HasPrefix(line, slashslash) { // Not comment line
|
||||
break
|
||||
}
|
||||
// Also identify any //go:build comments.
|
||||
content, goBuild, _, err := parseFileHeader(content)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
content = content[:end]
|
||||
|
||||
// Pass 2. Process each line in the run.
|
||||
p = content
|
||||
allok := true
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
// If //go:build line is present, it controls.
|
||||
// Otherwise fall back to +build processing.
|
||||
var shouldBuild bool
|
||||
switch {
|
||||
case goBuild != nil:
|
||||
x, err := constraint.Parse(string(goBuild))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if !bytes.HasPrefix(line, slashslash) {
|
||||
continue
|
||||
}
|
||||
line = bytes.TrimSpace(line[len(slashslash):])
|
||||
if len(line) > 0 && line[0] == '+' {
|
||||
// Looks like a comment +line.
|
||||
f := strings.Fields(string(line))
|
||||
if f[0] == "+build" {
|
||||
ok := false
|
||||
for _, tok := range f[1:] {
|
||||
if matchTags(tok, tags) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
allok = false
|
||||
shouldBuild = eval(x, tags, true)
|
||||
|
||||
default:
|
||||
shouldBuild = true
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
|
||||
continue
|
||||
}
|
||||
text := string(line)
|
||||
if !constraint.IsPlusBuild(text) {
|
||||
continue
|
||||
}
|
||||
if x, err := constraint.Parse(text); err == nil {
|
||||
if !eval(x, tags, true) {
|
||||
shouldBuild = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allok
|
||||
return shouldBuild
|
||||
}
|
||||
|
||||
// matchTags reports whether the name is one of:
|
||||
//
|
||||
// tag (if tags[tag] is true)
|
||||
// !tag (if tags[tag] is false)
|
||||
// a comma-separated list of any of these
|
||||
//
|
||||
func matchTags(name string, tags map[string]bool) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
|
||||
end := 0
|
||||
p := content
|
||||
ended := false // found non-blank, non-// line, so stopped accepting // +build lines
|
||||
inSlashStar := false // in /* */ comment
|
||||
|
||||
Lines:
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 && !ended { // Blank line
|
||||
// Remember position of most recent blank line.
|
||||
// When we find the first non-blank, non-// line,
|
||||
// this "end" position marks the latest file position
|
||||
// where a // +build line can appear.
|
||||
// (It must appear _before_ a blank line before the non-blank, non-// line.
|
||||
// Yes, that's confusing, which is part of why we moved to //go:build lines.)
|
||||
// Note that ended==false here means that inSlashStar==false,
|
||||
// since seeing a /* would have set ended==true.
|
||||
end = len(content) - len(p)
|
||||
continue Lines
|
||||
}
|
||||
if !bytes.HasPrefix(line, bSlashSlash) { // Not comment line
|
||||
ended = true
|
||||
}
|
||||
|
||||
if !inSlashStar && isGoBuildComment(line) {
|
||||
if goBuild != nil {
|
||||
return nil, nil, false, errMultipleGoBuild
|
||||
}
|
||||
goBuild = line
|
||||
}
|
||||
|
||||
Comments:
|
||||
for len(line) > 0 {
|
||||
if inSlashStar {
|
||||
if i := bytes.Index(line, bStarSlash); i >= 0 {
|
||||
inSlashStar = false
|
||||
line = bytes.TrimSpace(line[i+len(bStarSlash):])
|
||||
continue Comments
|
||||
}
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashSlash) {
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashStar) {
|
||||
inSlashStar = true
|
||||
line = bytes.TrimSpace(line[len(bSlashStar):])
|
||||
continue Comments
|
||||
}
|
||||
// Found non-comment text.
|
||||
break Lines
|
||||
}
|
||||
}
|
||||
if i := strings.Index(name, ","); i >= 0 {
|
||||
// comma-separated list
|
||||
ok1 := matchTags(name[:i], tags)
|
||||
ok2 := matchTags(name[i+1:], tags)
|
||||
return ok1 && ok2
|
||||
}
|
||||
if strings.HasPrefix(name, "!!") { // bad syntax, reject always
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(name, "!") { // negation
|
||||
return len(name) > 1 && matchTag(name[1:], tags, false)
|
||||
}
|
||||
return matchTag(name, tags, true)
|
||||
|
||||
return content[:end], goBuild, sawBinaryOnly, nil
|
||||
}
|
||||
|
||||
// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
|
||||
func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
// matchTag reports whether the tag name is valid and tags[name] is true.
|
||||
// As a special case, if tags["*"] is true and name is not empty or ignore,
|
||||
// then matchTag will return prefer instead of the actual answer,
|
||||
// which allows the caller to pretend in that case that most tags are
|
||||
// both true and false.
|
||||
func matchTag(name string, tags map[string]bool, prefer bool) bool {
|
||||
// Tags must be letters, digits, underscores or dots.
|
||||
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||
for _, c := range name {
|
||||
@@ -131,7 +199,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
// if we put * in the tags map then all tags
|
||||
// except "ignore" are considered both present and not
|
||||
// (so we return true no matter how 'want' is set).
|
||||
return true
|
||||
return prefer
|
||||
}
|
||||
|
||||
have := tags[name]
|
||||
@@ -144,7 +212,25 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
if name == "darwin" {
|
||||
have = have || tags["ios"]
|
||||
}
|
||||
return have == want
|
||||
return have
|
||||
}
|
||||
|
||||
// eval is like
|
||||
// x.Eval(func(tag string) bool { return matchTag(tag, tags) })
|
||||
// except that it implements the special case for tags["*"] meaning
|
||||
// all tags are both true and false at the same time.
|
||||
func eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
|
||||
switch x := x.(type) {
|
||||
case *constraint.TagExpr:
|
||||
return matchTag(x.Tag, tags, prefer)
|
||||
case *constraint.NotExpr:
|
||||
return !eval(x.X, tags, !prefer)
|
||||
case *constraint.AndExpr:
|
||||
return eval(x.X, tags, prefer) && eval(x.Y, tags, prefer)
|
||||
case *constraint.OrExpr:
|
||||
return eval(x.X, tags, prefer) || eval(x.Y, tags, prefer)
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected constraint expression %T", x))
|
||||
}
|
||||
|
||||
// MatchFile returns false if the name contains a $GOOS or $GOARCH
|
||||
|
||||
@@ -440,7 +440,7 @@ func (r *gitRepo) fetchRefsLocked() error {
|
||||
// statLocal returns a RevInfo describing rev in the local git repository.
|
||||
// It uses version as info.Version.
|
||||
func (r *gitRepo) statLocal(version, rev string) (*RevInfo, error) {
|
||||
out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "-n1", "--format=format:%H %ct %D", rev, "--")
|
||||
out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D", rev, "--")
|
||||
if err != nil {
|
||||
return nil, &UnknownRevisionError{Rev: rev}
|
||||
}
|
||||
|
||||
@@ -298,42 +298,61 @@ func (r *codeRepo) Latest() (*RevInfo, error) {
|
||||
// If statVers is a valid module version, it is used for the Version field.
|
||||
// Otherwise, the Version is derived from the passed-in info and recent tags.
|
||||
func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
|
||||
info2 := &RevInfo{
|
||||
Name: info.Name,
|
||||
Short: info.Short,
|
||||
Time: info.Time,
|
||||
}
|
||||
|
||||
// If this is a plain tag (no dir/ prefix)
|
||||
// and the module path is unversioned,
|
||||
// and if the underlying file tree has no go.mod,
|
||||
// then allow using the tag with a +incompatible suffix.
|
||||
var canUseIncompatible func() bool
|
||||
canUseIncompatible = func() bool {
|
||||
var ok bool
|
||||
if r.codeDir == "" && r.pathMajor == "" {
|
||||
//
|
||||
// (If the version is +incompatible, then the go.mod file must not exist:
|
||||
// +incompatible is not an ongoing opt-out from semantic import versioning.)
|
||||
incompatibleOk := map[string]bool{}
|
||||
canUseIncompatible := func(v string) bool {
|
||||
if r.codeDir != "" || r.pathMajor != "" {
|
||||
// A non-empty codeDir indicates a module within a subdirectory,
|
||||
// which necessarily has a go.mod file indicating the module boundary.
|
||||
// A non-empty pathMajor indicates a module path with a major-version
|
||||
// suffix, which must match.
|
||||
return false
|
||||
}
|
||||
|
||||
ok, seen := incompatibleOk[""]
|
||||
if !seen {
|
||||
_, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod)
|
||||
if errGoMod != nil {
|
||||
ok = true
|
||||
ok = (errGoMod != nil)
|
||||
incompatibleOk[""] = ok
|
||||
}
|
||||
if !ok {
|
||||
// A go.mod file exists at the repo root.
|
||||
return false
|
||||
}
|
||||
|
||||
// Per https://go.dev/issue/51324, previous versions of the 'go' command
|
||||
// didn't always check for go.mod files in subdirectories, so if the user
|
||||
// requests a +incompatible version explicitly, we should continue to allow
|
||||
// it. Otherwise, if vN/go.mod exists, expect that release tags for that
|
||||
// major version are intended for the vN module.
|
||||
if v != "" && !strings.HasSuffix(statVers, "+incompatible") {
|
||||
major := semver.Major(v)
|
||||
ok, seen = incompatibleOk[major]
|
||||
if !seen {
|
||||
_, errGoModSub := r.code.ReadFile(info.Name, path.Join(major, "go.mod"), codehost.MaxGoMod)
|
||||
ok = (errGoModSub != nil)
|
||||
incompatibleOk[major] = ok
|
||||
}
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
canUseIncompatible = func() bool { return ok }
|
||||
return ok
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
invalidf := func(format string, args ...interface{}) error {
|
||||
return &module.ModuleError{
|
||||
Path: r.modPath,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: info2.Version,
|
||||
Err: fmt.Errorf(format, args...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// checkGoMod verifies that the go.mod file for the module exists or does not
|
||||
// exist as required by info2.Version and the module path represented by r.
|
||||
checkGoMod := func() (*RevInfo, error) {
|
||||
// checkCanonical verifies that the canonical version v is compatible with the
|
||||
// module path represented by r, adding a "+incompatible" suffix if needed.
|
||||
//
|
||||
// If statVers is also canonical, checkCanonical also verifies that v is
|
||||
// either statVers or statVers with the added "+incompatible" suffix.
|
||||
checkCanonical := func(v string) (*RevInfo, error) {
|
||||
// If r.codeDir is non-empty, then the go.mod file must exist: the module
|
||||
// author — not the module consumer, — gets to decide how to carve up the repo
|
||||
// into modules.
|
||||
@@ -344,73 +363,91 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
||||
// r.findDir verifies both of these conditions. Execute it now so that
|
||||
// r.Stat will correctly return a notExistError if the go.mod location or
|
||||
// declared module path doesn't match.
|
||||
_, _, _, err := r.findDir(info2.Version)
|
||||
_, _, _, err := r.findDir(v)
|
||||
if err != nil {
|
||||
// TODO: It would be nice to return an error like "not a module".
|
||||
// Right now we return "missing go.mod", which is a little confusing.
|
||||
return nil, &module.ModuleError{
|
||||
Path: r.modPath,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: info2.Version,
|
||||
Version: v,
|
||||
Err: notExistError{err: err},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// If the version is +incompatible, then the go.mod file must not exist:
|
||||
// +incompatible is not an ongoing opt-out from semantic import versioning.
|
||||
if strings.HasSuffix(info2.Version, "+incompatible") {
|
||||
if !canUseIncompatible() {
|
||||
if r.pathMajor != "" {
|
||||
return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match")
|
||||
} else {
|
||||
return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required")
|
||||
}
|
||||
}
|
||||
|
||||
if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil {
|
||||
return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version))
|
||||
invalidf := func(format string, args ...interface{}) error {
|
||||
return &module.ModuleError{
|
||||
Path: r.modPath,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: v,
|
||||
Err: fmt.Errorf(format, args...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return info2, nil
|
||||
// Add the +incompatible suffix if needed or requested explicitly, and
|
||||
// verify that its presence or absence is appropriate for this version
|
||||
// (which depends on whether it has an explicit go.mod file).
|
||||
|
||||
if v == strings.TrimSuffix(statVers, "+incompatible") {
|
||||
v = statVers
|
||||
}
|
||||
base := strings.TrimSuffix(v, "+incompatible")
|
||||
var errIncompatible error
|
||||
if !module.MatchPathMajor(base, r.pathMajor) {
|
||||
if canUseIncompatible(base) {
|
||||
v = base + "+incompatible"
|
||||
} else {
|
||||
if r.pathMajor != "" {
|
||||
errIncompatible = invalidf("module path includes a major version suffix, so major version must match")
|
||||
} else {
|
||||
errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v)))
|
||||
}
|
||||
}
|
||||
} else if strings.HasSuffix(v, "+incompatible") {
|
||||
errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v))
|
||||
}
|
||||
|
||||
if statVers != "" && statVers == module.CanonicalVersion(statVers) {
|
||||
// Since the caller-requested version is canonical, it would be very
|
||||
// confusing to resolve it to anything but itself, possibly with a
|
||||
// "+incompatible" suffix. Error out explicitly.
|
||||
if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base {
|
||||
return nil, &module.ModuleError{
|
||||
Path: r.modPath,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: statVers,
|
||||
Err: fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errIncompatible != nil {
|
||||
return nil, errIncompatible
|
||||
}
|
||||
|
||||
return &RevInfo{
|
||||
Name: info.Name,
|
||||
Short: info.Short,
|
||||
Time: info.Time,
|
||||
Version: v,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Determine version.
|
||||
//
|
||||
// If statVers is canonical, then the original call was repo.Stat(statVers).
|
||||
// Since the version is canonical, we must not resolve it to anything but
|
||||
// itself, possibly with a '+incompatible' annotation: we do not need to do
|
||||
// the work required to look for an arbitrary pseudo-version.
|
||||
if statVers != "" && statVers == module.CanonicalVersion(statVers) {
|
||||
info2.Version = statVers
|
||||
|
||||
if module.IsPseudoVersion(info2.Version) {
|
||||
if err := r.validatePseudoVersion(info, info2.Version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return checkGoMod()
|
||||
if module.IsPseudoVersion(statVers) {
|
||||
if err := r.validatePseudoVersion(info, statVers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil {
|
||||
if canUseIncompatible() {
|
||||
info2.Version += "+incompatible"
|
||||
return checkGoMod()
|
||||
} else {
|
||||
if vErr, ok := err.(*module.InvalidVersionError); ok {
|
||||
// We're going to describe why the version is invalid in more detail,
|
||||
// so strip out the existing “invalid version” wrapper.
|
||||
err = vErr.Err
|
||||
}
|
||||
return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return checkGoMod()
|
||||
return checkCanonical(statVers)
|
||||
}
|
||||
|
||||
// statVers is empty or non-canonical, so we need to resolve it to a canonical
|
||||
// version or pseudo-version.
|
||||
// statVers is not a pseudo-version, so we need to either resolve it to a
|
||||
// canonical version or verify that it is already a canonical tag
|
||||
// (not a branch).
|
||||
|
||||
// Derive or verify a version from a code repo tag.
|
||||
// Tag must have a prefix matching codeDir.
|
||||
@@ -441,71 +478,62 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
||||
if v == "" || !strings.HasPrefix(trimmed, v) {
|
||||
return "", false // Invalid or incomplete version (just vX or vX.Y).
|
||||
}
|
||||
if isRetracted(v) {
|
||||
return "", false
|
||||
}
|
||||
if v == trimmed {
|
||||
tagIsCanonical = true
|
||||
}
|
||||
|
||||
if err := module.CheckPathMajor(v, r.pathMajor); err != nil {
|
||||
if canUseIncompatible() {
|
||||
return v + "+incompatible", tagIsCanonical
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
return v, tagIsCanonical
|
||||
}
|
||||
|
||||
// If the VCS gave us a valid version, use that.
|
||||
if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical {
|
||||
info2.Version = v
|
||||
return checkGoMod()
|
||||
if info, err := checkCanonical(v); err == nil {
|
||||
return info, err
|
||||
}
|
||||
}
|
||||
|
||||
// Look through the tags on the revision for either a usable canonical version
|
||||
// or an appropriate base for a pseudo-version.
|
||||
var pseudoBase string
|
||||
var (
|
||||
highestCanonical string
|
||||
pseudoBase string
|
||||
)
|
||||
for _, pathTag := range info.Tags {
|
||||
v, tagIsCanonical := tagToVersion(pathTag)
|
||||
if tagIsCanonical {
|
||||
if statVers != "" && semver.Compare(v, statVers) == 0 {
|
||||
// The user requested a non-canonical version, but the tag for the
|
||||
// canonical equivalent refers to the same revision. Use it.
|
||||
info2.Version = v
|
||||
return checkGoMod()
|
||||
if statVers != "" && semver.Compare(v, statVers) == 0 {
|
||||
// The tag is equivalent to the version requested by the user.
|
||||
if tagIsCanonical {
|
||||
// This tag is the canonical form of the requested version,
|
||||
// not some other form with extra build metadata.
|
||||
// Use this tag so that the resolved version will match exactly.
|
||||
// (If it isn't actually allowed, we'll error out in checkCanonical.)
|
||||
return checkCanonical(v)
|
||||
} else {
|
||||
// Save the highest canonical tag for the revision. If we don't find a
|
||||
// better match, we'll use it as the canonical version.
|
||||
// The user explicitly requested something equivalent to this tag. We
|
||||
// can't use the version from the tag directly: since the tag is not
|
||||
// canonical, it could be ambiguous. For example, tags v0.0.1+a and
|
||||
// v0.0.1+b might both exist and refer to different revisions.
|
||||
//
|
||||
// NOTE: Do not replace this with semver.Max. Despite the name,
|
||||
// semver.Max *also* canonicalizes its arguments, which uses
|
||||
// semver.Canonical instead of module.CanonicalVersion and thereby
|
||||
// strips our "+incompatible" suffix.
|
||||
if semver.Compare(info2.Version, v) < 0 {
|
||||
info2.Version = v
|
||||
}
|
||||
// The tag is otherwise valid for the module, so we can at least use it as
|
||||
// the base of an unambiguous pseudo-version.
|
||||
//
|
||||
// If multiple tags match, tagToVersion will canonicalize them to the same
|
||||
// base version.
|
||||
pseudoBase = v
|
||||
}
|
||||
}
|
||||
// Save the highest non-retracted canonical tag for the revision.
|
||||
// If we don't find a better match, we'll use it as the canonical version.
|
||||
if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
|
||||
if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible(v) {
|
||||
highestCanonical = v
|
||||
}
|
||||
} else if v != "" && semver.Compare(v, statVers) == 0 {
|
||||
// The user explicitly requested something equivalent to this tag. We
|
||||
// can't use the version from the tag directly: since the tag is not
|
||||
// canonical, it could be ambiguous. For example, tags v0.0.1+a and
|
||||
// v0.0.1+b might both exist and refer to different revisions.
|
||||
//
|
||||
// The tag is otherwise valid for the module, so we can at least use it as
|
||||
// the base of an unambiguous pseudo-version.
|
||||
//
|
||||
// If multiple tags match, tagToVersion will canonicalize them to the same
|
||||
// base version.
|
||||
pseudoBase = v
|
||||
}
|
||||
}
|
||||
|
||||
// If we found any canonical tag for the revision, return it.
|
||||
// If we found a valid canonical tag for the revision, return it.
|
||||
// Even if we found a good pseudo-version base, a canonical version is better.
|
||||
if info2.Version != "" {
|
||||
return checkGoMod()
|
||||
if highestCanonical != "" {
|
||||
return checkCanonical(highestCanonical)
|
||||
}
|
||||
|
||||
// Find the highest tagged version in the revision's history, subject to
|
||||
@@ -514,12 +542,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
||||
// retracted versions.
|
||||
allowedMajor := func(major string) func(v string) bool {
|
||||
return func(v string) bool {
|
||||
return (major == "" || semver.Major(v) == major) && !isRetracted(v)
|
||||
return ((major == "" && canUseIncompatible(v)) || semver.Major(v) == major) && !isRetracted(v)
|
||||
}
|
||||
}
|
||||
if pseudoBase == "" {
|
||||
var tag string
|
||||
if r.pseudoMajor != "" || canUseIncompatible() {
|
||||
if r.pseudoMajor != "" || canUseIncompatible("") {
|
||||
tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor))
|
||||
} else {
|
||||
// Allow either v1 or v0, but not incompatible higher versions.
|
||||
@@ -528,11 +556,10 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
||||
tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0"))
|
||||
}
|
||||
}
|
||||
pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid
|
||||
pseudoBase, _ = tagToVersion(tag)
|
||||
}
|
||||
|
||||
info2.Version = module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short)
|
||||
return checkGoMod()
|
||||
return checkCanonical(module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short))
|
||||
}
|
||||
|
||||
// validatePseudoVersion checks that version has a major version compatible with
|
||||
@@ -556,10 +583,6 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := module.CheckPathMajor(version, r.pathMajor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rev, err := module.PseudoVersionRev(version)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -418,171 +418,252 @@ var codeRepoTests = []codeRepoTest{
|
||||
zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=",
|
||||
zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5",
|
||||
},
|
||||
{
|
||||
// Git branch with a semver name, +incompatible version, and no go.mod file.
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/go/mod/gitrepo1",
|
||||
rev: "v2.3.4+incompatible",
|
||||
err: `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`,
|
||||
},
|
||||
{
|
||||
// Git branch with a semver name, matching go.mod file, and compatible version.
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/semver-branch.git",
|
||||
rev: "v1.0.0",
|
||||
err: `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`,
|
||||
},
|
||||
{
|
||||
// Git branch with a semver name, matching go.mod file, and disallowed +incompatible version.
|
||||
// The version/tag mismatch takes precedence over the +incompatible mismatched.
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/semver-branch.git",
|
||||
rev: "v2.0.0+incompatible",
|
||||
err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
|
||||
},
|
||||
{
|
||||
// Git branch with a semver name, matching go.mod file, and mismatched version.
|
||||
// The version/tag mismatch takes precedence over the +incompatible mismatched.
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/semver-branch.git",
|
||||
rev: "v2.0.0",
|
||||
err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
|
||||
},
|
||||
{
|
||||
// v3.0.0-devel is the same as tag v4.0.0-beta.1, but v4.0.0-beta.1 would
|
||||
// not be allowed because it is incompatible and a go.mod file exists.
|
||||
// The error message should refer to a valid pseudo-version, not the
|
||||
// unusable semver tag.
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/semver-branch.git",
|
||||
rev: "v3.0.0-devel",
|
||||
err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
|
||||
},
|
||||
|
||||
// If v2/go.mod exists, then we should prefer to match the "v2"
|
||||
// pseudo-versions to the nested module, and resolve the module in the parent
|
||||
// directory to only compatible versions.
|
||||
//
|
||||
// However (https://go.dev/issue/51324), previous versions of the 'go' command
|
||||
// didn't always do so, so if the user explicitly requests a +incompatible
|
||||
// version (as would be present in an existing go.mod file), we should
|
||||
// continue to allow it.
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "80beb17a1603",
|
||||
version: "v0.0.0-20220222205507-80beb17a1603",
|
||||
name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
|
||||
short: "80beb17a1603",
|
||||
time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.0",
|
||||
err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.1-0.20220222205507-80beb17a1603",
|
||||
err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.0+incompatible",
|
||||
version: "v2.0.0+incompatible",
|
||||
name: "5fcd3eaeeb391d399f562fd45a50dac9fc34ae8b",
|
||||
short: "5fcd3eaeeb39",
|
||||
time: time.Date(2022, 2, 22, 20, 53, 33, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
|
||||
version: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
|
||||
name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
|
||||
short: "80beb17a1603",
|
||||
time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
|
||||
},
|
||||
}
|
||||
|
||||
func TestCodeRepo(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "modfetch-test-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
for _, tt := range codeRepoTests {
|
||||
f := func(tt codeRepoTest) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if tt.vcs != "mod" {
|
||||
testenv.MustHaveExecPath(t, tt.vcs)
|
||||
}
|
||||
|
||||
t.Run("parallel", func(t *testing.T) {
|
||||
for _, tt := range codeRepoTests {
|
||||
f := func(tt codeRepoTest) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if tt.vcs != "mod" {
|
||||
testenv.MustHaveExecPath(t, tt.vcs)
|
||||
}
|
||||
repo := Lookup("direct", tt.path)
|
||||
|
||||
repo := Lookup("direct", tt.path)
|
||||
if tt.mpath == "" {
|
||||
tt.mpath = tt.path
|
||||
}
|
||||
if mpath := repo.ModulePath(); mpath != tt.mpath {
|
||||
t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
|
||||
}
|
||||
|
||||
if tt.mpath == "" {
|
||||
tt.mpath = tt.path
|
||||
}
|
||||
if mpath := repo.ModulePath(); mpath != tt.mpath {
|
||||
t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
|
||||
}
|
||||
|
||||
info, err := repo.Stat(tt.rev)
|
||||
if err != nil {
|
||||
if tt.err != "" {
|
||||
if !strings.Contains(err.Error(), tt.err) {
|
||||
t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
|
||||
}
|
||||
return
|
||||
}
|
||||
t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
|
||||
}
|
||||
info, err := repo.Stat(tt.rev)
|
||||
if err != nil {
|
||||
if tt.err != "" {
|
||||
t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
|
||||
}
|
||||
if info.Version != tt.version {
|
||||
t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
|
||||
}
|
||||
if info.Name != tt.name {
|
||||
t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
|
||||
}
|
||||
if info.Short != tt.short {
|
||||
t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
|
||||
}
|
||||
if !info.Time.Equal(tt.time) {
|
||||
t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
|
||||
if !strings.Contains(err.Error(), tt.err) {
|
||||
t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
|
||||
}
|
||||
return
|
||||
}
|
||||
t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
|
||||
}
|
||||
if tt.err != "" {
|
||||
t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
|
||||
}
|
||||
if info.Version != tt.version {
|
||||
t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
|
||||
}
|
||||
if info.Name != tt.name {
|
||||
t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
|
||||
}
|
||||
if info.Short != tt.short {
|
||||
t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
|
||||
}
|
||||
if !info.Time.Equal(tt.time) {
|
||||
t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
|
||||
}
|
||||
|
||||
if tt.gomod != "" || tt.gomodErr != "" {
|
||||
data, err := repo.GoMod(tt.version)
|
||||
if err != nil && tt.gomodErr == "" {
|
||||
t.Errorf("repo.GoMod(%q): %v", tt.version, err)
|
||||
} else if err != nil && tt.gomodErr != "" {
|
||||
if err.Error() != tt.gomodErr {
|
||||
t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
|
||||
}
|
||||
} else if tt.gomodErr != "" {
|
||||
t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
|
||||
} else if string(data) != tt.gomod {
|
||||
t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
|
||||
}
|
||||
}
|
||||
|
||||
needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
|
||||
if tt.zip != nil || tt.zipErr != "" || needHash {
|
||||
f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
|
||||
if err != nil {
|
||||
t.Fatalf("os.CreateTemp: %v", err)
|
||||
}
|
||||
zipfile := f.Name()
|
||||
defer func() {
|
||||
f.Close()
|
||||
os.Remove(zipfile)
|
||||
}()
|
||||
|
||||
var w io.Writer
|
||||
var h hash.Hash
|
||||
if needHash {
|
||||
h = sha256.New()
|
||||
w = io.MultiWriter(f, h)
|
||||
} else {
|
||||
w = f
|
||||
}
|
||||
err = repo.Zip(w, tt.version)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
if tt.zipErr != "" {
|
||||
if err.Error() == tt.zipErr {
|
||||
return
|
||||
}
|
||||
t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
|
||||
}
|
||||
t.Fatalf("repo.Zip(%q): %v", tt.version, err)
|
||||
}
|
||||
if tt.zipErr != "" {
|
||||
t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
|
||||
}
|
||||
|
||||
if tt.zip != nil {
|
||||
prefix := tt.path + "@" + tt.version + "/"
|
||||
z, err := zip.OpenReader(zipfile)
|
||||
if err != nil {
|
||||
t.Fatalf("open zip %s: %v", zipfile, err)
|
||||
}
|
||||
var names []string
|
||||
for _, file := range z.File {
|
||||
if !strings.HasPrefix(file.Name, prefix) {
|
||||
t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
|
||||
continue
|
||||
}
|
||||
names = append(names, file.Name[len(prefix):])
|
||||
}
|
||||
z.Close()
|
||||
if !reflect.DeepEqual(names, tt.zip) {
|
||||
t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
|
||||
}
|
||||
}
|
||||
|
||||
if needHash {
|
||||
sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
|
||||
if err != nil {
|
||||
t.Errorf("repo.Zip(%q): %v", tt.version, err)
|
||||
} else if sum != tt.zipSum {
|
||||
t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
|
||||
} else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
|
||||
t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
|
||||
}
|
||||
if tt.gomod != "" || tt.gomodErr != "" {
|
||||
data, err := repo.GoMod(tt.version)
|
||||
if err != nil && tt.gomodErr == "" {
|
||||
t.Errorf("repo.GoMod(%q): %v", tt.version, err)
|
||||
} else if err != nil && tt.gomodErr != "" {
|
||||
if err.Error() != tt.gomodErr {
|
||||
t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
|
||||
}
|
||||
} else if tt.gomodErr != "" {
|
||||
t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
|
||||
} else if string(data) != tt.gomod {
|
||||
t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
|
||||
if strings.HasPrefix(tt.path, vgotest1git) {
|
||||
for vcs, alt := range altVgotests {
|
||||
altTest := tt
|
||||
altTest.vcs = vcs
|
||||
altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
|
||||
if strings.HasPrefix(altTest.mpath, vgotest1git) {
|
||||
altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
|
||||
|
||||
needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
|
||||
if tt.zip != nil || tt.zipErr != "" || needHash {
|
||||
f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
|
||||
if err != nil {
|
||||
t.Fatalf("os.CreateTemp: %v", err)
|
||||
}
|
||||
var m map[string]string
|
||||
if alt == vgotest1hg {
|
||||
m = hgmap
|
||||
zipfile := f.Name()
|
||||
defer func() {
|
||||
f.Close()
|
||||
os.Remove(zipfile)
|
||||
}()
|
||||
|
||||
var w io.Writer
|
||||
var h hash.Hash
|
||||
if needHash {
|
||||
h = sha256.New()
|
||||
w = io.MultiWriter(f, h)
|
||||
} else {
|
||||
w = f
|
||||
}
|
||||
err = repo.Zip(w, tt.version)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
if tt.zipErr != "" {
|
||||
if err.Error() == tt.zipErr {
|
||||
return
|
||||
}
|
||||
t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
|
||||
}
|
||||
t.Fatalf("repo.Zip(%q): %v", tt.version, err)
|
||||
}
|
||||
if tt.zipErr != "" {
|
||||
t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
|
||||
}
|
||||
|
||||
if tt.zip != nil {
|
||||
prefix := tt.path + "@" + tt.version + "/"
|
||||
z, err := zip.OpenReader(zipfile)
|
||||
if err != nil {
|
||||
t.Fatalf("open zip %s: %v", zipfile, err)
|
||||
}
|
||||
var names []string
|
||||
for _, file := range z.File {
|
||||
if !strings.HasPrefix(file.Name, prefix) {
|
||||
t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
|
||||
continue
|
||||
}
|
||||
names = append(names, file.Name[len(prefix):])
|
||||
}
|
||||
z.Close()
|
||||
if !reflect.DeepEqual(names, tt.zip) {
|
||||
t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
|
||||
}
|
||||
}
|
||||
|
||||
if needHash {
|
||||
sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
|
||||
if err != nil {
|
||||
t.Errorf("repo.Zip(%q): %v", tt.version, err)
|
||||
} else if sum != tt.zipSum {
|
||||
t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
|
||||
} else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
|
||||
t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
|
||||
}
|
||||
}
|
||||
altTest.version = remap(altTest.version, m)
|
||||
altTest.name = remap(altTest.name, m)
|
||||
altTest.short = remap(altTest.short, m)
|
||||
altTest.rev = remap(altTest.rev, m)
|
||||
altTest.err = remap(altTest.err, m)
|
||||
altTest.gomodErr = remap(altTest.gomodErr, m)
|
||||
altTest.zipErr = remap(altTest.zipErr, m)
|
||||
altTest.zipSum = ""
|
||||
altTest.zipFileHash = ""
|
||||
t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
|
||||
if strings.HasPrefix(tt.path, vgotest1git) {
|
||||
for vcs, alt := range altVgotests {
|
||||
altTest := tt
|
||||
altTest.vcs = vcs
|
||||
altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
|
||||
if strings.HasPrefix(altTest.mpath, vgotest1git) {
|
||||
altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
|
||||
}
|
||||
var m map[string]string
|
||||
if alt == vgotest1hg {
|
||||
m = hgmap
|
||||
}
|
||||
altTest.version = remap(altTest.version, m)
|
||||
altTest.name = remap(altTest.name, m)
|
||||
altTest.short = remap(altTest.short, m)
|
||||
altTest.rev = remap(altTest.rev, m)
|
||||
altTest.err = remap(altTest.err, m)
|
||||
altTest.gomodErr = remap(altTest.gomodErr, m)
|
||||
altTest.zipErr = remap(altTest.zipErr, m)
|
||||
altTest.zipSum = ""
|
||||
altTest.zipFileHash = ""
|
||||
t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hgmap = map[string]string{
|
||||
|
||||
@@ -190,8 +190,8 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
|
||||
|
||||
// raiseLimitsForUpgrades increases the module versions in maxVersions to the
|
||||
// versions that would be needed to allow each of the modules in tryUpgrade
|
||||
// (individually) and all of the modules in mustSelect (simultaneously) to be
|
||||
// added as roots.
|
||||
// (individually or in any combination) and all of the modules in mustSelect
|
||||
// (simultaneously) to be added as roots.
|
||||
//
|
||||
// Versions not present in maxVersion are unrestricted, and it is assumed that
|
||||
// they will not be promoted to root requirements (and thus will not contribute
|
||||
@@ -213,18 +213,42 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
}
|
||||
}
|
||||
|
||||
var eagerUpgrades []module.Version
|
||||
var (
|
||||
eagerUpgrades []module.Version
|
||||
isLazyRootPath map[string]bool
|
||||
)
|
||||
if depth == eager {
|
||||
eagerUpgrades = tryUpgrade
|
||||
} else {
|
||||
isLazyRootPath = make(map[string]bool, len(maxVersion))
|
||||
for p := range maxVersion {
|
||||
isLazyRootPath[p] = true
|
||||
}
|
||||
for _, m := range tryUpgrade {
|
||||
isLazyRootPath[m.Path] = true
|
||||
}
|
||||
for _, m := range mustSelect {
|
||||
isLazyRootPath[m.Path] = true
|
||||
}
|
||||
|
||||
allowedRoot := map[module.Version]bool{}
|
||||
|
||||
var allowRoot func(m module.Version) error
|
||||
allowRoot = func(m module.Version) error {
|
||||
if allowedRoot[m] {
|
||||
return nil
|
||||
}
|
||||
allowedRoot[m] = true
|
||||
|
||||
if m.Path == Target.Path {
|
||||
// Target is already considered to be higher than any possible m, so we
|
||||
// won't be upgrading to it anyway and there is no point scanning its
|
||||
// dependencies.
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
allow(m)
|
||||
|
||||
summary, err := goModSummary(m)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -234,12 +258,27 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
// graph, rather than loading the (potentially-overlapping) subgraph for
|
||||
// each upgrade individually.
|
||||
eagerUpgrades = append(eagerUpgrades, m)
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, r := range summary.require {
|
||||
allow(r)
|
||||
if isLazyRootPath[r.Path] {
|
||||
// r could become a root as the result of an upgrade or downgrade,
|
||||
// in which case its dependencies will not be pruned out.
|
||||
// We need to allow those dependencies to be upgraded too.
|
||||
if err := allowRoot(r); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// r will not become a root, so its dependencies don't matter.
|
||||
// Allow only r itself.
|
||||
allow(r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, m := range tryUpgrade {
|
||||
allowRoot(m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,16 +307,41 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||
}
|
||||
}
|
||||
|
||||
if len(mustSelect) > 0 {
|
||||
mustGraph, err := readModGraph(ctx, depth, mustSelect)
|
||||
// Explicitly allow any (transitive) upgrades implied by mustSelect.
|
||||
nextRoots := append([]module.Version(nil), mustSelect...)
|
||||
for nextRoots != nil {
|
||||
module.Sort(nextRoots)
|
||||
rs := newRequirements(depth, nextRoots, nil)
|
||||
nextRoots = nil
|
||||
|
||||
rs, mustGraph, err := expandGraph(ctx, rs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range mustGraph.BuildList() {
|
||||
// Some module in mustSelect requires r, so we must allow at least r.Version
|
||||
// unless it conflicts with an entry in mustSelect.
|
||||
// Some module in mustSelect requires r, so we must allow at least
|
||||
// r.Version (unless it conflicts with another entry in mustSelect, in
|
||||
// which case we will error out either way).
|
||||
allow(r)
|
||||
|
||||
if isLazyRootPath[r.Path] {
|
||||
if v, ok := rs.rootSelected(r.Path); ok && r.Version == v {
|
||||
// r is already a root, so its requirements are already included in
|
||||
// the build list.
|
||||
continue
|
||||
}
|
||||
|
||||
// The dependencies in mustSelect may upgrade (or downgrade) an existing
|
||||
// root to match r, which will remain as a root. However, since r is not
|
||||
// a root of rs, its dependencies have been pruned out of this build
|
||||
// list. We need to add it back explicitly so that we allow any
|
||||
// transitive upgrades that r will pull in.
|
||||
if nextRoots == nil {
|
||||
nextRoots = rs.rootModules // already capped
|
||||
}
|
||||
nextRoots = append(nextRoots, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package vcs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
@@ -1189,8 +1188,9 @@ var vcsPaths = []*vcsPath{
|
||||
{
|
||||
pathPrefix: "bitbucket.org",
|
||||
regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: bitbucketVCS,
|
||||
check: noVCSSuffix,
|
||||
},
|
||||
|
||||
// IBM DevOps Services (JazzHub)
|
||||
@@ -1262,56 +1262,6 @@ func noVCSSuffix(match map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// bitbucketVCS determines the version control system for a
|
||||
// Bitbucket repository, by using the Bitbucket API.
|
||||
func bitbucketVCS(match map[string]string) error {
|
||||
if err := noVCSSuffix(match); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
SCM string `json:"scm"`
|
||||
}
|
||||
url := &urlpkg.URL{
|
||||
Scheme: "https",
|
||||
Host: "api.bitbucket.org",
|
||||
Path: expand(match, "/2.0/repositories/{bitname}"),
|
||||
RawQuery: "fields=scm",
|
||||
}
|
||||
data, err := web.GetBytes(url)
|
||||
if err != nil {
|
||||
if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 {
|
||||
// this may be a private repository. If so, attempt to determine which
|
||||
// VCS it uses. See issue 5375.
|
||||
root := match["root"]
|
||||
for _, vcs := range []string{"git", "hg"} {
|
||||
if vcsByCmd(vcs).Ping("https", root) == nil {
|
||||
resp.SCM = vcs
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resp.SCM == "" {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return fmt.Errorf("decoding %s: %v", url, err)
|
||||
}
|
||||
}
|
||||
|
||||
if vcsByCmd(resp.SCM) != nil {
|
||||
match["vcs"] = resp.SCM
|
||||
if resp.SCM == "git" {
|
||||
match["repo"] += ".git"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
|
||||
}
|
||||
|
||||
// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
|
||||
// "foo" could be a series name registered in Launchpad with its own branch,
|
||||
// and it could also be the name of a directory within the main project
|
||||
|
||||
@@ -183,6 +183,13 @@ func TestRepoRootForImportPath(t *testing.T) {
|
||||
"chiselapp.com/user/kyle/fossilgg",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"bitbucket.org/workspace/pkgname",
|
||||
&RepoRoot{
|
||||
VCS: vcsGit,
|
||||
Repo: "https://bitbucket.org/workspace/pkgname",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -142,6 +142,7 @@ var extraEnvKeys = []string{
|
||||
"GO_TESTING_GOTOOLS", // for gccgo testing
|
||||
"GCCGO", // for gccgo testing
|
||||
"GCCGOTOOLDIR", // for gccgo testing
|
||||
"MallocNanoZone", // Needed to work around an apparent kernel bug in macOS 12; see https://golang.org/issue/49138.
|
||||
}
|
||||
|
||||
// setup sets up the test execution temporary directory and environment.
|
||||
|
||||
41
src/cmd/go/testdata/script/list_all_gobuild.txt
vendored
Normal file
41
src/cmd/go/testdata/script/list_all_gobuild.txt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# go list all should work with GOOS=linux because all packages build on Linux
|
||||
env GOOS=linux
|
||||
go list all
|
||||
|
||||
# go list all should work with GOOS=darwin, but it used to fail because
|
||||
# in the absence of //go:build support, p looked like it needed q
|
||||
# (p_test.go was not properly excluded), and q was Linux-only.
|
||||
#
|
||||
# Also testing with r and s that +build lines keep working.
|
||||
env GOOS=darwin
|
||||
go list all
|
||||
|
||||
-- go.mod --
|
||||
go 1.17
|
||||
module m
|
||||
|
||||
-- p/p.go --
|
||||
package p
|
||||
|
||||
-- p/p_test.go --
|
||||
//go:build linux
|
||||
|
||||
package p
|
||||
|
||||
import "m/q"
|
||||
|
||||
-- q/q_linux.go --
|
||||
package q
|
||||
|
||||
-- r/r.go --
|
||||
package r
|
||||
|
||||
-- r/r_test.go --
|
||||
// +build linux
|
||||
|
||||
package r
|
||||
|
||||
import "m/s"
|
||||
|
||||
-- s/s_linux.go --
|
||||
package s
|
||||
67
src/cmd/go/testdata/script/mod_all.txt
vendored
67
src/cmd/go/testdata/script/mod_all.txt
vendored
@@ -202,9 +202,9 @@ go mod edit -go=1.17 u/go.mod
|
||||
go mod edit -go=1.17 w/go.mod
|
||||
go mod edit -go=1.17 x/go.mod
|
||||
go mod edit -go=1.17
|
||||
cp go.mod go.mod.orig
|
||||
cmp go.mod go.mod.beforetidy
|
||||
go mod tidy
|
||||
cmp go.mod go.mod.orig
|
||||
cmp go.mod go.mod.aftertidy
|
||||
|
||||
# With lazy loading, 'go list all' with neither -mod=vendor nor -test should
|
||||
# match -mod=vendor without -test in 1.15.
|
||||
@@ -466,3 +466,66 @@ module example.com/x
|
||||
go 1.15
|
||||
-- x/x.go --
|
||||
package x
|
||||
-- go.mod.beforetidy --
|
||||
module example.com/main
|
||||
|
||||
// Note: this go.mod file initially specifies go 1.15,
|
||||
// but includes some redundant roots so that it
|
||||
// also already obeys the 1.17 lazy loading invariants.
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
example.com/a v0.1.0
|
||||
example.com/b v0.1.0 // indirect
|
||||
example.com/q v0.1.0
|
||||
example.com/r v0.1.0 // indirect
|
||||
example.com/t v0.1.0
|
||||
example.com/u v0.1.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
example.com/a v0.1.0 => ./a
|
||||
example.com/b v0.1.0 => ./b
|
||||
example.com/c v0.1.0 => ./c
|
||||
example.com/d v0.1.0 => ./d
|
||||
example.com/q v0.1.0 => ./q
|
||||
example.com/r v0.1.0 => ./r
|
||||
example.com/s v0.1.0 => ./s
|
||||
example.com/t v0.1.0 => ./t
|
||||
example.com/u v0.1.0 => ./u
|
||||
example.com/w v0.1.0 => ./w
|
||||
example.com/x v0.1.0 => ./x
|
||||
)
|
||||
-- go.mod.aftertidy --
|
||||
module example.com/main
|
||||
|
||||
// Note: this go.mod file initially specifies go 1.15,
|
||||
// but includes some redundant roots so that it
|
||||
// also already obeys the 1.17 lazy loading invariants.
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
example.com/a v0.1.0
|
||||
example.com/q v0.1.0
|
||||
example.com/t v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
example.com/b v0.1.0 // indirect
|
||||
example.com/r v0.1.0 // indirect
|
||||
example.com/u v0.1.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
example.com/a v0.1.0 => ./a
|
||||
example.com/b v0.1.0 => ./b
|
||||
example.com/c v0.1.0 => ./c
|
||||
example.com/d v0.1.0 => ./d
|
||||
example.com/q v0.1.0 => ./q
|
||||
example.com/r v0.1.0 => ./r
|
||||
example.com/s v0.1.0 => ./s
|
||||
example.com/t v0.1.0 => ./t
|
||||
example.com/u v0.1.0 => ./u
|
||||
example.com/w v0.1.0 => ./w
|
||||
example.com/x v0.1.0 => ./x
|
||||
)
|
||||
|
||||
28
src/cmd/go/testdata/script/mod_download_git_decorate_full.txt
vendored
Normal file
28
src/cmd/go/testdata/script/mod_download_git_decorate_full.txt
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
[!net] skip
|
||||
[!exec:git] skip
|
||||
|
||||
env GOPROXY=direct
|
||||
env HOME=$WORK/home/gopher
|
||||
|
||||
|
||||
go env GOPROXY
|
||||
stdout 'direct'
|
||||
|
||||
exec git config --get log.decorate
|
||||
stdout 'full'
|
||||
|
||||
# Test that Git log with user's global config '~/gitconfig' has log.decorate=full
|
||||
# go mod download has an error 'v1.x.y is not a tag'
|
||||
# with go1.16.14:
|
||||
# `go1.16.14 list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3`
|
||||
# will output with error:
|
||||
# go list -m: vcs-test.golang.org/git/gitrepo1.git@v1.2.3: invalid version: unknown revision v1.2.3
|
||||
# See golang/go#51312.
|
||||
go list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3
|
||||
stdout 'vcs-test.golang.org/git/gitrepo1.git v1.2.3'
|
||||
|
||||
-- $WORK/home/gopher/.gitconfig --
|
||||
[log]
|
||||
decorate = full
|
||||
@@ -10,7 +10,7 @@ env GO111MODULE=on
|
||||
env GOPROXY=direct
|
||||
env GOSUMDB=off
|
||||
|
||||
go list -m cloud.google.com/go@master
|
||||
go list -m cloud.google.com/go@main
|
||||
! stdout 'v0.0.0-'
|
||||
|
||||
-- go.mod --
|
||||
|
||||
117
src/cmd/go/testdata/script/mod_get_issue47979.txt
vendored
Normal file
117
src/cmd/go/testdata/script/mod_get_issue47979.txt
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# Regression test for https://golang.org/issue/47979:
|
||||
#
|
||||
# An argument to 'go get' that results in an upgrade to a different existing
|
||||
# root should be allowed, and should not panic the 'go' command.
|
||||
|
||||
cp go.mod go.mod.orig
|
||||
|
||||
|
||||
# Transitive upgrades from upgraded roots should not prevent
|
||||
# 'go get -u' from performing upgrades.
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go get -u -d .
|
||||
cmp go.mod go.mod.want
|
||||
|
||||
|
||||
# 'go get' of a specific version should allow upgrades of
|
||||
# every dependency (transitively) required by that version,
|
||||
# including dependencies that are pulled into the module
|
||||
# graph by upgrading other root requirements
|
||||
# (in this case, example.net/indirect).
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go get -d example.net/a@v0.2.0
|
||||
cmp go.mod go.mod.want
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module golang.org/issue47979
|
||||
|
||||
go 1.17
|
||||
|
||||
replace (
|
||||
example.net/a v0.1.0 => ./a1
|
||||
example.net/a v0.2.0 => ./a2
|
||||
example.net/indirect v0.1.0 => ./indirect1
|
||||
example.net/indirect v0.2.0 => ./indirect2
|
||||
example.net/other v0.1.0 => ./other
|
||||
example.net/other v0.2.0 => ./other
|
||||
)
|
||||
|
||||
require (
|
||||
example.net/a v0.1.0
|
||||
example.net/other v0.1.0
|
||||
)
|
||||
|
||||
require example.net/indirect v0.1.0 // indirect
|
||||
-- go.mod.want --
|
||||
module golang.org/issue47979
|
||||
|
||||
go 1.17
|
||||
|
||||
replace (
|
||||
example.net/a v0.1.0 => ./a1
|
||||
example.net/a v0.2.0 => ./a2
|
||||
example.net/indirect v0.1.0 => ./indirect1
|
||||
example.net/indirect v0.2.0 => ./indirect2
|
||||
example.net/other v0.1.0 => ./other
|
||||
example.net/other v0.2.0 => ./other
|
||||
)
|
||||
|
||||
require (
|
||||
example.net/a v0.2.0
|
||||
example.net/other v0.2.0
|
||||
)
|
||||
|
||||
require example.net/indirect v0.2.0 // indirect
|
||||
-- issue.go --
|
||||
package issue
|
||||
|
||||
import _ "example.net/a"
|
||||
-- useother/useother.go --
|
||||
package useother
|
||||
|
||||
import _ "example.net/other"
|
||||
-- a1/go.mod --
|
||||
module example.net/a
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/indirect v0.1.0
|
||||
-- a1/a.go --
|
||||
package a
|
||||
-- a2/go.mod --
|
||||
module example.net/a
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/indirect v0.2.0
|
||||
-- a2/a.go --
|
||||
package a
|
||||
|
||||
import "example.net/indirect"
|
||||
-- indirect1/go.mod --
|
||||
module example.net/indirect
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/other v0.1.0
|
||||
-- indirect1/indirect.go --
|
||||
package indirect
|
||||
-- indirect2/go.mod --
|
||||
module example.net/indirect
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.net/other v0.2.0
|
||||
-- indirect2/indirect.go --
|
||||
package indirect
|
||||
|
||||
import "example.net/other"
|
||||
-- other/go.mod --
|
||||
module example.net/other
|
||||
|
||||
go 1.17
|
||||
-- other/other.go --
|
||||
package other
|
||||
68
src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt
vendored
Normal file
68
src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# Check that 'go get -u' will upgrade a dependency (direct or indirect)
|
||||
# when the main module and the dependency are both lazy.
|
||||
# Verifies #47768.
|
||||
|
||||
# Check that go.mod is tidy, and an upgrade is available.
|
||||
cp go.mod go.mod.orig
|
||||
go mod tidy
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
go list -m -u example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.0 \[v0.1.1\] => ./lazyupgrade@v0.1.0$'
|
||||
|
||||
# 'go get -u' on a package that directly imports the dependency should upgrade.
|
||||
go get -u ./usedirect
|
||||
go list -m example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
|
||||
cp go.mod.orig go.mod
|
||||
|
||||
# 'go get -u' on a package that indirectly imports the dependency should upgrade.
|
||||
go get -u ./useindirect
|
||||
go list -m example.com/lazyupgrade
|
||||
stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
|
||||
|
||||
-- go.mod --
|
||||
module use
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
direct v0.0.0
|
||||
example.com/lazyupgrade v0.1.0
|
||||
)
|
||||
|
||||
replace (
|
||||
direct => ./direct
|
||||
example.com/lazyupgrade v0.1.0 => ./lazyupgrade@v0.1.0
|
||||
example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1
|
||||
)
|
||||
-- usedirect/usedirect.go --
|
||||
package use
|
||||
|
||||
import _ "example.com/lazyupgrade"
|
||||
-- useindirect/useindirect.go --
|
||||
package use
|
||||
|
||||
import _ "direct"
|
||||
-- direct/go.mod --
|
||||
module direct
|
||||
|
||||
go 1.17
|
||||
|
||||
require example.com/lazyupgrade v0.1.0
|
||||
-- direct/direct.go --
|
||||
package direct
|
||||
|
||||
import _ "example.com/lazyupgrade"
|
||||
-- lazyupgrade@v0.1.0/go.mod --
|
||||
module example.com/lazyupgrade
|
||||
|
||||
go 1.17
|
||||
-- lazyupgrade@v0.1.0/lazyupgrade.go --
|
||||
package lazyupgrade
|
||||
-- lazyupgrade@v0.1.1/go.mod --
|
||||
module example.com/lazyupgrade
|
||||
|
||||
go 1.17
|
||||
-- lazyupgrade@v0.1.1/lazyupgrade.go --
|
||||
package lazyupgrade
|
||||
@@ -194,10 +194,10 @@ cp go.mod.orig go.mod
|
||||
go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
|
||||
cd outside
|
||||
! go list -m github.com/pierrec/lz4
|
||||
stderr 'go list -m: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
|
||||
stderr '^go list -m: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
|
||||
cd ..
|
||||
! go list -m github.com/pierrec/lz4
|
||||
stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
|
||||
stderr '^go list -m: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
|
||||
|
||||
# A +incompatible pseudo-version is valid for a revision of the module
|
||||
# that lacks a go.mod file.
|
||||
@@ -222,7 +222,7 @@ stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible'
|
||||
# not resolve to a pseudo-version with a different major version.
|
||||
cp go.mod.orig go.mod
|
||||
! go get -d github.com/pierrec/lz4@v2.0.8
|
||||
stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2'
|
||||
stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
|
||||
|
||||
# An invalid +incompatible suffix for a canonical version should error out,
|
||||
# not resolve to a pseudo-version.
|
||||
@@ -233,10 +233,10 @@ cp go.mod.orig go.mod
|
||||
go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible
|
||||
cd outside
|
||||
! go list -m github.com/pierrec/lz4
|
||||
stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
|
||||
stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
|
||||
cd ..
|
||||
! go list -m github.com/pierrec/lz4
|
||||
stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
|
||||
stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
|
||||
|
||||
-- go.mod.orig --
|
||||
module example.com
|
||||
|
||||
22
src/cmd/go/testdata/script/mod_retention.txt
vendored
22
src/cmd/go/testdata/script/mod_retention.txt
vendored
@@ -81,14 +81,14 @@ require (
|
||||
package x
|
||||
import _ "rsc.io/quote"
|
||||
-- go.mod.crlf --
|
||||
module m
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
module m
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
-- go.mod.unsorted --
|
||||
module m
|
||||
|
||||
@@ -139,10 +139,10 @@ module m
|
||||
|
||||
go $goversion
|
||||
|
||||
require rsc.io/quote v1.5.2
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
|
||||
rsc.io/sampler v1.3.0 // indirect
|
||||
rsc.io/testonly v1.0.0 // indirect
|
||||
)
|
||||
|
||||
require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
|
||||
|
||||
@@ -72,10 +72,9 @@ go 1.17
|
||||
|
||||
replace example.net/indirect v0.1.0 => ./indirect
|
||||
|
||||
require (
|
||||
example.net/ambiguous/nested v0.1.0 // indirect
|
||||
example.net/indirect v0.1.0
|
||||
)
|
||||
require example.net/indirect v0.1.0
|
||||
|
||||
require example.net/ambiguous/nested v0.1.0 // indirect
|
||||
-- all-m.txt --
|
||||
example.com/m
|
||||
example.net/ambiguous v0.1.0
|
||||
|
||||
@@ -97,10 +97,9 @@ replace (
|
||||
example.net/requireincompatible v0.1.0 => ./requireincompatible
|
||||
)
|
||||
|
||||
require (
|
||||
example.com/retract/incompatible v1.0.0 // indirect
|
||||
example.net/lazy v0.1.0
|
||||
)
|
||||
require example.net/lazy v0.1.0
|
||||
|
||||
require example.com/retract/incompatible v1.0.0 // indirect
|
||||
-- incompatible.go --
|
||||
package incompatible
|
||||
|
||||
|
||||
@@ -2170,7 +2170,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
|
||||
}
|
||||
|
||||
n++
|
||||
if n > 20 {
|
||||
if n > 1000 {
|
||||
ctxt.Diag("span must be looping")
|
||||
log.Fatalf("loop")
|
||||
}
|
||||
|
||||
@@ -389,9 +389,12 @@ func makeBogusLico() lico {
|
||||
}
|
||||
|
||||
func makeLico(line, col uint) lico {
|
||||
if line > lineMax {
|
||||
if line >= lineMax {
|
||||
// cannot represent line, use max. line so we have some information
|
||||
line = lineMax
|
||||
// Drop column information if line number saturates.
|
||||
// Ensures line+col is monotonic. See issue 51193.
|
||||
col = 0
|
||||
}
|
||||
if col > colMax {
|
||||
// cannot represent column, use max. column so we have some information
|
||||
|
||||
@@ -140,8 +140,8 @@ func TestLico(t *testing.T) {
|
||||
{makeLico(1, 0), ":1", 1, 0},
|
||||
{makeLico(1, 1), ":1:1", 1, 1},
|
||||
{makeLico(2, 3), ":2:3", 2, 3},
|
||||
{makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1},
|
||||
{makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, // line too large, stick with max. line
|
||||
{makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1},
|
||||
{makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1}, // line too large, stick with max. line
|
||||
{makeLico(1, colMax), ":1", 1, colMax},
|
||||
{makeLico(1, colMax+1), ":1", 1, 0}, // column too large
|
||||
{makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0},
|
||||
@@ -170,8 +170,8 @@ func TestIsStmt(t *testing.T) {
|
||||
{makeLico(1, 1), ":1:1" + def, 1, 1},
|
||||
{makeLico(1, 1).withIsStmt(), ":1:1" + is, 1, 1},
|
||||
{makeLico(1, 1).withNotStmt(), ":1:1" + not, 1, 1},
|
||||
{makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax) + def, lineMax, 1},
|
||||
{makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax) + def, lineMax, 1}, // line too large, stick with max. line
|
||||
{makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1},
|
||||
{makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1}, // line too large, stick with max. line
|
||||
{makeLico(1, colMax), ":1" + def, 1, colMax},
|
||||
{makeLico(1, colMax+1), ":1" + def, 1, 0}, // column too large
|
||||
{makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 0},
|
||||
@@ -214,9 +214,9 @@ func TestLogue(t *testing.T) {
|
||||
{makeLico(1, 1).withXlogue(PosPrologueEnd), ":1:1" + defs + pro, 1, 1},
|
||||
{makeLico(1, 1).withXlogue(PosEpilogueBegin), ":1:1" + defs + epi, 1, 1},
|
||||
|
||||
{makeLico(lineMax, 1).withXlogue(PosDefaultLogue), fmt.Sprintf(":%d:1", lineMax) + defs + defp, lineMax, 1},
|
||||
{makeLico(lineMax, 1).withXlogue(PosPrologueEnd), fmt.Sprintf(":%d:1", lineMax) + defs + pro, lineMax, 1},
|
||||
{makeLico(lineMax, 1).withXlogue(PosEpilogueBegin), fmt.Sprintf(":%d:1", lineMax) + defs + epi, lineMax, 1},
|
||||
{makeLico(lineMax, 1).withXlogue(PosDefaultLogue), fmt.Sprintf(":%d", lineMax) + defs + defp, lineMax, 1},
|
||||
{makeLico(lineMax, 1).withXlogue(PosPrologueEnd), fmt.Sprintf(":%d", lineMax) + defs + pro, lineMax, 1},
|
||||
{makeLico(lineMax, 1).withXlogue(PosEpilogueBegin), fmt.Sprintf(":%d", lineMax) + defs + epi, lineMax, 1},
|
||||
} {
|
||||
x := test.x
|
||||
if got := formatstr("", x.Line(), x.Col(), true) + fmt.Sprintf(":%d:%d", x.IsStmt(), x.Xlogue()); got != test.string {
|
||||
|
||||
@@ -602,7 +602,7 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
|
||||
rs := r.Xsym
|
||||
rt := r.Type
|
||||
|
||||
if r.Xadd != signext21(r.Xadd) {
|
||||
if rt == objabi.R_ADDRARM64 && r.Xadd != signext21(r.Xadd) {
|
||||
// If the relocation target would overflow the addend, then target
|
||||
// a linker-manufactured label symbol with a smaller addend instead.
|
||||
label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
|
||||
|
||||
@@ -2450,6 +2450,12 @@ func splitTextSections(ctxt *Link) bool {
|
||||
return (ctxt.IsPPC64() || (ctxt.IsARM64() && ctxt.IsDarwin())) && ctxt.IsExternal()
|
||||
}
|
||||
|
||||
// On Wasm, we reserve 4096 bytes for zero page, then 8192 bytes for wasm_exec.js
|
||||
// to store command line args and environment variables.
|
||||
// Data sections starts from at least address 12288.
|
||||
// Keep in sync with wasm_exec.js.
|
||||
const wasmMinDataAddr = 4096 + 8192
|
||||
|
||||
// address assigns virtual addresses to all segments and sections and
|
||||
// returns all segments in file order.
|
||||
func (ctxt *Link) address() []*sym.Segment {
|
||||
@@ -2459,10 +2465,14 @@ func (ctxt *Link) address() []*sym.Segment {
|
||||
order = append(order, &Segtext)
|
||||
Segtext.Rwx = 05
|
||||
Segtext.Vaddr = va
|
||||
for _, s := range Segtext.Sections {
|
||||
for i, s := range Segtext.Sections {
|
||||
va = uint64(Rnd(int64(va), int64(s.Align)))
|
||||
s.Vaddr = va
|
||||
va += s.Length
|
||||
|
||||
if ctxt.IsWasm() && i == 0 && va < wasmMinDataAddr {
|
||||
va = wasmMinDataAddr
|
||||
}
|
||||
}
|
||||
|
||||
Segtext.Length = va - uint64(*FlagTextAddr)
|
||||
|
||||
@@ -132,7 +132,9 @@ func (d *deadcodePass) flood() {
|
||||
methods = methods[:0]
|
||||
for i := 0; i < relocs.Count(); i++ {
|
||||
r := relocs.At(i)
|
||||
if r.Weak() {
|
||||
// When build with "-linkshared", we can't tell if the interface
|
||||
// method in itab will be used or not. Ignore the weak attribute.
|
||||
if r.Weak() && !(d.ctxt.linkShared && d.ldr.IsItab(symIdx)) {
|
||||
continue
|
||||
}
|
||||
t := r.Type()
|
||||
@@ -348,7 +350,7 @@ func deadcode(ctxt *Link) {
|
||||
// in the last pass.
|
||||
rem := d.markableMethods[:0]
|
||||
for _, m := range d.markableMethods {
|
||||
if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||
if (d.reflectSeen && (m.isExported() || d.dynlink)) || d.ifaceMethod[m.m] {
|
||||
d.markMethod(m)
|
||||
} else {
|
||||
rem = append(rem, m)
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -1083,7 +1084,12 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
|
||||
}
|
||||
|
||||
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||
sh.Type = uint32(elf.SHT_PROGBITS)
|
||||
switch sect.Name {
|
||||
case ".init_array":
|
||||
sh.Type = uint32(elf.SHT_INIT_ARRAY)
|
||||
default:
|
||||
sh.Type = uint32(elf.SHT_PROGBITS)
|
||||
}
|
||||
} else {
|
||||
sh.Type = uint32(elf.SHT_NOBITS)
|
||||
}
|
||||
@@ -1749,7 +1755,7 @@ func asmbElf(ctxt *Link) {
|
||||
sh.Flags = uint64(elf.SHF_ALLOC)
|
||||
sh.Addralign = 1
|
||||
|
||||
if interpreter == "" && buildcfg.GO_LDSO != "" {
|
||||
if interpreter == "" && buildcfg.GOOS == runtime.GOOS && buildcfg.GOARCH == runtime.GOARCH && buildcfg.GO_LDSO != "" {
|
||||
interpreter = buildcfg.GO_LDSO
|
||||
}
|
||||
|
||||
|
||||
@@ -1267,7 +1267,10 @@ func (ctxt *Link) hostlink() {
|
||||
if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
|
||||
// -flat_namespace is deprecated on iOS.
|
||||
// It is useful for supporting plugins. We don't support plugins on iOS.
|
||||
argv = append(argv, "-Wl,-flat_namespace")
|
||||
// -flat_namespace may cause the dynamic linker to hang at forkExec when
|
||||
// resolving a lazy binding. See issue 38824.
|
||||
// Force eager resolution to work around.
|
||||
argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
|
||||
}
|
||||
if !combineDwarf {
|
||||
argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols
|
||||
|
||||
@@ -993,13 +993,31 @@ package main
|
||||
|
||||
var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
|
||||
|
||||
var addr = [...]*byte{
|
||||
&x[1<<23-1],
|
||||
&x[1<<23],
|
||||
&x[1<<23+1],
|
||||
&x[1<<24-1],
|
||||
&x[1<<24],
|
||||
&x[1<<24+1],
|
||||
}
|
||||
|
||||
func main() {
|
||||
// check relocations in instructions
|
||||
check(x[1<<23-1], 0)
|
||||
check(x[1<<23], 23)
|
||||
check(x[1<<23+1], 0)
|
||||
check(x[1<<24-1], 0)
|
||||
check(x[1<<24], 24)
|
||||
check(x[1<<24+1], 0)
|
||||
|
||||
// check absolute address relocations in data
|
||||
check(*addr[0], 0)
|
||||
check(*addr[1], 23)
|
||||
check(*addr[2], 0)
|
||||
check(*addr[3], 0)
|
||||
check(*addr[4], 24)
|
||||
check(*addr[5], 0)
|
||||
}
|
||||
|
||||
func check(x, y byte) {
|
||||
|
||||
@@ -106,6 +106,9 @@ var ppcGnuNeed = []string{
|
||||
}
|
||||
|
||||
func mustHaveDisasm(t *testing.T) {
|
||||
if strings.HasPrefix(testenv.Builder(), "darwin-arm64") {
|
||||
t.Skipf("builder %q has an incompatible version of XCode installed, see go.dev/issue/49700", testenv.Builder())
|
||||
}
|
||||
switch runtime.GOARCH {
|
||||
case "mips", "mipsle", "mips64", "mips64le":
|
||||
t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
|
||||
|
||||
313
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
313
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
@@ -956,170 +956,217 @@ func (f *File) SetRequire(req []*Require) {
|
||||
|
||||
// SetRequireSeparateIndirect updates the requirements of f to contain the given
|
||||
// requirements. Comment contents (except for 'indirect' markings) are retained
|
||||
// from the first existing requirement for each module path, and block structure
|
||||
// is maintained as long as the indirect markings match.
|
||||
// from the first existing requirement for each module path. Like SetRequire,
|
||||
// SetRequireSeparateIndirect adds requirements for new paths in req,
|
||||
// updates the version and "// indirect" comment on existing requirements,
|
||||
// and deletes requirements on paths not in req. Existing duplicate requirements
|
||||
// are deleted.
|
||||
//
|
||||
// Any requirements on paths not already present in the file are added. Direct
|
||||
// requirements are added to the last block containing *any* other direct
|
||||
// requirement. Indirect requirements are added to the last block containing
|
||||
// *only* other indirect requirements. If no suitable block exists, a new one is
|
||||
// added, with the last block containing a direct dependency (if any)
|
||||
// immediately before the first block containing only indirect dependencies.
|
||||
// As its name suggests, SetRequireSeparateIndirect puts direct and indirect
|
||||
// requirements into two separate blocks, one containing only direct
|
||||
// requirements, and the other containing only indirect requirements.
|
||||
// SetRequireSeparateIndirect may move requirements between these two blocks
|
||||
// when their indirect markings change. However, SetRequireSeparateIndirect
|
||||
// won't move requirements from other blocks, especially blocks with comments.
|
||||
//
|
||||
// The Syntax field is ignored for requirements in the given blocks.
|
||||
// If the file initially has one uncommented block of requirements,
|
||||
// SetRequireSeparateIndirect will split it into a direct-only and indirect-only
|
||||
// block. This aids in the transition to separate blocks.
|
||||
func (f *File) SetRequireSeparateIndirect(req []*Require) {
|
||||
type modKey struct {
|
||||
path string
|
||||
indirect bool
|
||||
}
|
||||
need := make(map[modKey]string)
|
||||
for _, r := range req {
|
||||
need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version
|
||||
// hasComments returns whether a line or block has comments
|
||||
// other than "indirect".
|
||||
hasComments := func(c Comments) bool {
|
||||
return len(c.Before) > 0 || len(c.After) > 0 || len(c.Suffix) > 1 ||
|
||||
(len(c.Suffix) == 1 &&
|
||||
strings.TrimSpace(strings.TrimPrefix(c.Suffix[0].Token, string(slashSlash))) != "indirect")
|
||||
}
|
||||
|
||||
comments := make(map[string]Comments)
|
||||
for _, r := range f.Require {
|
||||
v, ok := need[modKey{r.Mod.Path, r.Indirect}]
|
||||
if !ok {
|
||||
if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok {
|
||||
if _, dup := comments[r.Mod.Path]; !dup {
|
||||
comments[r.Mod.Path] = r.Syntax.Comments
|
||||
}
|
||||
// moveReq adds r to block. If r was in another block, moveReq deletes
|
||||
// it from that block and transfers its comments.
|
||||
moveReq := func(r *Require, block *LineBlock) {
|
||||
var line *Line
|
||||
if r.Syntax == nil {
|
||||
line = &Line{Token: []string{AutoQuote(r.Mod.Path), r.Mod.Version}}
|
||||
r.Syntax = line
|
||||
if r.Indirect {
|
||||
r.setIndirect(true)
|
||||
}
|
||||
r.markRemoved()
|
||||
continue
|
||||
} else {
|
||||
line = new(Line)
|
||||
*line = *r.Syntax
|
||||
if !line.InBlock && len(line.Token) > 0 && line.Token[0] == "require" {
|
||||
line.Token = line.Token[1:]
|
||||
}
|
||||
r.Syntax.Token = nil // Cleanup will delete the old line.
|
||||
r.Syntax = line
|
||||
}
|
||||
r.setVersion(v)
|
||||
delete(need, modKey{r.Mod.Path, r.Indirect})
|
||||
line.InBlock = true
|
||||
block.Line = append(block.Line, line)
|
||||
}
|
||||
|
||||
// Examine existing require lines and blocks.
|
||||
var (
|
||||
lastDirectOrMixedBlock Expr
|
||||
firstIndirectOnlyBlock Expr
|
||||
lastIndirectOnlyBlock Expr
|
||||
// We may insert new requirements into the last uncommented
|
||||
// direct-only and indirect-only blocks. We may also move requirements
|
||||
// to the opposite block if their indirect markings change.
|
||||
lastDirectIndex = -1
|
||||
lastIndirectIndex = -1
|
||||
|
||||
// If there are no direct-only or indirect-only blocks, a new block may
|
||||
// be inserted after the last require line or block.
|
||||
lastRequireIndex = -1
|
||||
|
||||
// If there's only one require line or block, and it's uncommented,
|
||||
// we'll move its requirements to the direct-only or indirect-only blocks.
|
||||
requireLineOrBlockCount = 0
|
||||
|
||||
// Track the block each requirement belongs to (if any) so we can
|
||||
// move them later.
|
||||
lineToBlock = make(map[*Line]*LineBlock)
|
||||
)
|
||||
for _, stmt := range f.Syntax.Stmt {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
switch stmt := stmt.(type) {
|
||||
case *Line:
|
||||
if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
|
||||
continue
|
||||
}
|
||||
if isIndirect(stmt) {
|
||||
lastIndirectOnlyBlock = stmt
|
||||
} else {
|
||||
lastDirectOrMixedBlock = stmt
|
||||
lastRequireIndex = i
|
||||
requireLineOrBlockCount++
|
||||
if !hasComments(stmt.Comments) {
|
||||
if isIndirect(stmt) {
|
||||
lastIndirectIndex = i
|
||||
} else {
|
||||
lastDirectIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
case *LineBlock:
|
||||
if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
|
||||
continue
|
||||
}
|
||||
indirectOnly := true
|
||||
lastRequireIndex = i
|
||||
requireLineOrBlockCount++
|
||||
allDirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
|
||||
allIndirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
|
||||
for _, line := range stmt.Line {
|
||||
if len(line.Token) == 0 {
|
||||
continue
|
||||
}
|
||||
if !isIndirect(line) {
|
||||
indirectOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if indirectOnly {
|
||||
lastIndirectOnlyBlock = stmt
|
||||
if firstIndirectOnlyBlock == nil {
|
||||
firstIndirectOnlyBlock = stmt
|
||||
}
|
||||
} else {
|
||||
lastDirectOrMixedBlock = stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOrContainsStmt := func(stmt Expr, target Expr) bool {
|
||||
if stmt == target {
|
||||
return true
|
||||
}
|
||||
if stmt, ok := stmt.(*LineBlock); ok {
|
||||
if target, ok := target.(*Line); ok {
|
||||
for _, line := range stmt.Line {
|
||||
if line == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
addRequire := func(path, vers string, indirect bool, comments Comments) {
|
||||
var line *Line
|
||||
if indirect {
|
||||
if lastIndirectOnlyBlock != nil {
|
||||
line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers)
|
||||
} else {
|
||||
// Add a new require block after the last direct-only or mixed "require"
|
||||
// block (if any).
|
||||
//
|
||||
// (f.Syntax.addLine would add the line to an existing "require" block if
|
||||
// present, but here the existing "require" blocks are all direct-only, so
|
||||
// we know we need to add a new block instead.)
|
||||
line = &Line{Token: []string{"require", path, vers}}
|
||||
lastIndirectOnlyBlock = line
|
||||
firstIndirectOnlyBlock = line // only block implies first block
|
||||
if lastDirectOrMixedBlock == nil {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, line)
|
||||
lineToBlock[line] = stmt
|
||||
if hasComments(line.Comments) {
|
||||
allDirect = false
|
||||
allIndirect = false
|
||||
} else if isIndirect(line) {
|
||||
allDirect = false
|
||||
} else {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
if isOrContainsStmt(stmt, lastDirectOrMixedBlock) {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size
|
||||
copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up
|
||||
f.Syntax.Stmt[i+1] = line
|
||||
break
|
||||
}
|
||||
}
|
||||
allIndirect = false
|
||||
}
|
||||
}
|
||||
if allDirect {
|
||||
lastDirectIndex = i
|
||||
}
|
||||
if allIndirect {
|
||||
lastIndirectIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oneFlatUncommentedBlock := requireLineOrBlockCount == 1 &&
|
||||
!hasComments(*f.Syntax.Stmt[lastRequireIndex].Comment())
|
||||
|
||||
// Create direct and indirect blocks if needed. Convert lines into blocks
|
||||
// if needed. If we end up with an empty block or a one-line block,
|
||||
// Cleanup will delete it or convert it to a line later.
|
||||
insertBlock := func(i int) *LineBlock {
|
||||
block := &LineBlock{Token: []string{"require"}}
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil)
|
||||
copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:])
|
||||
f.Syntax.Stmt[i] = block
|
||||
return block
|
||||
}
|
||||
|
||||
ensureBlock := func(i int) *LineBlock {
|
||||
switch stmt := f.Syntax.Stmt[i].(type) {
|
||||
case *LineBlock:
|
||||
return stmt
|
||||
case *Line:
|
||||
block := &LineBlock{
|
||||
Token: []string{"require"},
|
||||
Line: []*Line{stmt},
|
||||
}
|
||||
stmt.Token = stmt.Token[1:] // remove "require"
|
||||
stmt.InBlock = true
|
||||
f.Syntax.Stmt[i] = block
|
||||
return block
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected statement: %v", stmt))
|
||||
}
|
||||
}
|
||||
|
||||
var lastDirectBlock *LineBlock
|
||||
if lastDirectIndex < 0 {
|
||||
if lastIndirectIndex >= 0 {
|
||||
lastDirectIndex = lastIndirectIndex
|
||||
lastIndirectIndex++
|
||||
} else if lastRequireIndex >= 0 {
|
||||
lastDirectIndex = lastRequireIndex + 1
|
||||
} else {
|
||||
if lastDirectOrMixedBlock != nil {
|
||||
line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers)
|
||||
lastDirectIndex = len(f.Syntax.Stmt)
|
||||
}
|
||||
lastDirectBlock = insertBlock(lastDirectIndex)
|
||||
} else {
|
||||
lastDirectBlock = ensureBlock(lastDirectIndex)
|
||||
}
|
||||
|
||||
var lastIndirectBlock *LineBlock
|
||||
if lastIndirectIndex < 0 {
|
||||
lastIndirectIndex = lastDirectIndex + 1
|
||||
lastIndirectBlock = insertBlock(lastIndirectIndex)
|
||||
} else {
|
||||
lastIndirectBlock = ensureBlock(lastIndirectIndex)
|
||||
}
|
||||
|
||||
// Delete requirements we don't want anymore.
|
||||
// Update versions and indirect comments on requirements we want to keep.
|
||||
// If a requirement is in last{Direct,Indirect}Block with the wrong
|
||||
// indirect marking after this, or if the requirement is in an single
|
||||
// uncommented mixed block (oneFlatUncommentedBlock), move it to the
|
||||
// correct block.
|
||||
//
|
||||
// Some blocks may be empty after this. Cleanup will remove them.
|
||||
need := make(map[string]*Require)
|
||||
for _, r := range req {
|
||||
need[r.Mod.Path] = r
|
||||
}
|
||||
have := make(map[string]*Require)
|
||||
for _, r := range f.Require {
|
||||
path := r.Mod.Path
|
||||
if need[path] == nil || have[path] != nil {
|
||||
// Requirement not needed, or duplicate requirement. Delete.
|
||||
r.markRemoved()
|
||||
continue
|
||||
}
|
||||
have[r.Mod.Path] = r
|
||||
r.setVersion(need[path].Mod.Version)
|
||||
r.setIndirect(need[path].Indirect)
|
||||
if need[path].Indirect &&
|
||||
(oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) {
|
||||
moveReq(r, lastIndirectBlock)
|
||||
} else if !need[path].Indirect &&
|
||||
(oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) {
|
||||
moveReq(r, lastDirectBlock)
|
||||
}
|
||||
}
|
||||
|
||||
// Add new requirements.
|
||||
for path, r := range need {
|
||||
if have[path] == nil {
|
||||
if r.Indirect {
|
||||
moveReq(r, lastIndirectBlock)
|
||||
} else {
|
||||
// Add a new require block before the first indirect block (if any).
|
||||
//
|
||||
// That way if the file initially contains only indirect lines,
|
||||
// the direct lines still appear before it: we preserve existing
|
||||
// structure, but only to the extent that that structure already
|
||||
// reflects the direct/indirect split.
|
||||
line = &Line{Token: []string{"require", path, vers}}
|
||||
lastDirectOrMixedBlock = line
|
||||
if firstIndirectOnlyBlock == nil {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, line)
|
||||
} else {
|
||||
for i, stmt := range f.Syntax.Stmt {
|
||||
if isOrContainsStmt(stmt, firstIndirectOnlyBlock) {
|
||||
f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size
|
||||
copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up
|
||||
f.Syntax.Stmt[i] = line
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
moveReq(r, lastDirectBlock)
|
||||
}
|
||||
f.Require = append(f.Require, r)
|
||||
}
|
||||
|
||||
line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before)
|
||||
line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix)
|
||||
|
||||
r := &Require{
|
||||
Mod: module.Version{Path: path, Version: vers},
|
||||
Indirect: indirect,
|
||||
Syntax: line,
|
||||
}
|
||||
r.setIndirect(indirect)
|
||||
f.Require = append(f.Require, r)
|
||||
}
|
||||
|
||||
for k, vers := range need {
|
||||
addRequire(k.path, vers, k.indirect, comments[k.path])
|
||||
}
|
||||
f.SortBlocks()
|
||||
}
|
||||
|
||||
|
||||
4
src/cmd/vendor/modules.txt
vendored
4
src/cmd/vendor/modules.txt
vendored
@@ -24,11 +24,11 @@ golang.org/x/arch/arm/armasm
|
||||
golang.org/x/arch/arm64/arm64asm
|
||||
golang.org/x/arch/ppc64/ppc64asm
|
||||
golang.org/x/arch/x86/x86asm
|
||||
# golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e
|
||||
# golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e
|
||||
## explicit; go 1.17
|
||||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
||||
# golang.org/x/mod v0.5.1
|
||||
## explicit; go 1.17
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
||||
@@ -248,42 +248,40 @@ func (z *Reader) Read(p []byte) (n int, err error) {
|
||||
return 0, z.err
|
||||
}
|
||||
|
||||
n, z.err = z.decompressor.Read(p)
|
||||
z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
|
||||
z.size += uint32(n)
|
||||
if z.err != io.EOF {
|
||||
// In the normal case we return here.
|
||||
return n, z.err
|
||||
for n == 0 {
|
||||
n, z.err = z.decompressor.Read(p)
|
||||
z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
|
||||
z.size += uint32(n)
|
||||
if z.err != io.EOF {
|
||||
// In the normal case we return here.
|
||||
return n, z.err
|
||||
}
|
||||
|
||||
// Finished file; check checksum and size.
|
||||
if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
|
||||
z.err = noEOF(err)
|
||||
return n, z.err
|
||||
}
|
||||
digest := le.Uint32(z.buf[:4])
|
||||
size := le.Uint32(z.buf[4:8])
|
||||
if digest != z.digest || size != z.size {
|
||||
z.err = ErrChecksum
|
||||
return n, z.err
|
||||
}
|
||||
z.digest, z.size = 0, 0
|
||||
|
||||
// File is ok; check if there is another.
|
||||
if !z.multistream {
|
||||
return n, io.EOF
|
||||
}
|
||||
z.err = nil // Remove io.EOF
|
||||
|
||||
if _, z.err = z.readHeader(); z.err != nil {
|
||||
return n, z.err
|
||||
}
|
||||
}
|
||||
|
||||
// Finished file; check checksum and size.
|
||||
if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
|
||||
z.err = noEOF(err)
|
||||
return n, z.err
|
||||
}
|
||||
digest := le.Uint32(z.buf[:4])
|
||||
size := le.Uint32(z.buf[4:8])
|
||||
if digest != z.digest || size != z.size {
|
||||
z.err = ErrChecksum
|
||||
return n, z.err
|
||||
}
|
||||
z.digest, z.size = 0, 0
|
||||
|
||||
// File is ok; check if there is another.
|
||||
if !z.multistream {
|
||||
return n, io.EOF
|
||||
}
|
||||
z.err = nil // Remove io.EOF
|
||||
|
||||
if _, z.err = z.readHeader(); z.err != nil {
|
||||
return n, z.err
|
||||
}
|
||||
|
||||
// Read from next file, if necessary.
|
||||
if n > 0 {
|
||||
return n, nil
|
||||
}
|
||||
return z.Read(p)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close closes the Reader. It does not close the underlying io.Reader.
|
||||
|
||||
@@ -515,3 +515,19 @@ func TestTruncatedStreams(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202230631(t *testing.T) {
|
||||
var empty = []byte{0x1f, 0x8b, 0x08, 0x00, 0xa7, 0x8f, 0x43, 0x62, 0x00,
|
||||
0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
r := bytes.NewReader(bytes.Repeat(empty, 4e6))
|
||||
z, err := NewReader(r)
|
||||
if err != nil {
|
||||
t.Fatalf("NewReader: got %v, want nil", err)
|
||||
}
|
||||
// Prior to CVE-2022-30631 fix, this would cause an unrecoverable panic due
|
||||
// to stack exhaustion.
|
||||
_, err = z.Read(make([]byte, 10))
|
||||
if err != io.EOF {
|
||||
t.Errorf("Reader.Read: got %v, want %v", err, io.EOF)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,11 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
|
||||
return specific.IsOnCurve(x, y)
|
||||
}
|
||||
|
||||
if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
|
||||
y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y2 := new(big.Int).Mul(y, y)
|
||||
y2.Mod(y2, curve.P)
|
||||
|
||||
@@ -174,6 +174,61 @@ func testUnmarshalToLargeCoordinates(t *testing.T, curve Curve) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvalidCoordinates tests big.Int values that are not valid field elements
|
||||
// (negative or bigger than P). They are expected to return false from
|
||||
// IsOnCurve, all other behavior is undefined.
|
||||
func TestInvalidCoordinates(t *testing.T) {
|
||||
testAllCurves(t, testInvalidCoordinates)
|
||||
}
|
||||
|
||||
func testInvalidCoordinates(t *testing.T, curve Curve) {
|
||||
checkIsOnCurveFalse := func(name string, x, y *big.Int) {
|
||||
if curve.IsOnCurve(x, y) {
|
||||
t.Errorf("IsOnCurve(%s) unexpectedly returned true", name)
|
||||
}
|
||||
}
|
||||
|
||||
p := curve.Params().P
|
||||
_, x, y, _ := GenerateKey(curve, rand.Reader)
|
||||
xx, yy := new(big.Int), new(big.Int)
|
||||
|
||||
// Check if the sign is getting dropped.
|
||||
xx.Neg(x)
|
||||
checkIsOnCurveFalse("-x, y", xx, y)
|
||||
yy.Neg(y)
|
||||
checkIsOnCurveFalse("x, -y", x, yy)
|
||||
|
||||
// Check if negative values are reduced modulo P.
|
||||
xx.Sub(x, p)
|
||||
checkIsOnCurveFalse("x-P, y", xx, y)
|
||||
yy.Sub(y, p)
|
||||
checkIsOnCurveFalse("x, y-P", x, yy)
|
||||
|
||||
// Check if positive values are reduced modulo P.
|
||||
xx.Add(x, p)
|
||||
checkIsOnCurveFalse("x+P, y", xx, y)
|
||||
yy.Add(y, p)
|
||||
checkIsOnCurveFalse("x, y+P", x, yy)
|
||||
|
||||
// Check if the overflow is dropped.
|
||||
xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535))
|
||||
checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y)
|
||||
yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535))
|
||||
checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy)
|
||||
|
||||
// Check if P is treated like zero (if possible).
|
||||
// y^2 = x^3 - 3x + B
|
||||
// y = mod_sqrt(x^3 - 3x + B)
|
||||
// y = mod_sqrt(B) if x = 0
|
||||
// If there is no modsqrt, there is no point with x = 0, can't test x = P.
|
||||
if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil {
|
||||
if !curve.IsOnCurve(big.NewInt(0), yy) {
|
||||
t.Fatal("(0, mod_sqrt(B)) is not on the curve?")
|
||||
}
|
||||
checkIsOnCurveFalse("P, y", p, yy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalCompressed(t *testing.T) {
|
||||
t.Run("P-256/03", func(t *testing.T) {
|
||||
data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
|
||||
|
||||
@@ -48,6 +48,11 @@ func (curve p224Curve) Params() *CurveParams {
|
||||
}
|
||||
|
||||
func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool {
|
||||
if bigX.Sign() < 0 || bigX.Cmp(curve.P) >= 0 ||
|
||||
bigY.Sign() < 0 || bigY.Cmp(curve.P) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var x, y p224FieldElement
|
||||
p224FromBig(&x, bigX)
|
||||
p224FromBig(&y, bigY)
|
||||
|
||||
@@ -52,7 +52,7 @@ func p256GetScalar(out *[32]byte, in []byte) {
|
||||
n := new(big.Int).SetBytes(in)
|
||||
var scalarBytes []byte
|
||||
|
||||
if n.Cmp(p256Params.N) >= 0 {
|
||||
if n.Cmp(p256Params.N) >= 0 || len(in) > len(out) {
|
||||
n.Mod(n, p256Params.N)
|
||||
scalarBytes = n.Bytes()
|
||||
} else {
|
||||
|
||||
@@ -153,3 +153,17 @@ func TestP256CombinedMult(t *testing.T) {
|
||||
t.Errorf("1×G + (-1)×G = (%d, %d), should be ∞", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue52075(t *testing.T) {
|
||||
Gx, Gy := P256().Params().Gx, P256().Params().Gy
|
||||
scalar := make([]byte, 33)
|
||||
scalar[32] = 1
|
||||
x, y := P256().ScalarBaseMult(scalar)
|
||||
if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
|
||||
t.Errorf("unexpected output (%v,%v)", x, y)
|
||||
}
|
||||
x, y = P256().ScalarMult(Gx, Gy, scalar)
|
||||
if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
|
||||
t.Errorf("unexpected output (%v,%v)", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,11 @@ func (curve p521Curve) Params() *CurveParams {
|
||||
}
|
||||
|
||||
func (curve p521Curve) IsOnCurve(x, y *big.Int) bool {
|
||||
if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
|
||||
y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
x1 := bigIntToFiatP521(x)
|
||||
y1 := bigIntToFiatP521(y)
|
||||
b := bigIntToFiatP521(curve.B) // TODO: precompute this value.
|
||||
|
||||
@@ -23,3 +23,21 @@ var Reader io.Reader
|
||||
func Read(b []byte) (n int, err error) {
|
||||
return io.ReadFull(Reader, b)
|
||||
}
|
||||
|
||||
// batched returns a function that calls f to populate a []byte by chunking it
|
||||
// into subslices of, at most, readMax bytes.
|
||||
func batched(f func([]byte) error, readMax int) func([]byte) error {
|
||||
return func(out []byte) error {
|
||||
for len(out) > 0 {
|
||||
read := len(out)
|
||||
if read > readMax {
|
||||
read = readMax
|
||||
}
|
||||
if err := f(out[:read]); err != nil {
|
||||
return err
|
||||
}
|
||||
out = out[read:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"internal/syscall/unix"
|
||||
)
|
||||
|
||||
@@ -16,20 +17,6 @@ func init() {
|
||||
altGetRandom = batched(getRandomBatch, maxGetRandomRead)
|
||||
}
|
||||
|
||||
// batched returns a function that calls f to populate a []byte by chunking it
|
||||
// into subslices of, at most, readMax bytes.
|
||||
func batched(f func([]byte) bool, readMax int) func([]byte) bool {
|
||||
return func(buf []byte) bool {
|
||||
for len(buf) > readMax {
|
||||
if !f(buf[:readMax]) {
|
||||
return false
|
||||
}
|
||||
buf = buf[readMax:]
|
||||
}
|
||||
return len(buf) == 0 || f(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// If the kernel is too old to support the getrandom syscall(),
|
||||
// unix.GetRandom will immediately return ENOSYS and we will then fall back to
|
||||
// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
|
||||
@@ -37,7 +24,10 @@ func batched(f func([]byte) bool, readMax int) func([]byte) bool {
|
||||
// If the kernel supports the getrandom() syscall, unix.GetRandom will block
|
||||
// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
|
||||
// In this case, unix.GetRandom will not return an error.
|
||||
func getRandomBatch(p []byte) (ok bool) {
|
||||
func getRandomBatch(p []byte) error {
|
||||
n, err := unix.GetRandom(p, 0)
|
||||
return n == len(p) && err == nil
|
||||
if n != len(p) {
|
||||
return errors.New("short read")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,20 +9,21 @@ package rand
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBatched(t *testing.T) {
|
||||
fillBatched := batched(func(p []byte) bool {
|
||||
fillBatched := batched(func(p []byte) error {
|
||||
for i := range p {
|
||||
p[i] = byte(i)
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}, 5)
|
||||
|
||||
p := make([]byte, 13)
|
||||
if !fillBatched(p) {
|
||||
t.Fatal("batched function returned false")
|
||||
if err := fillBatched(p); err != nil {
|
||||
t.Fatalf("batched function returned error: %s", err)
|
||||
}
|
||||
expected := []byte{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2}
|
||||
if !bytes.Equal(expected, p) {
|
||||
@@ -31,15 +32,15 @@ func TestBatched(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBatchedError(t *testing.T) {
|
||||
b := batched(func(p []byte) bool { return false }, 5)
|
||||
if b(make([]byte, 13)) {
|
||||
t.Fatal("batched function should have returned false")
|
||||
b := batched(func(p []byte) error { return errors.New("") }, 5)
|
||||
if b(make([]byte, 13)) == nil {
|
||||
t.Fatal("batched function should have returned an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchedEmpty(t *testing.T) {
|
||||
b := batched(func(p []byte) bool { return false }, 5)
|
||||
if !b(make([]byte, 0)) {
|
||||
t.Fatal("empty slice should always return true")
|
||||
b := batched(func(p []byte) error { return errors.New("") }, 5)
|
||||
if err := b(make([]byte, 0)); err != nil {
|
||||
t.Fatalf("empty slice should always return nil: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || openbsd
|
||||
// +build darwin openbsd
|
||||
//go:build (darwin && !ios) || openbsd
|
||||
// +build darwin,!ios openbsd
|
||||
|
||||
package rand
|
||||
|
||||
@@ -15,7 +15,7 @@ func init() {
|
||||
altGetRandom = getEntropy
|
||||
}
|
||||
|
||||
func getEntropy(p []byte) (ok bool) {
|
||||
func getEntropy(p []byte) error {
|
||||
// getentropy(2) returns a maximum of 256 bytes per call
|
||||
for i := 0; i < len(p); i += 256 {
|
||||
end := i + 256
|
||||
@@ -24,8 +24,8 @@ func getEntropy(p []byte) (ok bool) {
|
||||
}
|
||||
err := unix.GetEntropy(p[i:end])
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ type devReader struct {
|
||||
|
||||
// altGetRandom if non-nil specifies an OS-specific function to get
|
||||
// urandom-style randomness.
|
||||
var altGetRandom func([]byte) (ok bool)
|
||||
var altGetRandom func([]byte) (err error)
|
||||
|
||||
func warnBlocked() {
|
||||
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
|
||||
@@ -59,7 +59,7 @@ func (r *devReader) Read(b []byte) (n int, err error) {
|
||||
t := time.AfterFunc(60*time.Second, warnBlocked)
|
||||
defer t.Stop()
|
||||
}
|
||||
if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
|
||||
if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) == nil {
|
||||
return len(b), nil
|
||||
}
|
||||
r.mu.Lock()
|
||||
|
||||
@@ -9,7 +9,6 @@ package rand
|
||||
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() { Reader = &rngReader{} }
|
||||
@@ -17,16 +16,11 @@ func init() { Reader = &rngReader{} }
|
||||
type rngReader struct{}
|
||||
|
||||
func (r *rngReader) Read(b []byte) (n int, err error) {
|
||||
// RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
|
||||
inputLen := uint32(len(b))
|
||||
|
||||
if inputLen == 0 {
|
||||
return 0, nil
|
||||
// RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at
|
||||
// most 1<<31-1 bytes at a time so that this works the same on 32-bit
|
||||
// and 64-bit systems.
|
||||
if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = windows.RtlGenRandom(b)
|
||||
if err != nil {
|
||||
return 0, os.NewSyscallError("RtlGenRandom", err)
|
||||
}
|
||||
return int(inputLen), nil
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ type Conn struct {
|
||||
|
||||
// handshakeStatus is 1 if the connection is currently transferring
|
||||
// application data (i.e. is not currently processing a handshake).
|
||||
// handshakeStatus == 1 implies handshakeErr == nil.
|
||||
// This field is only to be accessed with sync/atomic.
|
||||
handshakeStatus uint32
|
||||
// constant after handshake; protected by handshakeMutex
|
||||
@@ -1396,6 +1397,13 @@ func (c *Conn) HandshakeContext(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
// Fast sync/atomic-based exit if there is no handshake in flight and the
|
||||
// last one succeeded without an error. Avoids the expensive context setup
|
||||
// and mutex for most Read and Write calls.
|
||||
if c.handshakeComplete() {
|
||||
return nil
|
||||
}
|
||||
|
||||
handshakeCtx, cancel := context.WithCancel(ctx)
|
||||
// Note: defer this before starting the "interrupter" goroutine
|
||||
// so that we can tell the difference between the input being canceled and
|
||||
@@ -1454,6 +1462,9 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
if c.handshakeErr == nil && !c.handshakeComplete() {
|
||||
c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
|
||||
}
|
||||
if c.handshakeErr != nil && c.handshakeComplete() {
|
||||
panic("tls: internal error: handshake returned an error but is marked successful")
|
||||
}
|
||||
|
||||
return c.handshakeErr
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
@@ -741,6 +742,19 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
}
|
||||
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
|
||||
|
||||
// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
|
||||
// The value is not stored anywhere; we never need to check the ticket age
|
||||
// because 0-RTT is not supported.
|
||||
ageAdd := make([]byte, 4)
|
||||
_, err = hs.c.config.rand().Read(ageAdd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
|
||||
|
||||
// ticket_nonce, which must be unique per connection, is always left at
|
||||
// zero because we only ever send one ticket per connection.
|
||||
|
||||
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ func isPrintable(b byte) bool {
|
||||
}
|
||||
|
||||
// parseASN1String parses the ASN.1 string types T61String, PrintableString,
|
||||
// UTF8String, BMPString, and IA5String. This is mostly copied from the
|
||||
// respective encoding/asn1.parse... methods, rather than just increasing
|
||||
// the API surface of that package.
|
||||
// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied
|
||||
// from the respective encoding/asn1.parse... methods, rather than just
|
||||
// increasing the API surface of that package.
|
||||
func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
|
||||
switch tag {
|
||||
case cryptobyte_asn1.T61String:
|
||||
@@ -93,6 +93,13 @@ func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
|
||||
return "", errors.New("invalid IA5String")
|
||||
}
|
||||
return s, nil
|
||||
case cryptobyte_asn1.Tag(asn1.TagNumericString):
|
||||
for _, b := range value {
|
||||
if !('0' <= b && b <= '9' || b == ' ') {
|
||||
return "", errors.New("invalid NumericString")
|
||||
}
|
||||
}
|
||||
return string(value), nil
|
||||
}
|
||||
return "", fmt.Errorf("unsupported string type: %v", tag)
|
||||
}
|
||||
@@ -934,10 +941,10 @@ func parseCertificate(der []byte) (*Certificate, error) {
|
||||
}
|
||||
|
||||
if cert.Version > 1 {
|
||||
if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).Constructed().ContextSpecific()) {
|
||||
if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) {
|
||||
return nil, errors.New("x509: malformed issuerUniqueID")
|
||||
}
|
||||
if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).Constructed().ContextSpecific()) {
|
||||
if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) {
|
||||
return nil, errors.New("x509: malformed subjectUniqueID")
|
||||
}
|
||||
if cert.Version == 3 {
|
||||
|
||||
102
src/crypto/x509/parser_test.go
Normal file
102
src/crypto/x509/parser_test.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2021 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 x509
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"testing"
|
||||
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
)
|
||||
|
||||
func TestParseASN1String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tag cryptobyte_asn1.Tag
|
||||
value []byte
|
||||
expected string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "T61String",
|
||||
tag: cryptobyte_asn1.T61String,
|
||||
value: []byte{80, 81, 82},
|
||||
expected: string("PQR"),
|
||||
},
|
||||
{
|
||||
name: "PrintableString",
|
||||
tag: cryptobyte_asn1.PrintableString,
|
||||
value: []byte{80, 81, 82},
|
||||
expected: string("PQR"),
|
||||
},
|
||||
{
|
||||
name: "PrintableString (invalid)",
|
||||
tag: cryptobyte_asn1.PrintableString,
|
||||
value: []byte{1, 2, 3},
|
||||
expectedErr: "invalid PrintableString",
|
||||
},
|
||||
{
|
||||
name: "UTF8String",
|
||||
tag: cryptobyte_asn1.UTF8String,
|
||||
value: []byte{80, 81, 82},
|
||||
expected: string("PQR"),
|
||||
},
|
||||
{
|
||||
name: "UTF8String (invalid)",
|
||||
tag: cryptobyte_asn1.UTF8String,
|
||||
value: []byte{255},
|
||||
expectedErr: "invalid UTF-8 string",
|
||||
},
|
||||
{
|
||||
name: "BMPString",
|
||||
tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
|
||||
value: []byte{80, 81},
|
||||
expected: string("偑"),
|
||||
},
|
||||
{
|
||||
name: "BMPString (invalid length)",
|
||||
tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
|
||||
value: []byte{255},
|
||||
expectedErr: "invalid BMPString",
|
||||
},
|
||||
{
|
||||
name: "IA5String",
|
||||
tag: cryptobyte_asn1.IA5String,
|
||||
value: []byte{80, 81},
|
||||
expected: string("PQ"),
|
||||
},
|
||||
{
|
||||
name: "IA5String (invalid)",
|
||||
tag: cryptobyte_asn1.IA5String,
|
||||
value: []byte{255},
|
||||
expectedErr: "invalid IA5String",
|
||||
},
|
||||
{
|
||||
name: "NumericString",
|
||||
tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
|
||||
value: []byte{49, 50},
|
||||
expected: string("12"),
|
||||
},
|
||||
{
|
||||
name: "NumericString (invalid)",
|
||||
tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
|
||||
value: []byte{80},
|
||||
expectedErr: "invalid NumericString",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
out, err := parseASN1String(tc.tag, tc.value)
|
||||
if err != nil && err.Error() != tc.expectedErr {
|
||||
t.Fatalf("parseASN1String returned unexpected error: got %q, want %q", err, tc.expectedErr)
|
||||
} else if err == nil && tc.expectedErr != "" {
|
||||
t.Fatalf("parseASN1String didn't fail, expected: %s", tc.expectedErr)
|
||||
}
|
||||
if out != tc.expected {
|
||||
t.Fatalf("parseASN1String returned unexpected value: got %q, want %q", out, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3216,3 +3216,146 @@ func TestAuthKeyIdOptional(t *testing.T) {
|
||||
t.Fatalf("ParseCertificate to failed to parse certificate with optional authority key identifier fields: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
const largeOIDPEM = `
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
da:ba:53:19:1b:09:4b:82:b2:89:26:7d:c7:6f:a0:02
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: O = Acme Co
|
||||
Validity
|
||||
Not Before: Dec 21 16:59:27 2021 GMT
|
||||
Not After : Dec 21 16:59:27 2022 GMT
|
||||
Subject: O = Acme Co
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:bf:17:16:d8:bc:29:9c:16:e5:76:b4:93:15:78:
|
||||
ad:6e:45:c5:4a:63:46:a1:b2:76:71:65:51:9c:14:
|
||||
c4:ea:74:13:e4:34:df:2f:2c:65:11:e8:56:52:69:
|
||||
11:f9:0e:fc:77:bb:63:a8:7c:1a:c6:a1:7b:6e:6c:
|
||||
e7:18:25:25:c9:e8:fb:06:7f:a2:a9:98:fe:2a:bc:
|
||||
8a:b3:75:b6:b8:7d:b6:c9:6b:29:08:32:22:10:cb:
|
||||
8d:d6:60:c8:83:ad:f5:58:91:d6:11:e8:55:56:fb:
|
||||
8f:a3:a2:9f:48:cb:79:e4:65:4a:8c:a6:52:64:9f:
|
||||
99:38:35:d4:d5:ac:6f:cf:a0:cb:42:8c:07:eb:21:
|
||||
17:31:3a:eb:91:7b:62:43:a4:75:5f:ef:a7:2f:94:
|
||||
f8:69:0b:d4:ec:09:e6:00:c0:8c:dd:07:63:0b:e4:
|
||||
77:aa:60:18:3c:a0:e0:ae:0a:ea:0e:52:3b:b4:fa:
|
||||
6a:30:1b:50:62:21:73:53:33:01:60:a1:6b:99:58:
|
||||
00:f3:77:c6:0f:46:19:ca:c2:5d:cd:f5:e2:52:4d:
|
||||
84:94:23:d3:32:2f:ae:5f:da:43:a1:19:95:d2:17:
|
||||
dd:49:14:b4:d9:48:1c:08:13:93:8e:d5:09:43:21:
|
||||
b6:ce:52:e8:87:bb:d2:60:0d:c6:4e:bf:c5:93:6a:
|
||||
c6:bf
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:FALSE
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:longOID.example
|
||||
X509v3 Certificate Policies:
|
||||
Policy: 1.3.6.1.4.1.311.21.8.1492336001
|
||||
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
72:77:8b:de:48:fb:6d:9a:94:b1:be:d4:90:7d:4c:e6:d3:79:
|
||||
fa:fb:fc:3e:d5:3d:e9:a0:ce:28:2b:2f:94:77:3f:87:f8:9c:
|
||||
9f:91:1c:f3:f6:58:91:15:6b:24:b9:ca:ae:9f:ee:ca:c8:31:
|
||||
db:1a:3d:bb:6b:83:6d:bc:81:8b:a1:79:d5:3e:bb:dd:93:fe:
|
||||
35:3e:b7:99:e0:d6:eb:58:0c:fd:42:73:dc:49:da:e2:b7:ae:
|
||||
15:ee:e6:cc:aa:ef:91:41:9a:18:46:8d:4a:39:65:a2:85:3c:
|
||||
7f:0c:41:f8:0b:9c:e8:1f:35:36:60:8d:8c:e0:8e:18:b1:06:
|
||||
57:d0:4e:c4:c3:cd:8f:6f:e7:76:02:52:da:03:43:61:2b:b3:
|
||||
bf:19:fd:73:0d:6a:0b:b4:b6:cb:a9:6f:70:4e:53:2a:54:07:
|
||||
b3:74:fd:85:49:57:5b:23:8d:8c:6b:53:2b:09:e8:41:a5:80:
|
||||
3f:69:1b:11:d1:6b:13:35:2e:f9:d6:50:15:d9:91:38:42:43:
|
||||
e9:17:af:67:d9:96:a4:d1:6a:4f:cc:b4:a7:8e:48:1f:00:72:
|
||||
69:de:4d:f1:73:a4:47:12:67:e9:f9:07:3e:79:75:90:42:b8:
|
||||
d4:b5:fd:d1:7e:35:04:f7:00:04:cf:f1:36:be:0f:27:81:1f:
|
||||
a6:ba:88:6c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDHTCCAgWgAwIBAgIRANq6UxkbCUuCsokmfcdvoAIwDQYJKoZIhvcNAQELBQAw
|
||||
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0yMTEyMjExNjU5MjdaFw0yMjEyMjExNjU5
|
||||
MjdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQC/FxbYvCmcFuV2tJMVeK1uRcVKY0ahsnZxZVGcFMTqdBPkNN8vLGUR
|
||||
6FZSaRH5Dvx3u2OofBrGoXtubOcYJSXJ6PsGf6KpmP4qvIqzdba4fbbJaykIMiIQ
|
||||
y43WYMiDrfVYkdYR6FVW+4+jop9Iy3nkZUqMplJkn5k4NdTVrG/PoMtCjAfrIRcx
|
||||
OuuRe2JDpHVf76cvlPhpC9TsCeYAwIzdB2ML5HeqYBg8oOCuCuoOUju0+mowG1Bi
|
||||
IXNTMwFgoWuZWADzd8YPRhnKwl3N9eJSTYSUI9MyL65f2kOhGZXSF91JFLTZSBwI
|
||||
E5OO1QlDIbbOUuiHu9JgDcZOv8WTasa/AgMBAAGjbjBsMA4GA1UdDwEB/wQEAwIF
|
||||
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGC
|
||||
D2xvbmdPSUQuZXhhbXBsZTAbBgNVHSAEFDASMBAGDisGAQQBgjcVCIXHzPsBMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQByd4veSPttmpSxvtSQfUzm03n6+/w+1T3poM4oKy+U
|
||||
dz+H+JyfkRzz9liRFWskucqun+7KyDHbGj27a4NtvIGLoXnVPrvdk/41PreZ4Nbr
|
||||
WAz9QnPcSdrit64V7ubMqu+RQZoYRo1KOWWihTx/DEH4C5zoHzU2YI2M4I4YsQZX
|
||||
0E7Ew82Pb+d2AlLaA0NhK7O/Gf1zDWoLtLbLqW9wTlMqVAezdP2FSVdbI42Ma1Mr
|
||||
CehBpYA/aRsR0WsTNS751lAV2ZE4QkPpF69n2Zak0WpPzLSnjkgfAHJp3k3xc6RH
|
||||
Emfp+Qc+eXWQQrjUtf3RfjUE9wAEz/E2vg8ngR+muohs
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
func TestLargeOID(t *testing.T) {
|
||||
// See Issue 49678.
|
||||
b, _ := pem.Decode([]byte(largeOIDPEM))
|
||||
if b == nil {
|
||||
t.Fatalf("couldn't decode test certificate")
|
||||
}
|
||||
_, err := ParseCertificate(b.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseCertificate to failed to parse certificate with large OID: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueIDPEM = `-----BEGIN CERTIFICATE-----
|
||||
MIIFsDCCBJigAwIBAgIIrOyC1ydafZMwDQYJKoZIhvcNAQEFBQAwgY4xgYswgYgG
|
||||
A1UEAx6BgABNAGkAYwByAG8AcwBvAGYAdAAgAEYAbwByAGUAZgByAG8AbgB0ACAA
|
||||
VABNAEcAIABIAFQAVABQAFMAIABJAG4AcwBwAGUAYwB0AGkAbwBuACAAQwBlAHIA
|
||||
dABpAGYAaQBjAGEAdABpAG8AbgAgAEEAdQB0AGgAbwByAGkAdAB5MB4XDTE0MDEx
|
||||
ODAwNDEwMFoXDTE1MTExNTA5Mzc1NlowgZYxCzAJBgNVBAYTAklEMRAwDgYDVQQI
|
||||
EwdqYWthcnRhMRIwEAYDVQQHEwlJbmRvbmVzaWExHDAaBgNVBAoTE3N0aG9ub3Jl
|
||||
aG90ZWxyZXNvcnQxHDAaBgNVBAsTE3N0aG9ub3JlaG90ZWxyZXNvcnQxJTAjBgNV
|
||||
BAMTHG1haWwuc3Rob25vcmVob3RlbHJlc29ydC5jb20wggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCvuu0qpI+Ko2X84Twkf84cRD/rgp6vpgc5Ebejx/D4
|
||||
PEVON5edZkazrMGocK/oQqIlRxx/lefponN/chlGcllcVVPWTuFjs8k+Aat6T1qp
|
||||
4iXxZekAqX+U4XZMIGJD3PckPL6G2RQSlF7/LhGCsRNRdKpMWSTbou2Ma39g52Kf
|
||||
gsl3SK/GwLiWpxpcSkNQD1hugguEIsQYLxbeNwpcheXZtxbBGguPzQ7rH8c5vuKU
|
||||
BkMOzaiNKLzHbBdFSrua8KWwCJg76Vdq/q36O9GlW6YgG3i+A4pCJjXWerI1lWwX
|
||||
Ktk5V+SvUHGey1bkDuZKJ6myMk2pGrrPWCT7jP7WskChAgMBAAGBCQBCr1dgEleo
|
||||
cKOCAfswggH3MIHDBgNVHREEgbswgbiCHG1haWwuc3Rob25vcmVob3RlbHJlc29y
|
||||
dC5jb22CIGFzaGNoc3ZyLnN0aG9ub3JlaG90ZWxyZXNvcnQuY29tgiRBdXRvRGlz
|
||||
Y292ZXIuc3Rob25vcmVob3RlbHJlc29ydC5jb22CHEF1dG9EaXNjb3Zlci5ob3Rl
|
||||
bHJlc29ydC5jb22CCEFTSENIU1ZSghdzdGhvbm9yZWhvdGVscmVzb3J0LmNvbYIP
|
||||
aG90ZWxyZXNvcnQuY29tMCEGCSsGAQQBgjcUAgQUHhIAVwBlAGIAUwBlAHIAdgBl
|
||||
AHIwHQYDVR0OBBYEFMAC3UR4FwAdGekbhMgnd6lMejtbMAsGA1UdDwQEAwIFoDAT
|
||||
BgNVHSUEDDAKBggrBgEFBQcDATAJBgNVHRMEAjAAMIG/BgNVHQEEgbcwgbSAFGfF
|
||||
6xihk+gJJ5TfwvtWe1UFnHLQoYGRMIGOMYGLMIGIBgNVBAMegYAATQBpAGMAcgBv
|
||||
AHMAbwBmAHQAIABGAG8AcgBlAGYAcgBvAG4AdAAgAFQATQBHACAASABUAFQAUABT
|
||||
ACAASQBuAHMAcABlAGMAdABpAG8AbgAgAEMAZQByAHQAaQBmAGkAYwBhAHQAaQBv
|
||||
AG4AIABBAHUAdABoAG8AcgBpAHQAeYIIcKhXEmBXr0IwDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBABlSxyCMr3+ANr+WmPSjyN5YCJBgnS0IFCwJAzIYP87bcTye/U8eQ2+E6PqG
|
||||
Q7Huj7nfHEw9qnGo+HNyPp1ad3KORzXDb54c6xEoi+DeuPzYHPbn4c3hlH49I0aQ
|
||||
eWW2w4RslSWpLvO6Y7Lboyz2/Thk/s2kd4RHxkkWpH2ltPqJuYYg3X6oM5+gIFHJ
|
||||
WGnh+ojZ5clKvS5yXh3Wkj78M6sb32KfcBk0Hx6NkCYPt60ODYmWtvqwtw6r73u5
|
||||
TnTYWRNvo2svX69TriL+CkHY9O1Hkwf2It5zHl3gNiKTJVaak8AuEz/CKWZneovt
|
||||
yYLwhUhg3PX5Co1VKYE+9TxloiE=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
func TestParseUniqueID(t *testing.T) {
|
||||
b, _ := pem.Decode([]byte(uniqueIDPEM))
|
||||
if b == nil {
|
||||
t.Fatalf("couldn't decode test certificate")
|
||||
}
|
||||
cert, err := ParseCertificate(b.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseCertificate to failed to parse certificate with unique identifier id: %s", err)
|
||||
}
|
||||
if len(cert.Extensions) != 7 {
|
||||
t.Fatalf("unexpected number of extensions (probably because the extension section was not parsed): got %d, want 7", len(cert.Extensions))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +345,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hdr.Iundefsym > uint32(len(f.Symtab.Syms)) {
|
||||
return nil, &FormatError{offset, fmt.Sprintf(
|
||||
"undefined symbols index in dynamic symbol table command is greater than symbol table length (%d > %d)",
|
||||
hdr.Iundefsym, len(f.Symtab.Syms)), nil}
|
||||
} else if hdr.Iundefsym+hdr.Nundefsym > uint32(len(f.Symtab.Syms)) {
|
||||
return nil, &FormatError{offset, fmt.Sprintf(
|
||||
"number of undefined symbols after index in dynamic symbol table command is greater than symbol table length (%d > %d)",
|
||||
hdr.Iundefsym+hdr.Nundefsym, len(f.Symtab.Syms)), nil}
|
||||
}
|
||||
dat := make([]byte, hdr.Nindirectsyms*4)
|
||||
if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
|
||||
return nil, err
|
||||
@@ -641,10 +650,14 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for DWARF4 .debug_types sections.
|
||||
// Look for DWARF4 .debug_types sections and DWARF5 sections.
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix != "types" {
|
||||
if suffix == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := dat[suffix]; ok {
|
||||
// Already handled.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -653,7 +666,11 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
if suffix == "types" {
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
} else {
|
||||
err = d.AddSection(".debug_"+suffix, b)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -416,3 +416,10 @@ func TestTypeString(t *testing.T) {
|
||||
t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenBadDysymCmd(t *testing.T) {
|
||||
_, err := openObscured("testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64")
|
||||
if err == nil {
|
||||
t.Fatal("openObscured did not fail when opening a file with an invalid dynamic symbol table command")
|
||||
}
|
||||
}
|
||||
|
||||
1
src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64
vendored
Normal file
1
src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -272,10 +272,14 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for DWARF4 .debug_types sections.
|
||||
// Look for DWARF4 .debug_types sections and DWARF5 sections.
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix != "types" {
|
||||
if suffix == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := dat[suffix]; ok {
|
||||
// Already handled.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -284,7 +288,11 @@ func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
if suffix == "types" {
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
} else {
|
||||
err = d.AddSection(".debug_"+suffix, b)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -129,3 +129,43 @@ func TestUninitialized(t *testing.T) {
|
||||
t.Errorf("in uninitialized embed.FS, . is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloT []T
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloUint8 []uint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloEUint8 []EmbedUint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloBytes EmbedBytes
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloString EmbedString
|
||||
)
|
||||
|
||||
type T byte
|
||||
type EmbedUint8 uint8
|
||||
type EmbedBytes []byte
|
||||
type EmbedString string
|
||||
|
||||
// golang.org/issue/47735
|
||||
func TestAliases(t *testing.T) {
|
||||
all := testDirAll
|
||||
want, e := all.ReadFile("testdata/hello.txt")
|
||||
if e != nil {
|
||||
t.Fatal("ReadFile:", e)
|
||||
}
|
||||
check := func(g interface{}) {
|
||||
got := reflect.ValueOf(g)
|
||||
for i := 0; i < got.Len(); i++ {
|
||||
if byte(got.Index(i).Uint()) != want[i] {
|
||||
t.Fatalf("got %v want %v", got.Bytes(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
check(helloT)
|
||||
check(helloUint8)
|
||||
check(helloEUint8)
|
||||
check(helloBytes)
|
||||
check(helloString)
|
||||
}
|
||||
|
||||
@@ -871,8 +871,13 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
|
||||
return &op
|
||||
}
|
||||
|
||||
var maxIgnoreNestingDepth = 10000
|
||||
|
||||
// decIgnoreOpFor returns the decoding op for a field that has no destination.
|
||||
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp {
|
||||
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp {
|
||||
if depth > maxIgnoreNestingDepth {
|
||||
error_(errors.New("invalid nesting depth"))
|
||||
}
|
||||
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
|
||||
// Return the pointer to the op we're already building.
|
||||
if opPtr := inProgress[wireId]; opPtr != nil {
|
||||
@@ -896,7 +901,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp)
|
||||
errorf("bad data: undefined type %s", wireId.string())
|
||||
case wire.ArrayT != nil:
|
||||
elemId := wire.ArrayT.Elem
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
|
||||
op = func(i *decInstr, state *decoderState, value reflect.Value) {
|
||||
state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len)
|
||||
}
|
||||
@@ -904,15 +909,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp)
|
||||
case wire.MapT != nil:
|
||||
keyId := dec.wireType[wireId].MapT.Key
|
||||
elemId := dec.wireType[wireId].MapT.Elem
|
||||
keyOp := dec.decIgnoreOpFor(keyId, inProgress)
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
|
||||
keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1)
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
|
||||
op = func(i *decInstr, state *decoderState, value reflect.Value) {
|
||||
state.dec.ignoreMap(state, *keyOp, *elemOp)
|
||||
}
|
||||
|
||||
case wire.SliceT != nil:
|
||||
elemId := wire.SliceT.Elem
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
|
||||
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
|
||||
op = func(i *decInstr, state *decoderState, value reflect.Value) {
|
||||
state.dec.ignoreSlice(state, *elemOp)
|
||||
}
|
||||
@@ -1073,7 +1078,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
|
||||
func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine {
|
||||
engine := new(decEngine)
|
||||
engine.instr = make([]decInstr, 1) // one item
|
||||
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp))
|
||||
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0)
|
||||
ovfl := overflow(dec.typeString(remoteId))
|
||||
engine.instr[0] = decInstr{*op, 0, nil, ovfl}
|
||||
engine.numInstr = 1
|
||||
@@ -1118,7 +1123,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
|
||||
localField, present := srt.FieldByName(wireField.Name)
|
||||
// TODO(r): anonymous names
|
||||
if !present || !isExported(wireField.Name) {
|
||||
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp))
|
||||
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0)
|
||||
engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl}
|
||||
continue
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user