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
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
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
}
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 }
@ -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 == "." {

View File

@ -1073,12 +1073,62 @@ 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)
}
}
}
@ -1116,3 +1166,62 @@ func TestCVE202127919(t *testing.T) {
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 {
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()
}
}

View File

@ -61,6 +61,8 @@ 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,

View File

@ -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.

View File

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

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
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=

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
# 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"

View File

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

View File

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

View File

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

View File

@ -137,11 +137,13 @@ func trimOWS(x string) string {
// contains token amongst its comma-separated tokens, ASCII
// case-insensitively.
func headerValueContainsToken(v string, token string) bool {
v = trimOWS(v)
if comma := strings.IndexByte(v, ','); comma != -1 {
return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') {
if tokenEqual(trimOWS(v[:comma]), token) {
return true
}
v = v[comma+1:]
}
return tokenEqual(v, token)
return tokenEqual(trimOWS(v), token)
}
// 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)
// 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))
}

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)
}
}
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
// 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 != "" {

View File

@ -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"

View File

@ -5318,7 +5318,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" +
@ -5330,10 +5329,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 {
@ -5364,7 +5360,7 @@ func TestMissingStatusNoPanic(t *testing.T) {
t.Errorf("got=%v want=%q", err, want)
}
close(shutdown)
ln.Close()
<-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
// 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: "CNAME target is invalid", Name: host}
}
return cname, nil
}
// 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
// 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.
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 +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
// 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.
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.
//
// The returned mail server names are validated to be properly
// formatted presentation-format domain names.
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.
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.
//
// The returned name server names are validated to be properly
// formatted presentation-format domain names.
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.
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.
@ -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
// 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
// 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.
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/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
}

View File

@ -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" {

View File

@ -1287,6 +1287,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
@ -1949,9 +1952,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 {
@ -1972,9 +1987,20 @@ func mDoFixup() bool {
fn(false)
}
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.

View File

@ -584,10 +584,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
}

View File

@ -119,7 +119,7 @@ Send:
}
case sigFixup:
// 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,
// try the extend string.
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
}
}
@ -244,7 +244,7 @@ func (l *Location) firstZoneUsed() bool {
// 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
// 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 (
stdName, dstName string
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)
}
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,
@ -265,7 +265,7 @@ func tzset(s string, initEnd, sec int64) (name string, offset int, start, end in
if len(s) == 0 || s[0] == ',' {
// No daylight savings time.
return stdName, stdOffset, initEnd, omega, true
return stdName, stdOffset, initEnd, omega, false, true
}
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 {
return "", 0, 0, 0, false
return "", 0, 0, 0, false, false
}
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.
if s[0] != ',' && s[0] != ';' {
return "", 0, 0, 0, false
return "", 0, 0, 0, false, false
}
s = s[1:]
var startRule, endRule rule
startRule, s, ok = tzsetRule(s)
if !ok || len(s) == 0 || s[0] != ',' {
return "", 0, 0, 0, false
return "", 0, 0, 0, false, false
}
s = s[1:]
endRule, s, ok = tzsetRule(s)
if !ok || len(s) > 0 {
return "", 0, 0, 0, false
return "", 0, 0, 0, false, 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))
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 {
startSec, endSec = endSec, startSec
stdName, dstName = dstName, stdName
stdOffset, dstOffset = dstOffset, stdOffset
stdIsDST, dstIsDST = dstIsDST, stdIsDST
}
// 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
// the only caller that cares, which is Date.
if ysec < startSec {
return stdName, stdOffset, abs, startSec + abs, true
return stdName, stdOffset, abs, startSec + abs, stdIsDST, true
} else if ysec >= endSec {
return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, true
return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true
} 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).
return nil, badData
}
zone := make([]zone, nzone)
for i := range zone {
zones := make([]zone, nzone)
for i := range zones {
var ok bool
var n uint32
if n, ok = zonedata.big4(); !ok {
@ -259,22 +259,22 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
if uint32(int(n)) != n {
return nil, badData
}
zone[i].offset = int(int32(n))
zones[i].offset = int(int32(n))
var b byte
if b, ok = zonedata.byte(); !ok {
return nil, badData
}
zone[i].isDST = b != 0
zones[i].isDST = b != 0
if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
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-") {
// 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.
if name != "Etc/GMT+0" {
// 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
if int(txzones[i]) >= len(zone) {
if int(txzones[i]) >= len(zones) {
return nil, badData
}
tx[i].index = txzones[i]
@ -316,7 +316,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
}
// 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,
// 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) {
l.cacheStart = tx[i].when
l.cacheEnd = omega
zoneIdx := tx[i].index
l.cacheZone = &l.zone[tx[i].index]
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
} else if l.extend != "" {
// If we're at the end of the known zone transitions,
// 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.cacheEnd = eend
// Find the zone that is returned by tzset,
// the last transition is not always the correct zone.
for i, z := range l.zone {
if z.name == name {
zoneIdx = uint8(i)
break
// Find the zone that is returned by tzset to avoid allocation if possible.
if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 {
l.cacheZone = &l.zone[zoneIdx]
} else {
l.cacheZone = &zone{
name: name,
offset: offset,
isDST: isDST,
}
}
}
}
l.cacheZone = &l.zone[zoneIdx]
break
}
}
@ -352,6 +353,15 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
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
// in dir. dir can either be an uncompressed zip file, or a directory.
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/internal/subtle
golang.org/x/crypto/poly1305
# golang.org/x/net v0.0.0-20201209123823-ac852fbbde11
# golang.org/x/net v0.0.0-20210428183300-3f4a416c7d3b
## explicit
golang.org/x/net/dns/dnsmessage
golang.org/x/net/http/httpguts