[dev.unified] all: merge master (993c387) into dev.unified

Conflicts:

- test/run.go: textual conflict in 1.18 known failures list

Merge List:

+ 2022-06-30 993c387032 os: simplify deadline fluctuation tests
+ 2022-06-30 4914e4e334 cmd/go/internal/modindex: remove spurious field from index_format documentation
+ 2022-06-30 981d5947af cmd/go: include module root in package index key
+ 2022-06-30 84db00ffd1 cmd/go: add a 'sleep' command for script tests
+ 2022-06-30 31b8c23c57 cmd/compile: fix prove pass when upper condition is <= maxint
+ 2022-06-30 17083a2fdf spec: retitle section on "Assignments" to "Assignment statements"
+ 2022-06-30 4d95fe6653 test: add regress test for #53619
+ 2022-06-29 6a7c64fde5 debug/pe: add IMAGE_FILE_MACHINE_LOONGARCH{64,32}
+ 2022-06-29 b2cc0fecc2 net/http: preserve nil values in Header.Clone
+ 2022-06-29 64ef16e777 cmd/internal/obj/arm64: save LR and SP in one instruction for small frames
+ 2022-06-29 0750107074 go/token: use atomics not Mutex for last file cache
+ 2022-06-29 e5017a93fc net/http: don't strip whitespace from Transfer-Encoding headers
+ 2022-06-29 20760cff00 runtime: add race annotations to cbs.lock
+ 2022-06-29 e6c0546c54 crypto/x509/pkix: move crl deprecation message
+ 2022-06-29 3562977b6f cmd/internal/obj/mips,s390x,riscv: save LR after decrementing SP
+ 2022-06-29 d6481d5b96 runtime: add race annotations to metricsSema
+ 2022-06-29 bd1783e812 crypto/x509: improve RevocationList documentation
+ 2022-06-28 160414ca6a cmd/internal/obj/arm64: fix BITCON constant printing error
+ 2022-06-28 a30f434667 cmd/go: pass --no-decorate when listing git tags for a commit
+ 2022-06-28 3580ef9d64 os/exec: on Windows, suppress ErrDot if the implicit path matches the explicit one
+ 2022-06-28 34f3ac5f16 cmd/compile: fix generic inter-inter comparisons from value switch statements
+ 2022-06-28 7df0a002e6 cmd/go/internal/modfetch: cache latest revinfo in Versions func
+ 2022-06-28 d5bf9604aa test: add more tests for const decls with ommitted RHS expressions
+ 2022-06-28 533082d1a0 test: add test that gofrontend failed to compile
+ 2022-06-28 47e792e22e runtime: clean up unused function gosave on loong64
+ 2022-06-28 a6e5be0d30 cmd/go: omit build metadata that may contain system paths when -trimpath is set
+ 2022-06-28 d3ffff2790 api: correct debug/pe issue number for Go 1.19 changes
+ 2022-06-28 751cae8855 cmd/go/internal/modload: fix doc comment
+ 2022-06-28 85d7bab91d go/printer: report allocs and set bytes
+ 2022-06-27 3af5280c00 net: really skip Windows PTR tests if we say we are skipping them
+ 2022-06-27 a42573c2f1 net: avoid darwin/arm64 platform bug in TestCloseWrite
+ 2022-06-27 68289f39f0 html/template: fix typo in content_test.go
+ 2022-06-27 c3bea70d9b cmd/link: link against libsynchronization.a for -race on windows
+ 2022-06-27 f093cf90bf test: add test that caused gofrontend crash
+ 2022-06-27 155612a9b9 test: add test that caused gofrontend crash
+ 2022-06-27 a861eee51a cmd/go: compile runtime/internal/syscall as a runtime package
+ 2022-06-27 8f9bfa9b7b crypto/internal/boring: factor Cache into crypto/internal/boring/bcache
+ 2022-06-26 351e0f4083 runtime: avoid fma in mkfastlog2table
+ 2022-06-26 416c953960 test: add test that gofrontend gets wrong
+ 2022-06-26 666d736ecb cmd/compile: do branch/label checks only once
+ 2022-06-26 6b309be7ab cmd/compile/internal/syntax: check fallthrough in CheckBranches mode
+ 2022-06-25 1821639b57 runtime: mark string comparison hooks as no split
+ 2022-06-25 3b594b9255 io: clarify SeekEnd offset value
+ 2022-06-25 4f45ec5963 cmd/go: prepend builtin prolog when checking for preamble errors
+ 2022-06-24 41e1d9075e strconv: avoid panic on invalid call to FormatFloat
+ 2022-06-24 bd4753905d internal/trace: add Go 1.19 test data
+ 2022-06-24 6b6c64b1cc cmd/internal/archive: don't rely on an erroneous install target in tests

Change-Id: Ib43126833bf534c311730d4283d4d25381cd3428
This commit is contained in:
Matthew Dempsky 2022-06-30 13:39:49 -07:00
commit 1b838e9556
94 changed files with 1350 additions and 443 deletions

View File

@ -114,42 +114,46 @@ pkg debug/elf, const R_LARCH_TLS_TPREL64 R_LARCH #46229
pkg debug/elf, method (R_LARCH) GoString() string #46229
pkg debug/elf, method (R_LARCH) String() string #46229
pkg debug/elf, type R_LARCH int #46229
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY = 2 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY ideal-int #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE ideal-int #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH = 4 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH ideal-int #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST = 6 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST ideal-int #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES = 1 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES ideal-int #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE = 3 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE ideal-int #51686
pkg debug/pe, const IMAGE_SCN_CNT_CODE = 32 #51686
pkg debug/pe, const IMAGE_SCN_CNT_CODE ideal-int #51686
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA = 64 #51686
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA ideal-int #51686
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 128 #51686
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA ideal-int #51686
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT = 4096 #51686
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT ideal-int #51686
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE = 33554432 #51686
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE ideal-int #51686
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE = 536870912 #51686
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE ideal-int #51686
pkg debug/pe, const IMAGE_SCN_MEM_READ = 1073741824 #51686
pkg debug/pe, const IMAGE_SCN_MEM_READ ideal-int #51686
pkg debug/pe, const IMAGE_SCN_MEM_WRITE = 2147483648 #51686
pkg debug/pe, const IMAGE_SCN_MEM_WRITE ideal-int #51686
pkg debug/pe, method (*File) COFFSymbolReadSectionDefAux(int) (*COFFSymbolAuxFormat5, error) #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Checksum uint32 #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumLineNumbers uint16 #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumRelocs uint16 #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, SecNum uint16 #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Selection uint8 #51686
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Size uint32 #51686
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY = 2 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY ideal-int #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE ideal-int #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH = 4 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH ideal-int #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST = 6 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST ideal-int #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES = 1 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES ideal-int #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE = 3 #51868
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE ideal-int #51868
pkg debug/pe, const IMAGE_FILE_MACHINE_LOONGARCH32 = 25138 #46229
pkg debug/pe, const IMAGE_FILE_MACHINE_LOONGARCH32 ideal-int #46229
pkg debug/pe, const IMAGE_FILE_MACHINE_LOONGARCH64 = 25188 #46229
pkg debug/pe, const IMAGE_FILE_MACHINE_LOONGARCH64 ideal-int #46229
pkg debug/pe, const IMAGE_SCN_CNT_CODE = 32 #51868
pkg debug/pe, const IMAGE_SCN_CNT_CODE ideal-int #51868
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA = 64 #51868
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA ideal-int #51868
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 128 #51868
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA ideal-int #51868
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT = 4096 #51868
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT ideal-int #51868
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE = 33554432 #51868
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE ideal-int #51868
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE = 536870912 #51868
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE ideal-int #51868
pkg debug/pe, const IMAGE_SCN_MEM_READ = 1073741824 #51868
pkg debug/pe, const IMAGE_SCN_MEM_READ ideal-int #51868
pkg debug/pe, const IMAGE_SCN_MEM_WRITE = 2147483648 #51868
pkg debug/pe, const IMAGE_SCN_MEM_WRITE ideal-int #51868
pkg debug/pe, method (*File) COFFSymbolReadSectionDefAux(int) (*COFFSymbolAuxFormat5, error) #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Checksum uint32 #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumLineNumbers uint16 #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumRelocs uint16 #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, SecNum uint16 #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Selection uint8 #51868
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Size uint32 #51868
pkg encoding/binary, func AppendUvarint([]uint8, uint64) []uint8 #51644
pkg encoding/binary, func AppendVarint([]uint8, int64) []uint8 #51644
pkg encoding/binary, type AppendByteOrder interface { AppendUint16, AppendUint32, AppendUint64, String } #50601

View File

@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of June 21, 2022",
"Subtitle": "Version of June 29, 2022",
"Path": "/ref/spec"
}-->
@ -263,7 +263,7 @@ continue for import return var
<p>
The following character sequences represent <a href="#Operators">operators</a>
(including <a href="#Assignments">assignment operators</a>) and punctuation:
(including <a href="#Assignment_statements">assignment operators</a>) and punctuation:
</p>
<pre class="grammar">
+ &amp; += &amp;= &amp;&amp; == != ( )
@ -676,7 +676,7 @@ containing only untyped constant operands are untyped.
A constant may be given a type explicitly by a <a href="#Constant_declarations">constant declaration</a>
or <a href="#Conversions">conversion</a>, or implicitly when used in a
<a href="#Variable_declarations">variable declaration</a> or an
<a href="#Assignments">assignment</a> or as an
<a href="#Assignment_statements">assignment statement</a> or as an
operand in an <a href="#Expressions">expression</a>.
It is an error if the constant value
cannot be <a href="#Representability">represented</a> as a value of the respective type.
@ -780,7 +780,7 @@ x = v // x has value (*T)(nil) and dynamic type *T
<p>
A variable's value is retrieved by referring to the variable in an
<a href="#Expressions">expression</a>; it is the most recent value
<a href="#Assignments">assigned</a> to the variable.
<a href="#Assignment_statements">assigned</a> to the variable.
If a variable has not yet been assigned a value, its value is the
<a href="#The_zero_value">zero value</a> for its type.
</p>
@ -1591,7 +1591,7 @@ The number of map elements is called its length.
For a map <code>m</code>, it can be discovered using the
built-in function <a href="#Length_and_capacity"><code>len</code></a>
and may change during execution. Elements may be added during execution
using <a href="#Assignments">assignments</a> and retrieved with
using <a href="#Assignment_statements">assignments</a> and retrieved with
<a href="#Index_expressions">index expressions</a>; they may be removed with the
<a href="#Deletion_of_map_elements"><code>delete</code></a> built-in function.
</p>
@ -1634,7 +1634,7 @@ The optional <code>&lt;-</code> operator specifies the channel <i>direction</i>,
<i>send</i> or <i>receive</i>. If a direction is given, the channel is <i>directional</i>,
otherwise it is <i>bidirectional</i>.
A channel may be constrained only to send or only to receive by
<a href="#Assignments">assignment</a> or
<a href="#Assignment_statements">assignment</a> or
explicit <a href="#Conversions">conversion</a>.
</p>
@ -2241,7 +2241,7 @@ the body of any nested function.
The <i>blank identifier</i> is represented by the underscore character <code>_</code>.
It serves as an anonymous placeholder instead of a regular (non-blank)
identifier and has special meaning in <a href="#Declarations_and_scope">declarations</a>,
as an <a href="#Operands">operand</a>, and in <a href="#Assignments">assignments</a>.
as an <a href="#Operands">operand</a>, and in <a href="#Assignment_statements">assignment statements</a>.
</p>
@ -2748,7 +2748,7 @@ var _, found = entries[name] // map lookup; only interested in "found"
<p>
If a list of expressions is given, the variables are initialized
with the expressions following the rules for <a href="#Assignments">assignments</a>.
with the expressions following the rules for <a href="#Assignment_statements">assignment statements</a>.
Otherwise, each variable is initialized to its <a href="#The_zero_value">zero value</a>.
</p>
@ -3011,7 +3011,7 @@ resulting operand is an <a href="#Instantiations">instantiated</a> function.
<p>
The <a href="#Blank_identifier">blank identifier</a> may appear as an
operand only on the left-hand side of an <a href="#Assignments">assignment</a>.
operand only on the left-hand side of an <a href="#Assignment_statements">assignment statement</a>.
</p>
<p>
@ -3821,7 +3821,7 @@ Otherwise <code>a[x]</code> is illegal.
<p>
An index expression on a map <code>a</code> of type <code>map[K]V</code>
used in an <a href="#Assignments">assignment</a> or initialization of the special form
used in an <a href="#Assignment_statements">assignment statement</a> or initialization of the special form
</p>
<pre>
@ -4037,7 +4037,7 @@ func f(y I) {
</pre>
<p>
A type assertion used in an <a href="#Assignments">assignment</a> or initialization of the special form
A type assertion used in an <a href="#Assignment_statements">assignment statement</a> or initialization of the special form
</p>
<pre>
@ -5194,7 +5194,7 @@ f(&lt;-ch)
</pre>
<p>
A receive expression used in an <a href="#Assignments">assignment</a> or initialization of the special form
A receive expression used in an <a href="#Assignment_statements">assignment statement</a> or initialization of the special form
</p>
<pre>
@ -5942,7 +5942,7 @@ IncDecStmt = Expression ( "++" | "--" ) .
</pre>
<p>
The following <a href="#Assignments">assignment statements</a> are semantically
The following <a href="#Assignment_statements">assignment statements</a> are semantically
equivalent:
</p>
@ -5953,7 +5953,14 @@ x-- x -= 1
</pre>
<h3 id="Assignments">Assignments</h3>
<h3 id="Assignment_statements">Assignment statements</h3>
<p>
An <i>assignment</i> replaces the current value stored in a <a href="#Variables">variable</a>
with a new value specified by an <a href="#Expressions">expression</a>.
An assignment statement may assign a single value to a single variable, or multiple values to a
matching number of variables.
</p>
<pre class="ebnf">
Assignment = ExpressionList assign_op ExpressionList .
@ -6522,7 +6529,7 @@ is <code>nil</code>, the range expression blocks forever.
<p>
The iteration values are assigned to the respective
iteration variables as in an <a href="#Assignments">assignment statement</a>.
iteration variables as in an <a href="#Assignment_statements">assignment statement</a>.
</p>
<p>

View File

@ -112,6 +112,7 @@ func TestReportsTypeErrors(t *testing.T) {
"issue18889.go",
"issue28721.go",
"issue33061.go",
"issue50710.go",
} {
check(t, file)
}

14
misc/cgo/errors/testdata/issue50710.go vendored Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// size_t StrLen(_GoString_ s) {
// return _GoStringLen(s);
// }
import "C"
func main() {
C.StrLen1() // ERROR HERE
}

View File

@ -15,6 +15,14 @@ func TestSetgid(t *testing.T) {
}
testSetgid(t)
}
func TestSetgidStress(t *testing.T) {
if runtime.GOOS == "android" {
t.Skip("unsupported on Android")
}
testSetgidStress(t)
}
func Test1435(t *testing.T) { test1435(t) }
func Test6997(t *testing.T) { test6997(t) }
func TestBuildID(t *testing.T) { testBuildID(t) }

