libgo: update to Go1.16.5 release

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/326772
This commit is contained in:
Ian Lance Taylor 2021-06-10 12:37:34 -07:00
parent 00d07ec6e1
commit ee52bf609b
32 changed files with 782 additions and 132 deletions

View File

@ -1,4 +1,4 @@
5a801b15699cced5203af5c7339b375cd55ecbac bcafcb3c39530bb325514d6377747eb3127d1a03
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.

View File

@ -1,4 +1,4 @@
9baddd3f21230c55f0ad2a10f5f20579dcf0a0bb 7677616a263e8ded606cc8297cb67ddc667a876e
The first line of this file holds the git revision number of the The first line of this file holds the git revision number of the
last merge done from the master library sources. last merge done from the master library sources.

View File

@ -1 +1 @@
go1.16.3 go1.16.5

View File

@ -99,7 +99,15 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
return err return err
} }
z.r = r 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 z.Comment = end.comment
rs := io.NewSectionReader(r, 0, size) rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil { 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. // 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 { type fileListEntry struct {
name string name string
file *File // nil for directories file *File
isDir bool
} }
type fileInfoDirEntry interface { type fileInfoDirEntry interface {
@ -640,20 +649,26 @@ type fileInfoDirEntry interface {
} }
func (e *fileListEntry) stat() fileInfoDirEntry { func (e *fileListEntry) stat() fileInfoDirEntry {
if e.file != nil { if !e.isDir {
return headerFileInfo{&e.file.FileHeader} return headerFileInfo{&e.file.FileHeader}
} }
return e return e
} }
// Only used for directories. // Only used for directories.
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem } func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
func (f *fileListEntry) Size() int64 { return 0 } 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) Mode() fs.FileMode { return fs.ModeDir | 0555 } func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir } func (f *fileListEntry) IsDir() bool { return true }
func (f *fileListEntry) IsDir() bool { return true } func (f *fileListEntry) Sys() interface{} { return nil }
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 } func (f *fileListEntry) Info() (fs.FileInfo, error) { return f, nil }
@ -673,15 +688,32 @@ func toValidName(name string) string {
func (r *Reader) initFileList() { func (r *Reader) initFileList() {
r.fileListOnce.Do(func() { r.fileListOnce.Do(func() {
dirs := make(map[string]bool) dirs := make(map[string]bool)
knownDirs := make(map[string]bool)
for _, file := range r.File { for _, file := range r.File {
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
name := toValidName(file.Name) name := toValidName(file.Name)
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) { for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
dirs[dir] = true 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 { 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) }) 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) { if e == nil || !fs.ValidPath(name) {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} 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 return &openDir{e, r.openReadDir(name), 0}, nil
} }
rc, err := e.file.Open() 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 return name[:i], name[i+1:], isDir
} }
var dotFile = &fileListEntry{name: "./"} var dotFile = &fileListEntry{name: "./", isDir: true}
func (r *Reader) openLookup(name string) *fileListEntry { func (r *Reader) openLookup(name string) *fileListEntry {
if name == "." { if name == "." {

View File

@ -1073,12 +1073,62 @@ func TestIssue12449(t *testing.T) {
} }
func TestFS(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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := fstest.TestFS(z, "hello", "dir/bar", "dir/empty", "readonly"); err != nil { defer z.Close()
t.Fatal(err)
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)
}
} }
} }
@ -1116,3 +1166,62 @@ func TestCVE202127919(t *testing.T) {
t.Errorf("Error reading file: %v", err) 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
libgo/go/archive/zip/testdata/subdir.zip vendored Normal file

Binary file not shown.

View File

@ -86,9 +86,11 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
if !modload.HasModRoot() && len(args) == 0 { if !modload.HasModRoot() && len(args) == 0 {
base.Fatalf("go mod download: no modules specified (see 'go help mod download')") 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"} args = []string{"all"}
} else if modload.HasModRoot() { }
if modload.HasModRoot() {
modload.LoadModFile(ctx) // to fill Target modload.LoadModFile(ctx) // to fill Target
targetAtUpgrade := modload.Target.Path + "@upgrade" targetAtUpgrade := modload.Target.Path + "@upgrade"
targetAtPatch := modload.Target.Path + "@patch" targetAtPatch := modload.Target.Path + "@patch"
@ -137,7 +139,20 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
listRetractions := false listRetractions := false
type token struct{} type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0)) 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 { if info.Replace != nil {
info = info.Replace info = info.Replace
} }
@ -187,6 +202,13 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
base.ExitIfErrors() base.ExitIfErrors()
} }
// Update go.mod and especially go.sum if needed. // If there were explicit arguments, update go.mod and especially go.sum.
modload.WriteGoMod() // '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()
}
} }

