[dev.inline] merge with master at 894d24d617

Change-Id: I845eec08108c69228ebcba921f8a807a376d3fae
This commit is contained in:
Than McIntosh 2023-07-07 16:49:15 -04:00
commit 71aaa8bde1
55 changed files with 596 additions and 242 deletions

View File

@ -174,6 +174,7 @@ pkg go/build, type Package struct, Directives []Directive #56986
pkg go/build, type Package struct, TestDirectives []Directive #56986
pkg go/build, type Package struct, XTestDirectives []Directive #56986
pkg go/token, method (*File) Lines() []int #57708
pkg go/types, method (*Package) GoVersion() string #61175
pkg html/template, const ErrJSTemplate = 12 #59584
pkg html/template, const ErrJSTemplate ErrorCode #59584
pkg io/fs, func FormatDirEntry(DirEntry) string #54451

View File

@ -65,7 +65,7 @@ func (s *Slice) Col() int {
// #define A #define B(x) x
// and
// #define A #define B (x) x
// The first has definition of B has an argument, the second doesn't. Because we let
// The first definition of B has an argument, the second doesn't. Because we let
// text/scanner strip the blanks for us, this is extremely rare, hard to fix, and not worth it.
return s.pos
}

View File

@ -836,11 +836,11 @@
//
// Key:
//
// [+ -](x * y) [+ -] z.
// _ N A S
// D U
// D B
// [+ -](x * y [+ -] z).
// _ N A S
// D U
// D B
//
// Note: multiplication commutativity handled by rule generator.
(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)
(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMSUB|MSUB|NMADD|MADD)D x y z)
(F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)

View File

@ -3322,7 +3322,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
v_0 := v.Args[0]
// match: (FMADDD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
// result: (FNMADDD x y z)
// result: (FNMSUBD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@ -3335,7 +3335,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
v.reset(OpRISCV64FNMADDD)
v.reset(OpRISCV64FNMSUBD)
v.AddArg3(x, y, z)
return true
}
@ -3367,7 +3367,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
v_0 := v.Args[0]
// match: (FMSUBD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
// result: (FNMSUBD x y z)
// result: (FNMADDD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@ -3380,7 +3380,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
v.reset(OpRISCV64FNMSUBD)
v.reset(OpRISCV64FNMADDD)
v.AddArg3(x, y, z)
return true
}
@ -3412,7 +3412,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
v_0 := v.Args[0]
// match: (FNMADDD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
// result: (FMADDD x y z)
// result: (FMSUBD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@ -3425,7 +3425,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
v.reset(OpRISCV64FMADDD)
v.reset(OpRISCV64FMSUBD)
v.AddArg3(x, y, z)
return true
}
@ -3457,7 +3457,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
v_0 := v.Args[0]
// match: (FNMSUBD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
// result: (FMSUBD x y z)
// result: (FMADDD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@ -3470,7 +3470,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
v.reset(OpRISCV64FMSUBD)
v.reset(OpRISCV64FMADDD)
v.AddArg3(x, y, z)
return true
}

View File