View File

@ -0,0 +1,35 @@
// Copyright 2022 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.
// Stress test setgid and thread creation. A thread
// can get a SIGSETXID signal early on at thread
// initialization, causing crash. See issue 53374.
package cgotest
/*
#include <sys/types.h>
#include <unistd.h>
*/
import "C"
import (
"runtime"
"testing"
)
func testSetgidStress(t *testing.T) {
const N = 1000
ch := make(chan int, N)
for i := 0; i < N; i++ {
go func() {
C.setgid(0)
ch <- 1
runtime.LockOSThread() // so every goroutine uses a new thread
}()
}
for i := 0; i < N; i++ {
<-ch
}
}

View File

@ -21,9 +21,9 @@ label0:
BEQ R1, 2(PC)
JMP label0+0 // JMP 3 // 1000fffd
BEQ R1, 2(PC)
JAL 1(PC) // CALL 1(PC) // 0c00000e
JAL 1(PC) // CALL 1(PC) // 0c00000f
BEQ R1, 2(PC)
JAL label0+0 // CALL 3 // 0c000006
JAL label0+0 // CALL 3 // 0c000007
// LBRA addr
// {
@ -32,11 +32,11 @@ label0:
BEQ R1, 2(PC)
JMP 0(R1) // JMP (R1) // 00200008
BEQ R1, 2(PC)
JMP foo+0(SB) // JMP foo(SB) // 08000018
JMP foo+0(SB) // JMP foo(SB) // 08000019
BEQ R1, 2(PC)
JAL 0(R1) // CALL (R1) // 0020f809
BEQ R1, 2(PC)
JAL foo+0(SB) // CALL foo(SB) // 0c000020
JAL foo+0(SB) // CALL foo(SB) // 0c000021
//
// BEQ/BNE

View File

@ -488,7 +488,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// Check if compiling the preamble by itself causes any errors,
// because the messages we've printed out so far aren't helpful
// to users debugging preamble mistakes. See issue 8442.
preambleErrors := p.gccErrors([]byte(f.Preamble))
preambleErrors := p.gccErrors([]byte(builtinProlog + f.Preamble))
if len(preambleErrors) > 0 {
error_(token.NoPos, "\n%s errors for preamble:\n%s", gccBaseCmd[0], preambleErrors)
}

View File