View File

@ -61,6 +61,8 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
modload.ForceUseModules = true modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot modload.RootMode = modload.NeedRoot
modload.CheckTidyVersion(ctx, tidyE)
modload.LoadPackages(ctx, modload.PackageOpts{ modload.LoadPackages(ctx, modload.PackageOpts{
Tags: imports.AnyTags(), Tags: imports.AnyTags(),
ResolveMissingImports: true, ResolveMissingImports: true,

View File

@ -11,10 +11,13 @@ import (
"cmd/go/internal/mvs" "cmd/go/internal/mvs"
"context" "context"
"fmt" "fmt"
"go/build"
"os" "os"
"strings" "strings"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module" "golang.org/x/mod/module"
"golang.org/x/mod/semver"
) )
// buildList is the list of modules to use for building packages. // buildList is the list of modules to use for building packages.
@ -226,6 +229,33 @@ func ReloadBuildList() []module.Version {
return capVersionSlice(buildList) 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 // TidyBuildList trims the build list to the minimal requirements needed to
// retain the same versions of all packages from the preceding call to // retain the same versions of all packages from the preceding call to
// LoadPackages. // LoadPackages.

View File

@ -5,7 +5,7 @@ module "rsc.io/sampler"
require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
-- .info -- -- .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 -- -- hello.go --
// Copyright 2018 The Go Authors. All rights reserved. // Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

View File

@ -107,13 +107,28 @@ stderr '^go mod download: skipping argument m that resolves to the main module\n
! go mod download m@latest ! go mod download m@latest
stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$' 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 cd update
cp go.mod.orig go.mod
! exists go.sum ! exists go.sum
go mod download 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 grep '^rsc.io/sampler v1.3.0 ' go.sum
go list -m rsc.io/sampler cp go.mod.orig go.mod
stdout '^rsc.io/sampler v1.3.0$' 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 # allow go mod download without go.mod
env GO111MODULE=auto env GO111MODULE=auto
@ -131,7 +146,7 @@ stderr 'get '$GOPROXY
-- go.mod -- -- go.mod --
module m module m
-- update/go.mod -- -- update/go.mod.orig --
module m module m
go 1.16 go 1.16
@ -140,3 +155,16 @@ require (
rsc.io/quote v1.5.2 rsc.io/quote v1.5.2
rsc.io/sampler v1.2.1 // older version than in build list 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=

View File

@ -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 # 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 # 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 # ".go/" should try to list a package regardless of whether a file exists at the
@ -31,3 +28,10 @@ module m
go 1.13 go 1.13
require example.com/dotgo.go v1.0.0 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"

View File

@ -1,9 +1,7 @@
env GO111MODULE=on env GO111MODULE=on
# Populate go.sum.
# TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands # TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands
# below depend on the build list. # below depend on the build list.
go mod download
go list -m -versions rsc.io/quote 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$' 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 module x
require rsc.io/quote v1.0.0 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 -- -- use.go --
package use package use

View File

@ -89,7 +89,7 @@ stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get
-- go.mod -- -- go.mod --
module m module m
go 1.20 go 1.16
-- x.go -- -- x.go --
package x package x
@ -104,7 +104,7 @@ require (
-- go.mod.redundant -- -- go.mod.redundant --
module m module m
go 1.20 go 1.16
require ( require (
rsc.io/quote v1.5.2 rsc.io/quote v1.5.2
@ -114,7 +114,7 @@ require (
-- go.mod.indirect -- -- go.mod.indirect --
module m module m
go 1.20 go 1.16
require ( require (
rsc.io/quote v1.5.2 // indirect rsc.io/quote v1.5.2 // indirect
@ -124,7 +124,7 @@ require (
-- go.mod.untidy -- -- go.mod.untidy --
module m module m
go 1.20 go 1.16
require ( require (
rsc.io/sampler v1.3.0 // indirect rsc.io/sampler v1.3.0 // indirect

View File

@ -4,7 +4,7 @@ go 1.16
require ( require (
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 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/sys v0.0.0-20201204225414-ed752295db88 // indirect
golang.org/x/text v0.3.4 // indirect golang.org/x/text v0.3.4 // indirect
) )

View File

@ -137,11 +137,13 @@ func trimOWS(x string) string {
// contains token amongst its comma-separated tokens, ASCII // contains token amongst its comma-separated tokens, ASCII
// case-insensitively. // case-insensitively.
func headerValueContainsToken(v string, token string) bool { func headerValueContainsToken(v string, token string) bool {
v = trimOWS(v) for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') {
if comma := strings.IndexByte(v, ','); comma != -1 { if tokenEqual(trimOWS(v[:comma]), token) {
return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) return true
}
v = v[comma+1:]
} }
return tokenEqual(v, token) return tokenEqual(trimOWS(v), token)
} }
// lowerASCII returns the ASCII lowercase version of b. // lowerASCII returns the ASCII lowercase version of b.

View File

@ -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) // 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 // exponent may be provided as well, except for hexadecimal floats which
// only accept an (optional) ``p'' exponent (because an ``e'' or ``E'' cannot // 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 // 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. // operation failed, the value of z is undefined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) { func (z *Rat) SetString(s string) (*Rat, bool) {
@ -169,6 +170,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if n < 0 { if n < 0 {
n = -n 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 pow5 := z.b.abs.expNN(natFive, nat(nil).setWord(Word(n)), nil) // use underlying array of z.b.abs
if exp5 > 0 { if exp5 > 0 {
z.a.abs = z.a.abs.mul(z.a.abs, pow5) 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 // apply exp2 contributions
if exp2 < -1e7 || exp2 > 1e7 {
return nil, false // avoid excessively large exponents
}
if exp2 > 0 { if exp2 > 0 {
if int64(uint(exp2)) != exp2 {
panic("exponent too large")
}
z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2)) z.a.abs = z.a.abs.shl(z.a.abs, uint(exp2))
} else if exp2 < 0 { } 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)) z.b.abs = z.b.abs.shl(z.b.abs, uint(-exp2))
} }

View File

@ -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)
}
}
}

View File

@ -1798,3 +1798,161 @@ func TestPTRandNonPTR(t *testing.T) {
t.Errorf("names = %q; want %q", names, want) 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."),
},
},
)
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."),
},
},
)
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."),
},
},
)
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."),
},
},
)
}
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"
_, err := r.LookupCNAME(context.Background(), "golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected)
}
_, err = LookupCNAME("golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected)
}
_, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
}
_, _, err = LookupSRV("target", "tcp", "golang.org")
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
}
_, _, 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)
}
_, err = r.LookupMX(context.Background(), "golang.org")
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected)
}
_, err = LookupMX("golang.org")
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected)
}
_, err = r.LookupNS(context.Background(), "golang.org")
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected)
}
_, err = LookupNS("golang.org")
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected)
}
_, err = r.LookupAddr(context.Background(), "192.0.2.42")
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected)
}
_, err = LookupAddr("192.0.2.42")
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected)
}
}

