mirror of
https://github.com/golang/go.git
synced 2026-01-30 15:42:04 +03:00
Compare commits
65 Commits
dev.corety
...
go1.16.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 }
|
||||
@@ -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 (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,155 @@ 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))
|
||||
}
|
||||
}
|
||||
|
||||
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.AttrContentAddressable, 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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -64,10 +64,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")
|
||||
|
||||
|
||||
@@ -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 != "" {
|
||||
@@ -318,7 +316,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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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-20210428183300-3f4a416c7d3b
|
||||
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-20210428183300-3f4a416c7d3b h1:SQCMv1JDt7RN/Vp0bjtNMSufVVHgpFVzmDFdCLL31yY=
|
||||
golang.org/x/net v0.0.0-20210428183300-3f4a416c7d3b/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) {
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,22 +248,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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,9 +18,7 @@ setlocal
|
||||
|
||||
set GOBUILDFAIL=0
|
||||
|
||||
:: we disallow local import for non-local packages, if %GOROOT% happens
|
||||
:: to be under %GOPATH%, then some tests below will fail
|
||||
set GOPATH=
|
||||
set GOPATH=c:\nonexist-gopath
|
||||
:: Issue 14340: ignore GOBIN during all.bat.
|
||||
set GOBIN=
|
||||
set GOFLAGS=
|
||||
|
||||
@@ -12,10 +12,9 @@ if(! test -f ../bin/go){
|
||||
|
||||
eval `{../bin/go env}
|
||||
|
||||
GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
|
||||
# to be under $GOPATH, then some tests below will fail
|
||||
GOBIN = () # Issue 14340
|
||||
GOFLAGS = ()
|
||||
GO111MODULE = ()
|
||||
GOPATH=/nonexist-gopath
|
||||
GOBIN=() # Issue 14340
|
||||
GOFLAGS=()
|
||||
GO111MODULE=()
|
||||
|
||||
exec ../bin/go tool dist test -rebuild $*
|
||||
|
||||
@@ -32,7 +32,7 @@ typedef struct {
|
||||
|
||||
#define SET_RETVAL(fn) \
|
||||
uintptr_t ret = (uintptr_t) fn ; \
|
||||
if (ret == -1) { \
|
||||
if (ret == (uintptr_t) -1) { \
|
||||
x->retval = (uintptr_t) errno; \
|
||||
} else \
|
||||
x->retval = ret
|
||||
|
||||
@@ -279,7 +279,8 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
|
||||
|
||||
broken := false
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "ios", "dragonfly", "netbsd", "illumos", "solaris":
|
||||
// See https://golang.org/issue/45170 for AIX.
|
||||
case "darwin", "ios", "dragonfly", "netbsd", "illumos", "solaris", "aix":
|
||||
broken = true
|
||||
case "openbsd":
|
||||
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
|
||||
|
||||
@@ -1338,6 +1338,9 @@ func mPark() {
|
||||
g := getg()
|
||||
for {
|
||||
notesleep(&g.m.park)
|
||||
// Note, because of signal handling by this parked m,
|
||||
// a preemptive mDoFixup() may actually occur via
|
||||
// mDoFixupAndOSYield(). (See golang.org/issue/44193)
|
||||
noteclear(&g.m.park)
|
||||
if !mDoFixup() {
|
||||
return
|
||||
@@ -1571,6 +1574,22 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
|
||||
for atomic.Load(&sched.sysmonStarting) != 0 {
|
||||
osyield()
|
||||
}
|
||||
|
||||
// We don't want this thread to handle signals for the
|
||||
// duration of this critical section. The underlying issue
|
||||
// being that this locked coordinating m is the one monitoring
|
||||
// for fn() execution by all the other m's of the runtime,
|
||||
// while no regular go code execution is permitted (the world
|
||||
// is stopped). If this present m were to get distracted to
|
||||
// run signal handling code, and find itself waiting for a
|
||||
// second thread to execute go code before being able to
|
||||
// return from that signal handling, a deadlock will result.
|
||||
// (See golang.org/issue/44193.)
|
||||
lockOSThread()
|
||||
var sigmask sigset
|
||||
sigsave(&sigmask)
|
||||
sigblock(false)
|
||||
|
||||
stopTheWorldGC("doAllThreadsSyscall")
|
||||
if atomic.Load(&newmHandoff.haveTemplateThread) != 0 {
|
||||
// Ensure that there are no in-flight thread
|
||||
@@ -1622,6 +1641,7 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
|
||||
// the possibility of racing with mp.
|
||||
lock(&mp.mFixup.lock)
|
||||
mp.mFixup.fn = fn
|
||||
atomic.Store(&mp.mFixup.used, 1)
|
||||
if mp.doesPark {
|
||||
// For non-service threads this will
|
||||
// cause the wakeup to be short lived
|
||||
@@ -1638,9 +1658,7 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
|
||||
if mp.procid == tid {
|
||||
continue
|
||||
}
|
||||
lock(&mp.mFixup.lock)
|
||||
done = done && (mp.mFixup.fn == nil)
|
||||
unlock(&mp.mFixup.lock)
|
||||
done = atomic.Load(&mp.mFixup.used) == 0
|
||||
}
|
||||
if done {
|
||||
break
|
||||
@@ -1667,6 +1685,8 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
|
||||
unlock(&mFixupRace.lock)
|
||||
}
|
||||
startTheWorldGC()
|
||||
msigrestore(sigmask)
|
||||
unlockOSThread()
|
||||
}
|
||||
|
||||
// runSafePointFn runs the safe point function, if any, for this P.
|
||||
@@ -2157,9 +2177,21 @@ var mFixupRace struct {
|
||||
// mDoFixup runs any outstanding fixup function for the running m.
|
||||
// Returns true if a fixup was outstanding and actually executed.
|
||||
//
|
||||
// Note: to avoid deadlocks, and the need for the fixup function
|
||||
// itself to be async safe, signals are blocked for the working m
|
||||
// while it holds the mFixup lock. (See golang.org/issue/44193)
|
||||
//
|
||||
//go:nosplit
|
||||
func mDoFixup() bool {
|
||||
_g_ := getg()
|
||||
if used := atomic.Load(&_g_.m.mFixup.used); used == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// slow path - if fixup fn is used, block signals and lock.
|
||||
var sigmask sigset
|
||||
sigsave(&sigmask)
|
||||
sigblock(false)
|
||||
lock(&_g_.m.mFixup.lock)
|
||||
fn := _g_.m.mFixup.fn
|
||||
if fn != nil {
|
||||
@@ -2176,7 +2208,6 @@ func mDoFixup() bool {
|
||||
// is more obviously safe.
|
||||
throw("GC must be disabled to protect validity of fn value")
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(&_g_.m.mFixup.fn)) = 0
|
||||
if _g_.racectx != 0 || !raceenabled {
|
||||
fn(false)
|
||||
} else {
|
||||
@@ -2191,11 +2222,24 @@ func mDoFixup() bool {
|
||||
_g_.racectx = 0
|
||||
unlock(&mFixupRace.lock)
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(&_g_.m.mFixup.fn)) = 0
|
||||
atomic.Store(&_g_.m.mFixup.used, 0)
|
||||
}
|
||||
unlock(&_g_.m.mFixup.lock)
|
||||
msigrestore(sigmask)
|
||||
return fn != nil
|
||||
}
|
||||
|
||||
// mDoFixupAndOSYield is called when an m is unable to send a signal
|
||||
// because the allThreadsSyscall mechanism is in progress. That is, an
|
||||
// mPark() has been interrupted with this signal handler so we need to
|
||||
// ensure the fixup is executed from this context.
|
||||
//go:nosplit
|
||||
func mDoFixupAndOSYield() {
|
||||
mDoFixup()
|
||||
osyield()
|
||||
}
|
||||
|
||||
// templateThread is a thread in a known-good state that exists solely
|
||||
// to start new threads in known-good states when the calling thread
|
||||
// may not be in a good state.
|
||||
|
||||
@@ -537,10 +537,13 @@ type m struct {
|
||||
syscalltick uint32
|
||||
freelink *m // on sched.freem
|
||||
|
||||
// mFixup is used to synchronize OS related m state (credentials etc)
|
||||
// use mutex to access.
|
||||
// mFixup is used to synchronize OS related m state
|
||||
// (credentials etc) use mutex to access. To avoid deadlocks
|
||||
// an atomic.Load() of used being zero in mDoFixupFn()
|
||||
// guarantees fn is nil.
|
||||
mFixup struct {
|
||||
lock mutex
|
||||
used uint32
|
||||
fn func(bool) bool
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ Send:
|
||||
}
|
||||
case sigFixup:
|
||||
// nothing to do - we need to wait for sigIdle.
|
||||
osyield()
|
||||
mDoFixupAndOSYield()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,9 @@ func (ci *Frames) Next() (frame Frame, more bool) {
|
||||
name := funcname(funcInfo)
|
||||
if inldata := funcdata(funcInfo, _FUNCDATA_InlTree); inldata != nil {
|
||||
inltree := (*[1 << 20]inlinedCall)(inldata)
|
||||
ix := pcdatavalue(funcInfo, _PCDATA_InlTreeIndex, pc, nil)
|
||||
// Non-strict as cgoTraceback may have added bogus PCs
|
||||
// with a valid funcInfo but invalid PCDATA.
|
||||
ix := pcdatavalue1(funcInfo, _PCDATA_InlTreeIndex, pc, nil, false)
|
||||
if ix >= 0 {
|
||||
// Note: entry is not modified. It always refers to a real frame, not an inlined one.
|
||||
f = nil
|
||||
@@ -183,7 +185,9 @@ func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
|
||||
var cache pcvalueCache
|
||||
inltree := (*[1 << 20]inlinedCall)(inldata)
|
||||
for {
|
||||
ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, &cache)
|
||||
// Non-strict as cgoTraceback may have added bogus PCs
|
||||
// with a valid funcInfo but invalid PCDATA.
|
||||
ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, tracepc, &cache, false)
|
||||
if ix < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TestCaller(t *testing.T) {
|
||||
@@ -165,3 +166,87 @@ func TestNilName(t *testing.T) {
|
||||
t.Errorf("Name() = %q, want %q", got, "")
|
||||
}
|
||||
}
|
||||
|
||||
var dummy int
|
||||
|
||||
func inlined() {
|
||||
// Side effect to prevent elimination of this entire function.
|
||||
dummy = 42
|
||||
}
|
||||
|
||||
// A function with an InlTree. Returns a PC within the function body.
|
||||
//
|
||||
// No inline to ensure this complete function appears in output.
|
||||
//
|
||||
//go:noinline
|
||||
func tracebackFunc(t *testing.T) uintptr {
|
||||
// This body must be more complex than a single call to inlined to get
|
||||
// an inline tree.
|
||||
inlined()
|
||||
inlined()
|
||||
|
||||
// Acquire a PC in this function.
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
t.Fatalf("Caller(0) got ok false, want true")
|
||||
}
|
||||
|
||||
return pc
|
||||
}
|
||||
|
||||
// Test that CallersFrames handles PCs in the alignment region between
|
||||
// functions (int 3 on amd64) without crashing.
|
||||
//
|
||||
// Go will never generate a stack trace containing such an address, as it is
|
||||
// not a valid call site. However, the cgo traceback function passed to
|
||||
// runtime.SetCgoTraceback may not be completely accurate and may incorrect
|
||||
// provide PCs in Go code or the alignement region between functions.
|
||||
//
|
||||
// Go obviously doesn't easily expose the problematic PCs to running programs,
|
||||
// so this test is a bit fragile. Some details:
|
||||
//
|
||||
// * tracebackFunc is our target function. We want to get a PC in the
|
||||
// alignment region following this function. This function also has other
|
||||
// functions inlined into it to ensure it has an InlTree (this was the source
|
||||
// of the bug in issue 44971).
|
||||
//
|
||||
// * We acquire a PC in tracebackFunc, walking forwards until FuncForPC says
|
||||
// we're in a new function. The last PC of the function according to FuncForPC
|
||||
// should be in the alignment region (assuming the function isn't already
|
||||
// perfectly aligned).
|
||||
//
|
||||
// This is a regression test for issue 44971.
|
||||
func TestFunctionAlignmentTraceback(t *testing.T) {
|
||||
pc := tracebackFunc(t)
|
||||
|
||||
// Double-check we got the right PC.
|
||||
f := runtime.FuncForPC(pc)
|
||||
if !strings.HasSuffix(f.Name(), "tracebackFunc") {
|
||||
t.Fatalf("Caller(0) = %+v, want tracebackFunc", f)
|
||||
}
|
||||
|
||||
// Iterate forward until we find a different function. Back up one
|
||||
// instruction is (hopefully) an alignment instruction.
|
||||
for runtime.FuncForPC(pc) == f {
|
||||
pc++
|
||||
}
|
||||
pc--
|
||||
|
||||
// Is this an alignment region filler instruction? We only check this
|
||||
// on amd64 for simplicity. If this function has no filler, then we may
|
||||
// get a false negative, but will never get a false positive.
|
||||
if runtime.GOARCH == "amd64" {
|
||||
code := *(*uint8)(unsafe.Pointer(pc))
|
||||
if code != 0xcc { // INT $3
|
||||
t.Errorf("PC %v code got %#x want 0xcc", pc, code)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally ensure that Frames.Next doesn't crash when processing this
|
||||
// PC.
|
||||
frames := runtime.CallersFrames([]uintptr{pc})
|
||||
frame, _ := frames.Next()
|
||||
if frame.Func != f {
|
||||
t.Errorf("frames.Next() got %+v want %+v", frame.Func, f)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +263,9 @@ func addtimer(t *timer) {
|
||||
|
||||
when := t.when
|
||||
|
||||
// Disable preemption while using pp to avoid changing another P's heap.
|
||||
mp := acquirem()
|
||||
|
||||
pp := getg().m.p.ptr()
|
||||
lock(&pp.timersLock)
|
||||
cleantimers(pp)
|
||||
@@ -270,6 +273,8 @@ func addtimer(t *timer) {
|
||||
unlock(&pp.timersLock)
|
||||
|
||||
wakeNetPoller(when)
|
||||
|
||||
releasem(mp)
|
||||
}
|
||||
|
||||
// doaddtimer adds t to the current P's heap.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user