@ -41,7 +41,7 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
conf := types2.Config{
Context: ctxt,
GoVersion: base.Flag.Lang,
IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode
IgnoreBranchErrors: true, // parser already checked via syntax.CheckBranches mode
CompilerErrorMessages: true, // use error strings matching existing compiler errors
Error: func(err error) {
terr := err.(types2.Error)

View File

@ -27,8 +27,6 @@ import (
func LoadPackage(filenames []string) {
base.Timer.Start("fe", "parse")
mode := syntax.CheckBranches
// Limit the number of simultaneously open files.
sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
@ -58,7 +56,7 @@ func LoadPackage(filenames []string) {
}
defer f.Close()
p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error
p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
}()
}
}()

View File

@ -1214,7 +1214,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
break // Nothing to do here for type switches.
}
if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() {
if m.Tag != nil && !m.Tag.Type().IsEmptyInterface() && m.Tag.Type().HasShape() {
// To implement a switch on a value that is or has a type parameter, we first convert
// that thing we're switching on to an interface{}.
m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
@ -1223,7 +1223,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
for i, x := range c.List {
// If we have a case that is or has a type parameter, convert that case
// to an interface{}.
if !x.Type().IsInterface() && x.Type().HasShape() {
if !x.Type().IsEmptyInterface() && x.Type().HasShape() {
c.List[i] = assignconvfn(x, types.Types[types.TINTER])
}
}

View File

@ -159,6 +159,13 @@ func findIndVar(f *Func) []indVar {
step = -step
}
if flags&indVarMaxInc != 0 && max.Op == OpConst64 && max.AuxInt+step < max.AuxInt {
// For a <= comparison, we need to make sure that a value equal to
// max can be incremented without overflowing.
// (For a < comparison, the %step check below ensures no overflow.)
continue
}
// Up to now we extracted the induction variable (ind),
// the increment delta (inc), the temporary sum (nxt),
// the minimum value (min) and the maximum value (max).

View File

@ -6,12 +6,10 @@ package syntax
import "fmt"
// TODO(gri) consider making this part of the parser code
// checkBranches checks correct use of labels and branch
// statements (break, continue, goto) in a function body.
// statements (break, continue, fallthrough, goto) in a function body.
// It catches:
// - misplaced breaks and continues
// - misplaced breaks, continues, and fallthroughs
// - bad labeled breaks and continues
// - invalid, unused, duplicate, and missing labels
// - gotos jumping over variable declarations and into blocks
@ -123,6 +121,7 @@ func (ls *labelScope) enclosingTarget(b *block, name string) *LabeledStmt {
type targets struct {
breaks Stmt // *ForStmt, *SwitchStmt, *SelectStmt, or nil
continues *ForStmt // or nil
caseIndex int // case index of immediately enclosing switch statement, or < 0
}
// blockBranches processes a block's body starting at start and returns the
@ -163,7 +162,10 @@ func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledS
fwdGotos = append(fwdGotos, ls.blockBranches(b, ctxt, lstmt, start, body)...)
}
for _, stmt := range body {
// A fallthrough statement counts as last statement in a statement
// list even if there are trailing empty statements; remove them.
stmtList := trimTrailingEmptyStmts(body)
for stmtIndex, stmt := range stmtList {
lstmt = nil
L:
switch s := stmt.(type) {
@ -222,7 +224,20 @@ func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledS
ls.err(s.Pos(), "continue is not in a loop")
}
case _Fallthrough:
// nothing to do
msg := "fallthrough statement out of place"
if t, _ := ctxt.breaks.(*SwitchStmt); t != nil {
if _, ok := t.Tag.(*TypeSwitchGuard); ok {
msg = "cannot fallthrough in type switch"
} else if ctxt.caseIndex < 0 || stmtIndex+1 < len(stmtList) {
// fallthrough nested in a block or not the last statement
// use msg as is
} else if ctxt.caseIndex+1 == len(t.Body) {
msg = "cannot fallthrough final case in switch"
} else {
break // fallthrough ok
}
}
ls.err(s.Pos(), msg)
case _Goto:
fallthrough // should always have a label
default:
@ -282,25 +297,29 @@ func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledS
}
case *BlockStmt:
innerBlock(ctxt, s.Pos(), s.List)
inner := targets{ctxt.breaks, ctxt.continues, -1}
innerBlock(inner, s.Pos(), s.List)
case *IfStmt:
innerBlock(ctxt, s.Then.Pos(), s.Then.List)
inner := targets{ctxt.breaks, ctxt.continues, -1}
innerBlock(inner, s.Then.Pos(), s.Then.List)
if s.Else != nil {
innerBlock(ctxt, s.Else.Pos(), []Stmt{s.Else})
innerBlock(inner, s.Else.Pos(), []Stmt{s.Else})
}
case *ForStmt:
innerBlock(targets{s, s}, s.Body.Pos(), s.Body.List)
inner := targets{s, s, -1}
innerBlock(inner, s.Body.Pos(), s.Body.List)
case *SwitchStmt:
inner := targets{s, ctxt.continues}
for _, cc := range s.Body {
inner := targets{s, ctxt.continues, -1}
for i, cc := range s.Body {
inner.caseIndex = i
innerBlock(inner, cc.Pos(), cc.Body)
}
case *SelectStmt:
inner := targets{s, ctxt.continues}
inner := targets{s, ctxt.continues, -1}
for _, cc := range s.Body {
innerBlock(inner, cc.Pos(), cc.Body)
}
@ -309,3 +328,12 @@ func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledS
return fwdGotos
}
func trimTrailingEmptyStmts(list []Stmt) []Stmt {
for i := len(list); i > 0; i-- {
if _, ok := list[i-1].(*EmptyStmt); !ok {
return list[:i]
}
}
return nil
}

View File

@ -162,7 +162,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
} else {
t.Errorf("%s:%s: unexpected error: %s", filename, orig, e.Msg)
}
}, nil, 0)
}, nil, CheckBranches)
if *print {
fmt.Println()

View File

@ -0,0 +1,55 @@
// Copyright 2022 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 fallthroughs
func _() {
var x int
switch x {
case 0:
fallthrough
case 1:
fallthrough // ERROR fallthrough statement out of place
{
}
case 2:
{
fallthrough // ERROR fallthrough statement out of place
}
case 3:
for {
fallthrough // ERROR fallthrough statement out of place
}
case 4:
fallthrough // trailing empty statements are ok
;
;
case 5:
fallthrough
default:
fallthrough // ERROR cannot fallthrough final case in switch
}
fallthrough // ERROR fallthrough statement out of place
if true {
fallthrough // ERROR fallthrough statement out of place
}
for {
fallthrough // ERROR fallthrough statement out of place
}
var t any
switch t.(type) {
case int:
fallthrough // ERROR cannot fallthrough in type switch
}
}

View File

@ -128,9 +128,8 @@ type Config struct {
// Do not use casually!
FakeImportC bool
// If IgnoreLabels is set, correct label use is not checked.
// TODO(gri) Consolidate label checking and remove this flag.
IgnoreLabels bool
// If IgnoreBranchErrors is set, branch/label errors are ignored.
IgnoreBranchErrors bool
// If CompilerErrorMessages is set, errors are reported using
// cmd/compile error strings to match $GOROOT/test errors.

View File

@ -297,7 +297,7 @@ func TestManual(t *testing.T) {
// TODO(gri) go/types has extra TestLongConstants and TestIndexRepresentability tests
func TestCheck(t *testing.T) { testDirFiles(t, "testdata/check", 55, false) } // TODO(gri) narrow column tolerance
func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", 55, false) } // TODO(gri) narrow column tolerance
func TestSpec(t *testing.T) { testDirFiles(t, "testdata/spec", 0, false) }
func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", 0, false) }
func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", 0, false) }

View File

@ -41,7 +41,7 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
check.stmtList(0, body.List)
if check.hasLabel && !check.conf.IgnoreLabels {
if check.hasLabel && !check.conf.IgnoreBranchErrors {
check.labels(body)
}
@ -504,22 +504,17 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
check.hasLabel = true
break // checked in 2nd pass (check.labels)
}
if check.conf.IgnoreBranchErrors {
break
}
switch s.Tok {
case syntax.Break:
if ctxt&breakOk == 0 {
if check.conf.CompilerErrorMessages {
check.error(s, "break is not in a loop, switch, or select statement")
} else {
check.error(s, "break not in for, switch, or select statement")
}
check.error(s, "break not in for, switch, or select statement")
}
case syntax.Continue:
if ctxt&continueOk == 0 {
if check.conf.CompilerErrorMessages {
check.error(s, "continue is not in a loop")
} else {
check.error(s, "continue not in for statement")
}
check.error(s, "continue not in for statement")
}
case syntax.Fallthrough:
if ctxt&fallthroughOk == 0 {

View File

@ -135,4 +135,26 @@ const (
f // ERROR invalid array length
)
// Test that identifiers in implicit (omitted) RHS
// expressions of constant declarations are resolved
// in the correct context; see issues #49157, #53585.
const X = 2
func _() {
const (
A = iota // 0
iota = iota // 1
B // 1 (iota is declared locally on prev. line)
C // 1
)
assert(A == 0 && B == 1 && C == 1)
const (
X = X + X
Y
Z = iota
)
assert(X == 4 && Y == 8 && Z == 1)
}
// TODO(gri) move extra tests from testdata/const0.src into here

View File

@ -2347,7 +2347,17 @@ func (p *Package) setBuildInfo(includeVCS bool) {
appendSetting("-gcflags", gcflags)
}
if ldflags := BuildLdflags.String(); ldflags != "" {
appendSetting("-ldflags", ldflags)
// https://go.dev/issue/52372: only include ldflags if -trimpath is not set,
// since it can include system paths through various linker flags (notably
// -extar, -extld, and -extldflags).
//
// TODO: since we control cmd/link, in theory we can parse ldflags to
// determine whether they may refer to system paths. If we do that, we can
// redact only those paths from the recorded -ldflags setting and still
// record the system-independent parts of the flags.
if !cfg.BuildTrimpath {
appendSetting("-ldflags", ldflags)
}
}
if cfg.BuildMSan {
appendSetting("-msan", "true")
@ -2366,7 +2376,14 @@ func (p *Package) setBuildInfo(includeVCS bool) {
cgo = "1"
}
appendSetting("CGO_ENABLED", cgo)
if cfg.BuildContext.CgoEnabled {
// https://go.dev/issue/52372: only include CGO flags if -trimpath is not set.
// (If -trimpath is set, it is possible that these flags include system paths.)
// If cgo is involved, reproducibility is already pretty well ruined anyway,
// given that we aren't stamping header or library versions.
//
// TODO(bcmills): perhaps we could at least parse the flags and stamp the
// subset of flags that are known not to be paths?
if cfg.BuildContext.CgoEnabled && !cfg.BuildTrimpath {
for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
appendSetting(name, cfg.Getenv(name))
}

View File

@ -447,7 +447,7 @@ func (r *gitRepo) fetchRefsLocked() error {
// statLocal returns a RevInfo describing rev in the local git repository.
// It uses version as info.Version.
func (r *gitRepo) statLocal(version, rev string) (*RevInfo, error) {
out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "-n1", "--format=format:%H %ct %D", rev, "--")
out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D", rev, "--")
if err != nil {
return nil, &UnknownRevisionError{Rev: rev}
}

View File

@ -187,6 +187,10 @@ type proxyRepo struct {
url *url.URL
path string
redactedURL string
listLatestOnce sync.Once
listLatest *RevInfo
listLatestErr error
}
func newProxyRepo(baseURL, path string) (Repo, error) {
@ -214,7 +218,7 @@ func newProxyRepo(baseURL, path string) (Repo, error) {
redactedURL := base.Redacted()
base.Path = strings.TrimSuffix(base.Path, "/") + "/" + enc
base.RawPath = strings.TrimSuffix(base.RawPath, "/") + "/" + pathEscape(enc)
return &proxyRepo{base, path, redactedURL}, nil
return &proxyRepo{base, path, redactedURL, sync.Once{}, nil, nil}, nil
}
func (p *proxyRepo) ModulePath() string {
@ -278,32 +282,46 @@ func (p *proxyRepo) getBody(path string) (r io.ReadCloser, err error) {
func (p *proxyRepo) Versions(prefix string) ([]string, error) {
data, err := p.getBytes("@v/list")
if err != nil {
p.listLatestOnce.Do(func() {
p.listLatest, p.listLatestErr = nil, p.versionError("", err)
})
return nil, p.versionError("", err)
}
var list []string
for _, line := range strings.Split(string(data), "\n") {
allLine := strings.Split(string(data), "\n")
for _, line := range allLine {
f := strings.Fields(line)
if len(f) >= 1 && semver.IsValid(f[0]) && strings.HasPrefix(f[0], prefix) && !module.IsPseudoVersion(f[0]) {
list = append(list, f[0])
}
}
p.listLatestOnce.Do(func() {
p.listLatest, p.listLatestErr = p.latestFromList(allLine)
})
semver.Sort(list)
return list, nil
}
func (p *proxyRepo) latest() (*RevInfo, error) {
data, err := p.getBytes("@v/list")
if err != nil {
return nil, p.versionError("", err)
}
p.listLatestOnce.Do(func() {
data, err := p.getBytes("@v/list")
if err != nil {
p.listLatestErr = p.versionError("", err)
return
}
list := strings.Split(string(data), "\n")
p.listLatest, p.listLatestErr = p.latestFromList(list)
})
return p.listLatest, p.listLatestErr
}
func (p *proxyRepo) latestFromList(allLine []string) (*RevInfo, error) {
var (
bestTime time.Time
bestTimeIsFromPseudo bool
bestVersion string
)
for _, line := range strings.Split(string(data), "\n") {
for _, line := range allLine {
f := strings.Fields(line)
if len(f) >= 1 && semver.IsValid(f[0]) {
// If the proxy includes timestamps, prefer the timestamp it reports.

View File

@ -16,15 +16,14 @@ dirnames [n]uint32 - offsets to package names in string table; names sorted by r
packages [n]uint32 - offset where package begins
for each RawPackage:
error uint32 - string offset // error is produced by fsys.ReadDir or fmt.Errorf
path uint32 - string offset
dir uint32 - string offset (directory path relative to module root)
len(sourceFiles) uint32
sourceFiles [n]uint32 - offset to source file (relative to start of index file)
for each sourceFile:
error - string offset // error is either produced by fmt.Errorf,errors.New or is io.EOF
parseError - string offset // if non-empty, a json-encoded parseError struct (see below). Is either produced by io.ReadAll,os.ReadFile,errors.New or is scanner.Error,scanner.ErrorList
name - string offset
synopsis - string offset
name - string offset
pkgName - string offset
ignoreFile - int32 bool // report the file in Ignored(Go|Other)Files because there was an error reading it or parsing its build constraints.
binaryOnly uint32 bool
@ -47,7 +46,7 @@ The following is the format for a single indexed package:
“go index v0\n”
str uint32 - offset of string table
for the single RawPackage:
[same RawPackage format as above]
[same RawPackage format as above]
[string table]
The following is the definition of the json-serialized parseError struct:
@ -55,4 +54,4 @@ The following is the definition of the json-serialized parseError struct:
type parseError struct {
ErrorList *scanner.ErrorList // non-nil if the error was an ErrorList, nil otherwise
ErrorString string // non-empty for all other cases
}
}

View File

@ -73,6 +73,10 @@ func moduleHash(modroot string, ismodcache bool) (cache.ActionID, error) {
}
h := cache.NewHash("moduleIndex")
// TODO(bcmills): Since modules in the index are checksummed, we could
// probably improve the cache hit rate by keying off of the module
// path@version (perhaps including the checksum?) instead of the module root
// directory.
fmt.Fprintf(h, "module index %s %s %v\n", runtime.Version(), indexVersion, modroot)
return h.Sum(), nil
}
@ -81,8 +85,9 @@ const modTimeCutoff = 2 * time.Second
// dirHash returns an ActionID corresponding to the state of the package
// located at filesystem path pkgdir.
func dirHash(pkgdir string) (cache.ActionID, error) {
func dirHash(modroot, pkgdir string) (cache.ActionID, error) {
h := cache.NewHash("moduleIndex")
fmt.Fprintf(h, "modroot %s\n", modroot)
fmt.Fprintf(h, "package %s %s %v\n", runtime.Version(), indexVersion, pkgdir)
entries, err := fsys.ReadDir(pkgdir)
if err != nil {
@ -206,8 +211,8 @@ func openIndexPackage(modroot, pkgdir string) (*IndexPackage, error) {
pkg *IndexPackage
err error
}
r := pcache.Do(pkgdir, func() any {
id, err := dirHash(pkgdir)
r := pcache.Do([2]string{modroot, pkgdir}, func() any {
id, err := dirHash(modroot, pkgdir)
if err != nil {
return result{nil, err}
}
@ -851,12 +856,12 @@ func (sf *sourceFile) error() string {
func (sf *sourceFile) parseError() string {
return sf.od.stringAt(sourceFileParseError)
}
func (sf *sourceFile) name() string {
return sf.od.stringAt(sourceFileName)
}
func (sf *sourceFile) synopsis() string {
return sf.od.stringAt(sourceFileSynopsis)
}
func (sf *sourceFile) name() string {
return sf.od.stringAt(sourceFileName)
}
func (sf *sourceFile) pkgName() string {
return sf.od.stringAt(sourceFilePkgName)
}

View File

@ -56,7 +56,7 @@ func indexModule(modroot string) ([]byte, error) {
return nil
}
if !str.HasFilePathPrefix(path, modroot) {
panic(fmt.Errorf("path %v in walk doesn't have modroot %v as prefix:", path, modroot))
panic(fmt.Errorf("path %v in walk doesn't have modroot %v as prefix", path, modroot))
}
rel := str.TrimFilePathPrefix(path, modroot)
packages = append(packages, importRaw(modroot, rel))

View File

@ -32,29 +32,28 @@ import (
// The module must be a complete module path.
// The version must take one of the following forms:
//
// - the literal string "latest", denoting the latest available, allowed
// - the literal string "latest", denoting the latest available, allowed
// tagged version, with non-prereleases preferred over prereleases.
// If there are no tagged versions in the repo, latest returns the most
// recent commit.
//
// tagged version, with non-prereleases preferred over prereleases.
// If there are no tagged versions in the repo, latest returns the most
// recent commit.
// - the literal string "upgrade", equivalent to "latest" except that if
// current is a newer version, current will be returned (see below).
//
// - the literal string "upgrade", equivalent to "latest" except that if
// - the literal string "patch", denoting the latest available tagged version
// with the same major and minor number as current (see below).
//
// current is a newer version, current will be returned (see below).
// - v1, denoting the latest available tagged version v1.x.x.
//
// - the literal string "patch", denoting the latest available tagged version
// - v1.2, denoting the latest available tagged version v1.2.x.
//
// with the same major and minor number as current (see below).
// - v1.2.3, a semantic version string denoting that tagged version.
//
// - v1, denoting the latest available tagged version v1.x.x.
// - v1.2, denoting the latest available tagged version v1.2.x.
// - v1.2.3, a semantic version string denoting that tagged version.
// - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3,
// - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3,
// denoting the version closest to the target and satisfying the given operator,
// with non-prereleases preferred over prereleases.
//
// denoting the version closest to the target and satisfying the given operator,
// with non-prereleases preferred over prereleases.
//
// - a repository commit identifier or tag, denoting that commit.
// - a repository commit identifier or tag, denoting that commit.
//
// current denotes the currently-selected version of the module; it may be
// "none" if no version is currently selected, or "" if the currently-selected

View File

@ -30,15 +30,16 @@ import (
const trimPathGoRootFinal string = "$GOROOT"
var runtimePackages = map[string]struct{}{
"internal/abi": struct{}{},
"internal/bytealg": struct{}{},
"internal/cpu": struct{}{},
"internal/goarch": struct{}{},
"internal/goos": struct{}{},
"runtime": struct{}{},
"runtime/internal/atomic": struct{}{},
"runtime/internal/math": struct{}{},
"runtime/internal/sys": struct{}{},
"internal/abi": struct{}{},
"internal/bytealg": struct{}{},
"internal/cpu": struct{}{},
"internal/goarch": struct{}{},
"internal/goos": struct{}{},
"runtime": struct{}{},
"runtime/internal/atomic": struct{}{},
"runtime/internal/math": struct{}{},
"runtime/internal/sys": struct{}{},
"runtime/internal/syscall": struct{}{},
}
// The Go toolchain.

View File

@ -521,6 +521,7 @@ var scriptCmds = map[string]func(*testScript, simpleStatus, []string){
"mv": (*testScript).cmdMv,
"rm": (*testScript).cmdRm,
"skip": (*testScript).cmdSkip,
"sleep": (*testScript).cmdSleep,
"stale": (*testScript).cmdStale,
"stderr": (*testScript).cmdStderr,
"stdout": (*testScript).cmdStdout,
@ -921,6 +922,21 @@ func (ts *testScript) cmdSkip(want simpleStatus, args []string) {
ts.t.Skip()
}
// sleep sleeps for the given duration
func (ts *testScript) cmdSleep(want simpleStatus, args []string) {
if len(args) != 1 {
ts.fatalf("usage: sleep duration")
}
d, err := time.ParseDuration(args[0])
if err != nil {
ts.fatalf("sleep: %v", err)
}
if want != success {
ts.fatalf("unsupported: %v sleep", want)
}
time.Sleep(d)
}
// stale checks that the named build targets are stale.
func (ts *testScript) cmdStale(want simpleStatus, args []string) {
if len(args) == 0 {

View File

@ -176,6 +176,11 @@ The commands are:
- skip [message]
Mark the test skipped, including the message if given.
- sleep duration
Sleep for the given duration (a time.Duration string).
(Tests should generally poll instead of sleeping, but sleeping may sometimes
be necessary, for example, to ensure that modified files have unique mtimes.)
- [!] stale path...
The packages named by the path arguments must (or must not)
be reported as "stale" by the go command.

View File

@ -0,0 +1,18 @@
[short] skip # sleeps to make mtime cacheable
go mod init example
cd subdir
go mod init example/subdir
sleep 2s # allow go.mod mtime to be cached
go list -f '{{.Dir}}: {{.ImportPath}}' ./pkg
stdout $PWD${/}pkg': example/subdir/pkg$'
rm go.mod # expose ../go.mod
go list -f '{{.Dir}}: {{.ImportPath}}' ./pkg
stdout $PWD${/}pkg': example/subdir/pkg$'
-- subdir/pkg/pkg.go --
package pkg

View File

@ -0,0 +1,28 @@
env GO111MODULE=on
[!net] skip
[!exec:git] skip
env GOPROXY=direct
env HOME=$WORK/home/gopher
go env GOPROXY
stdout 'direct'
exec git config --get log.decorate
stdout 'full'
# Test that Git log with user's global config '~/gitconfig' has log.decorate=full
# go mod download has an error 'v1.x.y is not a tag'
# with go1.16.14:
# `go1.16.14 list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3`
# will output with error:
# go list -m: vcs-test.golang.org/git/gitrepo1.git@v1.2.3: invalid version: unknown revision v1.2.3
# See golang/go#51312.
go list -m vcs-test.golang.org/git/gitrepo1.git@v1.2.3
stdout 'vcs-test.golang.org/git/gitrepo1.git v1.2.3'
-- $WORK/home/gopher/.gitconfig --
[log]
decorate = full

View File

@ -51,19 +51,34 @@ go build
go version -m m$GOEXE
stdout '^\tbuild\tCGO_ENABLED=0$'
! stdout CGO_CPPFLAGS|CGO_CFLAGS|CGO_CXXFLAGS|CGO_LDFLAGS
[cgo] env CGO_ENABLED=1
[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1
[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1
[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1
[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist
[cgo] go build
[cgo] go build '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist'
[cgo] go version -m m$GOEXE
[cgo] stdout '^\tbuild\t-ldflags="all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist"$'
[cgo] stdout '^\tbuild\tCGO_ENABLED=1$'
[cgo] stdout '^\tbuild\tCGO_CPPFLAGS=-DFROM_CPPFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_CFLAGS=-DFROM_CFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_CXXFLAGS=-DFROM_CXXFLAGS=1$'
[cgo] stdout '^\tbuild\tCGO_LDFLAGS=-L/extra/dir/does/not/exist$'
# https://go.dev/issue/52372: a cgo-enabled binary should not be stamped with
# CGO_ flags that contain paths.
[cgo] env CGO_ENABLED=1
[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1
[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1
[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1
[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist
[cgo] go build -trimpath '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist'
[cgo] go version -m m$GOEXE
[cgo] ! stdout '/extra/dir/does/not/exist'
[cgo] ! stdout '/bonus/dir/does/not/exist'
[cgo] stdout '^\tbuild\tCGO_ENABLED=1$'
-- go.mod --
module example.com/m

View File

@ -18,32 +18,23 @@ import (
"os/exec"
"path/filepath"
"runtime"
"sync"
"testing"
"unicode/utf8"
)
var (
buildDir string
go1obj string
go2obj string
goarchive string
cgoarchive string
)
var buildDir string
func TestMain(m *testing.M) {
if !testenv.HasGoBuild() {
return
}
if err := buildGoobj(); err != nil {
fmt.Println(err)
os.RemoveAll(buildDir)
os.Exit(1)
}
exit := m.Run()
os.RemoveAll(buildDir)
if buildDir != "" {
os.RemoveAll(buildDir)
}
os.Exit(exit)
}
@ -89,71 +80,91 @@ func copyFile(dst, src string) (err error) {
return nil
}
func buildGoobj() error {
var err error
var (
buildOnce sync.Once
builtGoobjs goobjPaths
buildErr error
)
buildDir, err = ioutil.TempDir("", "TestGoobj")
if err != nil {
return err
type goobjPaths struct {
go1obj string
go2obj string
goarchive string
cgoarchive string
}
func buildGoobj(t *testing.T) goobjPaths {
buildOnce.Do(func() {
buildErr = func() (err error) {
buildDir, err = ioutil.TempDir("", "TestGoobj")
if err != nil {
return err
}
go1obj := filepath.Join(buildDir, "go1.o")
go2obj := filepath.Join(buildDir, "go2.o")
goarchive := filepath.Join(buildDir, "go.a")
cgoarchive := ""
gotool, err := testenv.GoTool()
if err != nil {
return err
}
go1src := filepath.Join("testdata", "go1.go")
go2src := filepath.Join("testdata", "go2.go")
out, err := exec.Command(gotool, "tool", "compile", "-p=p", "-o", go1obj, go1src).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out)
}
out, err = exec.Command(gotool, "tool", "compile", "-p=p", "-o", go2obj, go2src).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out)
}
out, err = exec.Command(gotool, "tool", "pack", "c", goarchive, go1obj, go2obj).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool pack c %s %s %s: %v\n%s", goarchive, go1obj, go2obj, err, out)
}
if testenv.HasCGO() {
cgoarchive = filepath.Join(buildDir, "mycgo.a")
gopath := filepath.Join(buildDir, "gopath")
err = copyDir(filepath.Join(gopath, "src", "mycgo"), filepath.Join("testdata", "mycgo"))
if err == nil {
err = ioutil.WriteFile(filepath.Join(gopath, "src", "mycgo", "go.mod"), []byte("module mycgo\n"), 0666)
}
if err != nil {
return err
}
cmd := exec.Command(gotool, "build", "-buildmode=archive", "-o", cgoarchive, "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "mycgo")
cmd.Dir = filepath.Join(gopath, "src", "mycgo")
cmd.Env = append(os.Environ(), "GOPATH="+gopath)
out, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("go install mycgo: %v\n%s", err, out)
}
}
builtGoobjs = goobjPaths{
go1obj: go1obj,
go2obj: go2obj,
goarchive: goarchive,
cgoarchive: cgoarchive,
}
return nil
}()
})
if buildErr != nil {
t.Helper()
t.Fatal(buildErr)
}
go1obj = filepath.Join(buildDir, "go1.o")
go2obj = filepath.Join(buildDir, "go2.o")
goarchive = filepath.Join(buildDir, "go.a")
gotool, err := testenv.GoTool()
if err != nil {
return err
}
go1src := filepath.Join("testdata", "go1.go")
go2src := filepath.Join("testdata", "go2.go")
out, err := exec.Command(gotool, "tool", "compile", "-p=p", "-o", go1obj, go1src).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out)
}
out, err = exec.Command(gotool, "tool", "compile", "-p=p", "-o", go2obj, go2src).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out)
}
out, err = exec.Command(gotool, "tool", "pack", "c", goarchive, go1obj, go2obj).CombinedOutput()
if err != nil {
return fmt.Errorf("go tool pack c %s %s %s: %v\n%s", goarchive, go1obj, go2obj, err, out)
}
if testenv.HasCGO() {
gopath := filepath.Join(buildDir, "gopath")
err = copyDir(filepath.Join(gopath, "src", "mycgo"), filepath.Join("testdata", "mycgo"))
if err == nil {
err = ioutil.WriteFile(filepath.Join(gopath, "src", "mycgo", "go.mod"), []byte("module mycgo\n"), 0666)
}
if err != nil {
return err
}
cmd := exec.Command(gotool, "install", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "mycgo")
cmd.Dir = filepath.Join(gopath, "src", "mycgo")
cmd.Env = append(os.Environ(), "GOPATH="+gopath)
out, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("go install mycgo: %v\n%s", err, out)
}
pat := filepath.Join(gopath, "pkg", "*", "mycgo.a")
ms, err := filepath.Glob(pat)
if err != nil {
return err
}
if len(ms) == 0 {
return fmt.Errorf("cannot found paths for pattern %s", pat)
}
cgoarchive = ms[0]
}
return nil
return builtGoobjs
}
func TestParseGoobj(t *testing.T) {
path := go1obj
path := buildGoobj(t).go1obj
f, err := os.Open(path)
if err != nil {
@ -182,7 +193,7 @@ func TestParseGoobj(t *testing.T) {
}
func TestParseArchive(t *testing.T) {
path := goarchive
path := buildGoobj(t).goarchive
f, err := os.Open(path)
if err != nil {
@ -227,7 +238,7 @@ func TestParseArchive(t *testing.T) {
func TestParseCGOArchive(t *testing.T) {
testenv.MustHaveCGO(t)
path := cgoarchive
path := buildGoobj(t).cgoarchive
f, err := os.Open(path)
if err != nil {

View File

@ -1557,6 +1557,10 @@ func sequenceOfOnes(x uint64) bool {
// N=0, S=11110x -- period=2
// R is the shift amount, low bits of S = n-1
func bitconEncode(x uint64, mode int) uint32 {
if mode == 32 {
x &= 0xffffffff
x = x<<32 | x
}
var period uint32
// determine the period and sign-extend a unit to 64 bits
switch {
@ -1825,17 +1829,24 @@ func rclass(r int16) int {
// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
func (c *ctxt7) con32class(a *obj.Addr) int {
v := uint32(a.Offset)
// For 32-bit instruction with constant, rewrite
// the high 32-bit to be a repetition of the low
// 32-bit, so that the BITCON test can be shared
// for both 32-bit and 64-bit. 32-bit ops will
// zero the high 32-bit of the destination register
// anyway.
vbitcon := uint64(v)<<32 | uint64(v)
if v == 0 {
return C_ZCON
}
if isaddcon(int64(v)) {
if v <= 0xFFF {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_ABCON0
}
return C_ADDCON0
}
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_ABCON
}
if movcon(int64(v)) >= 0 {
@ -1849,7 +1860,7 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t := movcon(int64(v))
if t >= 0 {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_MBCON
}
return C_MOVCON
@ -1857,13 +1868,13 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t = movcon(int64(^v))
if t >= 0 {
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_MBCON
}
return C_MOVCON
}
if isbitcon(uint64(a.Offset)) {
if isbitcon(vbitcon) {
return C_BITCON
}

View File

@ -382,19 +382,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
}
// For 32-bit instruction with constant, rewrite
// the high 32-bit to be a repetition of the low
// 32-bit, so that the BITCON test can be shared
// for both 32-bit and 64-bit. 32-bit ops will
// zero the high 32-bit of the destination register
// anyway.
// For MOVW, the destination register can't be ZR,
// so don't bother rewriting it in this situation.
if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW && p.To.Reg != REGZERO) && p.From.Type == obj.TYPE_CONST {
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
if c.ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
}
@ -622,17 +609,17 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var prologueEnd *obj.Prog
aoffset := c.autosize
if aoffset > 0x1f0 {
// LDP offset variant range is -512 to 504, SP should be 16-byte aligned,
// so the maximum aoffset value is 496.
aoffset = 0x1f0
if aoffset > 0xf0 {
// MOVD.W offset variant range is -0x100 to 0xf8, SP should be 16-byte aligned.
// so the maximum aoffset value is 0xf0.
aoffset = 0xf0
}
// Frame is non-empty. Make sure to save link register, even if
// it is a leaf function, so that traceback works.
q = p
if c.autosize > aoffset {
// Frame size is too large for a STP instruction. Store the frame pointer
// Frame size is too large for a MOVD.W instruction. Store the frame pointer
// register and link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback code will
// not see a half-updated stack frame.
@ -692,50 +679,37 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Offset = -8
}
} else {
// small frame, save FP and LR with one STP instruction, then update SP.
// Store first, so if a signal comes during the execution of the function
// prologue, the traceback code will not see a half-updated stack frame.
// STP (R29, R30), -aoffset-8(RSP)
// small frame, update SP and save LR in a single MOVD.W instruction.
// So if a signal comes during the execution of the function prologue,
// the traceback code will not see a half-updated stack frame.
// Also, on Linux, in a cgo binary we may get a SIGSETXID signal
// early on before the signal stack is set, as glibc doesn't allow
// us to block SIGSETXID. So it is important that we don't write below
// the SP until the signal stack is set.
// Luckily, all the functions from thread entry to setting the signal
// stack have small frames.
q1 = obj.Appendp(q, c.newprog)
q1.As = ASTP
q1.As = AMOVD
q1.Pos = p.Pos
q1.From.Type = obj.TYPE_REGREG
q1.From.Reg = REGFP
q1.From.Offset = REGLINK
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGLINK
q1.To.Type = obj.TYPE_MEM
q1.To.Offset = int64(-aoffset - 8)
q1.To.Reg = REGSP
prologueEnd = q1
q1 = c.ctxt.StartUnsafePoint(q1, c.newprog)
// This instruction is not async preemptible, see the above comment.
// SUB $aoffset, RSP, RSP
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
q1.As = ASUB
q1.From.Type = obj.TYPE_CONST
q1.From.Offset = int64(aoffset)
q1.Reg = REGSP
q1.To.Type = obj.TYPE_REG
q1.Scond = C_XPRE
q1.To.Offset = int64(-aoffset)
q1.To.Reg = REGSP
q1.Spadj = aoffset
q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
prologueEnd = q1
if buildcfg.GOOS == "ios" {
// See the above comment.
// STP (R29, R30), -8(RSP)
q1 = obj.Appendp(q1, c.newprog)
q1.As = ASTP
q1.Pos = p.Pos
q1.From.Type = obj.TYPE_REGREG
q1.From.Reg = REGFP
q1.From.Offset = REGLINK
q1.To.Type = obj.TYPE_MEM
q1.To.Offset = int64(-8)
q1.To.Reg = REGSP
}
// Frame pointer.
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
q1.As = AMOVD
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGFP
q1.To.Type = obj.TYPE_MEM
q1.To.Reg = REGSP
q1.To.Offset = -8
}
prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)

View File

@ -343,6 +343,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = +autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
// On Linux, in a cgo binary we may get a SIGSETXID signal early on
// before the signal stack is set, as glibc doesn't allow us to block
// SIGSETXID. So a signal may land on the current stack and clobber
// the content below the SP. We store the LR again after the SP is
// decremented.
q = obj.Appendp(q, newprog)
q.As = mov
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
q.From.Reg = REGLINK
q.To.Type = obj.TYPE_MEM
q.To.Offset = 0
q.To.Reg = REGSP
}
if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {

View File

@ -410,6 +410,16 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
prologue.Spadj = int32(stacksize)
prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
// On Linux, in a cgo binary we may get a SIGSETXID signal early on
// before the signal stack is set, as glibc doesn't allow us to block
// SIGSETXID. So a signal may land on the current stack and clobber
// the content below the SP. We store the LR again after the SP is
// decremented.
prologue = obj.Appendp(prologue, newprog)
prologue.As = AMOV
prologue.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
}
if cursym.Func().Text.From.Sym.Wrapper() {

View File

@ -358,6 +358,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
// On Linux, in a cgo binary we may get a SIGSETXID signal early on
// before the signal stack is set, as glibc doesn't allow us to block
// SIGSETXID. So a signal may land on the current stack and clobber
// the content below the SP. We store the LR again after the SP is
// decremented.
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_LR
q.To.Type = obj.TYPE_MEM
q.To.Reg = REGSP
q.To.Offset = 0
} else if c.cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have

View File

@ -652,6 +652,11 @@ func loadWindowsHostArchives(ctxt *Link) {
hostObject(ctxt, "crt2", p)
}
}
if *flagRace {
if p := ctxt.findLibPath("libsynchronization.a"); p != "none" {
hostArchive(ctxt, p)
}
}
if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
hostArchive(ctxt, p)
}
@ -1705,6 +1710,11 @@ func (ctxt *Link) hostlink() {
p := writeGDBLinkerScript()
argv = append(argv, "-Wl,-T,"+p)
}
if *flagRace {
if p := ctxt.findLibPath("libsynchronization.a"); p != "libsynchronization.a" {
argv = append(argv, "-lsynchronization")
}
}
// libmingw32 and libmingwex have some inter-dependencies,
// so must use linker groups.
argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")

View File

@ -9,6 +9,7 @@ package ecdsa
import (
"crypto/internal/boring"
"crypto/internal/boring/bbig"
"crypto/internal/boring/bcache"
"math/big"
"unsafe"
)
@ -26,8 +27,8 @@ import (
// still matches before using the cached key. The theory is that the real
// operations are significantly more expensive than the comparison.
var pubCache boring.Cache
var privCache boring.Cache
var pubCache bcache.Cache
var privCache bcache.Cache
func init() {
pubCache.Register()

View File

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package boring
// Package bcache implements a GC-friendly cache (see [Cache]) for BoringCrypto.
package bcache
import (
"sync/atomic"

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.
package boring
package bcache
import (
"fmt"

View File

@ -9,6 +9,7 @@ package rsa
import (
"crypto/internal/boring"
"crypto/internal/boring/bbig"
"crypto/internal/boring/bcache"
"math/big"
"unsafe"
)
@ -31,8 +32,8 @@ type boringPub struct {
orig PublicKey
}
var pubCache boring.Cache
var privCache boring.Cache
var pubCache bcache.Cache
var privCache bcache.Cache
func init() {
pubCache.Register()

View File

@ -283,6 +283,8 @@ func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAn
// CertificateList represents the ASN.1 structure of the same name. See RFC
// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
// signature.
//
// Deprecated: x509.RevocationList should be used instead.
type CertificateList struct {
TBSCertList TBSCertificateList
SignatureAlgorithm AlgorithmIdentifier
@ -311,8 +313,6 @@ type TBSCertificateList struct {
// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
// 5280, section 5.1.
//
// Deprecated: x509.RevocationList should be used instead.
type RevokedCertificate struct {
SerialNumber *big.Int
RevocationTime time.Time

View File

@ -2097,11 +2097,19 @@ func (c *CertificateRequest) CheckSignature() error {
// RevocationList contains the fields used to create an X.509 v2 Certificate
// Revocation list with CreateRevocationList.
type RevocationList struct {
Raw []byte
// Raw contains the complete ASN.1 DER content of the CRL (tbsCertList,
// signatureAlgorithm, and signatureValue.)
Raw []byte
// RawTBSRevocationList contains just the tbsCertList portion of the ASN.1
// DER.
RawTBSRevocationList []byte
RawIssuer []byte
// RawIssuer contains the DER encoded Issuer.
RawIssuer []byte
Issuer pkix.Name
// Issuer contains the DN of the issuing certificate.
Issuer pkix.Name
// AuthorityKeyId is used to identify the public key associated with the
// issuing certificate.
AuthorityKeyId []byte
Signature []byte

View File

@ -87,28 +87,30 @@ type OptionalHeader64 struct {
}
const (
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
IMAGE_FILE_MACHINE_AM33 = 0x1d3
IMAGE_FILE_MACHINE_AMD64 = 0x8664
IMAGE_FILE_MACHINE_ARM = 0x1c0
IMAGE_FILE_MACHINE_ARMNT = 0x1c4
IMAGE_FILE_MACHINE_ARM64 = 0xaa64
IMAGE_FILE_MACHINE_EBC = 0xebc
IMAGE_FILE_MACHINE_I386 = 0x14c
IMAGE_FILE_MACHINE_IA64 = 0x200
IMAGE_FILE_MACHINE_M32R = 0x9041
IMAGE_FILE_MACHINE_MIPS16 = 0x266
IMAGE_FILE_MACHINE_MIPSFPU = 0x366
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
IMAGE_FILE_MACHINE_POWERPC = 0x1f0
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
IMAGE_FILE_MACHINE_R4000 = 0x166
IMAGE_FILE_MACHINE_SH3 = 0x1a2
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
IMAGE_FILE_MACHINE_SH4 = 0x1a6
IMAGE_FILE_MACHINE_SH5 = 0x1a8
IMAGE_FILE_MACHINE_THUMB = 0x1c2
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
IMAGE_FILE_MACHINE_AM33 = 0x1d3
IMAGE_FILE_MACHINE_AMD64 = 0x8664
IMAGE_FILE_MACHINE_ARM = 0x1c0
IMAGE_FILE_MACHINE_ARMNT = 0x1c4
IMAGE_FILE_MACHINE_ARM64 = 0xaa64
IMAGE_FILE_MACHINE_EBC = 0xebc
IMAGE_FILE_MACHINE_I386 = 0x14c
IMAGE_FILE_MACHINE_IA64 = 0x200
IMAGE_FILE_MACHINE_LOONGARCH32 = 0x6232
IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264
IMAGE_FILE_MACHINE_M32R = 0x9041
IMAGE_FILE_MACHINE_MIPS16 = 0x266
IMAGE_FILE_MACHINE_MIPSFPU = 0x366
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
IMAGE_FILE_MACHINE_POWERPC = 0x1f0
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
IMAGE_FILE_MACHINE_R4000 = 0x166
IMAGE_FILE_MACHINE_SH3 = 0x1a2
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
IMAGE_FILE_MACHINE_SH4 = 0x1a6
IMAGE_FILE_MACHINE_SH5 = 0x1a8
IMAGE_FILE_MACHINE_THUMB = 0x1c2
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
)
// IMAGE_DIRECTORY_ENTRY constants

View File

@ -393,7 +393,7 @@ var depsRules = `
< net/mail;
NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
sync/atomic < crypto/internal/boring/fipstls;
sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fipstls;
crypto/internal/boring/sig, crypto/internal/boring/fipstls < crypto/tls/fipsonly;
# CRYPTO is core crypto algorithms - no cgo, fmt, net.
@ -410,7 +410,10 @@ var depsRules = `
< crypto/internal/nistec
< crypto/internal/edwards25519/field, golang.org/x/crypto/curve25519/internal/field
< crypto/internal/edwards25519
< crypto/cipher
< crypto/cipher;
crypto/cipher,
crypto/internal/boring/bcache
< crypto/internal/boring
< crypto/boring
< crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,

View File

@ -17,7 +17,10 @@ import (
"testing"
)
var testfile *ast.File
var (
testfile *ast.File
testsize int64
)
func testprint(out io.Writer, file *ast.File) {
if err := (&Config{TabIndent | UseSpaces | normalizeNumbers, 8, 0}).Fprint(out, fset, file); err != nil {
@ -46,12 +49,15 @@ func initialize() {
}
testfile = file
testsize = int64(len(src))
}
func BenchmarkPrint(b *testing.B) {
if testfile == nil {
initialize()
}
b.ReportAllocs()
b.SetBytes(testsize)
for i := 0; i < b.N; i++ {
testprint(io.Discard, testfile)
}

View File

@ -8,6 +8,7 @@ import (
"fmt"
"sort"
"sync"
"sync/atomic"
)
// -----------------------------------------------------------------------------
@ -366,10 +367,10 @@ func (f *File) Position(p Pos) (pos Position) {
// interval later, using the FileSet.Base should be used as argument
// for FileSet.AddFile.
type FileSet struct {
mutex sync.RWMutex // protects the file set
base int // base offset for the next file
files []*File // list of files in the order added to the set
last *File // cache of last file looked up
mutex sync.RWMutex // protects the file set
base int // base offset for the next file
files []*File // list of files in the order added to the set
last atomic.Pointer[File] // cache of last file looked up
}
// NewFileSet creates a new file set.
@ -405,6 +406,9 @@ func (s *FileSet) Base() int {
// For convenience, File.Pos may be used to create file-specific position
// values from a file offset.
func (s *FileSet) AddFile(filename string, base, size int) *File {
// Allocate f outside the critical section.
f := &File{name: filename, size: size, lines: []int{0}}
s.mutex.Lock()
defer s.mutex.Unlock()
if base < 0 {
@ -413,11 +417,11 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
if base < s.base {
panic(fmt.Sprintf("invalid base %d (should be >= %d)", base, s.base))
}
f.base = base
if size < 0 {
panic(fmt.Sprintf("invalid size %d (should be >= 0)", size))
}
// base >= s.base && size >= 0
f := &File{name: filename, base: base, size: size, lines: []int{0}}
base += size + 1 // +1 because EOF also has a position
if base < 0 {
panic("token.Pos offset overflow (> 2G of source code in file set)")
@ -425,7 +429,7 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
// add the file to the file set
s.base = base
s.files = append(s.files, f)
s.last = f
s.last.Store(f)
return f
}
@ -450,25 +454,25 @@ func searchFiles(a []*File, x int) int {
}
func (s *FileSet) file(p Pos) *File {
s.mutex.RLock()
// common case: p is in last file
if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
s.mutex.RUnlock()
// common case: p is in last file.
if f := s.last.Load(); f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
return f
}
s.mutex.RLock()
defer s.mutex.RUnlock()
// p is not in last file - search all files
if i := searchFiles(s.files, int(p)); i >= 0 {
f := s.files[i]
// f.base <= int(p) by definition of searchFiles
if int(p) <= f.base+f.size {
s.mutex.RUnlock()
s.mutex.Lock()
s.last = f // race is ok - s.last is only a cache
s.mutex.Unlock()
// Update cache of last file. A race is ok,
// but an exclusive lock causes heavy contention.
s.last.Store(f)
return f
}
}
s.mutex.RUnlock()
return nil
}

View File

@ -39,7 +39,7 @@ func (s *FileSet) Read(decode func(any) error) error {
}
}
s.files = files
s.last = nil
s.last.Store(nil)
s.mutex.Unlock()
return nil

View File

@ -372,7 +372,7 @@ func TestIssue47243_TypedRHS(t *testing.T) {
testFiles(t, &StdSizes{4, 4}, []string{"p.go"}, [][]byte{[]byte(src)}, false, nil)
}
func TestCheck(t *testing.T) { testDirFiles(t, "testdata/check", false) }
func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", false) }
func TestSpec(t *testing.T) { testDirFiles(t, "testdata/spec", false) }
func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", false) }
func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", false) }

View File

@ -138,4 +138,26 @@ const (
f // ERROR invalid array length
)
// Test that identifiers in implicit (omitted) RHS
// expressions of constant declarations are resolved
// in the correct context; see issues #49157, #53585.
const X = 2
func _() {
const (
A = iota // 0
iota = iota // 1
B // 1 (iota is declared locally on prev. line)
C // 1
)
assert(A == 0 && B == 1 && C == 1)
const (
X = X + X
Y
Z = iota
)
assert(X == 4 && Y == 8 && Z == 1)
}
// TODO(gri) move extra tests from testdata/const0.src into here

View File

@ -280,7 +280,7 @@ func TestTypedContent(t *testing.T) {
[]string{
`#ZgotmplZ`,
`#ZgotmplZ`,
// Commas are not esacped
// Commas are not escaped.
`Hello,#ZgotmplZ`,
// Leading spaces are not percent escapes.
` dir=%22ltr%22`,

View File

@ -13,8 +13,8 @@ if [ $# != 1 ]; then
exit 1
fi
go test -run ClientServerParallel4 -trace "testdata/http_$1_good" net/http
go test -run 'TraceStress$|TraceStressStartStop$|TestUserTaskSpan$' runtime/trace -savetraces
go test -run '^$' -bench ClientServerParallel4 -benchtime 10x -trace "testdata/http_$1_good" net/http
go test -run 'TraceStress$|TraceStressStartStop$|TestUserTaskRegion$' runtime/trace -savetraces
mv ../../runtime/trace/TestTraceStress.trace "testdata/stress_$1_good"
mv ../../runtime/trace/TestTraceStressStartStop.trace "testdata/stress_start_stop_$1_good"
mv ../../runtime/trace/TestUserTaskSpan.trace "testdata/user_task_span_$1_good"
mv ../../runtime/trace/TestUserTaskRegion.trace "testdata/user_task_region_$1_good"

View File

@ -152,8 +152,8 @@ func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]stri
}
switch ver {
case 1005, 1007, 1008, 1009, 1010, 1011, 1019:
// Note: When adding a new version, add canned traces
// from the old version to the test suite using mkcanned.bash.
// Note: When adding a new version, confirm that canned traces from the
// old version are part of the test suite. Add them using mkcanned.bash.
break
default:
err = fmt.Errorf("unsupported trace file version %v.%v (update Go toolchain) %v", ver/1000, ver%1000, ver)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -111,7 +111,8 @@ type Closer interface {
// interpreted according to whence:
// SeekStart means relative to the start of the file,
// SeekCurrent means relative to the current offset, and
// SeekEnd means relative to the end.
// SeekEnd means relative to the end
// (for example, offset = -2 specifies the penultimate byte of the file).
// Seek returns the new offset relative to the start of the
// file or an error, if any.
//

View File

@ -103,6 +103,12 @@ func (h Header) Clone() Header {
sv := make([]string, nv) // shared backing array for headers' values
h2 := make(Header, len(h))
for k, vv := range h {
if vv == nil {
// Preserve nil values. ReverseProxy distinguishes
// between nil and zero-length header values.
h2[k] = nil
continue
}
n := copy(sv, vv)
h2[k] = sv[:n:n]
sv = sv[n:]

View File

@ -248,6 +248,11 @@ func TestCloneOrMakeHeader(t *testing.T) {
in: Header{"foo": {"bar"}},
want: Header{"foo": {"bar"}},
},
{
name: "nil value",
in: Header{"foo": nil},
want: Header{"foo": nil},
},
}
for _, tt := range tests {

View File

@ -6245,6 +6245,7 @@ func TestUnsupportedTransferEncodingsReturn501(t *testing.T) {
"fugazi",
"foo-bar",
"unknown",
"\rchunked",
}
for _, badTE := range unsupportedTEs {

View File

@ -642,7 +642,7 @@ func (t *transferReader) parseTransferEncoding() error {
if len(raw) != 1 {
return &unsupportedTEError{fmt.Sprintf("too many transfer encodings: %q", raw)}
}
if !ascii.EqualFold(textproto.TrimString(raw[0]), "chunked") {
if !ascii.EqualFold(raw[0], "chunked") {
return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])}
}

View File

@ -156,7 +156,7 @@ func TestLookupLocalPTR(t *testing.T) {
}
expected, err := lookupPTR(addr.String())
if err != nil {
t.Logf("skipping failed lookup %s test: %s", addr.String(), err)
t.Skipf("skipping failed lookup %s test: %s", addr.String(), err)
}
sort.Strings(expected)
sort.Strings(names)
@ -179,6 +179,7 @@ func TestLookupPTR(t *testing.T) {
expected, err := lookupPTR(addr)
if err != nil {
t.Logf("skipping failed lookup %s test: %s", addr, err)
continue
}
sort.Strings(expected)
sort.Strings(names)

View File

@ -97,6 +97,17 @@ func TestCloseWrite(t *testing.T) {
t.Error(err)
return
}
// Workaround for https://go.dev/issue/49352.
// On arm64 macOS (current as of macOS 12.4),
// reading from a socket at the same time as the client
// is closing it occasionally hangs for 60 seconds before
// returning ECONNRESET. Sleep for a bit to give the
// socket time to close before trying to read from it.
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
time.Sleep(10 * time.Millisecond)
}
if !deadline.IsZero() {
c.SetDeadline(deadline)
}

View File

@ -283,6 +283,7 @@ var readTimeoutTests = []struct {
{50 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
}
// There is a very similar copy of this in os/timeout_test.go.
func TestReadTimeout(t *testing.T) {
handler := func(ls *localServer, ln Listener) {
c, err := ln.Accept()
@ -334,6 +335,7 @@ func TestReadTimeout(t *testing.T) {
}
}
// There is a very similar copy of this in os/timeout_test.go.
func TestReadTimeoutMustNotReturn(t *testing.T) {
t.Parallel()
@ -466,6 +468,7 @@ var writeTimeoutTests = []struct {
{10 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
}
// There is a very similar copy of this in os/timeout_test.go.
func TestWriteTimeout(t *testing.T) {
t.Parallel()
@ -506,6 +509,7 @@ func TestWriteTimeout(t *testing.T) {
}
}
// There is a very similar copy of this in os/timeout_test.go.
func TestWriteTimeoutMustNotReturn(t *testing.T) {
t.Parallel()
@ -685,6 +689,7 @@ func nextTimeout(actual time.Duration) (next time.Duration, ok bool) {
return next, true
}
// There is a very similar copy of this in os/timeout_test.go.
func TestReadTimeoutFluctuation(t *testing.T) {
ln := newLocalListener(t, "tcp")
defer ln.Close()
@ -741,6 +746,7 @@ func TestReadTimeoutFluctuation(t *testing.T) {
}
}
// There is a very similar copy of this in os/timeout_test.go.
func TestReadFromTimeoutFluctuation(t *testing.T) {
c1 := newLocalPacketListener(t, "udp")
defer c1.Close()
@ -876,11 +882,13 @@ func TestWriteTimeoutFluctuation(t *testing.T) {
}
}
// There is a very similar copy of this in os/timeout_test.go.
func TestVariousDeadlines(t *testing.T) {
t.Parallel()
testVariousDeadlines(t)
}
// There is a very similar copy of this in os/timeout_test.go.
func TestVariousDeadlines1Proc(t *testing.T) {
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
@ -890,6 +898,7 @@ func TestVariousDeadlines1Proc(t *testing.T) {
testVariousDeadlines(t)
}
// There is a very similar copy of this in os/timeout_test.go.
func TestVariousDeadlines4Proc(t *testing.T) {
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
@ -1067,6 +1076,7 @@ func TestReadWriteProlongedTimeout(t *testing.T) {
}
}
// There is a very similar copy of this in os/timeout_test.go.
func TestReadWriteDeadlineRace(t *testing.T) {
t.Parallel()

View File

@ -15,6 +15,13 @@ import (
"testing"
)
var pathVar string = func() string {
if runtime.GOOS == "plan9" {
return "path"
}
return "PATH"
}()
func TestLookPath(t *testing.T) {
testenv.MustHaveExec(t)
@ -42,22 +49,24 @@ func TestLookPath(t *testing.T) {
if err = os.Chdir(tmpDir); err != nil {
t.Fatal(err)
}
origPath := os.Getenv("PATH")
defer os.Setenv("PATH", origPath)
t.Setenv("PWD", tmpDir)
t.Logf(". is %#q", tmpDir)
origPath := os.Getenv(pathVar)
// Add "." to PATH so that exec.LookPath looks in the current directory on all systems.
// And try to trick it with "../testdir" too.
for _, dir := range []string{".", "../testdir"} {
os.Setenv("PATH", dir+string(filepath.ListSeparator)+origPath)
t.Run("PATH="+dir, func(t *testing.T) {
t.Run(pathVar+"="+dir, func(t *testing.T) {
t.Setenv(pathVar, dir+string(filepath.ListSeparator)+origPath)
good := dir + "/execabs-test"
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
t.Fatalf("LookPath(%q) = %q, %v, want \"%s...\", nil", good, found, err, good)
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
}
if runtime.GOOS == "windows" {
good = dir + `\execabs-test`
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
t.Fatalf("LookPath(%q) = %q, %v, want \"%s...\", nil", good, found, err, good)
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
}
}
@ -84,4 +93,81 @@ func TestLookPath(t *testing.T) {
}
})
}
// Test the behavior when the first entry in PATH is an absolute name for the
// current directory.
//
// On Windows, "." may or may not be implicitly included before the explicit
// %PATH%, depending on the process environment;
// see https://go.dev/issue/4394.
//
// If the relative entry from "." resolves to the same executable as what
// would be resolved from an absolute entry in %PATH% alone, LookPath should
// return the absolute version of the path instead of ErrDot.
// (See https://go.dev/issue/53536.)
//
// If PATH does not implicitly include "." (such as on Unix platforms, or on
// Windows configured with NoDefaultCurrentDirectoryInExePath), then this
// lookup should succeed regardless of the behavior for ".", so it may be
// useful to run as a control case even on those platforms.
t.Run(pathVar+"=$PWD", func(t *testing.T) {
t.Setenv(pathVar, tmpDir+string(filepath.ListSeparator)+origPath)
good := filepath.Join(tmpDir, "execabs-test")
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
t.Fatalf(`LookPath(%#q) = %#q, %v, want \"%s...\", nil`, good, found, err, good)
}
if found, err := LookPath("execabs-test"); err != nil || !strings.HasPrefix(found, good) {
t.Fatalf(`LookPath(%#q) = %#q, %v, want \"%s...\", nil`, "execabs-test", found, err, good)
}
cmd := Command("execabs-test")
if cmd.Err != nil {
t.Fatalf("Command(%#q).Err = %v; want nil", "execabs-test", cmd.Err)
}
})
t.Run(pathVar+"=$OTHER", func(t *testing.T) {
// Control case: if the lookup returns ErrDot when PATH is empty, then we
// know that PATH implicitly includes ".". If it does not, then we don't
// expect to see ErrDot at all in this test (because the path will be
// unambiguously absolute).
wantErrDot := false
t.Setenv(pathVar, "")
if found, err := LookPath("execabs-test"); errors.Is(err, ErrDot) {
wantErrDot = true
} else if err == nil {
t.Fatalf(`with PATH='', LookPath(%#q) = %#q; want non-nil error`, "execabs-test", found)
}
// Set PATH to include an explicit directory that contains a completely
// independent executable that happens to have the same name as an
// executable in ".". If "." is included implicitly, looking up the
// (unqualified) executable name will return ErrDot; otherwise, the
// executable in "." should have no effect and the lookup should
// unambiguously resolve to the directory in PATH.
dir := t.TempDir()
executable := "execabs-test"
if runtime.GOOS == "windows" {
executable += ".exe"
}
if err := os.WriteFile(filepath.Join(dir, executable), []byte{1, 2, 3}, 0777); err != nil {
t.Fatal(err)
}
t.Setenv(pathVar, dir+string(filepath.ListSeparator)+origPath)
found, err := LookPath("execabs-test")
if wantErrDot {
wantFound := filepath.Join(".", executable)
if found != wantFound || !errors.Is(err, ErrDot) {
t.Fatalf(`LookPath(%#q) = %#q, %v, want %#q, Is ErrDot`, "execabs-test", found, err, wantFound)
}
} else {
wantFound := filepath.Join(dir, executable)
if found != wantFound || err != nil {
t.Fatalf(`LookPath(%#q) = %#q, %v, want %#q, nil`, "execabs-test", found, err, wantFound)
}
}
})
}

View File

@ -96,20 +96,43 @@ func LookPath(file string) (string, error) {
// have configured their environment this way!
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-needcurrentdirectoryforexepathw
// See also go.dev/issue/43947.
var (
dotf string
dotErr error
)
if _, found := syscall.Getenv("NoDefaultCurrentDirectoryInExePath"); !found {
if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
return f, &Error{file, ErrDot}
dotf, dotErr = f, &Error{file, ErrDot}
}
}
path := os.Getenv("path")
for _, dir := range filepath.SplitList(path) {
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
if dotErr != nil {
// https://go.dev/issue/53536: if we resolved a relative path implicitly,
// and it is the same executable that would be resolved from the explicit %PATH%,
// prefer the explicit name for the executable (and, likely, no error) instead
// of the equivalent implicit name with ErrDot.
//
// Otherwise, return the ErrDot for the implicit path as soon as we find
// out that the explicit one doesn't match.
dotfi, dotfiErr := os.Lstat(dotf)
fi, fiErr := os.Lstat(f)
if dotfiErr != nil || fiErr != nil || !os.SameFile(dotfi, fi) {
return dotf, dotErr
}
}
if !filepath.IsAbs(f) {
return f, &Error{file, ErrDot}
}
return f, nil
}
}
if dotErr != nil {
return dotf, dotErr
}
return "", &Error{file, ErrNotFound}
}

View File

@ -58,6 +58,7 @@ var readTimeoutTests = []struct {
{50 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
}
// There is a very similar copy of this in net/timeout_test.go.
func TestReadTimeout(t *testing.T) {
t.Parallel()
@ -98,6 +99,7 @@ func TestReadTimeout(t *testing.T) {
}
}
// There is a very similar copy of this in net/timeout_test.go.
func TestReadTimeoutMustNotReturn(t *testing.T) {
t.Parallel()
@ -149,6 +151,7 @@ var writeTimeoutTests = []struct {
{10 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
}
// There is a very similar copy of this in net/timeout_test.go.
func TestWriteTimeout(t *testing.T) {
t.Parallel()
@ -186,6 +189,7 @@ func TestWriteTimeout(t *testing.T) {
}
}
// There is a very similar copy of this in net/timeout_test.go.
func TestWriteTimeoutMustNotReturn(t *testing.T) {
t.Parallel()
@ -230,28 +234,60 @@ func TestWriteTimeoutMustNotReturn(t *testing.T) {
}
}
func timeoutReader(r *os.File, d, min, max time.Duration, ch chan<- error) {
var err error
defer func() { ch <- err }()
const (
// minDynamicTimeout is the minimum timeout to attempt for
// tests that automatically increase timeouts until success.
//
// Lower values may allow tests to succeed more quickly if the value is close
// to the true minimum, but may require more iterations (and waste more time
// and CPU power on failed attempts) if the timeout is too low.
minDynamicTimeout = 1 * time.Millisecond
t0 := time.Now()
if err = r.SetReadDeadline(time.Now().Add(d)); err != nil {
return
}
b := make([]byte, 256)
var n int
n, err = r.Read(b)
t1 := time.Now()
if n != 0 || err == nil || !isDeadlineExceeded(err) {
err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
return
}
if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
err = fmt.Errorf("Read took %s; expected %s", dt, d)
return
// maxDynamicTimeout is the maximum timeout to attempt for
// tests that automatically increase timeouts until succeess.
//
// This should be a strict upper bound on the latency required to hit a
// timeout accurately, even on a slow or heavily-loaded machine. If a test
// would increase the timeout beyond this value, the test fails.
maxDynamicTimeout = 4 * time.Second
)
// timeoutUpperBound returns the maximum time that we expect a timeout of
// duration d to take to return the caller.
func timeoutUpperBound(d time.Duration) time.Duration {
switch runtime.GOOS {
case "openbsd", "netbsd":
// NetBSD and OpenBSD seem to be unable to reliably hit deadlines even when
// the absolute durations are long.
// In https://build.golang.org/log/c34f8685d020b98377dd4988cd38f0c5bd72267e,
// we observed that an openbsd-amd64-68 builder took 4.090948779s for a
// 2.983020682s timeout (37.1% overhead).
// (See https://go.dev/issue/50189 for further detail.)
// Give them lots of slop to compensate.
return d * 3 / 2
}
// Other platforms seem to hit their deadlines more reliably,
// at least when they are long enough to cover scheduling jitter.
return d * 11 / 10
}
// nextTimeout returns the next timeout to try after an operation took the given
// actual duration with a timeout shorter than that duration.
func nextTimeout(actual time.Duration) (next time.Duration, ok bool) {
if actual >= maxDynamicTimeout {
return maxDynamicTimeout, false
}
// Since the previous attempt took actual, we can't expect to beat that
// duration by any significant margin. Try the next attempt with an arbitrary
// factor above that, so that our growth curve is at least exponential.
next = actual * 5 / 4
if next > maxDynamicTimeout {
return maxDynamicTimeout, true
}
return next, true
}
// There is a very similar copy of this in net/timeout_test.go.
func TestReadTimeoutFluctuation(t *testing.T) {
t.Parallel()
@ -262,47 +298,47 @@ func TestReadTimeoutFluctuation(t *testing.T) {
defer r.Close()
defer w.Close()
max := time.NewTimer(time.Second)
defer max.Stop()
ch := make(chan error)
go timeoutReader(r, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
select {
case <-max.C:
t.Fatal("Read took over 1s; expected 0.1s")
case err := <-ch:
if !isDeadlineExceeded(err) {
t.Fatal(err)
}
}
}
func timeoutWriter(w *os.File, d, min, max time.Duration, ch chan<- error) {
var err error
defer func() { ch <- err }()
t0 := time.Now()
if err = w.SetWriteDeadline(time.Now().Add(d)); err != nil {
return
}
var n int
d := minDynamicTimeout
b := make([]byte, 256)
for {
n, err = w.Write([]byte("TIMEOUT WRITER"))
if err != nil {
break
t.Logf("SetReadDeadline(+%v)", d)
t0 := time.Now()
deadline := t0.Add(d)
if err = r.SetReadDeadline(deadline); err != nil {
t.Fatalf("SetReadDeadline(%v): %v", deadline, err)
}
}
t1 := time.Now()
if err == nil || !isDeadlineExceeded(err) {
err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
return
}
if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
err = fmt.Errorf("Write took %s; expected %s", dt, d)
return
var n int
n, err = r.Read(b)
t1 := time.Now()
if n != 0 || err == nil || !isDeadlineExceeded(err) {
t.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
}
actual := t1.Sub(t0)
if t1.Before(deadline) {
t.Errorf("Read took %s; expected at least %s", actual, d)
}
if t.Failed() {
return
}
if want := timeoutUpperBound(d); actual > want {
next, ok := nextTimeout(actual)
if !ok {
t.Fatalf("Read took %s; expected at most %v", actual, want)
}
// Maybe this machine is too slow to reliably schedule goroutines within
// the requested duration. Increase the timeout and try again.
t.Logf("Read took %s (expected %s); trying with longer timeout", actual, d)
d = next
continue
}
break
}
}
// There is a very similar copy of this in net/timeout_test.go.
func TestWriteTimeoutFluctuation(t *testing.T) {
t.Parallel()
@ -313,27 +349,71 @@ func TestWriteTimeoutFluctuation(t *testing.T) {
defer r.Close()
defer w.Close()
d := time.Second
max := time.NewTimer(d)
defer max.Stop()
ch := make(chan error)
go timeoutWriter(w, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
select {
case <-max.C:
t.Fatalf("Write took over %v; expected 0.1s", d)
case err := <-ch:
if !isDeadlineExceeded(err) {
t.Fatal(err)
d := minDynamicTimeout
for {
t.Logf("SetWriteDeadline(+%v)", d)
t0 := time.Now()
deadline := t0.Add(d)
if err = w.SetWriteDeadline(deadline); err != nil {
t.Fatalf("SetWriteDeadline(%v): %v", deadline, err)
}
var n int64
for {
var dn int
dn, err = w.Write([]byte("TIMEOUT TRANSMITTER"))
n += int64(dn)
if err != nil {
break
}
}
t1 := time.Now()
if err == nil || !isDeadlineExceeded(err) {
t.Fatalf("Write did not return (any, timeout): (%d, %v)", n, err)
}
actual := t1.Sub(t0)
if t1.Before(deadline) {
t.Errorf("Write took %s; expected at least %s", actual, d)
}
if t.Failed() {
return
}
if want := timeoutUpperBound(d); actual > want {
if n > 0 {
// SetWriteDeadline specifies a time “after which I/O operations fail
// instead of blocking”. However, the kernel's send buffer is not yet
// full, we may be able to write some arbitrary (but finite) number of
// bytes to it without blocking.
t.Logf("Wrote %d bytes into send buffer; retrying until buffer is full", n)
if d <= maxDynamicTimeout/2 {
// We don't know how long the actual write loop would have taken if
// the buffer were full, so just guess and double the duration so that
// the next attempt can make twice as much progress toward filling it.
d *= 2
}
} else if next, ok := nextTimeout(actual); !ok {
t.Fatalf("Write took %s; expected at most %s", actual, want)
} else {
// Maybe this machine is too slow to reliably schedule goroutines within
// the requested duration. Increase the timeout and try again.
t.Logf("Write took %s (expected %s); trying with longer timeout", actual, d)
d = next
}
continue
}
break
}
}
// There is a very similar copy of this in net/timeout_test.go.
func TestVariousDeadlines(t *testing.T) {
t.Parallel()
testVariousDeadlines(t)
}
// There is a very similar copy of this in net/timeout_test.go.
func TestVariousDeadlines1Proc(t *testing.T) {
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
@ -343,6 +423,7 @@ func TestVariousDeadlines1Proc(t *testing.T) {
testVariousDeadlines(t)
}
// There is a very similar copy of this in net/timeout_test.go.
func TestVariousDeadlines4Proc(t *testing.T) {
// Cannot use t.Parallel - modifies global GOMAXPROCS.
if testing.Short() {
@ -454,6 +535,7 @@ func testVariousDeadlines(t *testing.T) {
}
}
// There is a very similar copy of this in net/timeout_test.go.
func TestReadWriteDeadlineRace(t *testing.T) {
t.Parallel()

View File

@ -90,21 +90,6 @@ TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
* go-routine
*/
// void gosave(Gobuf*)
// save state in Gobuf; setjmp
TEXT runtime·gosave(SB), NOSPLIT|NOFRAME, $0-8
MOVV buf+0(FP), R19
MOVV R3, gobuf_sp(R19)
MOVV R1, gobuf_pc(R19)
MOVV g, gobuf_g(R19)
MOVV R0, gobuf_lr(R19)
MOVV R0, gobuf_ret(R19)
// Assert ctxt is zero. See func save.
MOVV gobuf_ctxt(R19), R19
BEQ R19, 2(PC)
JAL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8

View File

@ -312,9 +312,9 @@ func ReadMetricsSlow(memStats *MemStats, samplesp unsafe.Pointer, len, cap int)
// Initialize the metrics beforehand because this could
// allocate and skew the stats.
semacquire(&metricsSema)
metricsLock()
initMetrics()
semrelease(&metricsSema)
metricsUnlock()
systemstack(func() {
// Read memstats first. It's going to flush

View File

@ -92,6 +92,8 @@ func init() {
// 4. result: an integer representing the comparison result. 0 indicates
// equality (comparison will ignored by libfuzzer), non-zero indicates a
// difference (comparison will be taken into consideration).
//
//go:nosplit
func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
if s1 != s2 {
libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
@ -102,6 +104,8 @@ func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
// This function has now the same implementation as libfuzzerHookStrCmp because we lack better checks
// for case-insensitive string equality in the runtime package.
//
//go:nosplit
func libfuzzerHookEqualFold(s1, s2 string, fakePC int) {
if s1 != s2 {
libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))

View File

@ -12,9 +12,12 @@ import (
)
var (
// metrics is a map of runtime/metrics keys to
// data used by the runtime to sample each metric's
// value.
// metrics is a map of runtime/metrics keys to data used by the runtime
// to sample each metric's value. metricsInit indicates it has been
// initialized.
//
// These fields are protected by metricsSema which should be
// locked/unlocked with metricsLock() / metricsUnlock().
metricsSema uint32 = 1
metricsInit bool
metrics map[string]metricData
@ -34,6 +37,23 @@ type metricData struct {
compute func(in *statAggregate, out *metricValue)
}
func metricsLock() {
// Acquire the metricsSema but with handoff. Operations are typically
// expensive enough that queueing up goroutines and handing off between
// them will be noticeably better-behaved.
semacquire1(&metricsSema, true, 0, 0)
if raceenabled {
raceacquire(unsafe.Pointer(&metricsSema))
}
}
func metricsUnlock() {
if raceenabled {
racerelease(unsafe.Pointer(&metricsSema))
}
semrelease(&metricsSema)
}
// initMetrics initializes the metrics map if it hasn't been yet.
//
// metricsSema must be held.
@ -570,10 +590,7 @@ func readMetrics(samplesp unsafe.Pointer, len int, cap int) {
sl := slice{samplesp, len, cap}
samples := *(*[]metricSample)(unsafe.Pointer(&sl))
// Acquire the metricsSema but with handoff. This operation
// is expensive enough that queueing up goroutines and handing
// off between them will be noticeably better-behaved.
semacquire1(&metricsSema, true, 0, 0)
metricsLock()
// Ensure the map is initialized.
initMetrics()
@ -597,5 +614,5 @@ func readMetrics(samplesp unsafe.Pointer, len int, cap int) {
data.compute(&agg, &sample.value)
}
semrelease(&metricsSema)
metricsUnlock()
}

View File

@ -1579,7 +1579,7 @@ func sync_runtime_registerPoolCleanup(f func()) {
poolcleanup = f
}
//go:linkname boring_registerCache crypto/internal/boring.registerCache
//go:linkname boring_registerCache crypto/internal/boring/bcache.registerCache
func boring_registerCache(p unsafe.Pointer) {
boringCaches = append(boringCaches, p)
}

View File

@ -46,7 +46,64 @@ const fastlogNumBits = 5
func computeTable() []float64 {
fastlog2Table := make([]float64, 1<<fastlogNumBits+1)
for i := 0; i <= (1 << fastlogNumBits); i++ {
fastlog2Table[i] = math.Log2(1.0 + float64(i)/(1<<fastlogNumBits))
fastlog2Table[i] = log2(1.0 + float64(i)/(1<<fastlogNumBits))
}
return fastlog2Table
}
// log2 is a local copy of math.Log2 with an explicit float64 conversion
// to disable FMA. This lets us generate the same output on all platforms.
func log2(x float64) float64 {
frac, exp := math.Frexp(x)
// Make sure exact powers of two give an exact answer.
// Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1.
if frac == 0.5 {
return float64(exp - 1)
}
return float64(nlog(frac)*(1/math.Ln2)) + float64(exp)
}
// nlog is a local copy of math.Log with explicit float64 conversions
// to disable FMA. This lets us generate the same output on all platforms.
func nlog(x float64) float64 {
const (
Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */
L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */
L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */
L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */
L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */
L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */
L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */
)
// special cases
switch {
case math.IsNaN(x) || math.IsInf(x, 1):
return x
case x < 0:
return math.NaN()
case x == 0:
return math.Inf(-1)
}
// reduce
f1, ki := math.Frexp(x)
if f1 < math.Sqrt2/2 {
f1 *= 2
ki--
}
f := f1 - 1
k := float64(ki)
// compute
s := float64(f / (2 + f))
s2 := float64(s * s)
s4 := float64(s2 * s2)
t1 := s2 * float64(L1+float64(s4*float64(L3+float64(s4*float64(L5+float64(s4*L7))))))
t2 := s4 * float64(L2+float64(s4*float64(L4+float64(s4*L6))))
R := float64(t1 + t2)
hfsq := float64(0.5 * f * f)
return float64(k*Ln2Hi) - ((hfsq - (float64(s*float64(hfsq+R)) + float64(k*Ln2Lo))) - f)
}

View File

@ -12,12 +12,30 @@ import (
// cbs stores all registered Go callbacks.
var cbs struct {
lock mutex
lock mutex // use cbsLock / cbsUnlock for race instrumentation.
ctxt [cb_max]winCallback
index map[winCallbackKey]int
n int
}
func cbsLock() {
lock(&cbs.lock)
// compileCallback is used by goenvs prior to completion of schedinit.
// raceacquire involves a racecallback to get the proc, which is not
// safe prior to scheduler initialization. Thus avoid instrumentation
// until then.
if raceenabled && mainStarted {
raceacquire(unsafe.Pointer(&cbs.lock))
}
}
func cbsUnlock() {
if raceenabled && mainStarted {
racerelease(unsafe.Pointer(&cbs.lock))
}
unlock(&cbs.lock)
}
// winCallback records information about a registered Go callback.
type winCallback struct {
fn *funcval // Go function
@ -302,11 +320,11 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) {
key := winCallbackKey{(*funcval)(fn.data), cdecl}
lock(&cbs.lock) // We don't unlock this in a defer because this is used from the system stack.
cbsLock()
// Check if this callback is already registered.
if n, ok := cbs.index[key]; ok {
unlock(&cbs.lock)
cbsUnlock()
return callbackasmAddr(n)
}
@ -316,7 +334,7 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) {
}
n := cbs.n
if n >= len(cbs.ctxt) {
unlock(&cbs.lock)
cbsUnlock()
throw("too many callback functions")
}
c := winCallback{key.fn, retPop, abiMap}
@ -324,7 +342,7 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) {
cbs.index[key] = n
cbs.n++
unlock(&cbs.lock)
cbsUnlock()
return callbackasmAddr(n)
}

View File

@ -138,6 +138,9 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
prec = 1
}
digits = prec
default:
// Invalid mode.
digits = 1
}
var buf [24]byte
if bitSize == 32 && digits <= 9 {

View File

@ -151,6 +151,11 @@ var ftoatests = []ftoaTest{
{498484681984085570, 'f', -1, "498484681984085570"},
{-5.8339553793802237e+23, 'g', -1, "-5.8339553793802237e+23"},
// Issue 52187
{123.45, '?', 0, "%?"},
{123.45, '?', 1, "%?"},
{123.45, '?', -1, "%?"},
// rounding
{2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"},
{2.275555555555555, 'x', 0, "0x1p+01"},

36
test/const8.go Normal file
View File

@ -0,0 +1,36 @@
// run
// Copyright 2022 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.
// Test that identifiers in implicit (omitted) RHS
// expressions of constant declarations are resolved
// in the correct context; see issues #49157, #53585.
package main
const X = 2
func main() {
const (
A = iota // 0
iota = iota // 1
B // 1 (iota is declared locally on prev. line)
C // 1
)
if A != 0 || B != 1 || C != 1 {
println("got", A, B, C, "want 0 1 1")
panic("FAILED")
}
const (
X = X + X
Y
Z = iota
)
if X != 4 || Y != 8 || Z != 1 {
println("got", X, Y, Z, "want 4 8 1")
panic("FAILED")
}
}

View File

@ -0,0 +1,17 @@
// compile
// Copyright 2022 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.
// gofrontend incorrectly gave an error for this code.
package p
type B bool
func main() {
var v B = false
if (true && true) && v {
}
}

View File

@ -0,0 +1,9 @@
// Copyright 2022 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 a
func F() any {
return struct{ int }{0}
}

View File

@ -0,0 +1,19 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "./a"
func F() any {
return struct{ int }{0}
}
func main() {
_, ok1 := F().(struct{ int })
_, ok2 := a.F().(struct{ int })
if !ok1 || ok2 {
panic(0)
}
}

View File

@ -0,0 +1,10 @@
// rundir
// Copyright 2022 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.
// Test that an embedded unexported type has a different name in
// different packages.
package ignored

View File

@ -0,0 +1,9 @@
// Copyright 2022 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 a
func F() complex128 {
return 0+0i
}

View File

@ -0,0 +1,11 @@
// Copyright 2022 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 b
import "./a"
func F() complex128 {
return a.F()
}

View File

@ -0,0 +1,9 @@
// compiledir
// Copyright 2022 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.
// gofrontend crash importing a complex zero value.
package ignored

View File

@ -0,0 +1,17 @@
// compile
// Copyright 2022 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.
// gofrontend crashed compiling this code.
package p
type S struct {}
func (s *S) test(_ string) {}
var T = [1]func(*S, string) {
(*S).test,
}

View File

@ -0,0 +1,42 @@
// run
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "math"
func main() {
f()
g()
h()
}
func f() {
for i := int64(math.MaxInt64); i <= math.MaxInt64; i++ {
if i < 0 {
println("done")
return
}
println(i, i < 0)
}
}
func g() {
for i := int64(math.MaxInt64) - 1; i <= math.MaxInt64; i++ {
if i < 0 {
println("done")
return
}
println(i, i < 0)
}
}
func h() {
for i := int64(math.MaxInt64) - 2; i <= math.MaxInt64; i += 2 {
if i < 0 {
println("done")
return
}
println(i, i < 0)
}
}

View File

@ -0,0 +1,8 @@
9223372036854775807 false
done
9223372036854775806 false
9223372036854775807 false
done
9223372036854775805 false
9223372036854775807 false
done

View File

@ -0,0 +1,21 @@
// run
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
var c = b
var d = a
var a, b any = any(nil).(bool)
func main() {
if c != false {
panic(c)
}
if d != false {
panic(d)
}
}

View File

@ -1967,7 +1967,6 @@ var go118Failures = setOf(
"typeparam/nested.go", // 1.18 compiler doesn't support function-local types with generics
"typeparam/issue51521.go", // 1.18 compiler produces bad panic message and link error
"typeparam/issue53419.go", // 1.18 compiler mishandles generic selector resolution
"typeparam/issue53477.go", // 1.18 compiler mishandles generic interface-interface comparisons from value switch statements
"typeparam/mdempsky/16.go", // 1.18 compiler uses interface shape type in failed type assertions
"typeparam/mdempsky/17.go", // 1.18 compiler mishandles implicit conversions from range loops
"typeparam/mdempsky/18.go", // 1.18 compiler mishandles implicit conversions in select statements