mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c580180744 | ||
|
|
4548fcc8df | ||
|
|
7d57324030 | ||
|
|
552410fec2 | ||
|
|
170a72e58b | ||
|
|
021fc241c9 | ||
|
|
8226cb06aa | ||
|
|
6c480017ae | ||
|
|
0d530843be | ||
|
|
d66b2112bd | ||
|
|
fa6aa87222 | ||
|
|
a6ca6d90b3 | ||
|
|
16ab7e49d4 | ||
|
|
37c117f2bf | ||
|
|
4c62fd3677 | ||
|
|
8b6ae9be12 | ||
|
|
3d5afa9610 | ||
|
|
0fb1e1438b | ||
|
|
accf363d5d | ||
|
|
ae7943e11b | ||
|
|
ed8cbbc3ae | ||
|
|
bc51e93027 | ||
|
|
58bc454a11 | ||
|
|
fb052db03a | ||
|
|
a91ed836c5 | ||
|
|
cb4cd9e177 | ||
|
|
d4ee0255f2 | ||
|
|
fd129a6b0e | ||
|
|
7677616a26 | ||
|
|
0d6115c352 | ||
|
|
f2222d8284 | ||
|
|
c9f27b8d31 | ||
|
|
dbf69b7da4 | ||
|
|
40b97d6921 | ||
|
|
1613be8481 | ||
|
|
0410005dc4 | ||
|
|
895fb1bb6f | ||
|
|
df6a737cc8 | ||
|
|
9210eaf7dc | ||
|
|
305fa952c2 | ||
|
|
c7248a0c94 | ||
|
|
04cd717a26 | ||
|
|
87ffba35dd | ||
|
|
ce04f86bd3 | ||
|
|
7e709791c2 | ||
|
|
ea0537f2fc | ||
|
|
e67a58b7cb | ||
|
|
d4adea20f0 | ||
|
|
f12cf7694f | ||
|
|
9baddd3f21 | ||
|
|
96139f2599 | ||
|
|
887c0d890f | ||
|
|
3a45c13094 | ||
|
|
2940614c63 | ||
|
|
1d967ab95c | ||
|
|
9c7463ca90 | ||
|
|
ac59d7abb9 | ||
|
|
33fb47921f | ||
|
|
902d16e97b | ||
|
|
f39c4deee8 | ||
|
|
0da04a662a | ||
|
|
3979fb9af9 | ||
|
|
5993fbbd48 | ||
|
|
6e04188440 | ||
|
|
b5c1b5aa07 | ||
|
|
e9e0473681 | ||
|
|
634d28d78c | ||
|
|
d86e53e896 | ||
|
|
3068d55c2f | ||
|
|
a9ba734e4d | ||
|
|
047ca22916 | ||
|
|
2b7243a62f | ||
|
|
a9547ad8ad | ||
|
|
292abd96ae | ||
|
|
88f91b709e | ||
|
|
4fd2617cd8 | ||
|
|
e0bd146a13 | ||
|
|
ca9cd629fb | ||
|
|
18e5d75ffb | ||
|
|
ddeae6b248 | ||
|
|
b7e0eb49d8 | ||
|
|
0b8c416688 | ||
|
|
1a7e9af153 | ||
|
|
f21be2fdc6 | ||
|
|
e34168e634 | ||
|
|
3e06467282 |
@@ -3,7 +3,7 @@
|
||||
Go is an open source programming language that makes it easy to build simple,
|
||||
reliable, and efficient software.
|
||||
|
||||

|
||||