@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"go/constant"
"internal/goversion"
. "internal/types/errors"
)
@ -231,19 +232,19 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
info = new(Info)
}
version, err := parseGoVersion(conf.GoVersion)
if err != nil {
panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
}
// Note: clients may call NewChecker with the Unsafe package, which is
// globally shared and must not be mutated. Therefore NewChecker must not
// mutate *pkg.
//
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
return &Checker{
conf: conf,
ctxt: conf.Context,
pkg: pkg,
Info: info,
version: version,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
conf: conf,
ctxt: conf.Context,
pkg: pkg,
Info: info,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
}
}
@ -333,6 +334,20 @@ func (check *Checker) Files(files []*syntax.File) error { return check.checkFile
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
func (check *Checker) checkFiles(files []*syntax.File) (err error) {
if check.pkg == Unsafe {
// Defensive handling for Unsafe, which cannot be type checked, and must
// not be mutated. See https://go.dev/issue/61212 for an example of where
// Unsafe is passed to NewChecker.
return nil
}
check.version, err = parseGoVersion(check.conf.GoVersion)
if err != nil {
return err
}
if check.version.after(version{1, goversion.Version}) {
return fmt.Errorf("package requires newer Go version %v", check.version)
}
if check.conf.FakeImportC && check.conf.go115UsesCgo {
return errBadCgo
}
@ -377,6 +392,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
check.monomorph()
}
check.pkg.goVersion = check.conf.GoVersion
check.pkg.complete = true
// no longer needed - release memory

View File

@ -497,14 +497,14 @@ func TestIssue43088(t *testing.T) {
// _ T2
// }
// }
n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil)
n1 := NewTypeName(nopos, nil, "T1", nil)
T1 := NewNamed(n1, nil, nil)
n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil)
n2 := NewTypeName(nopos, nil, "T2", nil)
T2 := NewNamed(n2, nil, nil)
s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
T1.SetUnderlying(s1)
s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil)
s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
T2.SetUnderlying(s3)
// These calls must terminate (no endless recursion).
@ -535,38 +535,69 @@ func TestIssue44515(t *testing.T) {
}
func TestIssue43124(t *testing.T) {
testenv.MustHaveGoBuild(t)
// TODO(rFindley) move this to testdata by enhancing support for importing.
testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files.
// All involved packages have the same name (template). Error messages should
// disambiguate between text/template and html/template by printing the full
// path.
const (
asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
bsrc = `
package b
import (
"a"
"html/template"
)
func _() {
// Packages should be fully qualified when there is ambiguity within the
// error string itself.
a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
}
`
csrc = `
package c
import (
"a"
"fmt"
"html/template"
)
// go.dev/issue/46905: make sure template is not the first package qualified.
var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
// Packages should be fully qualified when there is ambiguity in reachable
// packages. In this case both a (and for that matter html/template) import
// text/template.
func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) }
`
tsrc = `
package template
import "text/template"
type T int
// Verify that the current package name also causes disambiguation.
var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{}
`
)
a := mustTypecheck(asrc, nil, nil)
conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
imp := importHelper{pkg: a, fallback: defaultImporter()}
// Packages should be fully qualified when there is ambiguity within the
// error string itself.
_, err := typecheck(bsrc, &conf, nil)
if err == nil {
t.Fatal("package b had no errors")
}
if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
t.Errorf("type checking error for b does not disambiguate package template: %q", err)
withImporter := func(cfg *Config) {
cfg.Importer = imp
}
// ...and also when there is any ambiguity in reachable packages.
_, err = typecheck(csrc, &conf, nil)
if err == nil {
t.Fatal("package c had no errors")
}
if !strings.Contains(err.Error(), "html/template") {
t.Errorf("type checking error for c does not disambiguate package template: %q", err)
}
testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, 0, false, withImporter)
testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, 0, false, withImporter)
testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, 0, false, withImporter)
}
func TestIssue50646(t *testing.T) {

View File

@ -10,13 +10,14 @@ import (
// A Package describes a Go package.
type Package struct {
path string
name string
scope *Scope
imports []*Package
complete bool
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
path string
name string
scope *Scope
imports []*Package
complete bool
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
}
// NewPackage returns a new Package for the given package path and name.
@ -35,6 +36,12 @@ func (pkg *Package) Name() string { return pkg.name }
// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }
// GoVersion returns the minimum Go version required by this package.
// If the minimum version is unknown, GoVersion returns the empty string.
// Individual source files may specify a different minimum Go version,
// as reported in the [go/ast.File.GoVersion] field.
func (pkg *Package) GoVersion() string { return pkg.goVersion }
// Scope returns the (complete or incomplete) package scope
// holding the objects declared at package level (TypeNames,
// Consts, Vars, and Funcs).

View File

@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) {
// Misc
{Scope{}, 60, 104},
{Package{}, 36, 72},
{Package{}, 44, 88},
{_TypeSet{}, 28, 56},
}

View File

@ -6,7 +6,6 @@ package types2
import (
"cmd/compile/internal/syntax"
"errors"
"fmt"
"strings"
)
@ -44,23 +43,24 @@ var (
go1_21 = version{1, 21}
)
var errVersionSyntax = errors.New("invalid Go version syntax")
// parseGoVersion parses a Go version string (such as "go1.12")
// and returns the version, or an error. If s is the empty
// string, the version is 0.0.
func parseGoVersion(s string) (v version, err error) {
bad := func() (version, error) {
return version{}, fmt.Errorf("invalid Go version syntax %q", s)
}
if s == "" {
return
}
if !strings.HasPrefix(s, "go") {
return version{}, errVersionSyntax
return bad()
}
s = s[len("go"):]
i := 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
return version{}, errVersionSyntax
return bad()
}
v.major = 10*v.major + int(s[i]) - '0'
}
@ -68,7 +68,7 @@ func parseGoVersion(s string) (v version, err error) {
return
}
if i == 0 || s[i] != '.' {
return version{}, errVersionSyntax
return bad()
}
s = s[i+1:]
if s == "0" {
@ -81,14 +81,15 @@ func parseGoVersion(s string) (v version, err error) {
i = 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
return version{}, errVersionSyntax
return bad()
}
v.minor = 10*v.minor + int(s[i]) - '0'
}
if i > 0 && i == len(s) {
return
}
return version{}, errVersionSyntax
// Accept any suffix after the minor number.
// We are only looking for the language version (major.minor)
// but want to accept any valid Go version, like go1.21.0
// and go1.21rc2.
return
}
// langCompat reports an error if the representation of a numeric

View File

@ -0,0 +1,24 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types2
import "testing"
var parseGoVersionTests = []struct {
in string
out version
}{
{"go1.21", version{1, 21}},
{"go1.21.0", version{1, 21}},
{"go1.21rc2", version{1, 21}},
}
func TestParseGoVersion(t *testing.T) {
for _, tt := range parseGoVersionTests {
if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
}
}
}

View File