View File

@ -248,22 +248,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// important is "Connection" because we want a persistent // important is "Connection" because we want a persistent
// connection, regardless of what the client sent to us. // connection, regardless of what the client sent to us.
for _, h := range hopHeaders { 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) 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 // After stripping all the hop-by-hop connection headers above, add back any
// necessary for protocol upgrades, such as for websockets. // necessary for protocol upgrades, such as for websockets.
if reqUpType != "" { if reqUpType != "" {

View File

@ -90,8 +90,9 @@ func TestReverseProxy(t *testing.T) {
getReq, _ := http.NewRequest("GET", frontend.URL, nil) getReq, _ := http.NewRequest("GET", frontend.URL, nil)
getReq.Host = "some-name" getReq.Host = "some-name"
getReq.Header.Set("Connection", "close") getReq.Header.Set("Connection", "close, TE")
getReq.Header.Set("Te", "trailers") getReq.Header.Add("Te", "foo")
getReq.Header.Add("Te", "bar, trailers")
getReq.Header.Set("Proxy-Connection", "should be deleted") getReq.Header.Set("Proxy-Connection", "should be deleted")
getReq.Header.Set("Upgrade", "foo") getReq.Header.Set("Upgrade", "foo")
getReq.Close = true 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) { func TestXForwardedFor(t *testing.T) {
const prevForwardedFor = "client ip" const prevForwardedFor = "client ip"
const backendResponse = "I am the backend" const backendResponse = "I am the backend"

View File

@ -5318,7 +5318,6 @@ func TestMissingStatusNoPanic(t *testing.T) {
ln := newLocalListener(t) ln := newLocalListener(t)
addr := ln.Addr().String() addr := ln.Addr().String()
shutdown := make(chan bool, 1)
done := make(chan bool) done := make(chan bool)
fullAddrURL := fmt.Sprintf("http://%s", addr) fullAddrURL := fmt.Sprintf("http://%s", addr)
raw := "HTTP/1.1 400\r\n" + raw := "HTTP/1.1 400\r\n" +
@ -5330,10 +5329,7 @@ func TestMissingStatusNoPanic(t *testing.T) {
"Aloha Olaa" "Aloha Olaa"
go func() { go func() {
defer func() { defer close(done)
ln.Close()
close(done)
}()
conn, _ := ln.Accept() conn, _ := ln.Accept()
if conn != nil { if conn != nil {
@ -5364,7 +5360,7 @@ func TestMissingStatusNoPanic(t *testing.T) {
t.Errorf("got=%v want=%q", err, want) t.Errorf("got=%v want=%q", err, want)
} }
close(shutdown) ln.Close()
<-done <-done
} }

View File

@ -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 // LookupCNAME does not return an error if host does not
// contain DNS "CNAME" records, as long as host resolves to // contain DNS "CNAME" records, as long as host resolves to
// address records. // 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) { 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. // 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 // LookupCNAME does not return an error if host does not
// contain DNS "CNAME" records, as long as host resolves to // contain DNS "CNAME" records, as long as host resolves to
// address records. // 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: "CNAME target is invalid", Name: host}
}
return cname, nil
} }
// LookupSRV tries to resolve an SRV query of the given service, // LookupSRV tries to resolve an SRV query of the given service,
@ -416,8 +429,11 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string,
// That is, it looks up _service._proto.name. To accommodate services // That is, it looks up _service._proto.name. To accommodate services
// publishing SRV records under non-standard names, if both service // publishing SRV records under non-standard names, if both service
// and proto are empty strings, LookupSRV looks up name directly. // and proto are empty strings, LookupSRV looks up name directly.
//
// The returned service names are validated to be properly
// formatted presentation-format domain names.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 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, // LookupSRV tries to resolve an SRV query of the given service,
@ -429,28 +445,82 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
// That is, it looks up _service._proto.name. To accommodate services // That is, it looks up _service._proto.name. To accommodate services
// publishing SRV records under non-standard names, if both service // publishing SRV records under non-standard names, if both service
// and proto are empty strings, LookupSRV looks up name directly. // 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.
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}
}
for _, addr := range addrs {
if addr == nil {
continue
}
if !isDomainName(addr.Target) {
return "", nil, &DNSError{Err: "SRV target is invalid", Name: name}
}
}
return cname, addrs, nil
} }
// LookupMX returns the DNS MX records for the given domain name sorted by preference. // 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.
func LookupMX(name string) ([]*MX, error) { 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. // 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.
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 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
}
for _, mx := range records {
if mx == nil {
continue
}
if !isDomainName(mx.Host) {
return nil, &DNSError{Err: "MX target is invalid", Name: name}
}
}
return records, nil
} }
// LookupNS returns the DNS NS records for the given domain 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.
func LookupNS(name string) ([]*NS, error) { 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. // 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.
func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 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
}
for _, ns := range records {
if ns == nil {
continue
}
if !isDomainName(ns.Host) {
return nil, &DNSError{Err: "NS target is invalid", Name: name}
}
}
return records, nil
} }
// LookupTXT returns the DNS TXT records for the given domain name. // LookupTXT returns the DNS TXT records for the given domain name.
@ -466,14 +536,29 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
// LookupAddr performs a reverse lookup for the given address, returning a list // LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address. // of names mapping to that address.
// //
// The returned names are validated to be properly formatted presentation-format
// domain names.
//
// When using the host C library resolver, at most one result will be // When using the host C library resolver, at most one result will be
// returned. To bypass the host resolver, use a custom Resolver. // returned. To bypass the host resolver, use a custom Resolver.
func LookupAddr(addr string) (names []string, err error) { 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 // LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address. // 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.
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
names, err := r.lookupAddr(ctx, addr)
if err != nil {
return nil, err
}
for _, name := range names {
if !isDomainName(name) {
return nil, &DNSError{Err: "PTR target is invalid", Name: addr}
}
}
return names, nil
} }