|
||||
*Gopher image by [Renee French][rf], licensed under [Creative Commons 3.0 Attributions license][cc3-by].*
|
||||
|
||||
Our canonical Git repository is located at https://go.googlesource.com/go.
|
||||
|
||||
@@ -201,12 +201,18 @@ func TestMethod(t *testing.T) {
|
||||
// Exported symbol's method must be live.
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
|
||||
goCmd(t, "build", "-o", "method.exe", "./method/main.go")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "./method.exe")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
|
||||
}
|
||||
run(t, "./method.exe")
|
||||
}
|
||||
|
||||
func TestMethod2(t *testing.T) {
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "method2.so", "./method2/plugin.go")
|
||||
goCmd(t, "build", "-o", "method2.exe", "./method2/main.go")
|
||||
run(t, "./method2.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")
|
||||
}
|
||||
|
||||
7
misc/cgo/testplugin/testdata/issue44956/base/base.go
vendored
Normal file
7
misc/cgo/testplugin/testdata/issue44956/base/base.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// 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 base
|
||||
|
||||
var X = &map[int]int{123: 456}
|
||||
47
misc/cgo/testplugin/testdata/issue44956/main.go
vendored
Normal file
47
misc/cgo/testplugin/testdata/issue44956/main.go
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
// Issue 44956: writable static temp is not exported correctly.
|
||||
// In the test below, package base is
|
||||
//
|
||||
// X = &map{...}
|
||||
//
|
||||
// which compiles to
|
||||
//
|
||||
// X = &stmp // static
|
||||
// stmp = makemap(...) // in init function
|
||||
//
|
||||
// plugin1 and plugin2 both import base. plugin1 doesn't use
|
||||
// base.X, so that symbol is deadcoded in plugin1.
|
||||
//
|
||||
// plugin1 is loaded first. base.init runs at that point, which
|
||||
// initialize base.stmp.
|
||||
//
|
||||
// plugin2 is then loaded. base.init already ran, so it doesn't run
|
||||
// again. When base.stmp is not exported, plugin2's base.X points to
|
||||
// its own private base.stmp, which is not initialized, fail.
|
||||
|
||||
package main
|
||||
|
||||
import "plugin"
|
||||
|
||||
func main() {
|
||||
_, err := plugin.Open("issue44956p1.so")
|
||||
if err != nil {
|
||||
panic("FAIL")
|
||||
}
|
||||
|
||||
p2, err := plugin.Open("issue44956p2.so")
|
||||
if err != nil {
|
||||
panic("FAIL")
|
||||
}
|
||||
f, err := p2.Lookup("F")
|
||||
if err != nil {
|
||||
panic("FAIL")
|
||||
}
|
||||
x := f.(func() *map[int]int)()
|
||||
if x == nil || (*x)[123] != 456 {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
9
misc/cgo/testplugin/testdata/issue44956/plugin1.go
vendored
Normal file
9
misc/cgo/testplugin/testdata/issue44956/plugin1.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 _ "testplugin/issue44956/base"
|
||||
|
||||
func main() {}
|
||||
11
misc/cgo/testplugin/testdata/issue44956/plugin2.go
vendored
Normal file
11
misc/cgo/testplugin/testdata/issue44956/plugin2.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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 "testplugin/issue44956/base"
|
||||
|
||||
func F() *map[int]int { return base.X }
|
||||
|
||||
func main() {}
|
||||
32
misc/cgo/testplugin/testdata/method2/main.go
vendored
Normal file
32
misc/cgo/testplugin/testdata/method2/main.go
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
|
||||
// A type can be passed to a plugin and converted to interface
|
||||
// there. So its methods need to be live.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"plugin"
|
||||
|
||||
"testplugin/method2/p"
|
||||
)
|
||||
|
||||
var t p.T
|
||||
|
||||
type I interface { M() }
|
||||
|
||||
func main() {
|
||||
pl, err := plugin.Open("method2.so")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f, err := pl.Lookup("F")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f.(func(p.T) interface{})(t).(I).M()
|
||||
}
|
||||
9
misc/cgo/testplugin/testdata/method2/p/p.go
vendored
Normal file
9
misc/cgo/testplugin/testdata/method2/p/p.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 p
|
||||
|
||||
type T int
|
||||
|
||||
func (T) M() { println("M") }
|
||||
11
misc/cgo/testplugin/testdata/method2/plugin.go
vendored
Normal file
11
misc/cgo/testplugin/testdata/method2/plugin.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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 "testplugin/method2/p"
|
||||
|
||||
func main() {}
|
||||
|
||||
func F(t p.T) interface{} { return t }
|
||||
@@ -564,6 +564,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 + 4096;
|
||||
if (offset >= wasmMinDataAddr) {
|
||||
throw new Error("command line too long");
|
||||
}
|
||||
|
||||
this._inst.exports.run(argc, argv);
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise();
|
||||
|
||||
@@ -99,7 +99,15 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
||||
return err
|
||||
}
|
||||
z.r = r
|
||||
z.File = make([]*File, 0, end.directoryRecords)
|
||||
// Since the number of directory records is not validated, it is not
|
||||
// safe to preallocate z.File without first checking that the specified
|
||||
// number of files is reasonable, since a malformed archive may
|
||||
// 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 end.directorySize < uint64(size) && (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
|
||||
z.File = make([]*File, 0, end.directoryRecords)
|
||||
}
|
||||
z.Comment = end.comment
|
||||
rs := io.NewSectionReader(r, 0, size)
|
||||
if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
|
||||
@@ -628,10 +636,11 @@ func (b *readBuf) sub(n int) readBuf {
|
||||
}
|
||||
|
||||
// A fileListEntry is a File and its ename.
|
||||
// If file == nil, the fileListEntry describes a directory, without metadata.
|
||||
// If file == nil, the fileListEntry describes a directory without metadata.
|
||||
type fileListEntry struct {
|
||||
name string
|
||||
file *File // nil for directories
|
||||
name string
|
||||
file *File
|
||||
isDir bool
|
||||
}
|
||||
|
||||
type fileInfoDirEntry interface {
|
||||
@@ -640,20 +649,26 @@ type fileInfoDirEntry interface {
|
||||
}
|
||||
|
||||
func (e *fileListEntry) stat() fileInfoDirEntry {
|
||||
if e.file != nil {
|
||||
if !e.isDir {
|
||||
return headerFileInfo{&e.file.FileHeader}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Only used for directories.
|
||||
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
|
||||
func (f *fileListEntry) Size() int64 { return 0 }
|
||||
func (f *fileListEntry) ModTime() time.Time { return time.Time{} }
|
||||
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||
func (f *fileListEntry) IsDir() bool { return true }
|
||||
func (f *fileListEntry) Sys() interface{} { return nil }
|
||||
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
|
||||
func (f *fileListEntry) Size() int64 { return 0 }
|
||||
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||
func (f *fileListEntry) IsDir() bool { return true }
|
||||
func (f *fileListEntry) Sys() interface{} { return nil }
|
||||
|
||||
func (f *fileListEntry) ModTime() time.Time {
|
||||
if f.file == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return f.file.FileHeader.Modified.UTC()
|
||||
}
|
||||
|
||||
func (f *fileListEntry) Info() (fs.FileInfo, error) { return f, nil }
|
||||
|
||||
@@ -664,7 +679,7 @@ func toValidName(name string) string {
|
||||
if strings.HasPrefix(p, "/") {
|
||||
p = p[len("/"):]
|
||||
}
|
||||
for strings.HasPrefix(name, "../") {
|
||||
for strings.HasPrefix(p, "../") {
|
||||
p = p[len("../"):]
|
||||
}
|
||||
return p
|
||||
@@ -673,15 +688,32 @@ func toValidName(name string) string {
|
||||
func (r *Reader) initFileList() {
|
||||
r.fileListOnce.Do(func() {
|
||||
dirs := make(map[string]bool)
|
||||
knownDirs := make(map[string]bool)
|
||||
for _, file := range r.File {
|
||||
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
||||
name := toValidName(file.Name)
|
||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||
dirs[dir] = true
|
||||
}
|
||||
r.fileList = append(r.fileList, fileListEntry{name, file})
|
||||
entry := fileListEntry{
|
||||
name: name,
|
||||
file: file,
|
||||
isDir: isDir,
|
||||
}
|
||||
r.fileList = append(r.fileList, entry)
|
||||
if isDir {
|
||||
knownDirs[name] = true
|
||||
}
|
||||
}
|
||||
for dir := range dirs {
|
||||
r.fileList = append(r.fileList, fileListEntry{dir + "/", nil})
|
||||
if !knownDirs[dir] {
|
||||
entry := fileListEntry{
|
||||
name: dir,
|
||||
file: nil,
|
||||
isDir: true,
|
||||
}
|
||||
r.fileList = append(r.fileList, entry)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(r.fileList, func(i, j int) bool { return fileEntryLess(r.fileList[i].name, r.fileList[j].name) })
|
||||
@@ -705,7 +737,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
|
||||
if e == nil || !fs.ValidPath(name) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||
}
|
||||
if e.file == nil || strings.HasSuffix(e.file.Name, "/") {
|
||||
if e.isDir {
|
||||
return &openDir{e, r.openReadDir(name), 0}, nil
|
||||
}
|
||||
rc, err := e.file.Open()
|
||||
@@ -730,7 +762,7 @@ func split(name string) (dir, elem string, isDir bool) {
|
||||
return name[:i], name[i+1:], isDir
|
||||
}
|
||||
|
||||
var dotFile = &fileListEntry{name: "./"}
|
||||
var dotFile = &fileListEntry{name: "./", isDir: true}
|
||||
|
||||
func (r *Reader) openLookup(name string) *fileListEntry {
|
||||
if name == "." {
|
||||
|
||||
@@ -1073,11 +1073,173 @@ func TestIssue12449(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFS(t *testing.T) {
|
||||
z, err := OpenReader("testdata/unix.zip")
|
||||
for _, test := range []struct {
|
||||
file string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
"testdata/unix.zip",
|
||||
[]string{"hello", "dir/bar", "readonly"},
|
||||
},
|
||||
{
|
||||
"testdata/subdir.zip",
|
||||
[]string{"a/b/c"},
|
||||
},
|
||||
} {
|
||||
t.Run(test.file, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
z, err := OpenReader(test.file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer z.Close()
|
||||
if err := fstest.TestFS(z, test.want...); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSModTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
z, err := OpenReader("testdata/subdir.zip")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fstest.TestFS(z, "hello", "dir/bar", "dir/empty", "readonly"); err != nil {
|
||||
t.Fatal(err)
|
||||
defer z.Close()
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
want time.Time
|
||||
}{
|
||||
{
|
||||
"a",
|
||||
time.Date(2021, 4, 19, 12, 29, 56, 0, timeZone(-7*time.Hour)).UTC(),
|
||||
},
|
||||
{
|
||||
"a/b/c",
|
||||
time.Date(2021, 4, 19, 12, 29, 59, 0, timeZone(-7*time.Hour)).UTC(),
|
||||
},
|
||||
} {
|
||||
fi, err := fs.Stat(z, test.name)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if got := fi.ModTime(); !got.Equal(test.want) {
|
||||
t.Errorf("%s: got modtime %v, want %v", test.name, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202127919(t *testing.T) {
|
||||
// Archive containing only the file "../test.txt"
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e,
|
||||
0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78,
|
||||
0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c,
|
||||
0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51,
|
||||
0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc,
|
||||
0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff,
|
||||
0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed,
|
||||
0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00,
|
||||
0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14,
|
||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
|
||||
0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
|
||||
0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00,
|
||||
0x00, 0x00, 0x59, 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)
|
||||
}
|
||||
_, err = r.Open("test.txt")
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202133196(t *testing.T) {
|
||||
// Archive that indicates it has 1 << 128 -1 files,
|
||||
// this would previously cause a panic due to attempting
|
||||
// to allocate a slice with 1 << 128 -1 elements.
|
||||
data := []byte{
|
||||
0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02,
|
||||
0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00,
|
||||
0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20,
|
||||
0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
|
||||
0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
|
||||
0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00,
|
||||
0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50,
|
||||
0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
}
|
||||
_, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != ErrFormat {
|
||||
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
|
||||
}
|
||||
|
||||
// Also check that an archive containing a handful of empty
|
||||
// files doesn't cause an issue
|
||||
b := bytes.NewBuffer(nil)
|
||||
w := NewWriter(b)
|
||||
for i := 0; i < 5; i++ {
|
||||
_, err := w.Create("")
|
||||
if err != nil {
|
||||
t.Fatalf("Writer.Create failed: %s", err)
|
||||
}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatalf("Writer.Close failed: %s", err)
|
||||
}
|
||||
r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
|
||||
if err != nil {
|
||||
t.Fatalf("NewReader failed: %s", err)
|
||||
}
|
||||
if len(r.File) != 5 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/archive/zip/testdata/subdir.zip
vendored
Normal file
BIN
src/archive/zip/testdata/subdir.zip
vendored
Normal file
Binary file not shown.
@@ -243,7 +243,8 @@ func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int {
|
||||
DeclCol: pos.Col(),
|
||||
}
|
||||
if _, found := m[vp]; found {
|
||||
Fatalf("child dcl collision on symbol %s within %v\n", n.Sym.Name, fnsym.Name)
|
||||
// We can see collisions (variables with the same name/file/line/col) in obfuscated or machine-generated code -- see issue 44378 for an example. Skip duplicates in such cases, since it is unlikely that a human will be debugging such code.
|
||||
continue
|
||||
}
|
||||
m[vp] = i
|
||||
}
|
||||
|
||||
@@ -1376,9 +1376,10 @@ func containsClosure(f, c *Node) bool {
|
||||
|
||||
// leak records that parameter l leaks to sink.
|
||||
func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
|
||||
// If sink is a result parameter and we can fit return bits
|
||||
// into the escape analysis tag, then record a return leak.
|
||||
if sink.isName(PPARAMOUT) && sink.curfn == l.curfn {
|
||||
// If sink is a result parameter that doesn't escape (#44614)
|
||||
// and we can fit return bits into the escape analysis tag,
|
||||
// then record as a result leak.
|
||||
if !sink.escapes && sink.isName(PPARAMOUT) && sink.curfn == l.curfn {
|
||||
// TODO(mdempsky): Eliminate dependency on Vargen here.
|
||||
ri := int(sink.n.Name.Vargen) - 1
|
||||
if ri < numEscResults {
|
||||
|
||||
@@ -1053,18 +1053,26 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
}
|
||||
|
||||
// We can delay declaring+initializing result parameters if:
|
||||
// (1) there's exactly one "return" statement in the inlined function;
|
||||
// (2) it's not an empty return statement (#44355); and
|
||||
// (3) the result parameters aren't named.
|
||||
delayretvars := true
|
||||
|
||||
nreturns := 0
|
||||
inspectList(asNodes(fn.Func.Inl.Body), func(n *Node) bool {
|
||||
if n != nil && n.Op == ORETURN {
|
||||
nreturns++
|
||||
if n.List.Len() == 0 {
|
||||
delayretvars = false // empty return statement (case 2)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// We can delay declaring+initializing result parameters if:
|
||||
// (1) there's only one "return" statement in the inlined
|
||||
// function, and (2) the result parameters aren't named.
|
||||
delayretvars := nreturns == 1
|
||||
if nreturns != 1 {
|
||||
delayretvars = false // not exactly one return statement (case 1)
|
||||
}
|
||||
|
||||
// temporaries for return values.
|
||||
var retvars []*Node
|
||||
@@ -1074,7 +1082,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
m = inlvar(n)
|
||||
m = typecheck(m, ctxExpr)
|
||||
inlvars[n] = m
|
||||
delayretvars = false // found a named result parameter
|
||||
delayretvars = false // found a named result parameter (case 3)
|
||||
} else {
|
||||
// anonymous return values, synthesize names for use in assignment that replaces return
|
||||
m = retvar(t, i)
|
||||
|
||||
@@ -163,6 +163,7 @@ func dumpdata() {
|
||||
if zerosize > 0 {
|
||||
zero := mappkg.Lookup("zero")
|
||||
ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
|
||||
zero.Linksym().Set(obj.AttrStatic, true)
|
||||
}
|
||||
|
||||
addGCLocals()
|
||||
|
||||
@@ -363,15 +363,15 @@ func staticname(t *types.Type) *Node {
|
||||
n := newname(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
|
||||
statuniqgen++
|
||||
addvar(n, t, PEXTERN)
|
||||
n.Sym.Linksym().Set(obj.AttrLocal, true)
|
||||
return n
|
||||
}
|
||||
|
||||
// readonlystaticname returns a name backed by a (writable) static data symbol.
|
||||
// readonlystaticname returns a name backed by a read-only static data symbol.
|
||||
func readonlystaticname(t *types.Type) *Node {
|
||||
n := staticname(t)
|
||||
n.MarkReadonly()
|
||||
n.Sym.Linksym().Set(obj.AttrContentAddressable, true)
|
||||
n.Sym.Linksym().Set(obj.AttrLocal, true)
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
@@ -3927,15 +3927,22 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
}
|
||||
}
|
||||
|
||||
wrapArgs := n.List.Slice()
|
||||
// If there's a receiver argument, it needs to be passed through the wrapper too.
|
||||
if n.Op == OCALLMETH || n.Op == OCALLINTER {
|
||||
recv := n.Left.Left
|
||||
wrapArgs = append([]*Node{recv}, wrapArgs...)
|
||||
}
|
||||
|
||||
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
|
||||
origArgs := make([]*Node, n.List.Len())
|
||||
origArgs := make([]*Node, len(wrapArgs))
|
||||
t := nod(OTFUNC, nil, nil)
|
||||
for i, arg := range n.List.Slice() {
|
||||
for i, arg := range wrapArgs {
|
||||
s := lookupN("a", i)
|
||||
if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
|
||||
origArgs[i] = arg
|
||||
arg = arg.Left
|
||||
n.List.SetIndex(i, arg)
|
||||
wrapArgs[i] = arg
|
||||
}
|
||||
t.List.Append(symfield(s, arg.Type))
|
||||
}
|
||||
@@ -3953,6 +3960,12 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
arg.Type = origArg.Type
|
||||
args[i] = arg
|
||||
}
|
||||
if n.Op == OCALLMETH || n.Op == OCALLINTER {
|
||||
// Move wrapped receiver argument back to its appropriate place.
|
||||
recv := typecheck(args[0], ctxExpr)
|
||||
n.Left.Left = recv
|
||||
args = args[1:]
|
||||
}
|
||||
call := nod(n.Op, nil, nil)
|
||||
if !isBuiltinCall {
|
||||
call.Op = OCALL
|
||||
@@ -3970,7 +3983,7 @@ func wrapCall(n *Node, init *Nodes) *Node {
|
||||
|
||||
call = nod(OCALL, nil, nil)
|
||||
call.Left = fn.Func.Nname
|
||||
call.List.Set(n.List.Slice())
|
||||
call.List.Set(wrapArgs)
|
||||
call = typecheck(call, ctxStmt)
|
||||
call = walkexpr(call, init)
|
||||
return call
|
||||
|
||||
@@ -623,6 +623,14 @@
|
||||
// Recognize bit setting (a |= 1<<b) and toggling (a ^= 1<<b)
|
||||
(OR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTS(Q|L) x y)
|
||||
(XOR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTC(Q|L) x y)
|
||||
(ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) =>
|
||||
(BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
(ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) =>
|
||||
(BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
(XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) =>
|
||||
(BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
(XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) =>
|
||||
(BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
|
||||
// Convert ORconst into BTS, if the code gets smaller, with boundary being
|
||||
// (ORL $40,AX is 3 bytes, ORL $80,AX is 6 bytes).
|
||||
@@ -645,6 +653,10 @@
|
||||
=> (BTRQconst [int8(log64(^c))] x)
|
||||
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
||||
=> (BTRLconst [int8(log32(^c))] x)
|
||||
(ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) <t> x)) mem) =>
|
||||
(BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
(ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) <t> x)) mem) =>
|
||||
(BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
|
||||
// Special-case bit patterns on first/last bit.
|
||||
// generic.rules changes ANDs of high-part/low-part masks into a couple of shifts,
|
||||
@@ -2050,11 +2062,15 @@
|
||||
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
|
||||
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
|
||||
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
|
||||
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem)
|
||||
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
|
||||
(MOVLstore {sym} [off] ptr y:((BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) <t> x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((BTC|BTR|BTS)Lmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
(MOVQstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Qload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
|
||||
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off] {sym} ptr x mem)
|
||||
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((ADD|SUB|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
|
||||
(MOVQstore {sym} [off] ptr y:((BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) <t> x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
|
||||
((BTC|BTR|BTS)Qmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
|
||||
// Merge ADDQconst and LEAQ into atomic loads.
|
||||
(MOV(Q|L|B)atomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
|
||||
@@ -358,6 +358,11 @@ func init() {
|
||||
{name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8"}, // set bit auxint in arg0, 0 <= auxint < 64
|
||||
|
||||
// direct bit operation on memory operand
|
||||
//
|
||||
// Note that these operations do not mask the bit offset (arg1), and will write beyond their expected
|
||||
// bounds if that argument is larger than 64/32 (for BT*Q and BT*L, respectively). If the compiler
|
||||
// cannot prove that arg1 is in range, it must be explicitly masked (see e.g. the patterns that produce
|
||||
// BT*modify from (MOVstore (BT* (MOVLload ptr mem) x) mem)).
|
||||
{name: "BTCQmodify", argLength: 3, reg: gpstore, asm: "BTCQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // complement bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
|
||||
{name: "BTCLmodify", argLength: 3, reg: gpstore, asm: "BTCL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // complement bit arg1 in 32-bit arg0+auxint+aux, arg2=mem
|
||||
{name: "BTSQmodify", argLength: 3, reg: gpstore, asm: "BTSQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // set bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
|
||||
|
||||
@@ -502,13 +502,14 @@ func init() {
|
||||
// auxint = offset into duffzero code to start executing
|
||||
// returns mem
|
||||
// R20 changed as side effect
|
||||
// R16 and R17 may be clobbered by linker trampoline.
|
||||
{
|
||||
name: "DUFFZERO",
|
||||
aux: "Int64",
|
||||
argLength: 2,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{buildReg("R20")},
|
||||
clobbers: buildReg("R20 R30"),
|
||||
clobbers: buildReg("R16 R17 R20 R30"),
|
||||
},
|
||||
faultOnNilArg0: true,
|
||||
unsafePoint: true, // FP maintenance around DUFFZERO can be clobbered by interrupts
|
||||
@@ -542,13 +543,14 @@ func init() {
|
||||
// auxint = offset into duffcopy code to start executing
|
||||
// returns mem
|
||||
// R20, R21 changed as side effect
|
||||
// R16 and R17 may be clobbered by linker trampoline.
|
||||
{
|
||||
name: "DUFFCOPY",
|
||||
aux: "Int64",
|
||||
argLength: 3,
|
||||
reg: regInfo{
|
||||
inputs: []regMask{buildReg("R21"), buildReg("R20")},
|
||||
clobbers: buildReg("R20 R21 R26 R30"),
|
||||
clobbers: buildReg("R16 R17 R20 R21 R26 R30"),
|
||||
},
|
||||
faultOnNilArg0: true,
|
||||
faultOnNilArg1: true,
|
||||
@@ -707,7 +709,8 @@ func init() {
|
||||
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
|
||||
// It saves all GP registers if necessary,
|
||||
// but clobbers R30 (LR) because it's a call.
|
||||
{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R2"), buildReg("R3")}, clobbers: (callerSave &^ gpg) | buildReg("R30")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
|
||||
// R16 and R17 may be clobbered by linker trampoline.
|
||||
{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R2"), buildReg("R3")}, clobbers: (callerSave &^ gpg) | buildReg("R16 R17 R30")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
|
||||
|
||||
// There are three of these functions so that they can have three different register inputs.
|
||||
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
|
||||
|
||||
@@ -20848,7 +20848,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1048576}, // R20
|
||||
},
|
||||
clobbers: 537919488, // R20 R30
|
||||
clobbers: 538116096, // R16 R17 R20 R30
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -20876,7 +20876,7 @@ var opcodeTable = [...]opInfo{
|
||||
{0, 2097152}, // R21
|
||||
{1, 1048576}, // R20
|
||||
},
|
||||
clobbers: 607125504, // R20 R21 R26 R30
|
||||
clobbers: 607322112, // R16 R17 R20 R21 R26 R30
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -21373,7 +21373,7 @@ var opcodeTable = [...]opInfo{
|
||||
{0, 4}, // R2
|
||||
{1, 8}, // R3
|
||||
},
|
||||
clobbers: 9223372035244163072, // R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
|
||||
clobbers: 9223372035244359680, // R16 R17 R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1469,7 +1469,7 @@ func mergePPC64AndSrwi(m, s int64) int64 {
|
||||
if !isPPC64WordRotateMask(mask) {
|
||||
return 0
|
||||
}
|
||||
return encodePPC64RotateMask(32-s, mask, 32)
|
||||
return encodePPC64RotateMask((32-s)&31, mask, 32)
|
||||
}
|
||||
|
||||
// Test if a shift right feeding into a CLRLSLDI can be merged into RLWINM.
|
||||
|
||||
@@ -2998,6 +2998,36 @@ func rewriteValueAMD64_OpAMD64ANDLmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) <t> x)) mem)
|
||||
// result: (BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
if v_1.Op != OpAMD64NOTL {
|
||||
break
|
||||
}
|
||||
s := v_1.Args[0]
|
||||
if s.Op != OpAMD64SHLL {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTRLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (ANDLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (ANDLmodify [off1+off2] {sym} base val mem)
|
||||
@@ -3377,6 +3407,36 @@ func rewriteValueAMD64_OpAMD64ANDQmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) <t> x)) mem)
|
||||
// result: (BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
if v_1.Op != OpAMD64NOTQ {
|
||||
break
|
||||
}
|
||||
s := v_1.Args[0]
|
||||
if s.Op != OpAMD64SHLQ {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTRQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (ANDQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (ANDQmodify [off1+off2] {sym} base val mem)
|
||||
@@ -12709,9 +12769,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTCL l:(MOVLload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTCL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTCLmodify [off] {sym} ptr x mem)
|
||||
// result: (BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -12720,6 +12780,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTCL {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -12732,12 +12793,15 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTCLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTRL l:(MOVLload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTRL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTRLmodify [off] {sym} ptr x mem)
|
||||
// result: (BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -12746,6 +12810,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTRL {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -12758,12 +12823,15 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTRLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTSL l:(MOVLload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVLstore {sym} [off] ptr y:(BTSL l:(MOVLload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTSLmodify [off] {sym} ptr x mem)
|
||||
// result: (BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -12772,6 +12840,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTSL {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVLload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -12784,7 +12853,10 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTSLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem)
|
||||
@@ -13525,6 +13597,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (MOVQstore [off1+off2] {sym} ptr val mem)
|
||||
@@ -13890,9 +13963,9 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTCQ l:(MOVQload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTCQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTCQmodify [off] {sym} ptr x mem)
|
||||
// result: (BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -13901,6 +13974,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTCQ {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -13913,12 +13987,15 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTCQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTRQ l:(MOVQload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTRQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTRQmodify [off] {sym} ptr x mem)
|
||||
// result: (BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -13927,6 +14004,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTRQ {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -13939,12 +14017,15 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTRQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTSQ l:(MOVQload [off] {sym} ptr mem) x) mem)
|
||||
// match: (MOVQstore {sym} [off] ptr y:(BTSQ l:(MOVQload [off] {sym} ptr mem) <t> x) mem)
|
||||
// cond: y.Uses==1 && l.Uses==1 && clobber(y, l)
|
||||
// result: (BTSQmodify [off] {sym} ptr x mem)
|
||||
// result: (BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
@@ -13953,6 +14034,7 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
if y.Op != OpAMD64BTSQ {
|
||||
break
|
||||
}
|
||||
t := y.Type
|
||||
x := y.Args[1]
|
||||
l := y.Args[0]
|
||||
if l.Op != OpAMD64MOVQload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym {
|
||||
@@ -13965,7 +14047,10 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
|
||||
v.reset(OpAMD64BTSQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
v0 := b.NewValue0(l.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem)
|
||||
@@ -18352,6 +18437,33 @@ func rewriteValueAMD64_OpAMD64ORLmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem)
|
||||
// result: (BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
s := v_1
|
||||
if s.Op != OpAMD64SHLL {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTSLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (ORLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (ORLmodify [off1+off2] {sym} base val mem)
|
||||
@@ -19979,6 +20091,33 @@ func rewriteValueAMD64_OpAMD64ORQmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem)
|
||||
// result: (BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
s := v_1
|
||||
if s.Op != OpAMD64SHLQ {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTSQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (ORQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (ORQmodify [off1+off2] {sym} base val mem)
|
||||
@@ -28014,6 +28153,33 @@ func rewriteValueAMD64_OpAMD64XORLmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem)
|
||||
// result: (BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
s := v_1
|
||||
if s.Op != OpAMD64SHLL {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVLconst || auxIntToInt32(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTCLmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(31)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (XORLmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (XORLmodify [off1+off2] {sym} base val mem)
|
||||
@@ -28382,6 +28548,33 @@ func rewriteValueAMD64_OpAMD64XORQmodify(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
// match: (XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem)
|
||||
// result: (BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
|
||||
for {
|
||||
off := auxIntToInt32(v.AuxInt)
|
||||
sym := auxToSym(v.Aux)
|
||||
ptr := v_0
|
||||
s := v_1
|
||||
if s.Op != OpAMD64SHLQ {
|
||||
break
|
||||
}
|
||||
t := s.Type
|
||||
x := s.Args[1]
|
||||
s_0 := s.Args[0]
|
||||
if s_0.Op != OpAMD64MOVQconst || auxIntToInt64(s_0.AuxInt) != 1 {
|
||||
break
|
||||
}
|
||||
mem := v_2
|
||||
v.reset(OpAMD64BTCQmodify)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ANDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(63)
|
||||
v0.AddArg(x)
|
||||
v.AddArg3(ptr, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (XORQmodify [off1] {sym} (ADDQconst [off2] base) val mem)
|
||||
// cond: is32Bit(int64(off1)+int64(off2))
|
||||
// result: (XORQmodify [off1+off2] {sym} base val mem)
|
||||
|
||||
@@ -205,6 +205,7 @@ func TestMergePPC64AndSrwi(t *testing.T) {
|
||||
{0x00000000, 4, false, 0, 0},
|
||||
{0xF0000000, 4, false, 0, 0},
|
||||
{0xF0000000, 32, false, 0, 0},
|
||||
{0xFFFFFFFF, 0, true, 0, 0xFFFFFFFF},
|
||||
}
|
||||
for i, v := range tests {
|
||||
result := mergePPC64AndSrwi(v.and, v.srw)
|
||||
|
||||
@@ -138,6 +138,24 @@ func shortcircuitBlock(b *Block) bool {
|
||||
if len(b.Values) != nval+nOtherPhi {
|
||||
return false
|
||||
}
|
||||
if nOtherPhi > 0 {
|
||||
// Check for any phi which is the argument of another phi.
|
||||
// These cases are tricky, as substitutions done by replaceUses
|
||||
// are no longer trivial to do in any ordering. See issue 45175.
|
||||
m := make(map[*Value]bool, 1+nOtherPhi)
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpPhi {
|
||||
m[v] = true
|
||||
}
|
||||
}
|
||||
for v := range m {
|
||||
for _, a := range v.Args {
|
||||
if a != v && m[a] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Locate index of first const phi arg.
|
||||
cidx := -1
|
||||
|
||||
@@ -6,7 +6,7 @@ require (
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
|
||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||
golang.org/x/mod v0.4.1
|
||||
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||
golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
|
||||
)
|
||||
|
||||
@@ -14,8 +14,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea h1:zAn46O7Vmm6KdLXx+635hPZSArrt/wNctv4Ab70Jw3k=
|
||||
golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
|
||||
@@ -692,18 +692,22 @@
|
||||
// arguments must satisfy the following constraints:
|
||||
//
|
||||
// - Arguments must be package paths or package patterns (with "..." wildcards).
|
||||
// They must not be standard packages (like fmt), meta-patterns (std, cmd,
|
||||
// all), or relative or absolute file paths.
|
||||
// They must not be standard packages (like fmt), meta-patterns (std, cmd,
|
||||
// all), or relative or absolute file paths.
|
||||
//
|
||||
// - All arguments must have the same version suffix. Different queries are not
|
||||
// allowed, even if they refer to the same version.
|
||||
// allowed, even if they refer to the same version.
|
||||
//
|
||||
// - All arguments must refer to packages in the same module at the same version.
|
||||
//
|
||||
// - No module is considered the "main" module. If the module containing
|
||||
// packages named on the command line has a go.mod file, it must not contain
|
||||
// directives (replace and exclude) that would cause it to be interpreted
|
||||
// differently than if it were the main module. The module must not require
|
||||
// a higher version of itself.
|
||||
// packages named on the command line has a go.mod file, it must not contain
|
||||
// directives (replace and exclude) that would cause it to be interpreted
|
||||
// differently than if it were the main module. The module must not require
|
||||
// a higher version of itself.
|
||||
//
|
||||
// - Package path arguments must refer to main packages. Pattern arguments
|
||||
// will only match main packages.
|
||||
// will only match main packages.
|
||||
//
|
||||
// If the arguments don't have version suffixes, "go install" may run in
|
||||
// module-aware mode or GOPATH mode, depending on the GO111MODULE environment
|
||||
|
||||
@@ -431,7 +431,7 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
importPrefix = importPrefix[:slash]
|
||||
}
|
||||
if err := module.CheckImportPath(importPrefix); err != nil {
|
||||
if err := checkImportPath(importPrefix); err != nil {
|
||||
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
||||
}
|
||||
security := web.SecureOnly
|
||||
@@ -591,3 +591,31 @@ func selectTag(goVersion string, tags []string) (match string) {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// checkImportPath is like module.CheckImportPath, but it forbids leading dots
|
||||
// in path elements. This can lead to 'go get' creating .git and other VCS
|
||||
// directories in places we might run VCS tools later.
|
||||
func checkImportPath(path string) error {
|
||||
if err := module.CheckImportPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
checkElem := func(elem string) error {
|
||||
if elem[0] == '.' {
|
||||
return fmt.Errorf("malformed import path %q: leading dot in path element", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
elemStart := 0
|
||||
for i, r := range path {
|
||||
if r == '/' {
|
||||
if err := checkElem(path[elemStart:]); err != nil {
|
||||
return err
|
||||
}
|
||||
elemStart = i + 1
|
||||
}
|
||||
}
|
||||
if err := checkElem(path[elemStart:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1323,6 +1323,11 @@ func reusePackage(p *Package, stk *ImportStack) *Package {
|
||||
Err: errors.New("import cycle not allowed"),
|
||||
IsImportCycle: true,
|
||||
}
|
||||
} else if !p.Error.IsImportCycle {
|
||||
// If the error is already set, but it does not indicate that
|
||||
// we are in an import cycle, set IsImportCycle so that we don't
|
||||
// end up stuck in a loop down the road.
|
||||
p.Error.IsImportCycle = true
|
||||
}
|
||||
p.Incomplete = true
|
||||
}
|
||||
|
||||
@@ -86,9 +86,11 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if !modload.HasModRoot() && len(args) == 0 {
|
||||
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
haveExplicitArgs := len(args) > 0
|
||||
if !haveExplicitArgs {
|
||||
args = []string{"all"}
|
||||
} else if modload.HasModRoot() {
|
||||
}
|
||||
if modload.HasModRoot() {
|
||||
modload.LoadModFile(ctx) // to fill Target
|
||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
||||
targetAtPatch := modload.Target.Path + "@patch"
|
||||
@@ -137,7 +139,20 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
listRetractions := false
|
||||
type token struct{}
|
||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||
for _, info := range modload.ListModules(ctx, args, listU, listVersions, listRetractions) {
|
||||
infos := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
|
||||
if !haveExplicitArgs {
|
||||
// 'go mod download' is sometimes run without arguments to pre-populate
|
||||
// the module cache. It may fetch modules that aren't needed to build
|
||||
// packages in the main mdoule. This is usually not intended, so don't save
|
||||
// sums for downloaded modules (golang.org/issue/45332).
|
||||
// TODO(golang.org/issue/45551): For now, save sums needed to load the
|
||||
// build list (same as 1.15 behavior). In the future, report an error if
|
||||
// go.mod or go.sum need to be updated after loading the build list.
|
||||
modload.WriteGoMod()
|
||||
modload.DisallowWriteGoMod()
|
||||
}
|
||||
|
||||
for _, info := range infos {
|
||||
if info.Replace != nil {
|
||||
info = info.Replace
|
||||
}
|
||||
@@ -187,6 +202,13 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
// Update go.mod and especially go.sum if needed.
|
||||
modload.WriteGoMod()
|
||||
// If there were explicit arguments, update go.mod and especially go.sum.
|
||||
// 'go mod download mod@version' is a useful way to add a sum without using
|
||||
// 'go get mod@version', which may have other side effects. We print this in
|
||||
// some error message hints.
|
||||
//
|
||||
// Don't save sums for 'go mod download' without arguments; see comment above.
|
||||
if haveExplicitArgs {
|
||||
modload.WriteGoMod()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,11 +61,14 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NeedRoot
|
||||
|
||||
modload.CheckTidyVersion(ctx, tidyE)
|
||||
|
||||
modload.LoadPackages(ctx, modload.PackageOpts{
|
||||
Tags: imports.AnyTags(),
|
||||
ResolveMissingImports: true,
|
||||
LoadTests: true,
|
||||
AllowErrors: tidyE,
|
||||
Tags: imports.AnyTags(),
|
||||
ResolveMissingImports: true,
|
||||
LoadTests: true,
|
||||
AllowErrors: tidyE,
|
||||
SilenceMissingStdImports: true,
|
||||
}, "all")
|
||||
|
||||
modload.TidyBuildList()
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -64,10 +65,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.RootMode = modload.NeedRoot
|
||||
|
||||
loadOpts := modload.PackageOpts{
|
||||
Tags: imports.AnyTags(),
|
||||
ResolveMissingImports: true,
|
||||
UseVendorAll: true,
|
||||
AllowErrors: vendorE,
|
||||
Tags: imports.AnyTags(),
|
||||
ResolveMissingImports: true,
|
||||
UseVendorAll: true,
|
||||
AllowErrors: vendorE,
|
||||
SilenceMissingStdImports: true,
|
||||
}
|
||||
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||
|
||||
@@ -280,7 +282,7 @@ func copyMetadata(modPath, pkg, dst, src string, copiedFiles map[string]bool) {
|
||||
if modPath == pkg {
|
||||
break
|
||||
}
|
||||
pkg = filepath.Dir(pkg)
|
||||
pkg = path.Dir(pkg)
|
||||
dst = filepath.Dir(dst)
|
||||
src = filepath.Dir(src)
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ func DownloadDir(m module.Version) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Check whether the directory itself exists.
|
||||
dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer)
|
||||
if fi, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
return dir, err
|
||||
@@ -92,6 +93,9 @@ func DownloadDir(m module.Version) (string, error) {
|
||||
} else if !fi.IsDir() {
|
||||
return dir, &DownloadDirPartialError{dir, errors.New("not a directory")}
|
||||
}
|
||||
|
||||
// Check if a .partial file exists. This is created at the beginning of
|
||||
// a download and removed after the zip is extracted.
|
||||
partialPath, err := CachePath(m, "partial")
|
||||
if err != nil {
|
||||
return dir, err
|
||||
@@ -101,6 +105,19 @@ func DownloadDir(m module.Version) (string, error) {
|
||||
} else if !os.IsNotExist(err) {
|
||||
return dir, err
|
||||
}
|
||||
|
||||
// Check if a .ziphash file exists. It should be created before the
|
||||
// zip is extracted, but if it was deleted (by another program?), we need
|
||||
// to re-calculate it.
|
||||
ziphashPath, err := CachePath(m, "ziphash")
|
||||
if err != nil {
|
||||
return dir, err
|
||||
}
|
||||
if _, err := os.Stat(ziphashPath); os.IsNotExist(err) {
|
||||
return dir, &DownloadDirPartialError{dir, errors.New("ziphash file is missing")}
|
||||
} else if err != nil {
|
||||
return dir, err
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -170,13 +170,16 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e
|
||||
if err != nil {
|
||||
return cached{"", err}
|
||||
}
|
||||
ziphashfile := zipfile + "hash"
|
||||
|
||||
// Skip locking if the zipfile already exists.
|
||||
// Return without locking if the zip and ziphash files exist.
|
||||
if _, err := os.Stat(zipfile); err == nil {
|
||||
return cached{zipfile, nil}
|
||||
if _, err := os.Stat(ziphashfile); err == nil {
|
||||
return cached{zipfile, nil}
|
||||
}
|
||||
}
|
||||
|
||||
// The zip file does not exist. Acquire the lock and create it.
|
||||
// The zip or ziphash file does not exist. Acquire the lock and create them.
|
||||
if cfg.CmdName != "mod download" {
|
||||
fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
|
||||
}
|
||||
@@ -186,14 +189,6 @@ func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err e
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
// Double-check that the zipfile was not created while we were waiting for
|
||||
// the lock.
|
||||
if _, err := os.Stat(zipfile); err == nil {
|
||||
return cached{zipfile, nil}
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
|
||||
return cached{"", err}
|
||||
}
|
||||
if err := downloadZip(ctx, mod, zipfile); err != nil {
|
||||
return cached{"", err}
|
||||
}
|
||||
@@ -206,6 +201,25 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
|
||||
ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile)
|
||||
defer span.Done()
|
||||
|
||||
// Double-check that the zipfile was not created while we were waiting for
|
||||
// the lock in DownloadZip.
|
||||
ziphashfile := zipfile + "hash"
|
||||
var zipExists, ziphashExists bool
|
||||
if _, err := os.Stat(zipfile); err == nil {
|
||||
zipExists = true
|
||||
}
|
||||
if _, err := os.Stat(ziphashfile); err == nil {
|
||||
ziphashExists = true
|
||||
}
|
||||
if zipExists && ziphashExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create parent directories.
|
||||
if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clean up any remaining tempfiles from previous runs.
|
||||
// This is only safe to do because the lock file ensures that their
|
||||
// writers are no longer active.
|
||||
@@ -217,6 +231,12 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
|
||||
}
|
||||
}
|
||||
|
||||
// If the zip file exists, the ziphash file must have been deleted
|
||||
// or lost after a file system crash. Re-hash the zip without downloading.
|
||||
if zipExists {
|
||||
return hashZip(mod, zipfile, ziphashfile)
|
||||
}
|
||||
|
||||
// From here to the os.Rename call below is functionally almost equivalent to
|
||||
// renameio.WriteToFile, with one key difference: we want to validate the
|
||||
// contents of the file (by hashing it) before we commit it. Because the file
|
||||
@@ -289,15 +309,7 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
|
||||
}
|
||||
|
||||
// Hash the zip file and check the sum before renaming to the final location.
|
||||
hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkModSum(mod, hash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil {
|
||||
if err := hashZip(mod, f.Name(), ziphashfile); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(f.Name(), zipfile); err != nil {
|
||||
@@ -309,6 +321,22 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
|
||||
return nil
|
||||
}
|
||||
|
||||
// hashZip reads the zip file opened in f, then writes the hash to ziphashfile,
|
||||
// overwriting that file if it exists.
|
||||
//
|
||||
// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns
|
||||
// an error and does not write ziphashfile.
|
||||
func hashZip(mod module.Version, zipfile, ziphashfile string) error {
|
||||
hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkModSum(mod, hash); err != nil {
|
||||
return err
|
||||
}
|
||||
return renameio.WriteFile(ziphashfile, []byte(hash), 0666)
|
||||
}
|
||||
|
||||
// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir
|
||||
// and its transitive contents.
|
||||
func makeDirsReadOnly(dir string) {
|
||||
@@ -452,11 +480,6 @@ func HaveSum(mod module.Version) bool {
|
||||
|
||||
// checkMod checks the given module's checksum.
|
||||
func checkMod(mod module.Version) {
|
||||
if cfg.GOMODCACHE == "" {
|
||||
// Do not use current directory.
|
||||
return
|
||||
}
|
||||
|
||||
// Do the file I/O before acquiring the go.sum lock.
|
||||
ziphash, err := CachePath(mod, "ziphash")
|
||||
if err != nil {
|
||||
@@ -464,10 +487,6 @@ func checkMod(mod module.Version) {
|
||||
}
|
||||
data, err := renameio.ReadFile(ziphash)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
|
||||
return
|
||||
}
|
||||
base.Fatalf("verifying %v", module.VersionError(mod, err))
|
||||
}
|
||||
h := strings.TrimSpace(string(data))
|
||||
|
||||
@@ -1514,7 +1514,7 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns
|
||||
}
|
||||
}
|
||||
if retractPath != "" {
|
||||
fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest", retractPath)
|
||||
fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ func (q *query) validate() error {
|
||||
if q.pattern == "all" {
|
||||
// If there is no main module, "all" is not meaningful.
|
||||
if !modload.HasModRoot() {
|
||||
return fmt.Errorf(`cannot match "all": working directory is not part of a module`)
|
||||
return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
|
||||
}
|
||||
if !versionOkForMainModule(q.version) {
|
||||
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
||||
|
||||
@@ -11,10 +11,13 @@ import (
|
||||
"cmd/go/internal/mvs"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// buildList is the list of modules to use for building packages.
|
||||
@@ -226,6 +229,33 @@ func ReloadBuildList() []module.Version {
|
||||
return capVersionSlice(buildList)
|
||||
}
|
||||
|
||||
// CheckTidyVersion reports an error to stderr if the Go version indicated by
|
||||
// the go.mod file is not supported by this version of the 'go' command.
|
||||
//
|
||||
// If allowError is false, such an error terminates the program.
|
||||
func CheckTidyVersion(ctx context.Context, allowError bool) {
|
||||
LoadModFile(ctx)
|
||||
if index.goVersionV == "" {
|
||||
return
|
||||
}
|
||||
|
||||
tags := build.Default.ReleaseTags
|
||||
maxGo := tags[len(tags)-1]
|
||||
if !strings.HasPrefix(maxGo, "go") || !modfile.GoVersionRE.MatchString(maxGo[2:]) {
|
||||
base.Fatalf("go: unrecognized go version %q", maxGo)
|
||||
}
|
||||
max := maxGo[2:]
|
||||
|
||||
if semver.Compare(index.goVersionV, "v"+max) > 0 {
|
||||
have := index.goVersionV[1:]
|
||||
if allowError {
|
||||
fmt.Fprintf(os.Stderr, "go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", have, max)
|
||||
} else {
|
||||
base.Fatalf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", have, max)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TidyBuildList trims the build list to the minimal requirements needed to
|
||||
// retain the same versions of all packages from the preceding call to
|
||||
// LoadPackages.
|
||||
|
||||
@@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string {
|
||||
if e.isStd {
|
||||
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
|
||||
}
|
||||
if e.QueryErr != nil {
|
||||
if e.QueryErr != nil && e.QueryErr != ErrNoModRoot {
|
||||
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
|
||||
}
|
||||
if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) {
|
||||
@@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string {
|
||||
return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg)
|
||||
}
|
||||
|
||||
suggestion := ""
|
||||
if !HasModRoot() {
|
||||
suggestion = ": working directory is not part of a module"
|
||||
} else {
|
||||
suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path)
|
||||
message := fmt.Sprintf("no required module provides package %s", e.Path)
|
||||
if e.QueryErr != nil {
|
||||
return fmt.Sprintf("%s: %v", message, e.QueryErr)
|
||||
}
|
||||
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
|
||||
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
|
||||
}
|
||||
|
||||
if e.newMissingVersion != "" {
|
||||
@@ -162,11 +160,13 @@ func (e *ImportMissingSumError) Error() string {
|
||||
// Importing package is unknown, or the missing package was named on the
|
||||
// command line. Recommend 'go mod download' for the modules that could
|
||||
// provide the package, since that shouldn't change go.mod.
|
||||
args := make([]string, len(e.mods))
|
||||
for i, mod := range e.mods {
|
||||
args[i] = mod.Path
|
||||
if len(e.mods) > 0 {
|
||||
args := make([]string, len(e.mods))
|
||||
for i, mod := range e.mods {
|
||||
args[i] = mod.Path
|
||||
}
|
||||
hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
|
||||
}
|
||||
hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
|
||||
} else {
|
||||
// Importing package is known (common case). Recommend 'go get' on the
|
||||
// current version of the importing package.
|
||||
@@ -318,7 +318,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||
return mods[0], dirs[0], nil
|
||||
}
|
||||
|
||||
return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd}
|
||||
var queryErr error
|
||||
if !HasModRoot() {
|
||||
queryErr = ErrNoModRoot
|
||||
}
|
||||
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
|
||||
}
|
||||
|
||||
// queryImport attempts to locate a module that can be added to the current
|
||||
|
||||
@@ -177,7 +177,7 @@ func Init() {
|
||||
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
|
||||
}
|
||||
if RootMode == NeedRoot {
|
||||
base.Fatalf("go: cannot find main module; see 'go help modules'")
|
||||
base.Fatalf("go: %v", ErrNoModRoot)
|
||||
}
|
||||
if !mustUseModules {
|
||||
// GO111MODULE is 'auto', and we can't find a module root.
|
||||
@@ -338,9 +338,11 @@ func die() {
|
||||
}
|
||||
base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd)
|
||||
}
|
||||
base.Fatalf("go: cannot find main module; see 'go help modules'")
|
||||
base.Fatalf("go: %v", ErrNoModRoot)
|
||||
}
|
||||
|
||||
var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'")
|
||||
|
||||
// LoadModFile sets Target and, if there is a main module, parses the initial
|
||||
// build list from its go.mod file.
|
||||
//
|
||||
@@ -539,9 +541,10 @@ func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer {
|
||||
}
|
||||
}
|
||||
if vers != "" && module.CanonicalVersion(vers) == vers {
|
||||
if err := module.CheckPathMajor(vers, pathMajor); err == nil {
|
||||
return vers, nil
|
||||
if err := module.CheckPathMajor(vers, pathMajor); err != nil {
|
||||
return "", module.VersionError(module.Version{Path: path, Version: vers}, err)
|
||||
}
|
||||
return vers, nil
|
||||
}
|
||||
|
||||
info, err := Query(ctx, path, vers, "", nil)
|
||||
|
||||
@@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted
|
||||
base.Fatalf("go: cannot use relative path %s to specify module", arg)
|
||||
}
|
||||
if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) {
|
||||
base.Fatalf("go: cannot match %q: working directory is not part of a module", arg)
|
||||
base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
|
||||
}
|
||||
if i := strings.Index(arg, "@"); i >= 0 {
|
||||
path := arg[:i]
|
||||
|
||||
@@ -170,6 +170,12 @@ type PackageOpts struct {
|
||||
// that occur while loading packages. SilenceErrors implies AllowErrors.
|
||||
SilenceErrors bool
|
||||
|
||||
// SilenceMissingStdImports indicates that LoadPackages should not print
|
||||
// errors or terminate the process if an imported package is missing, and the
|
||||
// import path looks like it might be in the standard library (perhaps in a
|
||||
// future version).
|
||||
SilenceMissingStdImports bool
|
||||
|
||||
// SilenceUnmatchedWarnings suppresses the warnings normally emitted for
|
||||
// patterns that did not match any packages.
|
||||
SilenceUnmatchedWarnings bool
|
||||
@@ -287,8 +293,13 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||
sumErr.importerIsTest = importer.testOf != nil
|
||||
}
|
||||
}
|
||||
silence := opts.SilenceErrors
|
||||
if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) &&
|
||||
stdErr.isStd && opts.SilenceMissingStdImports {
|
||||
silence = true
|
||||
}
|
||||
|
||||
if !opts.SilenceErrors {
|
||||
if !silence {
|
||||
if opts.AllowErrors {
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err)
|
||||
} else {
|
||||
|
||||
@@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.Fatalf("go run: no go files listed")
|
||||
}
|
||||
cmdArgs := args[i:]
|
||||
if p.Error != nil {
|
||||
base.Fatalf("%s", p.Error)
|
||||
}
|
||||
load.CheckPackageErrors([]*load.Package{p})
|
||||
|
||||
p.Internal.OmitDebug = true
|
||||
if len(p.DepsErrors) > 0 {
|
||||
// Since these are errors in dependencies,
|
||||
// the same error might show up multiple times,
|
||||
// once in each package that depends on it.
|
||||
// Only print each once.
|
||||
printed := map[*load.PackageError]bool{}
|
||||
for _, err := range p.DepsErrors {
|
||||
if !printed[err] {
|
||||
printed[err] = true
|
||||
base.Errorf("%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
if p.Name != "main" {
|
||||
base.Fatalf("go run: cannot run non-main package")
|
||||
}
|
||||
p.Internal.OmitDebug = true
|
||||
p.Target = "" // must build - not up to date
|
||||
if p.Internal.CmdlineFiles {
|
||||
//set executable name if go file is given as cmd-argument
|
||||
|
||||
@@ -482,18 +482,22 @@ To eliminate ambiguity about which module versions are used in the build, the
|
||||
arguments must satisfy the following constraints:
|
||||
|
||||
- Arguments must be package paths or package patterns (with "..." wildcards).
|
||||
They must not be standard packages (like fmt), meta-patterns (std, cmd,
|
||||
all), or relative or absolute file paths.
|
||||
They must not be standard packages (like fmt), meta-patterns (std, cmd,
|
||||
all), or relative or absolute file paths.
|
||||
|
||||
- All arguments must have the same version suffix. Different queries are not
|
||||
allowed, even if they refer to the same version.
|
||||
allowed, even if they refer to the same version.
|
||||
|
||||
- All arguments must refer to packages in the same module at the same version.
|
||||
|
||||
- No module is considered the "main" module. If the module containing
|
||||
packages named on the command line has a go.mod file, it must not contain
|
||||
directives (replace and exclude) that would cause it to be interpreted
|
||||
differently than if it were the main module. The module must not require
|
||||
a higher version of itself.
|
||||
packages named on the command line has a go.mod file, it must not contain
|
||||
directives (replace and exclude) that would cause it to be interpreted
|
||||
differently than if it were the main module. The module must not require
|
||||
a higher version of itself.
|
||||
|
||||
- Package path arguments must refer to main packages. Pattern arguments
|
||||
will only match main packages.
|
||||
will only match main packages.
|
||||
|
||||
If the arguments don't have version suffixes, "go install" may run in
|
||||
module-aware mode or GOPATH mode, depending on the GO111MODULE environment
|
||||
|
||||
@@ -5,7 +5,7 @@ module "rsc.io/sampler"
|
||||
|
||||
require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
|
||||
-- .info --
|
||||
{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}EOF
|
||||
{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}
|
||||
-- hello.go --
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
15
src/cmd/go/testdata/script/list_err_cycle.txt
vendored
Normal file
15
src/cmd/go/testdata/script/list_err_cycle.txt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Check that we don't get infinite recursion when loading a package with
|
||||
# an import cycle and another error. Verifies #25830.
|
||||
! go list
|
||||
stderr 'found packages a \(a.go\) and b \(b.go\)'
|
||||
|
||||
-- go.mod --
|
||||
module errcycle
|
||||
|
||||
go 1.16
|
||||
-- a.go --
|
||||
package a
|
||||
|
||||
import _ "errcycle"
|
||||
-- b.go --
|
||||
package b
|
||||
@@ -18,7 +18,7 @@ stdout '^m$'
|
||||
# Test that we ignore directories when trying to find alternate config files.
|
||||
cd $WORK/gopkgdir/x
|
||||
! go list .
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! stderr 'Gopkg.lock'
|
||||
|
||||
-- $WORK/test/Gopkg.lock --
|
||||
|
||||
36
src/cmd/go/testdata/script/mod_download.txt
vendored
36
src/cmd/go/testdata/script/mod_download.txt
vendored
@@ -107,13 +107,28 @@ stderr '^go mod download: skipping argument m that resolves to the main module\n
|
||||
! go mod download m@latest
|
||||
stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$'
|
||||
|
||||
# download updates go.mod and populates go.sum
|
||||
# download without arguments updates go.mod and go.sum after loading the
|
||||
# build list, but does not save sums for downloaded zips.
|
||||
cd update
|
||||
cp go.mod.orig go.mod
|
||||
! exists go.sum
|
||||
go mod download
|
||||
cmp go.mod.update go.mod
|
||||
cmp go.sum.update go.sum
|
||||
cp go.mod.orig go.mod
|
||||
rm go.sum
|
||||
|
||||
# download with arguments (even "all") does update go.mod and go.sum.
|
||||
go mod download rsc.io/sampler
|
||||
cmp go.mod.update go.mod
|
||||
grep '^rsc.io/sampler v1.3.0 ' go.sum
|
||||
go list -m rsc.io/sampler
|
||||
stdout '^rsc.io/sampler v1.3.0$'
|
||||
cp go.mod.orig go.mod
|
||||
rm go.sum
|
||||
|
||||
go mod download all
|
||||
cmp go.mod.update go.mod
|
||||
grep '^rsc.io/sampler v1.3.0 ' go.sum
|
||||
cd ..
|
||||
|
||||
# allow go mod download without go.mod
|
||||
env GO111MODULE=auto
|
||||
@@ -131,7 +146,7 @@ stderr 'get '$GOPROXY
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
-- update/go.mod --
|
||||
-- update/go.mod.orig --
|
||||
module m
|
||||
|
||||
go 1.16
|
||||
@@ -140,3 +155,16 @@ require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/sampler v1.2.1 // older version than in build list
|
||||
)
|
||||
-- update/go.mod.update --
|
||||
module m
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
rsc.io/sampler v1.3.0 // older version than in build list
|
||||
)
|
||||
-- update/go.sum.update --
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
16
src/cmd/go/testdata/script/mod_edit.txt
vendored
16
src/cmd/go/testdata/script/mod_edit.txt
vendored
@@ -16,9 +16,9 @@ cmpenv go.mod $WORK/go.mod.init
|
||||
cmpenv go.mod $WORK/go.mod.init
|
||||
|
||||
# go mod edits
|
||||
go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0
|
||||
go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0
|
||||
cmpenv go.mod $WORK/go.mod.edit1
|
||||
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0]
|
||||
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0]
|
||||
cmpenv go.mod $WORK/go.mod.edit2
|
||||
|
||||
# -exclude and -retract reject invalid versions.
|
||||
@@ -27,6 +27,17 @@ stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of t
|
||||
! go mod edit -retract=bad
|
||||
stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$'
|
||||
|
||||
! go mod edit -exclude=example.com/m@v2.0.0
|
||||
stderr '^go mod: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$'
|
||||
|
||||
! go mod edit -exclude=example.com/m/v2@v1.0.0
|
||||
stderr '^go mod: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$'
|
||||
|
||||
! go mod edit -exclude=gopkg.in/example.v1@v2.0.0
|
||||
stderr '^go mod: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$'
|
||||
|
||||
cmpenv go.mod $WORK/go.mod.edit2
|
||||
|
||||
# go mod edit -json
|
||||
go mod edit -json
|
||||
cmpenv stdout $WORK/go.mod.json
|
||||
@@ -88,6 +99,7 @@ require x.1 v1.0.0
|
||||
exclude (
|
||||
x.1 v1.2.0
|
||||
x.1 v1.2.1
|
||||
x.1 v2.0.0+incompatible
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
2
src/cmd/go/testdata/script/mod_find.txt
vendored
2
src/cmd/go/testdata/script/mod_find.txt
vendored
@@ -49,7 +49,7 @@ rm go.mod
|
||||
# Test that we ignore directories when trying to find go.mod.
|
||||
cd $WORK/gomoddir
|
||||
! go list .
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
[!symlink] stop
|
||||
|
||||
|
||||
55
src/cmd/go/testdata/script/mod_get_missing_ziphash.txt
vendored
Normal file
55
src/cmd/go/testdata/script/mod_get_missing_ziphash.txt
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Test that if the module cache contains an extracted source directory but not
|
||||
# a ziphash, 'go build' complains about a missing sum, and 'go get' adds
|
||||
# the sum. Verifies #44749.
|
||||
|
||||
# With a tidy go.sum, go build succeeds. This also populates the module cache.
|
||||
cp go.sum.tidy go.sum
|
||||
go build -n use
|
||||
env GOPROXY=off
|
||||
env GOSUMDB=off
|
||||
|
||||
# Control case: if we delete the hash for rsc.io/quote v1.5.2,
|
||||
# 'go build' reports an error. 'go get' adds the sum.
|
||||
cp go.sum.bug go.sum
|
||||
! go build -n use
|
||||
stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
|
||||
go get -d use
|
||||
cmp go.sum go.sum.tidy
|
||||
go build -n use
|
||||
|
||||
# If we delete the hash *and* the ziphash file, we should see the same behavior.
|
||||
cp go.sum.bug go.sum
|
||||
rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash
|
||||
! go build -n use
|
||||
stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
|
||||
go get -d use
|
||||
cmp go.sum go.sum.tidy
|
||||
go build -n use
|
||||
|
||||
-- go.mod --
|
||||
module use
|
||||
|
||||
go 1.17
|
||||
|
||||
require rsc.io/quote v1.5.2
|
||||
-- go.sum.tidy --
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
|
||||
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
|
||||
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
|
||||
rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
|
||||
-- go.sum.bug --
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
|
||||
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
|
||||
rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
|
||||
-- use.go --
|
||||
package use
|
||||
|
||||
import _ "rsc.io/quote"
|
||||
@@ -11,7 +11,7 @@ cp go.mod.orig go.mod
|
||||
go mod edit -require example.com/retract/self/prev@v1.9.0
|
||||
go get -d example.com/retract/self/prev
|
||||
stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$'
|
||||
stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest$'
|
||||
stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest\n$'
|
||||
go list -m example.com/retract/self/prev
|
||||
stdout '^example.com/retract/self/prev v1.9.0$'
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Populate go.sum
|
||||
go mod download
|
||||
|
||||
# go list should succeed to load a package ending with ".go" if the path does
|
||||
# not correspond to an existing local file. Listing a pattern ending with
|
||||
# ".go/" should try to list a package regardless of whether a file exists at the
|
||||
@@ -31,3 +28,10 @@ module m
|
||||
go 1.13
|
||||
|
||||
require example.com/dotgo.go v1.0.0
|
||||
-- go.sum --
|
||||
example.com/dotgo.go v1.0.0 h1:XKJfs0V8x2PvY2tX8bJBCEbCDLnt15ma2onwhVpew/I=
|
||||
example.com/dotgo.go v1.0.0/go.mod h1:Qi6z/X3AC5vHiuMt6HF2ICx3KhIBGrMdrA7YoPDKqR0=
|
||||
-- use.go --
|
||||
package use
|
||||
|
||||
import _ "example.com/dotgo.go"
|
||||
|
||||
5
src/cmd/go/testdata/script/mod_install_hint.txt
vendored
Normal file
5
src/cmd/go/testdata/script/mod_install_hint.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Module is replaced but not required. No hint appears as no module is suggested.
|
||||
go mod init m
|
||||
go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0
|
||||
! go install github.com/notrequired
|
||||
! stderr 'to add it:'
|
||||
@@ -59,9 +59,9 @@ rm $GOPATH/bin
|
||||
env GO111MODULE=on
|
||||
go mod download rsc.io/fortune@v1.0.0
|
||||
! go install $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
|
||||
stderr '^go: cannot find main module; see ''go help modules''$'
|
||||
stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go install ../pkg/mod/rsc.io/fortune@v1.0.0
|
||||
stderr '^go: cannot find main module; see ''go help modules''$'
|
||||
stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
mkdir tmp
|
||||
cd tmp
|
||||
go mod init tmp
|
||||
|
||||
24
src/cmd/go/testdata/script/mod_invalid_path.txt
vendored
24
src/cmd/go/testdata/script/mod_invalid_path.txt
vendored
@@ -23,6 +23,20 @@ cd $WORK/gopath/src/badname
|
||||
! go list .
|
||||
stderr 'invalid module path'
|
||||
|
||||
# Test that an import path containing an element with a leading dot is valid,
|
||||
# but such a module path is not.
|
||||
# Verifies #43985.
|
||||
cd $WORK/gopath/src/dotname
|
||||
go list ./.dot
|
||||
stdout '^example.com/dotname/.dot$'
|
||||
go list ./use
|
||||
stdout '^example.com/dotname/use$'
|
||||
! go list -m example.com/dotname/.dot@latest
|
||||
stderr '^go list -m: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$'
|
||||
go get -d example.com/dotname/.dot
|
||||
go get -d example.com/dotname/use
|
||||
go mod tidy
|
||||
|
||||
-- mod/go.mod --
|
||||
|
||||
-- mod/foo.go --
|
||||
@@ -38,3 +52,13 @@ module .\.
|
||||
-- badname/foo.go --
|
||||
package badname
|
||||
|
||||
-- dotname/go.mod --
|
||||
module example.com/dotname
|
||||
|
||||
go 1.16
|
||||
-- dotname/.dot/dot.go --
|
||||
package dot
|
||||
-- dotname/use/use.go --
|
||||
package use
|
||||
|
||||
import _ "example.com/dotname/.dot"
|
||||
|
||||
32
src/cmd/go/testdata/script/mod_invalid_path_plus.txt
vendored
Normal file
32
src/cmd/go/testdata/script/mod_invalid_path_plus.txt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# https://golang.org/issue/44776
|
||||
# The '+' character should be disallowed in module paths, but allowed in package
|
||||
# paths within valid modules.
|
||||
|
||||
go get -d example.net/cmd
|
||||
go list example.net/cmd/x++
|
||||
|
||||
! go list -versions -m 'example.net/bad++'
|
||||
stderr '^go list -m: module example.net/bad\+\+: malformed module path "example.net/bad\+\+": invalid char ''\+''$'
|
||||
|
||||
# TODO(bcmills): 'go get -d example.net/cmd/x++' should also work, but currently
|
||||
# it does not. This might be fixed by https://golang.org/cl/297891.
|
||||
! go get -d example.net/cmd/x++
|
||||
stderr '^go get: malformed module path "example.net/cmd/x\+\+": invalid char ''\+''$'
|
||||
|
||||
-- go.mod --
|
||||
module example.com/m
|
||||
|
||||
go 1.16
|
||||
|
||||
replace (
|
||||
example.net/cmd => ./cmd
|
||||
)
|
||||
|
||||
-- cmd/go.mod --
|
||||
module example.net/cmd
|
||||
|
||||
go 1.16
|
||||
-- cmd/x++/main.go --
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
52
src/cmd/go/testdata/script/mod_outside.txt
vendored
52
src/cmd/go/testdata/script/mod_outside.txt
vendored
@@ -12,13 +12,13 @@ stdout 'NUL|/dev/null'
|
||||
# 'go list' without arguments implicitly operates on the current directory,
|
||||
# which is not in a module.
|
||||
! go list
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
go list -m
|
||||
stdout '^command-line-arguments$'
|
||||
# 'go list' in the working directory should fail even if there is a a 'package
|
||||
# main' present: without a main module, we do not know its package path.
|
||||
! go list ./needmod
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go list all' lists the transitive import graph of the main module,
|
||||
# which is empty if there is no main module.
|
||||
@@ -41,7 +41,7 @@ stdout 'command-line-arguments'
|
||||
|
||||
# 'go list' on a package from a module should fail.
|
||||
! go list example.com/printversion
|
||||
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
|
||||
stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go list -m' with an explicit version should resolve that version.
|
||||
@@ -54,19 +54,19 @@ stdout 'v1.0.0\s+v1.0.1\s+v1.1.0'
|
||||
|
||||
# 'go list -m all' should fail. "all" is not meaningful outside of a module.
|
||||
! go list -m all
|
||||
stderr 'go: cannot match "all": working directory is not part of a module'
|
||||
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go list -m <mods> all' should also fail.
|
||||
! go list -m example.com/printversion@v1.0.0 all
|
||||
stderr 'go: cannot match "all": working directory is not part of a module'
|
||||
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! stdout 'example.com/version'
|
||||
|
||||
# 'go list -m' with wildcards should fail. Wildcards match modules in the
|
||||
# build list, so they aren't meaningful outside a module.
|
||||
! go list -m ...
|
||||
stderr 'go: cannot match "...": working directory is not part of a module'
|
||||
stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go list -m rsc.io/quote/...
|
||||
stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module'
|
||||
stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go clean' should skip the current directory if it isn't in a module.
|
||||
@@ -76,20 +76,20 @@ go clean -n
|
||||
|
||||
# 'go mod graph' should fail, since there's no module graph.
|
||||
! go mod graph
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go mod why' should fail, since there is no main module to depend on anything.
|
||||
! go mod why -m example.com/version
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail:
|
||||
# there is no go.mod file to edit.
|
||||
! go mod tidy
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go mod edit -fmt
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go mod edit -require example.com/version@v1.0.0
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go mod download' without arguments should report an error.
|
||||
@@ -104,33 +104,33 @@ exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip
|
||||
|
||||
# 'go mod download all' should fail. "all" is not meaningful outside of a module.
|
||||
! go mod download all
|
||||
stderr 'go: cannot match "all": working directory is not part of a module'
|
||||
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go mod vendor' should fail: it starts by clearing the existing vendor
|
||||
# directory, and we don't know where that is.
|
||||
! go mod vendor
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go mod verify' should fail: we have no modules to verify.
|
||||
! go mod verify
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go get' without arguments implicitly operates on the main module, and thus
|
||||
# should fail.
|
||||
! go get
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go get -u
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
! go get -u ./needmod
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go get -u all' upgrades the transitive import graph of the main module,
|
||||
# which is empty.
|
||||
! go get -u all
|
||||
stderr 'go get: cannot match "all": working directory is not part of a module'
|
||||
stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go get' should check the proposed module graph for consistency,
|
||||
# even though we won't write it anywhere.
|
||||
@@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/version@v1.0.0
|
||||
# 'go build' without arguments implicitly operates on the current directory, and should fail.
|
||||
cd needmod
|
||||
! go build
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
cd ..
|
||||
|
||||
# 'go build' of a non-module directory should fail too.
|
||||
! go build ./needmod
|
||||
stderr 'cannot find main module'
|
||||
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go build' of source files should fail if they import anything outside std.
|
||||
! go build -n ./needmod/needmod.go
|
||||
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
|
||||
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go build' of source files should succeed if they do not import anything outside std.
|
||||
go build -n -o ignore ./stdonly/stdonly.go
|
||||
@@ -179,7 +179,7 @@ go doc fmt
|
||||
|
||||
# 'go doc' should fail for a package path outside a module.
|
||||
! go doc example.com/version
|
||||
stderr 'doc: no required module provides package example.com/version: working directory is not part of a module'
|
||||
stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go install' with a version should succeed if all constraints are met.
|
||||
# See mod_install_pkg_version.
|
||||
@@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu
|
||||
# 'go install' should fail if a source file imports a package that must be
|
||||
# resolved to a module.
|
||||
! go install ./needmod/needmod.go
|
||||
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module'
|
||||
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go install' should succeed with a package in GOROOT.
|
||||
go install cmd/addr2line
|
||||
@@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with'
|
||||
|
||||
# 'go run' should fail if a package argument must be resolved to a module.
|
||||
! go run example.com/printversion
|
||||
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
|
||||
stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
# 'go run' should fail if a source file imports a package that must be
|
||||
# resolved to a module.
|
||||
! go run ./needmod/needmod.go
|
||||
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
|
||||
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
|
||||
|
||||
|
||||
# 'go fmt' should be able to format files outside of a module.
|
||||
|
||||
5
src/cmd/go/testdata/script/mod_query.txt
vendored
5
src/cmd/go/testdata/script/mod_query.txt
vendored
@@ -1,9 +1,7 @@
|
||||
env GO111MODULE=on
|
||||
|
||||
# Populate go.sum.
|
||||
# TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands
|
||||
# below depend on the build list.
|
||||
go mod download
|
||||
|
||||
go list -m -versions rsc.io/quote
|
||||
stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$'
|
||||
@@ -36,6 +34,9 @@ stdout 'no matching versions for query ">v1.5.3"'
|
||||
module x
|
||||
require rsc.io/quote v1.0.0
|
||||
|
||||
-- go.sum --
|
||||
rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
|
||||
rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
|
||||
-- use.go --
|
||||
package use
|
||||
|
||||
|
||||
8
src/cmd/go/testdata/script/mod_readonly.txt
vendored
8
src/cmd/go/testdata/script/mod_readonly.txt
vendored
@@ -89,7 +89,7 @@ stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
go 1.16
|
||||
|
||||
-- x.go --
|
||||
package x
|
||||
@@ -104,7 +104,7 @@ require (
|
||||
-- go.mod.redundant --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2
|
||||
@@ -114,7 +114,7 @@ require (
|
||||
-- go.mod.indirect --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
rsc.io/quote v1.5.2 // indirect
|
||||
@@ -124,7 +124,7 @@ require (
|
||||
-- go.mod.untidy --
|
||||
module m
|
||||
|
||||
go 1.20
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
rsc.io/sampler v1.3.0 // indirect
|
||||
|
||||
8
src/cmd/go/testdata/script/mod_retract.txt
vendored
8
src/cmd/go/testdata/script/mod_retract.txt
vendored
@@ -1,8 +1,5 @@
|
||||
cp go.mod go.mod.orig
|
||||
|
||||
# Populate go.sum.
|
||||
go mod download
|
||||
|
||||
# 'go list pkg' does not report an error when a retracted version is used.
|
||||
go list -e -f '{{if .Error}}{{.Error}}{{end}}' ./use
|
||||
! stdout .
|
||||
@@ -32,6 +29,11 @@ go 1.15
|
||||
|
||||
require example.com/retract v1.0.0-bad
|
||||
|
||||
-- go.sum --
|
||||
example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis=
|
||||
example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y=
|
||||
example.com/retract/self/prev v1.1.0 h1:0/8I/GTG+1eJTFeDQ/fUbgrMsVHHyKhh3Z8DSZp1fuA=
|
||||
example.com/retract/self/prev v1.1.0/go.mod h1:xl2EcklWuZZHVtHWcpzfSJQmnzAGpKZYpA/Wto7SZN4=
|
||||
-- use/use.go --
|
||||
package use
|
||||
|
||||
|
||||
48
src/cmd/go/testdata/script/mod_retract_fix_version.txt
vendored
Normal file
48
src/cmd/go/testdata/script/mod_retract_fix_version.txt
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# retract must not be used without a module directive.
|
||||
! go list -m all
|
||||
stderr 'go.mod:3: no module directive found, so retract cannot be used$'
|
||||
|
||||
# Commands that update go.mod should fix non-canonical versions in
|
||||
# retract directives.
|
||||
# Verifies #44494.
|
||||
go mod edit -module=rsc.io/quote/v2
|
||||
! go list -m all
|
||||
stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$'
|
||||
go mod tidy
|
||||
go list -m all
|
||||
cmp go.mod go.mod.want
|
||||
|
||||
# If a retracted version doesn't match the module's major version suffx,
|
||||
# an error should be reported.
|
||||
! go mod edit -retract=v3.0.1
|
||||
stderr '^go mod: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$'
|
||||
cp go.mod.mismatch-v2 go.mod
|
||||
! go list -m all
|
||||
stderr 'go.mod:3: retract rsc.io/quote/v2: version "v3.0.1" invalid: should be v2, not v3$'
|
||||
|
||||
cp go.mod.mismatch-v1 go.mod
|
||||
! go list -m all
|
||||
stderr 'go.mod:3: retract rsc.io/quote: version "v3.0.1" invalid: should be v0 or v1, not v3$'
|
||||
|
||||
-- go.mod --
|
||||
go 1.16
|
||||
|
||||
retract latest
|
||||
-- go.mod.want --
|
||||
go 1.16
|
||||
|
||||
retract v2.0.1
|
||||
|
||||
module rsc.io/quote/v2
|
||||
-- go.mod.mismatch-v2 --
|
||||
go 1.16
|
||||
|
||||
retract v3.0.1
|
||||
|
||||
module rsc.io/quote/v2
|
||||
-- go.mod.mismatch-v1 --
|
||||
go 1.16
|
||||
|
||||
retract v3.0.1
|
||||
|
||||
module rsc.io/quote
|
||||
@@ -4,12 +4,12 @@ env GO111MODULE=on
|
||||
# 'go mod tidy' and 'go mod vendor' should not hide loading errors.
|
||||
|
||||
! go mod tidy
|
||||
stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)'
|
||||
! stderr 'package nonexist is not in GOROOT'
|
||||
stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com'
|
||||
stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist'
|
||||
|
||||
! go mod vendor
|
||||
stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)'
|
||||
! stderr 'package nonexist is not in GOROOT'
|
||||
stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com'
|
||||
stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist'
|
||||
|
||||
|
||||
48
src/cmd/go/testdata/script/mod_tidy_too_new.txt
vendored
Normal file
48
src/cmd/go/testdata/script/mod_tidy_too_new.txt
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# https://golang.org/issue/46142: 'go mod tidy' should error out if the version
|
||||
# in the go.mod file is newer than the most recent supported version.
|
||||
|
||||
cp go.mod go.mod.orig
|
||||
|
||||
|
||||
# If the go.mod file specifies an unsupported Go version, 'go mod tidy' should
|
||||
# refuse to edit it: we don't know what a tidy go.mod file for that version
|
||||
# would look like.
|
||||
|
||||
! go mod tidy
|
||||
stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
|
||||
cmp go.mod go.mod.orig
|
||||
|
||||
|
||||
# The -e flag should push past the error and edit the file anyway,
|
||||
# but preserve the too-high version.
|
||||
|
||||
cp go.mod.orig go.mod
|
||||
go mod tidy -e
|
||||
stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
|
||||
cmp go.mod go.mod.tidy
|
||||
|
||||
|
||||
-- go.mod --
|
||||
module example.net/from/the/future
|
||||
|
||||
go 2000.0
|
||||
|
||||
replace example.net/m v0.0.0 => ./m
|
||||
-- go.mod.tidy --
|
||||
module example.net/from/the/future
|
||||
|
||||
go 2000.0
|
||||
|
||||
replace example.net/m v0.0.0 => ./m
|
||||
|
||||
require example.net/m v0.0.0
|
||||
-- x.go --
|
||||
package x
|
||||
|
||||
import "example.net/m"
|
||||
-- m/go.mod --
|
||||
module example.net/m
|
||||
|
||||
go 1.17
|
||||
-- m/m.go --
|
||||
package m
|
||||
7
src/cmd/go/testdata/script/mod_verify.txt
vendored
7
src/cmd/go/testdata/script/mod_verify.txt
vendored
@@ -48,10 +48,13 @@ go mod tidy
|
||||
grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
|
||||
grep '^rsc.io/quote v1.1.0 ' go.sum
|
||||
|
||||
# sync should ignore missing ziphash; verify should not
|
||||
# verify should fail on a missing ziphash. tidy should restore it.
|
||||
rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
|
||||
go mod tidy
|
||||
! go mod verify
|
||||
stderr '^rsc.io/quote v1.1.0: missing ziphash: open '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash'
|
||||
go mod tidy
|
||||
exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
|
||||
go mod verify
|
||||
|
||||
# Packages below module root should not be mentioned in go.sum.
|
||||
rm go.sum
|
||||
|
||||
@@ -370,10 +370,16 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
r := relocs.At(ri)
|
||||
switch r.Type() {
|
||||
case objabi.R_CALLARM:
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t := (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
var t int64
|
||||
// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
|
||||
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
|
||||
// in dependency order.
|
||||
if ldr.SymValue(rs) != 0 {
|
||||
// r.Add is the instruction
|
||||
// low 24-bit encodes the target address
|
||||
t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4
|
||||
}
|
||||
if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
// direct call too far, need to insert trampoline.
|
||||
// look up existing trampolines first. if we found one within the range
|
||||
// of direct call, we can reuse it. otherwise create a new one.
|
||||
@@ -445,7 +451,7 @@ func gentramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *l
|
||||
arch.ByteOrder.PutUint32(P[8:], o3)
|
||||
tramp.SetData(P)
|
||||
|
||||
if linkmode == ld.LinkExternal {
|
||||
if linkmode == ld.LinkExternal || ldr.SymValue(target) == 0 {
|
||||
r, _ := tramp.AddRel(objabi.R_ADDR)
|
||||
r.SetOff(8)
|
||||
r.SetSiz(4)
|
||||
|
||||
@@ -106,14 +106,12 @@ func trampoline(ctxt *Link, s loader.Sym) {
|
||||
}
|
||||
rs = ldr.ResolveABIAlias(rs)
|
||||
if ldr.SymValue(rs) == 0 && (ldr.SymType(rs) != sym.SDYNIMPORT && ldr.SymType(rs) != sym.SUNDEFEXT) {
|
||||
if ldr.SymPkg(rs) != ldr.SymPkg(s) {
|
||||
if !isRuntimeDepPkg(ldr.SymPkg(s)) || !isRuntimeDepPkg(ldr.SymPkg(rs)) {
|
||||
ctxt.Errorf(s, "unresolved inter-package jump to %s(%s) from %s", ldr.SymName(rs), ldr.SymPkg(rs), ldr.SymPkg(s))
|
||||
}
|
||||
// runtime and its dependent packages may call to each other.
|
||||
// they are fine, as they will be laid down together.
|
||||
if ldr.SymPkg(rs) == ldr.SymPkg(s) {
|
||||
continue // symbols in the same package are laid out together
|
||||
}
|
||||
if isRuntimeDepPkg(ldr.SymPkg(s)) && isRuntimeDepPkg(ldr.SymPkg(rs)) {
|
||||
continue // runtime packages are laid out together
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
thearch.Trampoline(ctxt, ldr, ri, rs, s)
|
||||
@@ -2332,6 +2330,11 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s loader.Sym, va uint64
|
||||
return sect, n, va
|
||||
}
|
||||
|
||||
// On Wasm, we reserve 4096 bytes for zero page, then 4096 bytes for wasm_exec.js
|
||||
// to store command line args. Data sections starts from at least address 8192.
|
||||
// Keep in sync with wasm_exec.js.
|
||||
const wasmMinDataAddr = 4096 + 4096
|
||||
|
||||
// address assigns virtual addresses to all segments and sections and
|
||||
// returns all segments in file order.
|
||||
func (ctxt *Link) address() []*sym.Segment {
|
||||
@@ -2341,10 +2344,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)
|
||||
|
||||
@@ -24,6 +24,7 @@ type deadcodePass struct {
|
||||
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
|
||||
markableMethods []methodref // methods of reached types
|
||||
reflectSeen bool // whether we have seen a reflect method call
|
||||
dynlink bool
|
||||
|
||||
methodsigstmp []methodsig // scratch buffer for decoding method signatures
|
||||
}
|
||||
@@ -34,6 +35,7 @@ func (d *deadcodePass) init() {
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
|
||||
}
|
||||
d.dynlink = d.ctxt.DynlinkingGo()
|
||||
|
||||
if d.ctxt.BuildMode == BuildModeShared {
|
||||
// Mark all symbols defined in this library as reachable when
|
||||
@@ -111,6 +113,11 @@ func (d *deadcodePass) flood() {
|
||||
var usedInIface bool
|
||||
|
||||
if isgotype {
|
||||
if d.dynlink {
|
||||
// When dynaamic linking, a type may be passed across DSO
|
||||
// boundary and get converted to interface at the other side.
|
||||
d.ldr.SetAttrUsedInIface(symIdx, true)
|
||||
}
|
||||
usedInIface = d.ldr.AttrUsedInIface(symIdx)
|
||||
}
|
||||
|
||||
|
||||
@@ -1086,7 +1086,7 @@ func elfrelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym)
|
||||
}
|
||||
}
|
||||
|
||||
eaddr := int32(sect.Vaddr + sect.Length)
|
||||
eaddr := sect.Vaddr + sect.Length
|
||||
for _, s := range syms {
|
||||
if !ldr.AttrReachable(s) {
|
||||
continue
|
||||
|
||||
@@ -533,7 +533,10 @@ func (ctxt *Link) loadlib() {
|
||||
// up symbol by name may not get expected result.
|
||||
|
||||
iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
|
||||
ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil
|
||||
|
||||
// Plugins a require cgo support to function. Similarly, plugins may require additional
|
||||
// internal linker support on some platforms which may not be implemented.
|
||||
ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil && iscgo
|
||||
|
||||
// We now have enough information to determine the link mode.
|
||||
determineLinkMode(ctxt)
|
||||
|
||||
@@ -1168,7 +1168,7 @@ func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sy
|
||||
}
|
||||
}
|
||||
|
||||
eaddr := int32(sect.Vaddr + sect.Length)
|
||||
eaddr := sect.Vaddr + sect.Length
|
||||
for _, s := range syms {
|
||||
if !ldr.AttrReachable(s) {
|
||||
continue
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
@@ -102,10 +103,14 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
|
||||
elfshnum = xosect.Elfsect.(*ElfShdr).shnum
|
||||
}
|
||||
|
||||
sname := ldr.SymExtname(x)
|
||||
|
||||
// One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL,
|
||||
// maybe one day elf.STB_WEAK.
|
||||
bind := elf.STB_GLOBAL
|
||||
if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
|
||||
if ldr.IsFileLocal(x) && !isStaticTmp(sname) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
|
||||
// Static tmp is package local, but a package can be shared among multiple DSOs.
|
||||
// They need to have a single view of the static tmp that are writable.
|
||||
bind = elf.STB_LOCAL
|
||||
}
|
||||
|
||||
@@ -140,8 +145,6 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
|
||||
other |= 3 << 5
|
||||
}
|
||||
|
||||
sname := ldr.SymExtname(x)
|
||||
|
||||
// When dynamically linking, we create Symbols by reading the names from
|
||||
// the symbol tables of the shared libraries and so the names need to
|
||||
// match exactly. Tools like DTrace will have to wait for now.
|
||||
@@ -823,3 +826,7 @@ func setCarrierSize(typ sym.SymKind, sz int64) {
|
||||
}
|
||||
CarrierSymByType[typ].Size = sz
|
||||
}
|
||||
|
||||
func isStaticTmp(name string) bool {
|
||||
return strings.Contains(name, "."+obj.StaticNamePref)
|
||||
}
|
||||
|
||||
@@ -474,6 +474,15 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
|
||||
if l.flags&FlagStrictDups != 0 {
|
||||
l.checkdup(name, r, li, oldi)
|
||||
}
|
||||
// Fix for issue #47185 -- given two dupok symbols with
|
||||
// different sizes, favor symbol with larger size. See
|
||||
// also issue #46653.
|
||||
szdup := l.SymSize(oldi)
|
||||
sz := int64(r.Sym(li).Siz())
|
||||
if szdup < sz {
|
||||
// new symbol overwrites old symbol.
|
||||
l.objSyms[oldi] = objSym{r.objidx, li}
|
||||
}
|
||||
return oldi
|
||||
}
|
||||
oldr, oldli := l.toLocal(oldi)
|
||||
|
||||
@@ -642,6 +642,16 @@ func archrelocaddr(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r l
|
||||
return int64(o2)<<32 | int64(o1)
|
||||
}
|
||||
|
||||
// Determine if the code was compiled so that the TOC register R2 is initialized and maintained
|
||||
func r2Valid(ctxt *ld.Link) bool {
|
||||
switch ctxt.BuildMode {
|
||||
case ld.BuildModeCArchive, ld.BuildModeCShared, ld.BuildModePIE, ld.BuildModeShared, ld.BuildModePlugin:
|
||||
return true
|
||||
}
|
||||
// -linkshared option
|
||||
return ctxt.IsSharedGoLink()
|
||||
}
|
||||
|
||||
// resolve direct jump relocation r in s, and add trampoline if necessary
|
||||
func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
|
||||
@@ -649,20 +659,26 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
// For internal linking, trampolines are always created for long calls.
|
||||
// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
|
||||
// r2. For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
|
||||
if ctxt.IsExternal() && (ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE) {
|
||||
if ctxt.IsExternal() && r2Valid(ctxt) {
|
||||
// No trampolines needed since r2 contains the TOC
|
||||
return
|
||||
}
|
||||
|
||||
relocs := ldr.Relocs(s)
|
||||
r := relocs.At(ri)
|
||||
t := ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
|
||||
var t int64
|
||||
// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
|
||||
// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
|
||||
// in dependency order.
|
||||
if ldr.SymValue(rs) != 0 {
|
||||
t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
|
||||
}
|
||||
switch r.Type() {
|
||||
case objabi.R_CALLPOWER:
|
||||
|
||||
// If branch offset is too far then create a trampoline.
|
||||
|
||||
if (ctxt.IsExternal() && ldr.SymSect(s) != ldr.SymSect(rs)) || (ctxt.IsInternal() && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
if (ctxt.IsExternal() && ldr.SymSect(s) != ldr.SymSect(rs)) || (ctxt.IsInternal() && int64(int32(t<<6)>>6) != t) || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) {
|
||||
var tramp loader.Sym
|
||||
for i := 0; ; i++ {
|
||||
|
||||
@@ -697,7 +713,7 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
|
||||
}
|
||||
}
|
||||
if ldr.SymType(tramp) == 0 {
|
||||
if ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
|
||||
if r2Valid(ctxt) {
|
||||
// Should have returned for above cases
|
||||
ctxt.Errorf(s, "unexpected trampoline for shared or dynamic linking")
|
||||
} else {
|
||||
@@ -749,7 +765,7 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
|
||||
|
||||
// With external linking, the target address must be
|
||||
// relocated using LO and HA
|
||||
if ctxt.IsExternal() {
|
||||
if ctxt.IsExternal() || ldr.SymValue(target) == 0 {
|
||||
r, _ := tramp.AddRel(objabi.R_ADDRPOWER)
|
||||
r.SetOff(0)
|
||||
r.SetSiz(8) // generates 2 relocations: HA + LO
|
||||
|
||||
167
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
167
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
@@ -125,6 +125,12 @@ func (f *File) AddComment(text string) {
|
||||
|
||||
type VersionFixer func(path, version string) (string, error)
|
||||
|
||||
// errDontFix is returned by a VersionFixer to indicate the version should be
|
||||
// left alone, even if it's not canonical.
|
||||
var dontFixRetract VersionFixer = func(_, vers string) (string, error) {
|
||||
return vers, nil
|
||||
}
|
||||
|
||||
// Parse parses the data, reported in errors as being from file,
|
||||
// into a File struct. It applies fix, if non-nil, to canonicalize all module versions found.
|
||||
func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
|
||||
@@ -142,7 +148,7 @@ func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) {
|
||||
return parseToFile(file, data, fix, false)
|
||||
}
|
||||
|
||||
func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) {
|
||||
func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parsed *File, err error) {
|
||||
fs, err := parse(file, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -150,8 +156,18 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File
|
||||
f := &File{
|
||||
Syntax: fs,
|
||||
}
|
||||
|
||||
var errs ErrorList
|
||||
|
||||
// fix versions in retract directives after the file is parsed.
|
||||
// We need the module path to fix versions, and it might be at the end.
|
||||
defer func() {
|
||||
oldLen := len(errs)
|
||||
f.fixRetract(fix, &errs)
|
||||
if len(errs) > oldLen {
|
||||
parsed, err = nil, errs
|
||||
}
|
||||
}()
|
||||
|
||||
for _, x := range fs.Stmt {
|
||||
switch x := x.(type) {
|
||||
case *Line:
|
||||
@@ -370,7 +386,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||
|
||||
case "retract":
|
||||
rationale := parseRetractRationale(block, line)
|
||||
vi, err := parseVersionInterval(verb, &args, fix)
|
||||
vi, err := parseVersionInterval(verb, "", &args, dontFixRetract)
|
||||
if err != nil {
|
||||
if strict {
|
||||
wrapError(err)
|
||||
@@ -397,6 +413,47 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||
}
|
||||
}
|
||||
|
||||
// fixRetract applies fix to each retract directive in f, appending any errors
|
||||
// to errs.
|
||||
//
|
||||
// Most versions are fixed as we parse the file, but for retract directives,
|
||||
// the relevant module path is the one specified with the module directive,
|
||||
// and that might appear at the end of the file (or not at all).
|
||||
func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) {
|
||||
if fix == nil {
|
||||
return
|
||||
}
|
||||
path := ""
|
||||
if f.Module != nil {
|
||||
path = f.Module.Mod.Path
|
||||
}
|
||||
var r *Retract
|
||||
wrapError := func(err error) {
|
||||
*errs = append(*errs, Error{
|
||||
Filename: f.Syntax.Name,
|
||||
Pos: r.Syntax.Start,
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
|
||||
for _, r = range f.Retract {
|
||||
if path == "" {
|
||||
wrapError(errors.New("no module directive found, so retract cannot be used"))
|
||||
return // only print the first one of these
|
||||
}
|
||||
|
||||
args := r.Syntax.Token
|
||||
if args[0] == "retract" {
|
||||
args = args[1:]
|
||||
}
|
||||
vi, err := parseVersionInterval("retract", path, &args, fix)
|
||||
if err != nil {
|
||||
wrapError(err)
|
||||
}
|
||||
r.VersionInterval = vi
|
||||
}
|
||||
}
|
||||
|
||||
// isIndirect reports whether line has a "// indirect" comment,
|
||||
// meaning it is in go.mod only for its effect on indirect dependencies,
|
||||
// so that it can be dropped entirely once the effective version of the
|
||||
@@ -491,13 +548,13 @@ func AutoQuote(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (VersionInterval, error) {
|
||||
func parseVersionInterval(verb string, path string, args *[]string, fix VersionFixer) (VersionInterval, error) {
|
||||
toks := *args
|
||||
if len(toks) == 0 || toks[0] == "(" {
|
||||
return VersionInterval{}, fmt.Errorf("expected '[' or version")
|
||||
}
|
||||
if toks[0] != "[" {
|
||||
v, err := parseVersion(verb, "", &toks[0], fix)
|
||||
v, err := parseVersion(verb, path, &toks[0], fix)
|
||||
if err != nil {
|
||||
return VersionInterval{}, err
|
||||
}
|
||||
@@ -509,7 +566,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio
|
||||
if len(toks) == 0 {
|
||||
return VersionInterval{}, fmt.Errorf("expected version after '['")
|
||||
}
|
||||
low, err := parseVersion(verb, "", &toks[0], fix)
|
||||
low, err := parseVersion(verb, path, &toks[0], fix)
|
||||
if err != nil {
|
||||
return VersionInterval{}, err
|
||||
}
|
||||
@@ -523,7 +580,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio
|
||||
if len(toks) == 0 {
|
||||
return VersionInterval{}, fmt.Errorf("expected version after ','")
|
||||
}
|
||||
high, err := parseVersion(verb, "", &toks[0], fix)
|
||||
high, err := parseVersion(verb, path, &toks[0], fix)
|
||||
if err != nil {
|
||||
return VersionInterval{}, err
|
||||
}
|
||||
@@ -631,8 +688,7 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string
|
||||
}
|
||||
}
|
||||
if fix != nil {
|
||||
var err error
|
||||
t, err = fix(path, t)
|
||||
fixed, err := fix(path, t)
|
||||
if err != nil {
|
||||
if err, ok := err.(*module.ModuleError); ok {
|
||||
return "", &Error{
|
||||
@@ -643,19 +699,23 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
t = fixed
|
||||
} else {
|
||||
cv := module.CanonicalVersion(t)
|
||||
if cv == "" {
|
||||
return "", &Error{
|
||||
Verb: verb,
|
||||
ModPath: path,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: t,
|
||||
Err: errors.New("must be of the form v1.2.3"),
|
||||
},
|
||||
}
|
||||
}
|
||||
t = cv
|
||||
}
|
||||
if v := module.CanonicalVersion(t); v != "" {
|
||||
*s = v
|
||||
return *s, nil
|
||||
}
|
||||
return "", &Error{
|
||||
Verb: verb,
|
||||
ModPath: path,
|
||||
Err: &module.InvalidVersionError{
|
||||
Version: t,
|
||||
Err: errors.New("must be of the form v1.2.3"),
|
||||
},
|
||||
}
|
||||
*s = t
|
||||
return *s, nil
|
||||
}
|
||||
|
||||
func modulePathMajor(path string) (string, error) {
|
||||
@@ -835,11 +895,8 @@ func (f *File) DropRequire(path string) error {
|
||||
// AddExclude adds a exclude statement to the mod file. Errors if the provided
|
||||
// version is not a canonical version string
|
||||
func (f *File) AddExclude(path, vers string) error {
|
||||
if !isCanonicalVersion(vers) {
|
||||
return &module.InvalidVersionError{
|
||||
Version: vers,
|
||||
Err: errors.New("must be of the form v1.2.3"),
|
||||
}
|
||||
if err := checkCanonicalVersion(path, vers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var hint *Line
|
||||
@@ -916,17 +973,15 @@ func (f *File) DropReplace(oldPath, oldVers string) error {
|
||||
// AddRetract adds a retract statement to the mod file. Errors if the provided
|
||||
// version interval does not consist of canonical version strings
|
||||
func (f *File) AddRetract(vi VersionInterval, rationale string) error {
|
||||
if !isCanonicalVersion(vi.High) {
|
||||
return &module.InvalidVersionError{
|
||||
Version: vi.High,
|
||||
Err: errors.New("must be of the form v1.2.3"),
|
||||
}
|
||||
var path string
|
||||
if f.Module != nil {
|
||||
path = f.Module.Mod.Path
|
||||
}
|
||||
if !isCanonicalVersion(vi.Low) {
|
||||
return &module.InvalidVersionError{
|
||||
Version: vi.Low,
|
||||
Err: errors.New("must be of the form v1.2.3"),
|
||||
}
|
||||
if err := checkCanonicalVersion(path, vi.High); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkCanonicalVersion(path, vi.Low); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := &Retract{
|
||||
@@ -1086,8 +1141,40 @@ func lineRetractLess(li, lj *Line) bool {
|
||||
return semver.Compare(vii.High, vij.High) > 0
|
||||
}
|
||||
|
||||
// isCanonicalVersion tests if the provided version string represents a valid
|
||||
// canonical version.
|
||||
func isCanonicalVersion(vers string) bool {
|
||||
return vers != "" && semver.Canonical(vers) == vers
|
||||
// checkCanonicalVersion returns a non-nil error if vers is not a canonical
|
||||
// version string or does not match the major version of path.
|
||||
//
|
||||
// If path is non-empty, the error text suggests a format with a major version
|
||||
// corresponding to the path.
|
||||
func checkCanonicalVersion(path, vers string) error {
|
||||
_, pathMajor, pathMajorOk := module.SplitPathVersion(path)
|
||||
|
||||
if vers == "" || vers != module.CanonicalVersion(vers) {
|
||||
if pathMajor == "" {
|
||||
return &module.InvalidVersionError{
|
||||
Version: vers,
|
||||
Err: fmt.Errorf("must be of the form v1.2.3"),
|
||||
}
|
||||
}
|
||||
return &module.InvalidVersionError{
|
||||
Version: vers,
|
||||
Err: fmt.Errorf("must be of the form %s.2.3", module.PathMajorPrefix(pathMajor)),
|
||||
}
|
||||
}
|
||||
|
||||
if pathMajorOk {
|
||||
if err := module.CheckPathMajor(vers, pathMajor); err != nil {
|
||||
if pathMajor == "" {
|
||||
// In this context, the user probably wrote "v2.3.4" when they meant
|
||||
// "v2.3.4+incompatible". Suggest that instead of "v0 or v1".
|
||||
return &module.InvalidVersionError{
|
||||
Version: vers,
|
||||
Err: fmt.Errorf("should be %s+incompatible (or module %s/%v)", vers, path, semver.Major(vers)),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
76
src/cmd/vendor/golang.org/x/mod/module/module.go
generated
vendored
76
src/cmd/vendor/golang.org/x/mod/module/module.go
generated
vendored
@@ -224,12 +224,16 @@ func firstPathOK(r rune) bool {
|
||||
'a' <= r && r <= 'z'
|
||||
}
|
||||
|
||||
// pathOK reports whether r can appear in an import path element.
|
||||
// modPathOK reports whether r can appear in a module path element.
|
||||
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
|
||||
// This matches what "go get" has historically recognized in import paths.
|
||||
//
|
||||
// This matches what "go get" has historically recognized in import paths,
|
||||
// and avoids confusing sequences like '%20' or '+' that would change meaning
|
||||
// if used in a URL.
|
||||
//
|
||||
// TODO(rsc): We would like to allow Unicode letters, but that requires additional
|
||||
// care in the safe encoding (see "escaped paths" above).
|
||||
func pathOK(r rune) bool {
|
||||
func modPathOK(r rune) bool {
|
||||
if r < utf8.RuneSelf {
|
||||
return r == '-' || r == '.' || r == '_' || r == '~' ||
|
||||
'0' <= r && r <= '9' ||
|
||||
@@ -239,6 +243,17 @@ func pathOK(r rune) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// modPathOK reports whether r can appear in a package import path element.
|
||||
//
|
||||
// Import paths are intermediate between module paths and file paths: we allow
|
||||
// disallow characters that would be confusing or ambiguous as arguments to
|
||||
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
|
||||
// otherwise-unambiguous on the command line and historically used for some
|
||||
// binary names (such as '++' as a suffix for compiler binaries and wrappers).
|
||||
func importPathOK(r rune) bool {
|
||||
return modPathOK(r) || r == '+'
|
||||
}
|
||||
|
||||
// fileNameOK reports whether r can appear in a file name.
|
||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
||||
// If we expand the set of allowed characters here, we have to
|
||||
@@ -270,7 +285,7 @@ func fileNameOK(r rune) bool {
|
||||
|
||||
// CheckPath checks that a module path is valid.
|
||||
// A valid module path is a valid import path, as checked by CheckImportPath,
|
||||
// with two additional constraints.
|
||||
// with three additional constraints.
|
||||
// First, the leading path element (up to the first slash, if any),
|
||||
// by convention a domain name, must contain only lower-case ASCII letters,
|
||||
// ASCII digits, dots (U+002E), and dashes (U+002D);
|
||||
@@ -280,8 +295,9 @@ func fileNameOK(r rune) bool {
|
||||
// and must not contain any dots. For paths beginning with "gopkg.in/",
|
||||
// this second requirement is replaced by a requirement that the path
|
||||
// follow the gopkg.in server's conventions.
|
||||
// Third, no path element may begin with a dot.
|
||||
func CheckPath(path string) error {
|
||||
if err := checkPath(path, false); err != nil {
|
||||
if err := checkPath(path, modulePath); err != nil {
|
||||
return fmt.Errorf("malformed module path %q: %v", path, err)
|
||||
}
|
||||
i := strings.Index(path, "/")
|
||||
@@ -315,7 +331,7 @@ func CheckPath(path string) error {
|
||||
//
|
||||
// A valid path element is a non-empty string made up of
|
||||
// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
|
||||
// It must not begin or end with a dot (U+002E), nor contain two dots in a row.
|
||||
// It must not end with a dot (U+002E), nor contain two dots in a row.
|
||||
//
|
||||
// The element prefix up to the first dot must not be a reserved file name
|
||||
// on Windows, regardless of case (CON, com1, NuL, and so on). The element
|
||||
@@ -326,19 +342,29 @@ func CheckPath(path string) error {
|
||||
// top-level package documentation for additional information about
|
||||
// subtleties of Unicode.
|
||||
func CheckImportPath(path string) error {
|
||||
if err := checkPath(path, false); err != nil {
|
||||
if err := checkPath(path, importPath); err != nil {
|
||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathKind indicates what kind of path we're checking. Module paths,
|
||||
// import paths, and file paths have different restrictions.
|
||||
type pathKind int
|
||||
|
||||
const (
|
||||
modulePath pathKind = iota
|
||||
importPath
|
||||
filePath
|
||||
)
|
||||
|
||||
// checkPath checks that a general path is valid.
|
||||
// It returns an error describing why but not mentioning path.
|
||||
// Because these checks apply to both module paths and import paths,
|
||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
||||
// fileName indicates whether the final element of the path is a file name
|
||||
// (as opposed to a directory name).
|
||||
func checkPath(path string, fileName bool) error {
|
||||
func checkPath(path string, kind pathKind) error {
|
||||
if !utf8.ValidString(path) {
|
||||
return fmt.Errorf("invalid UTF-8")
|
||||
}
|
||||
@@ -357,39 +383,45 @@ func checkPath(path string, fileName bool) error {
|
||||
elemStart := 0
|
||||
for i, r := range path {
|
||||
if r == '/' {
|
||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
||||
if err := checkElem(path[elemStart:i], kind); err != nil {
|
||||
return err
|
||||
}
|
||||
elemStart = i + 1
|
||||
}
|
||||
}
|
||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
||||
if err := checkElem(path[elemStart:], kind); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkElem checks whether an individual path element is valid.
|
||||
// fileName indicates whether the element is a file name (not a directory name).
|
||||
func checkElem(elem string, fileName bool) error {
|
||||
func checkElem(elem string, kind pathKind) error {
|
||||
if elem == "" {
|
||||
return fmt.Errorf("empty path element")
|
||||
}
|
||||
if strings.Count(elem, ".") == len(elem) {
|
||||
return fmt.Errorf("invalid path element %q", elem)
|
||||
}
|
||||
if elem[0] == '.' && !fileName {
|
||||
if elem[0] == '.' && kind == modulePath {
|
||||
return fmt.Errorf("leading dot in path element")
|
||||
}
|
||||
if elem[len(elem)-1] == '.' {
|
||||
return fmt.Errorf("trailing dot in path element")
|
||||
}
|
||||
charOK := pathOK
|
||||
if fileName {
|
||||
charOK = fileNameOK
|
||||
}
|
||||
for _, r := range elem {
|
||||
if !charOK(r) {
|
||||
ok := false
|
||||
switch kind {
|
||||
case modulePath:
|
||||
ok = modPathOK(r)
|
||||
case importPath:
|
||||
ok = importPathOK(r)
|
||||
case filePath:
|
||||
ok = fileNameOK(r)
|
||||
default:
|
||||
panic(fmt.Sprintf("internal error: invalid kind %v", kind))
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid char %q", r)
|
||||
}
|
||||
}
|
||||
@@ -406,7 +438,7 @@ func checkElem(elem string, fileName bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
if fileName {
|
||||
if kind == filePath {
|
||||
// don't check for Windows short-names in file names. They're
|
||||
// only an issue for import paths.
|
||||
return nil
|
||||
@@ -444,7 +476,7 @@ func checkElem(elem string, fileName bool) error {
|
||||
// top-level package documentation for additional information about
|
||||
// subtleties of Unicode.
|
||||
func CheckFilePath(path string) error {
|
||||
if err := checkPath(path, true); err != nil {
|
||||
if err := checkPath(path, filePath); err != nil {
|
||||
return fmt.Errorf("malformed file path %q: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
@@ -647,7 +679,7 @@ func EscapePath(path string) (escaped string, err error) {
|
||||
// Versions are allowed to be in non-semver form but must be valid file names
|
||||
// and not contain exclamation marks.
|
||||
func EscapeVersion(v string) (escaped string, err error) {
|
||||
if err := checkElem(v, true); err != nil || strings.Contains(v, "!") {
|
||||
if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") {
|
||||
return "", &InvalidVersionError{
|
||||
Version: v,
|
||||
Err: fmt.Errorf("disallowed version string"),
|
||||
@@ -706,7 +738,7 @@ func UnescapeVersion(escaped string) (v string, err error) {
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid escaped version %q", escaped)
|
||||
}
|
||||
if err := checkElem(v, true); err != nil {
|
||||
if err := checkElem(v, filePath); err != nil {
|
||||
return "", fmt.Errorf("invalid escaped version %q: %v", v, err)
|
||||
}
|
||||
return v, nil
|
||||
|
||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
@@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
||||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/mod v0.4.1
|
||||
# golang.org/x/mod v0.4.2-0.20210325185522-dbbbf8a3c6ea
|
||||
## explicit
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
||||
@@ -67,7 +67,11 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
|
||||
rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
|
||||
}
|
||||
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder {
|
||||
// it will return an error.
|
||||
//
|
||||
// Token implements XML name spaces as described by
|
||||
// https://www.w3.org/TR/REC-xml-names/. Each of the
|
||||
// https://www.w3.org/TR/REC-xml-names/. Each of the
|
||||
// Name structures contained in the Token has the Space
|
||||
// set to the URL identifying its name space when known.
|
||||
// If Token encounters an unrecognized name space prefix,
|
||||
@@ -285,16 +285,17 @@ func (d *Decoder) Token() (Token, error) {
|
||||
if d.nextToken != nil {
|
||||
t = d.nextToken
|
||||
d.nextToken = nil
|
||||
} else if t, err = d.rawToken(); err != nil {
|
||||
switch {
|
||||
case err == io.EOF && d.t != nil:
|
||||
err = nil
|
||||
case err == io.EOF && d.stk != nil && d.stk.kind != stkEOF:
|
||||
err = d.syntaxError("unexpected EOF")
|
||||
} else {
|
||||
if t, err = d.rawToken(); t == nil && err != nil {
|
||||
if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF {
|
||||
err = d.syntaxError("unexpected EOF")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return t, err
|
||||
// We still have a token to process, so clear any
|
||||
// errors (e.g. EOF) and proceed.
|
||||
err = nil
|
||||
}
|
||||
|
||||
if !d.Strict {
|
||||
if t1, ok := d.autoClose(t); ok {
|
||||
d.nextToken = t
|
||||
|
||||
@@ -33,30 +33,90 @@ func (t *toks) Token() (Token, error) {
|
||||
|
||||
func TestDecodeEOF(t *testing.T) {
|
||||
start := StartElement{Name: Name{Local: "test"}}
|
||||
t.Run("EarlyEOF", func(t *testing.T) {
|
||||
d := NewTokenDecoder(&toks{earlyEOF: true, t: []Token{
|
||||
start,
|
||||
start.End(),
|
||||
}})
|
||||
err := d.Decode(&struct {
|
||||
XMLName Name `xml:"test"`
|
||||
}{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
tests := []struct {
|
||||
name string
|
||||
tokens []Token
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
tokens: []Token{
|
||||
start,
|
||||
start.End(),
|
||||
},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
name: "Malformed",
|
||||
tokens: []Token{
|
||||
start,
|
||||
StartElement{Name: Name{Local: "bad"}},
|
||||
start.End(),
|
||||
},
|
||||
ok: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
for _, eof := range []bool{true, false} {
|
||||
name := fmt.Sprintf("%s/earlyEOF=%v", tc.name, eof)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
d := NewTokenDecoder(&toks{
|
||||
earlyEOF: eof,
|
||||
t: tc.tokens,
|
||||
})
|
||||
err := d.Decode(&struct {
|
||||
XMLName Name `xml:"test"`
|
||||
}{})
|
||||
if tc.ok && err != nil {
|
||||
t.Fatalf("d.Decode: expected nil error, got %v", err)
|
||||
}
|
||||
if _, ok := err.(*SyntaxError); !tc.ok && !ok {
|
||||
t.Errorf("d.Decode: expected syntax error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
t.Run("LateEOF", func(t *testing.T) {
|
||||
d := NewTokenDecoder(&toks{t: []Token{
|
||||
start,
|
||||
start.End(),
|
||||
}})
|
||||
err := d.Decode(&struct {
|
||||
XMLName Name `xml:"test"`
|
||||
}{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
type toksNil struct {
|
||||
returnEOF bool
|
||||
t []Token
|
||||
}
|
||||
|
||||
func (t *toksNil) Token() (Token, error) {
|
||||
if len(t.t) == 0 {
|
||||
if !t.returnEOF {
|
||||
// Return nil, nil before returning an EOF. It's legal, but
|
||||
// discouraged.
|
||||
t.returnEOF = true
|
||||
return nil, nil
|
||||
}
|
||||
})
|
||||
return nil, io.EOF
|
||||
}
|
||||
var tok Token
|
||||
tok, t.t = t.t[0], t.t[1:]
|
||||
return tok, nil
|
||||
}
|
||||
|
||||
func TestDecodeNilToken(t *testing.T) {
|
||||
for _, strict := range []bool{true, false} {
|
||||
name := fmt.Sprintf("Strict=%v", strict)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
start := StartElement{Name: Name{Local: "test"}}
|
||||
bad := StartElement{Name: Name{Local: "bad"}}
|
||||
d := NewTokenDecoder(&toksNil{
|
||||
// Malformed
|
||||
t: []Token{start, bad, start.End()},
|
||||
})
|
||||
d.Strict = strict
|
||||
err := d.Decode(&struct {
|
||||
XMLName Name `xml:"test"`
|
||||
}{})
|
||||
if _, ok := err.(*SyntaxError); !ok {
|
||||
t.Errorf("d.Decode: expected syntax error, got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const testInput = `
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.16
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11
|
||||
golang.org/x/net v0.0.0-20210901185431-d2e9a4ea682f
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
)
|
||||
|
||||
@@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210901185431-d2e9a4ea682f h1:pkBhRt1hlsctT9xYRDknb4y+e/yiacRWlnft5a4QH8Y=
|
||||
golang.org/x/net v0.0.0-20210901185431-d2e9a4ea682f/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -612,7 +612,7 @@ func TestImportPackageOutsideModule(t *testing.T) {
|
||||
ctxt.GOPATH = gopath
|
||||
ctxt.Dir = filepath.Join(gopath, "src/example.com/p")
|
||||
|
||||
want := "working directory is not part of a module"
|
||||
want := "go.mod file not found in current directory or any parent directory"
|
||||
if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
|
||||
t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
|
||||
} else if errStr := err.Error(); !strings.Contains(errStr, want) {
|
||||
|
||||
@@ -184,7 +184,7 @@ func TestInstallationImporter(t *testing.T) {
|
||||
{pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"},
|
||||
{pkgpath: "math", name: "Pi", want: "const Pi untyped float"},
|
||||
{pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"},
|
||||
{pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"},
|
||||
{pkgpath: "sort", name: "Search", want: "func Search(n int, f func(int) bool) int"},
|
||||
{pkgpath: "unsafe", name: "Pointer", want: "type Pointer"},
|
||||
} {
|
||||
runImporterTest(t, imp, nil, &test)
|
||||
|
||||
@@ -1720,8 +1720,6 @@ var v = "v";
|
||||
`
|
||||
|
||||
func TestEscapeRace(t *testing.T) {
|
||||
t.Skip("this test currently fails with -race; see issue #39807")
|
||||
|
||||
tmpl := New("")
|
||||
_, err := tmpl.New("templ.html").Parse(raceText)
|
||||
if err != nil {
|
||||
|
||||
@@ -51,7 +51,8 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
|
||||
// An optional base-10 ``e'' or base-2 ``p'' (or their upper-case variants)
|
||||
// exponent may be provided as well, except for hexadecimal floats which
|
||||
// only accept an (optional) ``p'' exponent (because an ``e'' or ``E'' cannot
|
||||
// be distinguished from a mantissa digit).
|
||||
// be distinguished from a mantissa digit). If the exponent's absolute value
|
||||
// is too large, the operation may fail.
|
||||
// The entire string, not just a prefix, must be valid for success. If the
|
||||
// operation failed, the value of z is undefined but the returned value is nil.
|
||||
func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
@@ -169,6 +170,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
if n < 0 {
|
||||
n = -n
|
||||
}
|
||||
if n > 1e6 {
|
||||
return nil, false // avoid excessively large exponents
|
||||
}
|
||||
pow5 := z.b.abs.expNN(natFive, nat(nil).setWord(Word(n)), nil) // use underlying array of z.b.abs
|
||||
if exp5 > 0 {
|
||||
z.a.abs = z.a.abs.mul(z.a.abs, pow5)
|
||||
@@ -181,15 +185,12 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
}
|
||||
|
||||
// apply exp2 contributions
|
||||
if exp2 < -1e7 || exp2 > 1e7 {
|
||||
return nil, false // avoid excessively large exponents
|
||||
}
|
||||
if exp2 > 0 {
|
||||
if int64(uint(exp2)) != exp2 {
|
||||
panic("exponent too large")
|
||||
}
|
||||
z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2))
|
||||
} else if exp2 < 0 {
|
||||
if int64(uint(-exp2)) != -exp2 {
|
||||
panic("exponent too large")
|
||||
}
|
||||
z.b.abs = z.b.abs.shl(z.b.abs, uint(-exp2))
|
||||
}
|
||||
|
||||
|
||||
@@ -589,3 +589,28 @@ func TestIssue31184(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue45910(t *testing.T) {
|
||||
var x Rat
|
||||
for _, test := range []struct {
|
||||
input string
|
||||
want bool
|
||||
}{
|
||||
{"1e-1000001", false},
|
||||
{"1e-1000000", true},
|
||||
{"1e+1000000", true},
|
||||
{"1e+1000001", false},
|
||||
|
||||
{"0p1000000000000", true},
|
||||
{"1p-10000001", false},
|
||||
{"1p-10000000", true},
|
||||
{"1p+10000000", true},
|
||||
{"1p+10000001", false},
|
||||
{"1.770p02041010010011001001", false}, // test case from issue
|
||||
} {
|
||||
_, got := x.SetString(test.input)
|
||||
if got != test.want {
|
||||
t.Errorf("SetString(%s) got ok = %v; want %v", test.input, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1798,3 +1798,324 @@ func TestPTRandNonPTR(t *testing.T) {
|
||||
t.Errorf("names = %q; want %q", names, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCVE202133195(t *testing.T) {
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
r := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.Header.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
RecursionAvailable: true,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
}
|
||||
switch q.Questions[0].Type {
|
||||
case dnsmessage.TypeCNAME:
|
||||
r.Answers = []dnsmessage.Resource{}
|
||||
case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy
|
||||
r.Answers = append(r.Answers,
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.AResource{
|
||||
A: TestAddr,
|
||||
},
|
||||
},
|
||||
)
|
||||
case dnsmessage.TypeSRV:
|
||||
n := q.Questions[0].Name
|
||||
if n.String() == "_hdr._tcp.golang.org." {
|
||||
n = dnsmessage.MustNewName("<html>.golang.org.")
|
||||
}
|
||||
r.Answers = append(r.Answers,
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: n,
|
||||
Type: dnsmessage.TypeSRV,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.SRVResource{
|
||||
Target: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
},
|
||||
},
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: n,
|
||||
Type: dnsmessage.TypeSRV,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.SRVResource{
|
||||
Target: dnsmessage.MustNewName("good.golang.org."),
|
||||
},
|
||||
},
|
||||
)
|
||||
case dnsmessage.TypeMX:
|
||||
r.Answers = append(r.Answers,
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
Type: dnsmessage.TypeMX,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.MXResource{
|
||||
MX: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
},
|
||||
},
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("good.golang.org."),
|
||||
Type: dnsmessage.TypeMX,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.MXResource{
|
||||
MX: dnsmessage.MustNewName("good.golang.org."),
|
||||
},
|
||||
},
|
||||
)
|
||||
case dnsmessage.TypeNS:
|
||||
r.Answers = append(r.Answers,
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
Type: dnsmessage.TypeNS,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.NSResource{
|
||||
NS: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
},
|
||||
},
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("good.golang.org."),
|
||||
Type: dnsmessage.TypeNS,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.NSResource{
|
||||
NS: dnsmessage.MustNewName("good.golang.org."),
|
||||
},
|
||||
},
|
||||
)
|
||||
case dnsmessage.TypePTR:
|
||||
r.Answers = append(r.Answers,
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
Type: dnsmessage.TypePTR,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.PTRResource{
|
||||
PTR: dnsmessage.MustNewName("<html>.golang.org."),
|
||||
},
|
||||
},
|
||||
dnsmessage.Resource{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: dnsmessage.MustNewName("good.golang.org."),
|
||||
Type: dnsmessage.TypePTR,
|
||||
Class: dnsmessage.ClassINET,
|
||||
Length: 4,
|
||||
},
|
||||
Body: &dnsmessage.PTRResource{
|
||||
PTR: dnsmessage.MustNewName("good.golang.org."),
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
return r, nil
|
||||
},
|
||||
}
|
||||
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
// Change the default resolver to match our manipulated resolver
|
||||
originalDefault := DefaultResolver
|
||||
DefaultResolver = &r
|
||||
defer func() { DefaultResolver = originalDefault }()
|
||||
// Redirect host file lookups.
|
||||
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
|
||||
testHookHostsPath = "testdata/hosts"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
f func(*testing.T)
|
||||
}{
|
||||
{
|
||||
name: "CNAME",
|
||||
f: func(t *testing.T) {
|
||||
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
|
||||
_, err := r.LookupCNAME(context.Background(), "golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
_, err = LookupCNAME("golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SRV (bad record)",
|
||||
f: func(t *testing.T) {
|
||||
expected := []*SRV{
|
||||
{
|
||||
Target: "good.golang.org.",
|
||||
},
|
||||
}
|
||||
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
|
||||
_, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
_, records, err = LookupSRV("target", "tcp", "golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SRV (bad header)",
|
||||
f: func(t *testing.T) {
|
||||
_, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
|
||||
if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, _, err = LookupSRV("hdr", "tcp", "golang.org.")
|
||||
if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MX",
|
||||
f: func(t *testing.T) {
|
||||
expected := []*MX{
|
||||
{
|
||||
Host: "good.golang.org.",
|
||||
},
|
||||
}
|
||||
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
|
||||
records, err := r.LookupMX(context.Background(), "golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
records, err = LookupMX("golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NS",
|
||||
f: func(t *testing.T) {
|
||||
expected := []*NS{
|
||||
{
|
||||
Host: "good.golang.org.",
|
||||
},
|
||||
}
|
||||
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
|
||||
records, err := r.LookupNS(context.Background(), "golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
records, err = LookupNS("golang.org")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Addr",
|
||||
f: func(t *testing.T) {
|
||||
expected := []string{"good.golang.org."}
|
||||
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
|
||||
records, err := r.LookupAddr(context.Background(), "192.0.2.42")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
records, err = LookupAddr("192.0.2.42")
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(records, expected) {
|
||||
t.Error("Unexpected record set")
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, tc.f)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNullMX(t *testing.T) {
|
||||
fake := fakeDNSServer{
|
||||
rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
|
||||
r := dnsmessage.Message{
|
||||
Header: dnsmessage.Header{
|
||||
ID: q.Header.ID,
|
||||
Response: true,
|
||||
RCode: dnsmessage.RCodeSuccess,
|
||||
},
|
||||
Questions: q.Questions,
|
||||
Answers: []dnsmessage.Resource{
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
Name: q.Questions[0].Name,
|
||||
Type: dnsmessage.TypeMX,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.MXResource{
|
||||
MX: dnsmessage.MustNewName("."),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return r, nil
|
||||
},
|
||||
}
|
||||
r := Resolver{PreferGo: true, Dial: fake.DialContext}
|
||||
rrset, err := r.LookupMX(context.Background(), "golang.org")
|
||||
if err != nil {
|
||||
t.Fatalf("LookupMX: %v", err)
|
||||
}
|
||||
if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) {
|
||||
records := []string{}
|
||||
for _, rr := range rrset {
|
||||
records = append(records, fmt.Sprintf("%v", rr))
|
||||
}
|
||||
t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4435,6 +4435,15 @@ func (sc *http2serverConn) serve() {
|
||||
case res := <-sc.wroteFrameCh:
|
||||
sc.wroteFrame(res)
|
||||
case res := <-sc.readFrameCh:
|
||||
// Process any written frames before reading new frames from the client since a
|
||||
// written frame could have triggered a new stream to be started.
|
||||
if sc.writingFrameAsync {
|
||||
select {
|
||||
case wroteRes := <-sc.wroteFrameCh:
|
||||
sc.wroteFrame(wroteRes)
|
||||
default:
|
||||
}
|
||||
}
|
||||
if !sc.processFrameFromReader(res) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -234,6 +234,15 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.ContentLength == 0 {
|
||||
outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
|
||||
}
|
||||
if outreq.Body != nil {
|
||||
// Reading from the request body after returning from a handler is not
|
||||
// allowed, and the RoundTrip goroutine that reads the Body can outlive
|
||||
// this handler. This can lead to a crash if the handler panics (see
|
||||
// Issue 46866). Although calling Close doesn't guarantee there isn't
|
||||
// any Read in flight after the handle returns, in practice it's safe to
|
||||
// read after closing it.
|
||||
defer outreq.Body.Close()
|
||||
}
|
||||
if outreq.Header == nil {
|
||||
outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate
|
||||
}
|
||||
@@ -248,22 +257,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
// important is "Connection" because we want a persistent
|
||||
// connection, regardless of what the client sent to us.
|
||||
for _, h := range hopHeaders {
|
||||
hv := outreq.Header.Get(h)
|
||||
if hv == "" {
|
||||
continue
|
||||
}
|
||||
if h == "Te" && hv == "trailers" {
|
||||
// Issue 21096: tell backend applications that
|
||||
// care about trailer support that we support
|
||||
// trailers. (We do, but we don't go out of
|
||||
// our way to advertise that unless the
|
||||
// incoming client request thought it was
|
||||
// worth mentioning)
|
||||
continue
|
||||
}
|
||||
outreq.Header.Del(h)
|
||||
}
|
||||
|
||||
// Issue 21096: tell backend applications that care about trailer support
|
||||
// that we support trailers. (We do, but we don't go out of our way to
|
||||
// advertise that unless the incoming client request thought it was worth
|
||||
// mentioning.) Note that we look at req.Header, not outreq.Header, since
|
||||
// the latter has passed through removeConnectionHeaders.
|
||||
if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") {
|
||||
outreq.Header.Set("Te", "trailers")
|
||||
}
|
||||
|
||||
// After stripping all the hop-by-hop connection headers above, add back any
|
||||
// necessary for protocol upgrades, such as for websockets.
|
||||
if reqUpType != "" {
|
||||
|
||||
@@ -90,8 +90,9 @@ func TestReverseProxy(t *testing.T) {
|
||||
|
||||
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
|
||||
getReq.Host = "some-name"
|
||||
getReq.Header.Set("Connection", "close")
|
||||
getReq.Header.Set("Te", "trailers")
|
||||
getReq.Header.Set("Connection", "close, TE")
|
||||
getReq.Header.Add("Te", "foo")
|
||||
getReq.Header.Add("Te", "bar, trailers")
|
||||
getReq.Header.Set("Proxy-Connection", "should be deleted")
|
||||
getReq.Header.Set("Upgrade", "foo")
|
||||
getReq.Close = true
|
||||
@@ -235,6 +236,64 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyStripEmptyConnection(t *testing.T) {
|
||||
// See Issue 46313.
|
||||
const backendResponse = "I am the backend"
|
||||
|
||||
// someConnHeader is some arbitrary header to be declared as a hop-by-hop header
|
||||
// in the Request's Connection header.
|
||||
const someConnHeader = "X-Some-Conn-Header"
|
||||
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if c := r.Header.Values("Connection"); len(c) != 0 {
|
||||
t.Errorf("handler got header %q = %v; want empty", "Connection", c)
|
||||
}
|
||||
if c := r.Header.Get(someConnHeader); c != "" {
|
||||
t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
|
||||
}
|
||||
w.Header().Add("Connection", "")
|
||||
w.Header().Add("Connection", someConnHeader)
|
||||
w.Header().Set(someConnHeader, "should be deleted")
|
||||
io.WriteString(w, backendResponse)
|
||||
}))
|
||||
defer backend.Close()
|
||||
backendURL, err := url.Parse(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proxyHandler := NewSingleHostReverseProxy(backendURL)
|
||||
frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
proxyHandler.ServeHTTP(w, r)
|
||||
if c := r.Header.Get(someConnHeader); c != "should be deleted" {
|
||||
t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted")
|
||||
}
|
||||
}))
|
||||
defer frontend.Close()
|
||||
|
||||
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
|
||||
getReq.Header.Add("Connection", "")
|
||||
getReq.Header.Add("Connection", someConnHeader)
|
||||
getReq.Header.Set(someConnHeader, "should be deleted")
|
||||
res, err := frontend.Client().Do(getReq)
|
||||
if err != nil {
|
||||
t.Fatalf("Get: %v", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
bodyBytes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("reading body: %v", err)
|
||||
}
|
||||
if got, want := string(bodyBytes), backendResponse; got != want {
|
||||
t.Errorf("got body %q; want %q", got, want)
|
||||
}
|
||||
if c := res.Header.Get("Connection"); c != "" {
|
||||
t.Errorf("handler got header %q = %q; want empty", "Connection", c)
|
||||
}
|
||||
if c := res.Header.Get(someConnHeader); c != "" {
|
||||
t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestXForwardedFor(t *testing.T) {
|
||||
const prevForwardedFor = "client ip"
|
||||
const backendResponse = "I am the backend"
|
||||
@@ -1062,6 +1121,45 @@ func TestReverseProxy_PanicBodyError(t *testing.T) {
|
||||
rproxy.ServeHTTP(httptest.NewRecorder(), req)
|
||||
}
|
||||
|
||||
// Issue #46866: panic without closing incoming request body causes a panic
|
||||
func TestReverseProxy_PanicClosesIncomingBody(t *testing.T) {
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
out := "this call was relayed by the reverse proxy"
|
||||
// Coerce a wrong content length to induce io.ErrUnexpectedEOF
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2))
|
||||
fmt.Fprintln(w, out)
|
||||
}))
|
||||
defer backend.Close()
|
||||
backendURL, err := url.Parse(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proxyHandler := NewSingleHostReverseProxy(backendURL)
|
||||
proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests
|
||||
frontend := httptest.NewServer(proxyHandler)
|
||||
defer frontend.Close()
|
||||
frontendClient := frontend.Client()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 2; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 10; j++ {
|
||||
const reqLen = 6 * 1024 * 1024
|
||||
req, _ := http.NewRequest("POST", frontend.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen})
|
||||
req.ContentLength = reqLen
|
||||
resp, _ := frontendClient.Transport.RoundTrip(req)
|
||||
if resp != nil {
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestSelectFlushInterval(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -577,37 +577,17 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
|
||||
return io.CopyBuffer(writerOnly{w}, src, buf)
|
||||
}
|
||||
|
||||
// sendfile path:
|
||||
|
||||
// Do not start actually writing response until src is readable.
|
||||
// If body length is <= sniffLen, sendfile/splice path will do
|
||||
// little anyway. This small read also satisfies sniffing the
|
||||
// body in case Content-Type is missing.
|
||||
nr, er := src.Read(buf[:sniffLen])
|
||||
atEOF := errors.Is(er, io.EOF)
|
||||
n += int64(nr)
|
||||
|
||||
if nr > 0 {
|
||||
// Write the small amount read normally.
|
||||
nw, ew := w.Write(buf[:nr])
|
||||
if ew != nil {
|
||||
err = ew
|
||||
} else if nr != nw {
|
||||
err = io.ErrShortWrite
|
||||
// Copy the first sniffLen bytes before switching to ReadFrom.
|
||||
// This ensures we don't start writing the response before the
|
||||
// source is available (see golang.org/issue/5660) and provides
|
||||
// enough bytes to perform Content-Type sniffing when required.
|
||||
if !w.cw.wroteHeader {
|
||||
n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf)
|
||||
n += n0
|
||||
if err != nil || n0 < sniffLen {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
if err == nil && er != nil && !atEOF {
|
||||
err = er
|
||||
}
|
||||
|
||||
// Do not send StatusOK in the error case where nothing has been written.
|
||||
if err == nil && !w.wroteHeader {
|
||||
w.WriteHeader(StatusOK) // nr == 0, no error (or EOF)
|
||||
}
|
||||
|
||||
if err != nil || atEOF {
|
||||
return n, err
|
||||
}
|
||||
|
||||
w.w.Flush() // get rid of any previous writes
|
||||
w.cw.flush() // make sure Header is written; flush data to rwc
|
||||
@@ -620,7 +600,7 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
n0, err := io.Copy(writerOnly{w}, src)
|
||||
n0, err := io.CopyBuffer(writerOnly{w}, src, buf)
|
||||
n += n0
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -157,9 +157,25 @@ func testServerIssue5953(t *testing.T, h2 bool) {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) }
|
||||
func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) }
|
||||
func testContentTypeWithCopy(t *testing.T, h2 bool) {
|
||||
type byteAtATimeReader struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func (b *byteAtATimeReader) Read(p []byte) (n int, err error) {
|
||||
if len(p) < 1 {
|
||||
return 0, nil
|
||||
}
|
||||
if len(b.buf) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
p[0] = b.buf[0]
|
||||
b.buf = b.buf[1:]
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func TestContentTypeWithVariousSources_h1(t *testing.T) { testContentTypeWithVariousSources(t, h1Mode) }
|
||||
func TestContentTypeWithVariousSources_h2(t *testing.T) { testContentTypeWithVariousSources(t, h2Mode) }
|
||||
func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
|
||||
defer afterTest(t)
|
||||
|
||||
const (
|
||||
@@ -167,30 +183,86 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
|
||||
expected = "text/html; charset=utf-8"
|
||||
)
|
||||
|
||||
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
// Use io.Copy from a bytes.Buffer to trigger ReadFrom.
|
||||
buf := bytes.NewBuffer([]byte(input))
|
||||
n, err := io.Copy(w, buf)
|
||||
if int(n) != len(input) || err != nil {
|
||||
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
|
||||
}
|
||||
}))
|
||||
defer cst.close()
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
handler func(ResponseWriter, *Request)
|
||||
}{{
|
||||
name: "write",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Write the whole input at once.
|
||||
n, err := w.Write([]byte(input))
|
||||
if int(n) != len(input) || err != nil {
|
||||
t.Errorf("w.Write(%q) = %v, %v want %d, nil", input, n, err, len(input))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "write one byte at a time",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Write the input one byte at a time.
|
||||
buf := []byte(input)
|
||||
for i := range buf {
|
||||
n, err := w.Write(buf[i : i+1])
|
||||
if n != 1 || err != nil {
|
||||
t.Errorf("w.Write(%q) = %v, %v want 1, nil", input, n, err)
|
||||
}
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "copy from Reader",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Use io.Copy from a plain Reader.
|
||||
type readerOnly struct{ io.Reader }
|
||||
buf := bytes.NewBuffer([]byte(input))
|
||||
n, err := io.Copy(w, readerOnly{buf})
|
||||
if int(n) != len(input) || err != nil {
|
||||
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "copy from bytes.Buffer",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Use io.Copy from a bytes.Buffer to trigger ReadFrom.
|
||||
buf := bytes.NewBuffer([]byte(input))
|
||||
n, err := io.Copy(w, buf)
|
||||
if int(n) != len(input) || err != nil {
|
||||
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
|
||||
}
|
||||
},
|
||||
}, {
|
||||
name: "copy one byte at a time",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Use io.Copy from a Reader that returns one byte at a time.
|
||||
n, err := io.Copy(w, &byteAtATimeReader{[]byte(input)})
|
||||
if int(n) != len(input) || err != nil {
|
||||
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
|
||||
}
|
||||
},
|
||||
}} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
cst := newClientServerTest(t, h2, HandlerFunc(test.handler))
|
||||
defer cst.close()
|
||||
|
||||
resp, err := cst.c.Get(cst.ts.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("Get: %v", err)
|
||||
}
|
||||
if ct := resp.Header.Get("Content-Type"); ct != expected {
|
||||
t.Errorf("Content-Type = %q, want %q", ct, expected)
|
||||
}
|
||||
if want, got := resp.Header.Get("Content-Length"), fmt.Sprint(len(input)); want != got {
|
||||
t.Errorf("Content-Length = %q, want %q", want, got)
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("reading body: %v", err)
|
||||
} else if !bytes.Equal(data, []byte(input)) {
|
||||
t.Errorf("data is %q, want %q", data, input)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
})
|
||||
|
||||
resp, err := cst.c.Get(cst.ts.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("Get: %v", err)
|
||||
}
|
||||
if ct := resp.Header.Get("Content-Type"); ct != expected {
|
||||
t.Errorf("Content-Type = %q, want %q", ct, expected)
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("reading body: %v", err)
|
||||
} else if !bytes.Equal(data, []byte(input)) {
|
||||
t.Errorf("data is %q, want %q", data, input)
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
|
||||
|
||||
@@ -5314,7 +5314,6 @@ func TestMissingStatusNoPanic(t *testing.T) {
|
||||
|
||||
ln := newLocalListener(t)
|
||||
addr := ln.Addr().String()
|
||||
shutdown := make(chan bool, 1)
|
||||
done := make(chan bool)
|
||||
fullAddrURL := fmt.Sprintf("http://%s", addr)
|
||||
raw := "HTTP/1.1 400\r\n" +
|
||||
@@ -5326,10 +5325,7 @@ func TestMissingStatusNoPanic(t *testing.T) {
|
||||
"Aloha Olaa"
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
ln.Close()
|
||||
close(done)
|
||||
}()
|
||||
defer close(done)
|
||||
|
||||
conn, _ := ln.Accept()
|
||||
if conn != nil {
|
||||
@@ -5360,7 +5356,7 @@ func TestMissingStatusNoPanic(t *testing.T) {
|
||||
t.Errorf("got=%v want=%q", err, want)
|
||||
}
|
||||
|
||||
close(shutdown)
|
||||
ln.Close()
|
||||
<-done
|
||||
}
|
||||
|
||||
@@ -6437,10 +6433,11 @@ func TestErrorWriteLoopRace(t *testing.T) {
|
||||
// Test that a new request which uses the connection of an active request
|
||||
// cannot cause it to be canceled as well.
|
||||
func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
reqc := make(chan chan struct{}, 2)
|
||||
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) {
|
||||
ch := make(chan struct{}, 1)
|
||||
reqc <- ch
|
||||
<-ch
|
||||
w.Header().Add("Content-Length", "0")
|
||||
}))
|
||||
defer ts.Close()
|
||||
@@ -6452,34 +6449,58 @@ func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ctx.Err() == nil {
|
||||
reqctx, reqcancel := context.WithCancel(ctx)
|
||||
go reqcancel()
|
||||
req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil)
|
||||
res, err := client.Do(req)
|
||||
if err == nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for ctx.Err() == nil {
|
||||
req, _ := NewRequest("GET", ts.URL, nil)
|
||||
if res, err := client.Do(req); err != nil {
|
||||
t.Errorf("unexpected: %p %v", req, err)
|
||||
break
|
||||
} else {
|
||||
wg.Add(1)
|
||||
putidlec := make(chan chan struct{})
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
|
||||
PutIdleConn: func(error) {
|
||||
// Signal that the idle conn has been returned to the pool,
|
||||
// and wait for the order to proceed.
|
||||
ch := make(chan struct{})
|
||||
putidlec <- ch
|
||||
<-ch
|
||||
},
|
||||
})
|
||||
req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
|
||||
res, err := client.Do(req)
|
||||
if err == nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("request 1: got err %v, want nil", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the first request to receive a response and return the
|
||||
// connection to the idle pool.
|
||||
r1c := <-reqc
|
||||
close(r1c)
|
||||
idlec := <-putidlec
|
||||
|
||||
wg.Add(1)
|
||||
cancelctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil)
|
||||
res, err := client.Do(req)
|
||||
if err == nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Errorf("request 2: got err %v, want Canceled", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for the second request to arrive at the server, and then cancel
|
||||
// the request context.
|
||||
r2c := <-reqc
|
||||
cancel()
|
||||
|
||||
// Give the cancelation a moment to take effect, and then unblock the first request.
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
close(idlec)
|
||||
|
||||
close(r2c)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
@@ -389,8 +389,11 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por
|
||||
// LookupCNAME does not return an error if host does not
|
||||
// contain DNS "CNAME" records, as long as host resolves to
|
||||
// address records.
|
||||
//
|
||||
// The returned canonical name is validated to be a properly
|
||||
// formatted presentation-format domain name.
|
||||
func LookupCNAME(host string) (cname string, err error) {
|
||||
return DefaultResolver.lookupCNAME(context.Background(), host)
|
||||
return DefaultResolver.LookupCNAME(context.Background(), host)
|
||||
}
|
||||
|
||||
// LookupCNAME returns the canonical name for the given host.
|
||||
@@ -403,8 +406,18 @@ func LookupCNAME(host string) (cname string, err error) {
|
||||
// LookupCNAME does not return an error if host does not
|
||||
// contain DNS "CNAME" records, as long as host resolves to
|
||||
// address records.
|
||||
func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
|
||||
return r.lookupCNAME(ctx, host)
|
||||
//
|
||||
// The returned canonical name is validated to be a properly
|
||||
// formatted presentation-format domain name.
|
||||
func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
|
||||
cname, err := r.lookupCNAME(ctx, host)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !isDomainName(cname) {
|
||||
return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
|
||||
}
|
||||
return cname, nil
|
||||
}
|
||||
|
||||
// LookupSRV tries to resolve an SRV query of the given service,
|
||||
@@ -416,8 +429,13 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string,
|
||||
// That is, it looks up _service._proto.name. To accommodate services
|
||||
// publishing SRV records under non-standard names, if both service
|
||||
// and proto are empty strings, LookupSRV looks up name directly.
|
||||
//
|
||||
// The returned service names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
|
||||
return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
|
||||
return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
|
||||
}
|
||||
|
||||
// LookupSRV tries to resolve an SRV query of the given service,
|
||||
@@ -429,28 +447,115 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
|
||||
// That is, it looks up _service._proto.name. To accommodate services
|
||||
// publishing SRV records under non-standard names, if both service
|
||||
// and proto are empty strings, LookupSRV looks up name directly.
|
||||
func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
|
||||
return r.lookupSRV(ctx, service, proto, name)
|
||||
//
|
||||
// The returned service names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
|
||||
cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if cname != "" && !isDomainName(cname) {
|
||||
return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
|
||||
}
|
||||
filteredAddrs := make([]*SRV, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
if !isDomainName(addr.Target) {
|
||||
continue
|
||||
}
|
||||
filteredAddrs = append(filteredAddrs, addr)
|
||||
}
|
||||
if len(addrs) != len(filteredAddrs) {
|
||||
return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
|
||||
}
|
||||
return cname, filteredAddrs, nil
|
||||
}
|
||||
|
||||
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
|
||||
//
|
||||
// The returned mail server names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
//
|
||||
// LookupMX uses context.Background internally; to specify the context, use
|
||||
// Resolver.LookupMX.
|
||||
func LookupMX(name string) ([]*MX, error) {
|
||||
return DefaultResolver.lookupMX(context.Background(), name)
|
||||
return DefaultResolver.LookupMX(context.Background(), name)
|
||||
}
|
||||
|
||||
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
|
||||
//
|
||||
// The returned mail server names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
|
||||
return r.lookupMX(ctx, name)
|
||||
records, err := r.lookupMX(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filteredMX := make([]*MX, 0, len(records))
|
||||
for _, mx := range records {
|
||||
if mx == nil {
|
||||
continue
|
||||
}
|
||||
// Bypass the hostname validity check for targets which contain only a dot,
|
||||
// as this is used to represent a 'Null' MX record.
|
||||
if mx.Host != "." && !isDomainName(mx.Host) {
|
||||
continue
|
||||
}
|
||||
filteredMX = append(filteredMX, mx)
|
||||
}
|
||||
if len(records) != len(filteredMX) {
|
||||
return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
|
||||
}
|
||||
return filteredMX, nil
|
||||
}
|
||||
|
||||
// LookupNS returns the DNS NS records for the given domain name.
|
||||
//
|
||||
// The returned name server names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
//
|
||||
// LookupNS uses context.Background internally; to specify the context, use
|
||||
// Resolver.LookupNS.
|
||||
func LookupNS(name string) ([]*NS, error) {
|
||||
return DefaultResolver.lookupNS(context.Background(), name)
|
||||
return DefaultResolver.LookupNS(context.Background(), name)
|
||||
}
|
||||
|
||||
// LookupNS returns the DNS NS records for the given domain name.
|
||||
//
|
||||
// The returned name server names are validated to be properly
|
||||
// formatted presentation-format domain names. If the response contains
|
||||
// invalid names, those records are filtered out and an error
|
||||
// will be returned alongside the the remaining results, if any.
|
||||
func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
|
||||
return r.lookupNS(ctx, name)
|
||||
records, err := r.lookupNS(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filteredNS := make([]*NS, 0, len(records))
|
||||
for _, ns := range records {
|
||||
if ns == nil {
|
||||
continue
|
||||
}
|
||||
if !isDomainName(ns.Host) {
|
||||
continue
|
||||
}
|
||||
filteredNS = append(filteredNS, ns)
|
||||
}
|
||||
if len(records) != len(filteredNS) {
|
||||
return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
|
||||
}
|
||||
return filteredNS, nil
|
||||
}
|
||||
|
||||
// LookupTXT returns the DNS TXT records for the given domain name.
|
||||
@@ -466,14 +571,40 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
|
||||
// LookupAddr performs a reverse lookup for the given address, returning a list
|
||||
// of names mapping to that address.
|
||||
//
|
||||
// The returned names are validated to be properly formatted presentation-format
|
||||
// domain names. If the response contains invalid names, those records are filtered
|
||||
// out and an error will be returned alongside the the remaining results, if any.
|
||||
//
|
||||
// When using the host C library resolver, at most one result will be
|
||||
// returned. To bypass the host resolver, use a custom Resolver.
|
||||
func LookupAddr(addr string) (names []string, err error) {
|
||||
return DefaultResolver.lookupAddr(context.Background(), addr)
|
||||
return DefaultResolver.LookupAddr(context.Background(), addr)
|
||||
}
|
||||
|
||||
// LookupAddr performs a reverse lookup for the given address, returning a list
|
||||
// of names mapping to that address.
|
||||
func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
|
||||
return r.lookupAddr(ctx, addr)
|
||||
//
|
||||
// The returned names are validated to be properly formatted presentation-format
|
||||
// domain names. If the response contains invalid names, those records are filtered
|
||||
// out and an error will be returned alongside the the remaining results, if any.
|
||||
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
|
||||
names, err := r.lookupAddr(ctx, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filteredNames := make([]string, 0, len(names))
|
||||
for _, name := range names {
|
||||
if isDomainName(name) {
|
||||
filteredNames = append(filteredNames, name)
|
||||
}
|
||||
}
|
||||
if len(names) != len(filteredNames) {
|
||||
return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
|
||||
}
|
||||
return filteredNames, nil
|
||||
}
|
||||
|
||||
// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
|
||||
// method recieves DNS records which contain invalid DNS names. This may be returned alongside
|
||||
// results which have had the malformed records filtered out.
|
||||
var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"runtime/trace"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -853,3 +854,44 @@ func TestNotifyContextStringer(t *testing.T) {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// #44193 test signal handling while stopping and starting the world.
|
||||
func TestSignalTrace(t *testing.T) {
|
||||
done := make(chan struct{})
|
||||
quit := make(chan struct{})
|
||||
c := make(chan os.Signal, 1)
|
||||
Notify(c, syscall.SIGHUP)
|
||||
|
||||
// Source and sink for signals busy loop unsynchronized with
|
||||
// trace starts and stops. We are ultimately validating that
|
||||
// signals and runtime.(stop|start)TheWorldGC are compatible.
|
||||
go func() {
|
||||
defer close(done)
|
||||
defer Stop(c)
|
||||
pid := syscall.Getpid()
|
||||
for {
|
||||
select {
|
||||
case <-quit:
|
||||
return
|
||||
default:
|
||||
syscall.Kill(pid, syscall.SIGHUP)
|
||||
}
|
||||
waitSig(t, c, syscall.SIGHUP)
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := trace.Start(buf); err != nil {
|
||||
t.Fatalf("[%d] failed to start tracing: %v", i, err)
|
||||
}
|
||||
time.After(1 * time.Microsecond)
|
||||
trace.Stop()
|
||||
size := buf.Len()
|
||||
if size == 0 {
|
||||
t.Fatalf("[%d] trace is empty", i)
|
||||
}
|
||||
}
|
||||
close(quit)
|
||||
<-done
|
||||
}
|
||||
|
||||
10
src/run.bash
10
src/run.bash
@@ -23,15 +23,7 @@ fi
|
||||
|
||||
eval $(../bin/go env)
|
||||
export GOROOT # The api test requires GOROOT to be set, so set it to match ../bin/go.
|
||||
|
||||
# We disallow local import for non-local packages, if $GOROOT happens
|
||||
# to be under $GOPATH, then some tests below will fail. $GOPATH needs
|
||||
# to be set to a non-empty string, else Go will set a default value
|
||||
# that may also conflict with $GOROOT. The $GOPATH value doesn't need
|
||||
# to point to an actual directory, it just needs to pass the semantic
|
||||
# checks performed by Go. Use $GOROOT to define $GOPATH so that we
|
||||
# don't blunder into a user-defined symbolic link.
|
||||
export GOPATH=/dev/null
|
||||
export GOPATH=/nonexist-gopath
|
||||
|
||||
unset CDPATH # in case user has it set
|
||||
export GOBIN=$GOROOT/bin # Issue 14340
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user