@ -1115,6 +1115,7 @@ type vetConfig struct {
PackageVetx map[string]string // map package path to vetx data from earlier vet run
VetxOnly bool // only compute vetx data; don't report detected problems
VetxOutput string // write vetx data to this output file
GoVersion string // Go version for package
SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
}
@ -1149,6 +1150,13 @@ func buildVetConfig(a *Action, srcfiles []string) {
PackageFile: make(map[string]string),
Standard: make(map[string]bool),
}
if a.Package.Module != nil {
v := a.Package.Module.GoVersion
if v == "" {
v = gover.DefaultGoModVersion
}
vcfg.GoVersion = "go" + v
}
a.vetCfg = vcfg
for i, raw := range a.Package.Internal.RawImports {
final := a.Package.Imports[i]

View File

@ -85,19 +85,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
if p.Module != nil {
v := p.Module.GoVersion
if v == "" {
// We started adding a 'go' directive to the go.mod file unconditionally
// as of Go 1.12, so any module that still lacks such a directive must
// either have been authored before then, or have a hand-edited go.mod
// file that hasn't been updated by cmd/go since that edit.
//
// Unfortunately, through at least Go 1.16 we didn't add versions to
// vendor/modules.txt. So this could also be a vendored 1.16 dependency.
//
// Fortunately, there were no breaking changes to the language between Go
// 1.11 and 1.16, so if we assume Go 1.16 semantics we will not introduce
// any spurious errors — we will only mask errors, and not particularly
// important ones at that.
v = "1.16"
v = gover.DefaultGoModVersion
}
if allowedVersion(v) {
defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(v))

View File

@ -2944,15 +2944,17 @@ func (rs *Rows) initContextClose(ctx, txctx context.Context) {
if bypassRowsAwaitDone {
return
}
ctx, rs.cancel = context.WithCancel(ctx)
go rs.awaitDone(ctx, txctx)
closectx, cancel := context.WithCancel(ctx)
rs.cancel = cancel
go rs.awaitDone(ctx, txctx, closectx)
}
// awaitDone blocks until either ctx or txctx is canceled. The ctx is provided
// from the query context and is canceled when the query Rows is closed.
// awaitDone blocks until ctx, txctx, or closectx is canceled.
// The ctx is provided from the query context.
// If the query was issued in a transaction, the transaction's context
// is also provided in txctx to ensure Rows is closed if the Tx is closed.
func (rs *Rows) awaitDone(ctx, txctx context.Context) {
// is also provided in txctx, to ensure Rows is closed if the Tx is closed.
// The closectx is closed by an explicit call to rs.Close.
func (rs *Rows) awaitDone(ctx, txctx, closectx context.Context) {
var txctxDone <-chan struct{}
if txctx != nil {
txctxDone = txctx.Done()
@ -2964,6 +2966,9 @@ func (rs *Rows) awaitDone(ctx, txctx context.Context) {
case <-txctxDone:
err := txctx.Err()
rs.contextDone.Store(&err)
case <-closectx.Done():
// rs.cancel was called via Close(); don't store this into contextDone
// to ensure Err() is unaffected.
}
rs.close(ctx.Err())
}

View File

@ -4493,6 +4493,31 @@ func TestContextCancelBetweenNextAndErr(t *testing.T) {
}
}
func TestNilErrorAfterClose(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
// This WithCancel is important; Rows contains an optimization to avoid
// spawning a goroutine when the query/transaction context cannot be
// canceled, but this test tests a bug which is caused by said goroutine.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r, err := db.QueryContext(ctx, "SELECT|people|name|")
if err != nil {
t.Fatal(err)
}
if err := r.Close(); err != nil {
t.Fatal(err)
}
time.Sleep(10 * time.Millisecond) // increase odds of seeing failure
if err := r.Err(); err != nil {
t.Fatal(err)
}
}
// badConn implements a bad driver.Conn, for TestBadDriver.
// The Exec method panics.
type badConn struct{}

View File

@ -286,7 +286,7 @@ var depsRules = `
math/big, go/token
< go/constant;
container/heap, go/constant, go/parser, internal/types/errors
container/heap, go/constant, go/parser, internal/goversion, internal/types/errors
< go/types;
# The vast majority of standard library packages should not be resorting to regexp.

View File

@ -12,6 +12,7 @@ import (
"go/ast"
"go/constant"
"go/token"
"internal/goversion"
. "internal/types/errors"
)
@ -233,20 +234,20 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
info = new(Info)
}
version, err := parseGoVersion(conf.GoVersion)
if err != nil {
panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
}
// Note: clients may call NewChecker with the Unsafe package, which is
// globally shared and must not be mutated. Therefore NewChecker must not
// mutate *pkg.
//
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
return &Checker{
conf: conf,
ctxt: conf.Context,
fset: fset,
pkg: pkg,
Info: info,
version: version,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
conf: conf,
ctxt: conf.Context,
fset: fset,
pkg: pkg,
Info: info,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
}
}
@ -342,6 +343,20 @@ func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(f
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
func (check *Checker) checkFiles(files []*ast.File) (err error) {
if check.pkg == Unsafe {
// Defensive handling for Unsafe, which cannot be type checked, and must
// not be mutated. See https://go.dev/issue/61212 for an example of where
// Unsafe is passed to NewChecker.
return nil
}
check.version, err = parseGoVersion(check.conf.GoVersion)
if err != nil {
return err
}
if check.version.after(version{1, goversion.Version}) {
return fmt.Errorf("package requires newer Go version %v", check.version)
}
if check.conf.FakeImportC && check.conf.go115UsesCgo {
return errBadCgo
}
@ -386,6 +401,7 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
check.monomorph()
}
check.pkg.goVersion = check.conf.GoVersion
check.pkg.complete = true
// no longer needed - release memory

View File

@ -141,6 +141,7 @@ var filemap = map[string]action{
"universe.go": fixGlobalTypVarDecl,
"util_test.go": fixTokenPos,
"validtype.go": nil,
"version_test.go": nil,
}
// TODO(gri) We should be able to make these rewriters more configurable/composable.

View File

@ -12,13 +12,14 @@ import (
// A Package describes a Go package.
type Package struct {
path string
name string
scope *Scope
imports []*Package
complete bool
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
path string
name string
scope *Scope
imports []*Package
complete bool
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
}
// NewPackage returns a new Package for the given package path and name.
@ -37,6 +38,12 @@ func (pkg *Package) Name() string { return pkg.name }
// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }
// GoVersion returns the minimum Go version required by this package.
// If the minimum version is unknown, GoVersion returns the empty string.
// Individual source files may specify a different minimum Go version,
// as reported in the [go/ast.File.GoVersion] field.
func (pkg *Package) GoVersion() string { return pkg.goVersion }
// Scope returns the (complete or incomplete) package scope
// holding the objects declared at package level (TypeNames,
// Consts, Vars, and Funcs).

View File

@ -46,7 +46,7 @@ func TestSizeof(t *testing.T) {
// Misc
{Scope{}, 44, 88},
{Package{}, 36, 72},
{Package{}, 44, 88},
{_TypeSet{}, 28, 56},
}
for _, test := range tests {

View File

@ -5,7 +5,6 @@
package types
import (
"errors"
"fmt"
"go/ast"
"go/token"
@ -45,23 +44,24 @@ var (
go1_21 = version{1, 21}
)
var errVersionSyntax = errors.New("invalid Go version syntax")
// parseGoVersion parses a Go version string (such as "go1.12")
// and returns the version, or an error. If s is the empty
// string, the version is 0.0.
func parseGoVersion(s string) (v version, err error) {
bad := func() (version, error) {
return version{}, fmt.Errorf("invalid Go version syntax %q", s)
}
if s == "" {
return
}
if !strings.HasPrefix(s, "go") {
return version{}, errVersionSyntax
return bad()
}
s = s[len("go"):]
i := 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
return version{}, errVersionSyntax
return bad()
}
v.major = 10*v.major + int(s[i]) - '0'
}
@ -69,7 +69,7 @@ func parseGoVersion(s string) (v version, err error) {
return
}
if i == 0 || s[i] != '.' {
return version{}, errVersionSyntax
return bad()
}
s = s[i+1:]
if s == "0" {
@ -82,14 +82,15 @@ func parseGoVersion(s string) (v version, err error) {
i = 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
return version{}, errVersionSyntax
return bad()
}
v.minor = 10*v.minor + int(s[i]) - '0'
}
if i > 0 && i == len(s) {
return
}
return version{}, errVersionSyntax
// Accept any suffix after the minor number.
// We are only looking for the language version (major.minor)
// but want to accept any valid Go version, like go1.21.0
// and go1.21rc2.
return
}
// langCompat reports an error if the representation of a numeric

View File

@ -0,0 +1,26 @@
// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "testing"
var parseGoVersionTests = []struct {
in string
out version
}{
{"go1.21", version{1, 21}},
{"go1.21.0", version{1, 21}},
{"go1.21rc2", version{1, 21}},
}
func TestParseGoVersion(t *testing.T) {
for _, tt := range parseGoVersionTests {
if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
}
}
}

View File

@ -221,6 +221,11 @@ func (h *commonHandler) enabled(l Level) bool {
}
func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
// We are going to ignore empty groups, so if the entire slice consists of
// them, there is nothing to do.
if countEmptyGroups(as) == len(as) {
return h
}
h2 := h.clone()
// Pre-format the attributes as an optimization.
state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "")
@ -308,15 +313,20 @@ func (s *handleState) appendNonBuiltIns(r Record) {
}
// Attrs in Record -- unlike the built-in ones, they are in groups started
// from WithGroup.
s.prefix.WriteString(s.h.groupPrefix)
s.openGroups()
r.Attrs(func(a Attr) bool {
s.appendAttr(a)
return true
})
// If the record has no Attrs, don't output any groups.
nOpenGroups := s.h.nOpenGroups
if r.NumAttrs() > 0 {
s.prefix.WriteString(s.h.groupPrefix)
s.openGroups()
nOpenGroups = len(s.h.groups)
r.Attrs(func(a Attr) bool {
s.appendAttr(a)
return true
})
}
if s.h.json {
// Close all open groups.
for range s.h.groups {
for range s.h.groups[:nOpenGroups] {
s.buf.WriteByte('}')
}
// Close the top-level object.

View File

@ -214,6 +214,28 @@ func TestJSONAndTextHandlers(t *testing.T) {
wantText: "msg=message h.a=1",
wantJSON: `{"msg":"message","h":{"a":1}}`,
},
{
name: "nested empty group",
replace: removeKeys(TimeKey, LevelKey),
attrs: []Attr{
Group("g",
Group("h",
Group("i"), Group("j"))),
},
wantText: `msg=message`,
wantJSON: `{"msg":"message"}`,
},
{
name: "nested non-empty group",
replace: removeKeys(TimeKey, LevelKey),
attrs: []Attr{
Group("g",
Group("h",
Group("i"), Group("j", Int("a", 1)))),
},
wantText: `msg=message g.h.j.a=1`,
wantJSON: `{"msg":"message","g":{"h":{"j":{"a":1}}}}`,
},
{
name: "escapes",
replace: removeKeys(TimeKey, LevelKey),
@ -281,6 +303,34 @@ func TestJSONAndTextHandlers(t *testing.T) {
wantText: "msg=message p1=1 s1.s2.a=one s1.s2.b=2",
wantJSON: `{"msg":"message","p1":1,"s1":{"s2":{"a":"one","b":2}}}`,
},
{
name: "empty with-groups",
replace: removeKeys(TimeKey, LevelKey),
with: func(h Handler) Handler {
return h.WithGroup("x").WithGroup("y")
},
wantText: "msg=message",
wantJSON: `{"msg":"message"}`,
},
{
name: "empty with-groups, no non-empty attrs",
replace: removeKeys(TimeKey, LevelKey),
with: func(h Handler) Handler {
return h.WithGroup("x").WithAttrs([]Attr{Group("g")}).WithGroup("y")
},
wantText: "msg=message",
wantJSON: `{"msg":"message"}`,
},
{
name: "one empty with-group",
replace: removeKeys(TimeKey, LevelKey),
with: func(h Handler) Handler {
return h.WithGroup("x").WithAttrs([]Attr{Int("a", 1)}).WithGroup("y")
},
attrs: []Attr{Group("g", Group("h"))},
wantText: "msg=message x.a=1",
wantJSON: `{"msg":"message","x":{"a":1}}`,
},
{
name: "GroupValue as Attr value",
replace: removeKeys(TimeKey, LevelKey),

View File

@ -106,7 +106,7 @@ func TestConnections(t *testing.T) {
// log.Logger's output goes through the handler.
SetDefault(New(NewTextHandler(&slogbuf, &HandlerOptions{AddSource: true})))
log.Print("msg2")
checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3} msg=msg2`)
checkLogOutput(t, slogbuf.String(), "time="+timeRE+` level=INFO source=.*logger_test.go:\d{3}"? msg=msg2`)
// The default log.Logger always outputs at Info level.
slogbuf.Reset()

View File

@ -93,9 +93,17 @@ func (r Record) Attrs(f func(Attr) bool) {
}
// AddAttrs appends the given Attrs to the Record's list of Attrs.
// It omits empty groups.
func (r *Record) AddAttrs(attrs ...Attr) {
n := copy(r.front[r.nFront:], attrs)
r.nFront += n
var i int
for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ {
a := attrs[i]
if a.Value.isEmptyGroup() {
continue
}
r.front[r.nFront] = a
r.nFront++
}
// Check if a copy was modified by slicing past the end
// and seeing if the Attr there is non-zero.
if cap(r.back) > len(r.back) {
@ -104,15 +112,25 @@ func (r *Record) AddAttrs(attrs ...Attr) {
panic("copies of a slog.Record were both modified")
}
}
r.back = append(r.back, attrs[n:]...)
ne := countEmptyGroups(attrs[i:])
r.back = slices.Grow(r.back, len(attrs[i:])-ne)
for _, a := range attrs[i:] {
if !a.Value.isEmptyGroup() {
r.back = append(r.back, a)
}
}
}
// Add converts the args to Attrs as described in [Logger.Log],
// then appends the Attrs to the Record's list of Attrs.
// It omits empty groups.
func (r *Record) Add(args ...any) {
var a Attr
for len(args) > 0 {
a, args = argsToAttr(args)
if a.Value.isEmptyGroup() {
continue
}
if r.nFront < len(r.front) {
r.front[r.nFront] = a
r.nFront++

View File

@ -164,9 +164,32 @@ func DurationValue(v time.Duration) Value {
// GroupValue returns a new Value for a list of Attrs.
// The caller must not subsequently mutate the argument slice.
func GroupValue(as ...Attr) Value {
// Remove empty groups.
// It is simpler overall to do this at construction than
// to check each Group recursively for emptiness.
if n := countEmptyGroups(as); n > 0 {
as2 := make([]Attr, 0, len(as)-n)
for _, a := range as {
if !a.Value.isEmptyGroup() {
as2 = append(as2, a)
}
}
as = as2
}
return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
}
// countEmptyGroups returns the number of empty group values in its argument.
func countEmptyGroups(as []Attr) int {
n := 0
for _, a := range as {
if a.Value.isEmptyGroup() {
n++
}
}
return n
}
// AnyValue returns a Value for the supplied value.
//
// If the supplied value is of type Value, it is returned
@ -399,6 +422,17 @@ func (v Value) Equal(w Value) bool {
}
}
// isEmptyGroup reports whether v is a group that has no attributes.
func (v Value) isEmptyGroup() bool {
if v.Kind() != KindGroup {
return false
}
// We do not need to recursively examine the group's Attrs for emptiness,
// because GroupValue removed them when the group was constructed, and
// groups are immutable.
return len(v.group()) == 0
}
// append appends a text representation of v to dst.
// v is formatted as with fmt.Sprint.
func (v Value) append(dst []byte) []byte {

View File

@ -229,6 +229,18 @@ func TestZeroTime(t *testing.T) {
}
}
func TestEmptyGroup(t *testing.T) {
g := GroupValue(
Int("a", 1),
Group("g1", Group("g2")),
Group("g3", Group("g4", Int("b", 2))))
got := g.Group()
want := []Attr{Int("a", 1), Group("g3", Group("g4", Int("b", 2)))}
if !attrsEqual(got, want) {
t.Errorf("\ngot %v\nwant %v", got, want)
}
}
type replace struct {
v Value
}

View File

@ -2059,6 +2059,9 @@ var fmaC = []struct{ x, y, z, want float64 }{
// Special
{0, 0, 0, 0},
{Copysign(0, -1), 0, 0, 0},
{0, 0, Copysign(0, -1), 0},
{Copysign(0, -1), 0, Copysign(0, -1), Copysign(0, -1)},
{-1.1754226043408471e-38, NaN(), Inf(0), NaN()},
{0, 0, 2.22507385643494e-308, 2.22507385643494e-308},
{-8.65697792e+09, NaN(), -7.516192799999999e+09, NaN()},
@ -2077,6 +2080,10 @@ var fmaC = []struct{ x, y, z, want float64 }{
{4.612811918325842e+18, 1.4901161193847641e-08, 2.6077032311277997e-08, 6.873625395187494e+10},
{-9.094947033611148e-13, 4.450691014249257e-308, 2.086006742350485e-308, 2.086006742346437e-308},
{-7.751454006381804e-05, 5.588653777189071e-308, -2.2207280111272877e-308, -2.2211612130544025e-308},
// Issue #61130
{-1, 1, 1, 0},
{1, 1, -1, 0},
}
var sqrt32 = []float32{
@ -3099,6 +3106,45 @@ func TestFMA(t *testing.T) {
}
}
//go:noinline
func fmsub(x, y, z float64) float64 {
return FMA(x, y, -z)
}
//go:noinline
func fnmsub(x, y, z float64) float64 {
return FMA(-x, y, z)
}
//go:noinline
func fnmadd(x, y, z float64) float64 {
return FMA(-x, y, -z)
}
func TestFMANegativeArgs(t *testing.T) {
// Some architectures have instructions for fused multiply-subtract and
// also negated variants of fused multiply-add and subtract. This test
// aims to check that the optimizations that generate those instructions
// are applied correctly, if they exist.
for _, c := range fmaC {
want := PortableFMA(c.x, c.y, -c.z)
got := fmsub(c.x, c.y, c.z)
if !alike(got, want) {
t.Errorf("FMA(%g, %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
}
want = PortableFMA(-c.x, c.y, c.z)
got = fnmsub(c.x, c.y, c.z)
if !alike(got, want) {
t.Errorf("FMA(-(%g), %g, %g) == %g, want %g", c.x, c.y, c.z, got, want)
}
want = PortableFMA(-c.x, c.y, -c.z)
got = fnmadd(c.x, c.y, c.z)
if !alike(got, want) {
t.Errorf("FMA(-(%g), %g, -(%g)) == %g, want %g", c.x, c.y, c.z, got, want)
}
}
}
// Check that math functions of high angle values
// return accurate results. [Since (vf[i] + large) - large != vf[i],
// testing for Trig(vf[i] + large) == Trig(vf[i]), where large is

View File

@ -132,6 +132,11 @@ func FMA(x, y, z float64) float64 {
ps, pe, pm1, pm2, zs, ze, zm1, zm2 = zs, ze, zm1, zm2, ps, pe, pm1, pm2
}
// Special case: if p == -z the result is always +0 since neither operand is zero.
if ps != zs && pe == ze && pm1 == zm1 && pm2 == zm2 {
return 0
}
// Align significands
zm1, zm2 = shrcompress(zm1, zm2, uint(pe-ze))

View File

@ -3,12 +3,13 @@
// license that can be found in the LICENSE file.
// This file holds stub versions of the cgo functions called on Unix systems.
// We build this file if using the netgo build tag, or if cgo is not
// enabled and we are using a Unix system other than Darwin.
// Darwin is exempted because it always provides the cgo routines,
// in cgo_unix_syscall.go.
// We build this file:
// - if using the netgo build tag on a Unix system
// - on a Unix system without the cgo resolver functions
// (Darwin always provides the cgo functions, in cgo_unix_syscall.go)
// - on wasip1, where cgo is never available
//go:build netgo || (!cgo && unix && !darwin)
//go:build (netgo && unix) || (unix && !cgo && !darwin) || wasip1
package net

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !js && !wasip1
//go:build !js
package net

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !js && !wasip1
//go:build !js
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !js && !wasip1 && !windows
//go:build !js && !windows
// Read system DNS config from /etc/resolv.conf

View File

@ -48,35 +48,6 @@ func TestForeachHeaderElement(t *testing.T) {
}
}
func TestCleanHost(t *testing.T) {
tests := []struct {
in, want string
}{
{"www.google.com", "www.google.com"},
{"www.google.com foo", "www.google.com"},
{"www.google.com/foo", "www.google.com"},
{" first character is a space", ""},
{"[1::6]:8080", "[1::6]:8080"},
// Punycode:
{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
{"bücher.de", "xn--bcher-kva.de"},
{"bücher.de:8080", "xn--bcher-kva.de:8080"},
// Verify we convert to lowercase before punycode:
{"BÜCHER.de", "xn--bcher-kva.de"},
{"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
// Verify we normalize to NFC before punycode:
{"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
{"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
}
for _, tt := range tests {
got := cleanHost(tt.in)
if tt.want != got {
t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
// Test that cmd/go doesn't link in the HTTP server.
//
// This catches accidental dependencies between the HTTP transport and

View File

@ -17,7 +17,6 @@ import (
"io"
"mime"
"mime/multipart"
"net"
"net/http/httptrace"
"net/http/internal/ascii"
"net/textproto"
@ -27,6 +26,7 @@ import (
"strings"
"sync"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/idna"
)
@ -580,12 +580,19 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
// is not given, use the host from the request URL.
//
// Clean the host, in case it arrives with unexpected stuff in it.
host := cleanHost(r.Host)
host := r.Host
if host == "" {
if r.URL == nil {
return errMissingHost
}
host = cleanHost(r.URL.Host)
host = r.URL.Host
}
host, err = httpguts.PunycodeHostPort(host)
if err != nil {
return err
}
if !httpguts.ValidHostHeader(host) {
return errors.New("http: invalid Host header")
}
// According to RFC 6874, an HTTP client, proxy, or other
@ -742,40 +749,6 @@ func idnaASCII(v string) (string, error) {
return idna.Lookup.ToASCII(v)
}
// cleanHost cleans up the host sent in request's Host header.
//
// It both strips anything after '/' or ' ', and puts the value
// into Punycode form, if necessary.
//
// Ideally we'd clean the Host header according to the spec:
//
// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
//
// But practically, what we are trying to avoid is the situation in
// issue 11206, where a malformed Host header used in the proxy context
// would create a bad request. So it is enough to just truncate at the
// first offending character.
func cleanHost(in string) string {
if i := strings.IndexAny(in, " /"); i != -1 {
in = in[:i]
}
host, port, err := net.SplitHostPort(in)
if err != nil { // input was just a host
a, err := idnaASCII(in)
if err != nil {
return in // garbage in, garbage out
}
return a
}
a, err := idnaASCII(host)
if err != nil {
return in // garbage in, garbage out
}
return net.JoinHostPort(a, port)
}
// removeZone removes IPv6 zone identifier from host.
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
func removeZone(host string) string {

View File

@ -775,15 +775,8 @@ func TestRequestBadHost(t *testing.T) {
}
req.Host = "foo.com with spaces"
req.URL.Host = "foo.com with spaces"
req.Write(logWrites{t, &got})
want := []string{
"GET /after HTTP/1.1\r\n",
"Host: foo.com\r\n",
"User-Agent: " + DefaultUserAgent + "\r\n",
"\r\n",
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Writes = %q\n Want = %q", got, want)
if err := req.Write(logWrites{t, &got}); err == nil {
t.Errorf("Writing request with invalid Host: succeded, want error")
}
}

View File

@ -6731,3 +6731,22 @@ func testHandlerAbortRacesBodyRead(t *testing.T, mode testMode) {
}
wg.Wait()
}
func TestRequestSanitization(t *testing.T) { run(t, testRequestSanitization) }
func testRequestSanitization(t *testing.T, mode testMode) {
if mode == http2Mode {
// Remove this after updating x/net.
t.Skip("https://go.dev/issue/60374 test fails when run with HTTP/2")
}
ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
if h, ok := req.Header["X-Evil"]; ok {
t.Errorf("request has X-Evil header: %q", h)
}
})).ts
req, _ := NewRequest("GET", ts.URL, nil)
req.Host = "go.dev\r\nX-Evil:evil"
resp, _ := ts.Client().Do(req)
if resp != nil {
resp.Body.Close()
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (js && wasm) || wasip1
//go:build js && wasm
package net

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build unix
//go:build unix || wasip1
package net

View File

@ -15,8 +15,6 @@ import (
"sync"
"syscall"
"time"
"golang.org/x/net/dns/dnsmessage"
)
var listenersMu sync.Mutex
@ -406,7 +404,3 @@ func (fd *fakeNetFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int,
func (fd *fakeNetFD) dup() (f *os.File, err error) {
return nil, syscall.ENOSYS
}
func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
panic("unreachable")
}

View File

@ -8,7 +8,12 @@
package net
import "internal/poll"
import (
"context"
"internal/poll"
"golang.org/x/net/dns/dnsmessage"
)
// Network file descriptor.
type netFD struct {
@ -25,3 +30,7 @@ type netFD struct {
pfd poll.FD
isConnected bool // handshake completed or use of association with peer
}
func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Type, conf *dnsConfig) (dnsmessage.Parser, string, error) {
panic("unreachable")
}

View File

@ -54,6 +54,15 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn
if entptr == nil { // EOF
break
}
// Darwin may return a zero inode when a directory entry has been
// deleted but not yet removed from the directory. The man page for
// getdirentries(2) states that programs are responsible for skipping
// those entries:
//
// Users of getdirentries() should skip entries with d_fileno = 0,
// as such entries represent files which have been deleted but not
// yet removed from the directory entry.
//
if dirent.Ino == 0 {
continue
}

View File

@ -89,7 +89,11 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn
if !ok {
break
}
if ino == 0 {
// When building to wasip1, the host runtime might be running on Windows
// or might expose a remote file system which does not have the concept
// of inodes. Therefore, we cannot make the assumption that it is safe
// to skip entries with zero inodes.
if ino == 0 && runtime.GOOS != "wasip1" {
continue
}
const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))

View File

@ -130,7 +130,7 @@ func TestClearenv(t *testing.T) {
defer func(origEnv []string) {
for _, pair := range origEnv {
// Environment variables on Windows can begin with =
// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
i := strings.Index(pair[1:], "=") + 1
if err := Setenv(pair[:i], pair[i+1:]); err != nil {
t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)

View File

@ -534,7 +534,7 @@ func TestMemPprof(t *testing.T) {
got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput()
if err != nil {
t.Fatal(err)
t.Fatalf("testprog failed: %s, output:\n%s", err, got)
}
fn := strings.TrimSpace(string(got))
defer os.Remove(fn)

View File

@ -76,7 +76,7 @@ func TestCrashDumpsAllThreads(t *testing.T) {
testenv.MustHaveGoBuild(t)
if strings.Contains(os.Getenv("GCFLAGS"), "mayMoreStackPreempt") {
if strings.Contains(os.Getenv("GOFLAGS"), "mayMoreStackPreempt") {
// This test occasionally times out in this debug mode. This is probably
// revealing a real bug in the scheduler, but since it seems to only
// affect this test and this is itself a test of a debug mode, it's not

View File

@ -339,9 +339,11 @@ var allDesc = []Description{
Kind: KindUint64,
},
{
Name: "/memory/classes/heap/stacks:bytes",
Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use.",
Kind: KindUint64,
Name: "/memory/classes/heap/stacks:bytes",
Description: "Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use. " +
"Currently, this represents all stack memory for goroutines. It also includes all OS thread stacks in non-cgo programs. " +
"Note that stacks may be allocated differently in the future, and this may change.",
Kind: KindUint64,
},
{
Name: "/memory/classes/heap/unused:bytes",
@ -374,9 +376,13 @@ var allDesc = []Description{
Kind: KindUint64,
},
{
Name: "/memory/classes/os-stacks:bytes",
Description: "Stack memory allocated by the underlying operating system.",
Kind: KindUint64,
Name: "/memory/classes/os-stacks:bytes",
Description: "Stack memory allocated by the underlying operating system. " +
"In non-cgo programs this metric is currently zero. This may change in the future." +
"In cgo programs this metric includes OS thread stacks allocated directly from the OS. " +
"Currently, this only accounts for one stack in c-shared and c-archive build modes, " +
"and other sources of stacks from the OS are not measured. This too may change in the future.",
Kind: KindUint64,
},
{
Name: "/memory/classes/other:bytes",

View File

@ -318,7 +318,10 @@ Below is the full list of supported metrics, ordered lexicographically.
/memory/classes/heap/stacks:bytes
Memory allocated from the heap that is reserved for stack space,
whether or not it is currently in-use.
whether or not it is currently in-use. Currently, this
represents all stack memory for goroutines. It also includes all
OS thread stacks in non-cgo programs. Note that stacks may be
allocated differently in the future, and this may change.
/memory/classes/heap/unused:bytes
Memory that is reserved for heap objects but is not currently
@ -345,6 +348,12 @@ Below is the full list of supported metrics, ordered lexicographically.
/memory/classes/os-stacks:bytes
Stack memory allocated by the underlying operating system.
In non-cgo programs this metric is currently zero. This may
change in the future.In cgo programs this metric includes
OS thread stacks allocated directly from the OS. Currently,
this only accounts for one stack in c-shared and c-archive build
modes, and other sources of stacks from the OS are not measured.
This too may change in the future.
/memory/classes/other:bytes
Memory used by execution trace buffers, structures for debugging

View File

@ -199,7 +199,17 @@ type MemStats struct {
// StackSys is bytes of stack memory obtained from the OS.
//
// StackSys is StackInuse, plus any memory obtained directly
// from the OS for OS thread stacks (which should be minimal).
// from the OS for OS thread stacks.
//
// In non-cgo programs this metric is currently equal to StackInuse
// (but this should not be relied upon, and the value may change in
// the future).
//
// In cgo programs this metric includes OS thread stacks allocated
// directly from the OS. Currently, this only accounts for one stack in
// c-shared and c-archive build modes and other sources of stacks from
// the OS (notably, any allocated by C code) are not currently measured.
// Note this too may change in the future.
StackSys uint64
// Off-heap memory statistics.
@ -347,6 +357,7 @@ func init() {
// which is a snapshot as of the most recently completed garbage
// collection cycle.
func ReadMemStats(m *MemStats) {
_ = m.Alloc // nil check test before we switch stacks, see issue 61158
stopTheWorld(stwReadMemStats)
systemstack(func() {

View File

@ -1147,6 +1147,7 @@ func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool {
// isExportedRuntime reports whether name is an exported runtime function.
// It is only for runtime functions, so ASCII A-Z is fine.
// TODO: this handles exported functions but not exported methods.
func isExportedRuntime(name string) bool {
const n = len("runtime.")
return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'

View File

@ -6,7 +6,10 @@
package syscall
import "unsafe"
import (
"runtime"
"unsafe"
)
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
@ -75,7 +78,9 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
if !ok {
break
}
if ino == 0 { // File absent in directory.
// See src/os/dir_unix.go for the reason why this condition is
// excluded on wasip1.
if ino == 0 && runtime.GOOS != "wasip1" { // File absent in directory.
continue
}
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))

View File

@ -62,7 +62,7 @@ func Clearenv() {
for _, s := range Environ() {
// Environment variables can begin with =
// so start looking for the separator = at j=1.
// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
for j := 1; j < len(s); j++ {
if s[j] == '=' {
Unsetenv(s[0:j])

View File

@ -478,3 +478,16 @@ func SetNonblock(fd int, nonblocking bool) error {
errno := fd_fdstat_set_flags(int32(fd), flags)
return errnoErr(errno)
}
type Rlimit struct {
Cur uint64
Max uint64
}
const (
RLIMIT_NOFILE = iota
)
func Getrlimit(which int, lim *Rlimit) error {
return ENOSYS
}

View File

@ -20,6 +20,7 @@ func Mul2(f float64) float64 {
// arm/7:"ADDD",-"MULD"
// arm64:"FADDD",-"FMULD"
// ppc64x:"FADD",-"FMUL"
// riscv64:"FADDD",-"FMULD"
return f * 2.0
}
@ -29,6 +30,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// arm/7:"MULD",-"DIVD"
// arm64:"FMULD",-"FDIVD"
// ppc64x:"FMUL",-"FDIV"
// riscv64:"FMULD",-"FDIVD"
x := f1 / 16.0
// 386/sse2:"MULSD",-"DIVSD"
@ -36,6 +38,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// arm/7:"MULD",-"DIVD"
// arm64:"FMULD",-"FDIVD"
// ppc64x:"FMUL",-"FDIVD"
// riscv64:"FMULD",-"FDIVD"
y := f2 / 0.125
// 386/sse2:"ADDSD",-"DIVSD",-"MULSD"
@ -43,6 +46,7 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
// arm/7:"ADDD",-"MULD",-"DIVD"
// arm64:"FADDD",-"FMULD",-"FDIVD"
// ppc64x:"FADD",-"FMUL",-"FDIV"
// riscv64:"FADDD",-"FMULD",-"FDIVD"
z := f3 / 0.5
return x, y, z

View File

@ -143,13 +143,13 @@ func fms(x, y, z float64) float64 {
return math.FMA(x, y, -z)
}
func fnma(x, y, z float64) float64 {
// riscv64:"FNMADDD"
func fnms(x, y, z float64) float64 {
// riscv64:"FNMSUBD",-"FNMADDD"
return math.FMA(-x, y, z)
}
func fnms(x, y, z float64) float64 {
// riscv64:"FNMSUBD"
func fnma(x, y, z float64) float64 {
// riscv64:"FNMADDD",-"FNMSUBD"
return math.FMA(x, -y, -z)
}