View File

@ -15,6 +15,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"runtime" "runtime"
"runtime/trace"
"strconv" "strconv"
"sync" "sync"
"syscall" "syscall"
@ -853,3 +854,44 @@ func TestNotifyContextStringer(t *testing.T) {
t.Errorf("c.String() = %q, want %q", got, want) 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
}

View File

@ -279,7 +279,8 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
broken := false broken := false
switch runtime.GOOS { 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 broken = true
case "openbsd": case "openbsd":
if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {

View File

@ -1287,6 +1287,9 @@ func mPark() {
g := getg() g := getg()
for { for {
notesleep(&g.m.park) 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) noteclear(&g.m.park)
if !mDoFixup() { if !mDoFixup() {
return return
@ -1949,9 +1952,21 @@ var mFixupRace struct {
// mDoFixup runs any outstanding fixup function for the running m. // mDoFixup runs any outstanding fixup function for the running m.
// Returns true if a fixup was outstanding and actually executed. // 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 //go:nosplit
func mDoFixup() bool { func mDoFixup() bool {
_g_ := getg() _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) lock(&_g_.m.mFixup.lock)
fn := _g_.m.mFixup.fn fn := _g_.m.mFixup.fn
if fn != nil { if fn != nil {
@ -1972,9 +1987,20 @@ func mDoFixup() bool {
fn(false) fn(false)
} }
unlock(&_g_.m.mFixup.lock) unlock(&_g_.m.mFixup.lock)
msigrestore(sigmask)
return fn != nil 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 // templateThread is a thread in a known-good state that exists solely
// to start new threads in known-good states when the calling thread // to start new threads in known-good states when the calling thread
// may not be in a good state. // may not be in a good state.

View File

@ -584,10 +584,13 @@ type m struct {
syscalltick uint32 syscalltick uint32
freelink *m // on sched.freem freelink *m // on sched.freem
// mFixup is used to synchronize OS related m state (credentials etc) // mFixup is used to synchronize OS related m state
// use mutex to access. // (credentials etc) use mutex to access. To avoid deadlocks
// an atomic.Load() of used being zero in mDoFixupFn()
// guarantees fn is nil.
mFixup struct { mFixup struct {
lock mutex lock mutex
used uint32
fn func(bool) bool fn func(bool) bool
} }

View File

@ -119,7 +119,7 @@ Send:
} }
case sigFixup: case sigFixup:
// nothing to do - we need to wait for sigIdle. // nothing to do - we need to wait for sigIdle.
osyield() mDoFixupAndOSYield()
} }
} }

View File

@ -178,7 +178,7 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64)
// If we're at the end of the known zone transitions, // If we're at the end of the known zone transitions,
// try the extend string. // try the extend string.
if lo == len(tx)-1 && l.extend != "" { if lo == len(tx)-1 && l.extend != "" {
if ename, eoffset, estart, eend, ok := tzset(l.extend, end, sec); ok { if ename, eoffset, estart, eend, _, ok := tzset(l.extend, end, sec); ok {
return ename, eoffset, estart, eend return ename, eoffset, estart, eend
} }
} }
@ -244,7 +244,7 @@ func (l *Location) firstZoneUsed() bool {
// We call this a tzset string since in C the function tzset reads TZ. // We call this a tzset string since in C the function tzset reads TZ.
// The return values are as for lookup, plus ok which reports whether the // The return values are as for lookup, plus ok which reports whether the
// parse succeeded. // parse succeeded.
func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, ok bool) { func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) {
var ( var (
stdName, dstName string stdName, dstName string
stdOffset, dstOffset int stdOffset, dstOffset int
@ -255,7 +255,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
stdOffset, s, ok = tzsetOffset(s) stdOffset, s, ok = tzsetOffset(s)
} }
if !ok { if !ok {
return "", 0, 0, 0, false return "", 0, 0, 0, false, false
} }
// The numbers in the tzset string are added to local time to get UTC, // The numbers in the tzset string are added to local time to get UTC,
@ -265,7 +265,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
if len(s) == 0 || s[0] == ',' { if len(s) == 0 || s[0] == ',' {
// No daylight savings time. // No daylight savings time.
return stdName, stdOffset, initEnd, omega, true return stdName, stdOffset, initEnd, omega, false, true
} }
dstName, s, ok = tzsetName(s) dstName, s, ok = tzsetName(s)
@ -278,7 +278,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
} }
} }
if !ok { if !ok {
return "", 0, 0, 0, false return "", 0, 0, 0, false, false
} }
if len(s) == 0 { if len(s) == 0 {
@ -287,19 +287,19 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
} }
// The TZ definition does not mention ';' here but tzcode accepts it. // The TZ definition does not mention ';' here but tzcode accepts it.
if s[0] != ',' && s[0] != ';' { if s[0] != ',' && s[0] != ';' {
return "", 0, 0, 0, false return "", 0, 0, 0, false, false
} }
s = s[1:] s = s[1:]
var startRule, endRule rule var startRule, endRule rule
startRule, s, ok = tzsetRule(s) startRule, s, ok = tzsetRule(s)
if !ok || len(s) == 0 || s[0] != ',' { if !ok || len(s) == 0 || s[0] != ',' {
return "", 0, 0, 0, false return "", 0, 0, 0, false, false
} }
s = s[1:] s = s[1:]
endRule, s, ok = tzsetRule(s) endRule, s, ok = tzsetRule(s)
if !ok || len(s) > 0 { if !ok || len(s) > 0 {
return "", 0, 0, 0, false return "", 0, 0, 0, false, false
} }
year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false)
@ -313,10 +313,15 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
startSec := int64(tzruleTime(year, startRule, stdOffset)) startSec := int64(tzruleTime(year, startRule, stdOffset))
endSec := int64(tzruleTime(year, endRule, dstOffset)) endSec := int64(tzruleTime(year, endRule, dstOffset))
dstIsDST, stdIsDST := true, false
// Note: this is a flipping of "DST" and "STD" while retaining the labels
// This happens in southern hemispheres. The labelling here thus is a little
// inconsistent with the goal.
if endSec < startSec { if endSec < startSec {
startSec, endSec = endSec, startSec startSec, endSec = endSec, startSec
stdName, dstName = dstName, stdName stdName, dstName = dstName, stdName
stdOffset, dstOffset = dstOffset, stdOffset stdOffset, dstOffset = dstOffset, stdOffset
stdIsDST, dstIsDST = dstIsDST, stdIsDST
} }
// The start and end values that we return are accurate // The start and end values that we return are accurate
@ -324,11 +329,11 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
// just the start and end of the year. That suffices for // just the start and end of the year. That suffices for
// the only caller that cares, which is Date. // the only caller that cares, which is Date.
if ysec < startSec { if ysec < startSec {
return stdName, stdOffset, abs, startSec + abs, true return stdName, stdOffset, abs, startSec + abs, stdIsDST, true
} else if ysec >= endSec { } else if ysec >= endSec {
return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, true return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true
} else { } else {
return dstName, dstOffset, startSec + abs, endSec + abs, true return dstName, dstOffset, startSec + abs, endSec + abs, dstIsDST, true
} }
} }

View File

@ -249,8 +249,8 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
// This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437). // This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437).
return nil, badData return nil, badData
} }
zone := make([]zone, nzone) zones := make([]zone, nzone)
for i := range zone { for i := range zones {
var ok bool var ok bool
var n uint32 var n uint32
if n, ok = zonedata.big4(); !ok { if n, ok = zonedata.big4(); !ok {
@ -259,22 +259,22 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
if uint32(int(n)) != n { if uint32(int(n)) != n {
return nil, badData return nil, badData
} }
zone[i].offset = int(int32(n)) zones[i].offset = int(int32(n))
var b byte var b byte
if b, ok = zonedata.byte(); !ok { if b, ok = zonedata.byte(); !ok {
return nil, badData return nil, badData
} }
zone[i].isDST = b != 0 zones[i].isDST = b != 0
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
return nil, badData return nil, badData
} }
zone[i].name = byteString(abbrev[b:]) zones[i].name = byteString(abbrev[b:])
if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") { if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") {
// There is a bug with AIX 7.2 TL 0 with files in Etc, // There is a bug with AIX 7.2 TL 0 with files in Etc,
// GMT+1 will return GMT-1 instead of GMT+1 or -01. // GMT+1 will return GMT-1 instead of GMT+1 or -01.
if name != "Etc/GMT+0" { if name != "Etc/GMT+0" {
// GMT+0 is OK // GMT+0 is OK
zone[i].name = name[4:] zones[i].name = name[4:]
} }
} }
} }
@ -297,7 +297,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
} }
} }
tx[i].when = n tx[i].when = n
if int(txzones[i]) >= len(zone) { if int(txzones[i]) >= len(zones) {
return nil, badData return nil, badData
} }
tx[i].index = txzones[i] tx[i].index = txzones[i]
@ -316,7 +316,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
} }
// Committed to succeed. // Committed to succeed.
l := &Location{zone: zone, tx: tx, name: name, extend: extend} l := &Location{zone: zones, tx: tx, name: name, extend: extend}
// Fill in the cache with information about right now, // Fill in the cache with information about right now,
// since that will be the most common lookup. // since that will be the most common lookup.
@ -325,26 +325,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when l.cacheStart = tx[i].when
l.cacheEnd = omega l.cacheEnd = omega
zoneIdx := tx[i].index l.cacheZone = &l.zone[tx[i].index]
if i+1 < len(tx) { if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when l.cacheEnd = tx[i+1].when
} else if l.extend != "" { } else if l.extend != "" {
// If we're at the end of the known zone transitions, // If we're at the end of the known zone transitions,
// try the extend string. // try the extend string.
if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok {
l.cacheStart = estart l.cacheStart = estart
l.cacheEnd = eend l.cacheEnd = eend
// Find the zone that is returned by tzset, // Find the zone that is returned by tzset to avoid allocation if possible.
// the last transition is not always the correct zone. if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 {
for i, z := range l.zone { l.cacheZone = &l.zone[zoneIdx]
if z.name == name { } else {
zoneIdx = uint8(i) l.cacheZone = &zone{
break name: name,
offset: offset,
isDST: isDST,
} }
} }
} }
} }
l.cacheZone = &l.zone[zoneIdx]
break break
} }
} }
@ -352,6 +353,15 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
return l, nil return l, nil
} }
func findZone(zones []zone, name string, offset int, isDST bool) int {
for i, z := range zones {
if z.name == name && z.offset == offset && z.isDST == isDST {
return i
}
}
return -1
}
// loadTzinfoFromDirOrZip returns the contents of the file with the given name // loadTzinfoFromDirOrZip returns the contents of the file with the given name
// in dir. dir can either be an uncompressed zip file, or a directory. // in dir. dir can either be an uncompressed zip file, or a directory.
func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) { func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) {

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519
golang.org/x/crypto/hkdf golang.org/x/crypto/hkdf
golang.org/x/crypto/internal/subtle golang.org/x/crypto/internal/subtle
golang.org/x/crypto/poly1305 golang.org/x/crypto/poly1305
# golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 # golang.org/x/net v0.0.0-20210428183300-3f4a416c7d3b
## explicit ## explicit
golang.org/x/net/dns/dnsmessage golang.org/x/net/dns/dnsmessage
golang.org/x/net/http/httpguts golang.org/x/net/http/httpguts