Merge "[dev.typeparams] all: merge master (8212707) into dev.typeparams" into dev.typeparams

This commit is contained in:
Gerrit Code Review 2021-06-07 19:48:09 +00:00
commit f0c97219a3
33 changed files with 525 additions and 169 deletions

View file

@ -224,12 +224,6 @@ Do not send CLs removing the interior tags from such phrases.
TODO: complete the Vet section TODO: complete the Vet section
</p> </p>
<h2 id="runtime">Runtime</h2>
<p>
TODO: complete the Runtime section
</p>
<h2 id="compiler">Compiler</h2> <h2 id="compiler">Compiler</h2>
<p><!-- golang.org/issue/40724 --> <p><!-- golang.org/issue/40724 -->
@ -434,7 +428,7 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt> <dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
<dd> <dd>
<p><!-- CL 271788 --> <p><!-- CL 271788 -->
TODO: <a href="https://golang.org/cl/271788">https://golang.org/cl/271788</a>: panic if flag name begins with - or contains = Flag declarations now panic if an invalid name is specified.
</p> </p>
</dd> </dd>
</dl><!-- flag --> </dl><!-- flag -->
@ -651,15 +645,22 @@ Do not send CLs removing the interior tags from such phrases.
DragonFly and all OpenBSD systems (it was already defined on DragonFly and all OpenBSD systems (it was already defined on
some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems). some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
</p> </p>
<p><!-- CL 315281 -->
The constants <code>SYS_WAIT6</code> and <code>WEXITED</code>
are now defined on NetBSD systems (<code>SYS_WAIT6</code> was
already defined on DragonFly and FreeBSD systems;
<code>WEXITED</code> was already defined on Darwin, DragonFly,
FreeBSD, Linux, and Solaris systems).
</p>
</dd> </dd>
</dl><!-- syscall --> </dl><!-- syscall -->
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt> <dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
<dd> <dd>
<p><!-- CL 310033 --> <p><!-- CL 310033 -->
TODO: <a href="https://golang.org/cl/310033">https://golang.org/cl/310033</a>: add -shuffle=off|on|N to alter the execution order of tests and benchmarks Added a new <a href="/cmd/go/#hdr-Testing_flags">testing flag</a> <code>-shuffle</code> which controls the execution order of tests and benchmarks.
</p> </p>
<p><!-- CL 260577 --> <p><!-- CL 260577 -->
The new The new
<a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a> <a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a>
@ -689,15 +690,26 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 264077 --> <p><!-- CL 264077 -->
TODO: <a href="https://golang.org/cl/264077">https://golang.org/cl/264077</a>: add Time.IsDST() to check if its Location is in Daylight Savings Time The new <a href="/pkg/time/#Time.IsDST"><code>Time.IsDST</code></a> method can be used to check whether the time
is in Daylight Savings Time in its configured location.
</p> </p>
<p><!-- CL 293349 --> <p><!-- CL 293349 -->
TODO: <a href="https://golang.org/cl/293349">https://golang.org/cl/293349</a>: add Time.Unix{Milli,Micro} and to-Time helpers UnixMicro, UnixMilli The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
<a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a> methods return the number of milliseconds and
microseconds elapsed since January 1, 1970 UTC respectively.<br>
The new <code>UnixMilli</code> and <code>UnixMicro</code> functions return local Time corresponding to given
Unix time.
</p> </p>
<p><!-- CL 300996 --> <p><!-- CL 300996 -->
TODO: <a href="https://golang.org/cl/300996">https://golang.org/cl/300996</a>: support &#34;,&#34; as separator for fractional seconds The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time.
The following time formats are now accepted:
<ul>
<li>2006-01-02 14:06:03,999999999 -0700 MST</li>
<li>Mon Jan _2 14:06:03,120007 2006</li>
<li>Mon Jan 2 14:06:03,120007 2006</li>
</ul>
</p> </p>
<p><!-- CL 320252 --> <p><!-- CL 320252 -->

View file

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of Apr 28, 2021", "Subtitle": "Version of Jun 2, 2021",
"Path": "/ref/spec" "Path": "/ref/spec"
}--> }-->
@ -4909,7 +4909,7 @@ if x := f(); x &lt; y {
<p> <p>
"Switch" statements provide multi-way execution. "Switch" statements provide multi-way execution.
An expression or type specifier is compared to the "cases" An expression or type is compared to the "cases"
inside the "switch" to determine which branch inside the "switch" to determine which branch
to execute. to execute.
</p> </p>
@ -5020,7 +5020,7 @@ floating point, or string constants in case expressions.
A type switch compares types rather than values. It is otherwise similar A type switch compares types rather than values. It is otherwise similar
to an expression switch. It is marked by a special switch expression that to an expression switch. It is marked by a special switch expression that
has the form of a <a href="#Type_assertions">type assertion</a> has the form of a <a href="#Type_assertions">type assertion</a>
using the reserved word <code>type</code> rather than an actual type: using the keyword <code>type</code> rather than an actual type:
</p> </p>
<pre> <pre>

View file

@ -40,7 +40,8 @@ func check(t *testing.T, file string) {
if len(frags) == 1 { if len(frags) == 1 {
continue continue
} }
re, err := regexp.Compile(string(frags[1])) frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1])
re, err := regexp.Compile(frag)
if err != nil { if err != nil {
t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1]) t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
continue continue

View file

@ -40,15 +40,15 @@ func main() {
C.foop = x // ERROR HERE C.foop = x // ERROR HERE
// issue 13129: used to output error about C.unsignedshort with CC=clang // issue 13129: used to output error about C.unsignedshort with CC=clang
var x C.ushort var x1 C.ushort
x = int(0) // ERROR HERE: C\.ushort x1 = int(0) // ERROR HERE: C\.ushort
// issue 13423 // issue 13423
_ = C.fopen() // ERROR HERE _ = C.fopen() // ERROR HERE
// issue 13467 // issue 13467
var x rune = '✈' var x2 rune = '✈'
var _ rune = C.transform(x) // ERROR HERE: C\.int var _ rune = C.transform(x2) // ERROR HERE: C\.int
// issue 13635: used to output error about C.unsignedchar. // issue 13635: used to output error about C.unsignedchar.
// This test tests all such types. // This test tests all such types.
@ -91,10 +91,10 @@ func main() {
// issue 26745 // issue 26745
_ = func(i int) int { _ = func(i int) int {
return C.i + 1 // ERROR HERE: :13 return C.i + 1 // ERROR HERE: 14
} }
_ = func(i int) { _ = func(i int) {
C.fi(i) // ERROR HERE: :6 C.fi(i) // ERROR HERE: 7
} }
C.fi = C.fi // ERROR HERE C.fi = C.fi // ERROR HERE

View file

@ -1638,6 +1638,8 @@ func (p *Package) gccCmd() []string {
c = append(c, "-maix64") c = append(c, "-maix64")
c = append(c, "-mcmodel=large") c = append(c, "-mcmodel=large")
} }
// disable LTO so we get an object whose symbols we can read
c = append(c, "-fno-lto")
c = append(c, "-") //read input from standard input c = append(c, "-") //read input from standard input
return c return c
} }

View file

@ -168,8 +168,18 @@ func (p *Package) writeDefs() {
if *gccgo { if *gccgo {
fmt.Fprintf(fc, "extern byte *%s;\n", n.C) fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
} else { } else {
fmt.Fprintf(fm, "extern char %s[];\n", n.C) // Force a reference to all symbols so that
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) // the external linker will add DT_NEEDED
// entries as needed on ELF systems.
// Treat function variables differently
// to avoid type confict errors from LTO
// (Link Time Optimization).
if n.Kind == "fpvar" {
fmt.Fprintf(fm, "extern void %s();\n", n.C)
} else {
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
}
fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C) fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C) fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C) fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
@ -1042,7 +1052,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
// This unpacks the argument struct above and calls the Go function. // This unpacks the argument struct above and calls the Go function.
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype) fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
if gccResult != "void" { if gccResult != "void" {
// Write results back to frame. // Write results back to frame.

View file

@ -449,7 +449,7 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul
// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields) // parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
var parameterUpdateMu sync.Mutex var parameterUpdateMu sync.Mutex
// FieldOffsetOf returns a concurency-safe version of f.Offset // FieldOffsetOf returns a concurrency-safe version of f.Offset
func FieldOffsetOf(f *types.Field) int64 { func FieldOffsetOf(f *types.Field) int64 {
parameterUpdateMu.Lock() parameterUpdateMu.Lock()
defer parameterUpdateMu.Unlock() defer parameterUpdateMu.Unlock()

View file

@ -886,9 +886,6 @@ func (p *noder) typeExpr(typ syntax.Expr) ir.Ntype {
if n == nil { if n == nil {
return nil return nil
} }
if _, ok := n.(ir.Ntype); !ok {
ir.Dump("NOT NTYPE", n)
}
return n.(ir.Ntype) return n.(ir.Ntype)
} }

View file

@ -999,6 +999,12 @@ func tcRecover(n *ir.CallExpr) ir.Node {
// tcUnsafeAdd typechecks an OUNSAFEADD node. // tcUnsafeAdd typechecks an OUNSAFEADD node.
func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr { func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
if !types.AllowsGoVersion(curpkg(), 1, 17) {
base.ErrorfVers("go1.17", "unsafe.Add")
n.SetType(nil)
return n
}
n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add") n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add")
n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT]) n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT])
if n.X.Type() == nil || n.Y.Type() == nil { if n.X.Type() == nil || n.Y.Type() == nil {
@ -1015,6 +1021,12 @@ func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
// tcUnsafeSlice typechecks an OUNSAFESLICE node. // tcUnsafeSlice typechecks an OUNSAFESLICE node.
func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr { func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr {
if !types.AllowsGoVersion(curpkg(), 1, 17) {
base.ErrorfVers("go1.17", "unsafe.Slice")
n.SetType(nil)
return n
}
n.X = Expr(n.X) n.X = Expr(n.X)
n.Y = Expr(n.Y) n.Y = Expr(n.Y)
if n.X.Type() == nil || n.Y.Type() == nil { if n.X.Type() == nil || n.Y.Type() == nil {

View file

@ -579,6 +579,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Add: case _Add:
// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer // unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
if !check.allowVersion(check.pkg, 1, 17) {
check.error(call.Fun, "unsafe.Add requires go1.17 or later")
return
}
check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add") check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
if x.mode == invalid { if x.mode == invalid {
return return
@ -675,6 +680,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Slice: case _Slice:
// unsafe.Slice(ptr *T, len IntegerType) []T // unsafe.Slice(ptr *T, len IntegerType) []T
if !check.allowVersion(check.pkg, 1, 17) {
check.error(call.Fun, "unsafe.Slice requires go1.17 or later")
return
}
typ := asPointer(x.typ) typ := asPointer(x.typ)
if typ == nil { if typ == nil {
check.errorf(x, invalidArg+"%s is not a pointer", x) check.errorf(x, invalidArg+"%s is not a pointer", x)

29
src/cmd/dist/test.go vendored
View file

@ -722,14 +722,29 @@ func (t *tester) registerTests() {
}, },
}) })
if t.hasCxx() { if t.hasCxx() {
t.tests = append(t.tests, distTest{ t.tests = append(t.tests,
name: "swig_callback", distTest{
heading: "../misc/swig/callback", name: "swig_callback",
fn: func(dt *distTest) error { heading: "../misc/swig/callback",
t.addCmd(dt, "misc/swig/callback", t.goTest()) fn: func(dt *distTest) error {
return nil t.addCmd(dt, "misc/swig/callback", t.goTest())
return nil
},
}, },
}) distTest{
name: "swig_callback_lto",
heading: "../misc/swig/callback",
fn: func(dt *distTest) error {
cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
cmd.Env = append(os.Environ(),
"CGO_CFLAGS=-flto",
"CGO_CXXFLAGS=-flto",
"CGO_LDFLAGS=-flto",
)
return nil
},
},
)
} }
} }
} }

141
src/cmd/link/cgo_test.go Normal file
View file

@ -0,0 +1,141 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"internal/testenv"
"os"
"os/exec"
"path/filepath"
"testing"
)
// Issues 43830, 46295
func TestCGOLTO(t *testing.T) {
testenv.MustHaveCGO(t)
testenv.MustHaveGoBuild(t)
t.Parallel()
for _, cc := range []string{"gcc", "clang"} {
for test := 0; test < 2; test++ {
t.Run(fmt.Sprintf("%s-%d", cc, test), func(t *testing.T) {
testCGOLTO(t, cc, test)
})
}
}
}
const test1_main = `
package main
/*
extern int myadd(int, int);
int c_add(int a, int b) {
return myadd(a, b);
}
*/
import "C"
func main() {
println(C.c_add(1, 2))
}
`
const test1_add = `
package main
import "C"
/* test */
//export myadd
func myadd(a C.int, b C.int) C.int {
return a + b
}
`
const test2_main = `
package main
import "fmt"
/*
#include <stdio.h>
void hello(void) {
printf("hello\n");
}
*/
import "C"
func main() {
hello := C.hello
fmt.Printf("%v\n", hello)
}
`
func testCGOLTO(t *testing.T, cc string, test int) {
t.Parallel()
if _, err := exec.LookPath(cc); err != nil {
t.Skipf("no %s compiler", cc)
}
dir := t.TempDir()
writeTempFile := func(name, contents string) {
if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
t.Fatal(err)
}
}
writeTempFile("go.mod", "module cgolto\n")
switch test {
case 0:
writeTempFile("main.go", test1_main)
writeTempFile("add.go", test1_add)
case 1:
writeTempFile("main.go", test2_main)
default:
t.Fatalf("bad case %d", test)
}
cmd := exec.Command(testenv.GoToolPath(t), "build")
cmd.Dir = dir
cmd.Env = append(os.Environ(),
"CC="+cc,
"CGO_CFLAGS=-flto",
)
t.Log("go build")
out, err := cmd.CombinedOutput()
t.Logf("%s", out)
if err != nil {
t.Logf("go build failed: %v", err)
// Error messages we've seen indicating that LTO is not supported.
// These errors come from GCC or clang, not Go.
var noLTO = []string{
`unrecognized command line option "-flto"`,
"unable to pass LLVM bit-code files to linker",
"file not recognized: File format not recognized",
"LTO support has not been enabled",
"linker command failed with exit code",
"gcc: can't load library",
}
for _, msg := range noLTO {
if bytes.Contains(out, []byte(msg)) {
t.Skipf("C compiler %v does not support LTO", cc)
}
}
t.Error("failed")
}
}

View file

@ -124,6 +124,10 @@ func hostArchive(ctxt *Link, name string) {
libgcc := sym.Library{Pkg: "libgcc"} libgcc := sym.Library{Pkg: "libgcc"}
h := ldobj(ctxt, f, &libgcc, l, pname, name) h := ldobj(ctxt, f, &libgcc, l, pname, name)
if h.ld == nil {
Errorf(nil, "%s unrecognized object file at offset %d", name, off)
continue
}
f.MustSeek(h.off, 0) f.MustSeek(h.off, 0)
h.ld(ctxt, f, h.pkg, h.length, h.pn) h.ld(ctxt, f, h.pkg, h.length, h.pn)
} }

View file

@ -241,6 +241,10 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
return true, "dynamically linking with a shared library" return true, "dynamically linking with a shared library"
} }
if unknownObjFormat {
return true, "some input objects have an unrecognized file format"
}
return false, "" return false, ""
} }
@ -248,7 +252,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
// //
// It is called after flags are processed and inputs are processed, // It is called after flags are processed and inputs are processed,
// so the ctxt.LinkMode variable has an initial value from the -linkmode // so the ctxt.LinkMode variable has an initial value from the -linkmode
// flag and the iscgo externalobj variables are set. // flag and the iscgo, externalobj, and unknownObjFormat variables are set.
func determineLinkMode(ctxt *Link) { func determineLinkMode(ctxt *Link) {
extNeeded, extReason := mustLinkExternal(ctxt) extNeeded, extReason := mustLinkExternal(ctxt)
via := "" via := ""

View file

@ -343,10 +343,16 @@ var (
const pkgdef = "__.PKGDEF" const pkgdef = "__.PKGDEF"
var ( var (
// Set if we see an object compiled by the host compiler that is not // externalobj is set to true if we see an object compiled by
// from a package that is known to support internal linking mode. // the host compiler that is not from a package that is known
// to support internal linking mode.
externalobj = false externalobj = false
theline string
// unknownObjFormat is set to true if we see an object whose
// format we don't recognize.
unknownObjFormat = false
theline string
) )
func Lflag(ctxt *Link, arg string) { func Lflag(ctxt *Link, arg string) {
@ -1065,6 +1071,10 @@ func hostobjs(ctxt *Link) {
} }
f.MustSeek(h.off, 0) f.MustSeek(h.off, 0)
if h.ld == nil {
Errorf(nil, "%s: unrecognized object file format", h.pn)
continue
}
h.ld(ctxt, f, h.pkg, h.length, h.pn) h.ld(ctxt, f, h.pkg, h.length, h.pn)
f.Close() f.Close()
} }
@ -1855,6 +1865,14 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file) return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
} }
if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
// An unrecognized object is just passed to the external linker.
// If we try to read symbols from this object, we will
// report an error at that time.
unknownObjFormat = true
return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
}
/* check the header */ /* check the header */
line, err := f.ReadString('\n') line, err := f.ReadString('\n')
if err != nil { if err != nil {
@ -1874,7 +1892,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
return nil return nil
} }
Errorf(nil, "%s: not an object file: @%d %02x%02x%02x%02x", pn, start, c1, c2, c3, c4) Errorf(nil, "%s: not an object file: @%d %q", pn, start, line)
return nil return nil
} }

View file

@ -475,7 +475,7 @@ func (f *peFile) addDWARFSection(name string, size int) *peSection {
off := f.stringTable.add(name) off := f.stringTable.add(name)
h := f.addSection(name, size, size) h := f.addSection(name, size, size)
h.shortName = fmt.Sprintf("/%d", off) h.shortName = fmt.Sprintf("/%d", off)
h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA
return h return h
} }

View file

@ -455,7 +455,7 @@ func initP384() {
// Multiple invocations of this function will return the same value, so it can // Multiple invocations of this function will return the same value, so it can
// be used for equality checks and switch statements. // be used for equality checks and switch statements.
// //
// The cryptographic operations are implemented using constant-time algorithms. // ScalarMult and ScalarBaseMult are implemented using constant-time algorithms.
func P256() Curve { func P256() Curve {
initonce.Do(initAll) initonce.Do(initAll)
return p256 return p256
@ -479,7 +479,7 @@ func P384() Curve {
// Multiple invocations of this function will return the same value, so it can // Multiple invocations of this function will return the same value, so it can
// be used for equality checks and switch statements. // be used for equality checks and switch statements.
// //
// The cryptographic operations do not use constant-time algorithms. // The cryptographic operations are implemented using constant-time algorithms.
func P521() Curve { func P521() Curve {
initonce.Do(initAll) initonce.Do(initAll)
return p521 return p521

View file

@ -619,7 +619,7 @@ type Config struct {
// protocol will be one from this list, and the connection will fail // protocol will be one from this list, and the connection will fail
// if there is no mutually supported protocol. If NextProtos is empty // if there is no mutually supported protocol. If NextProtos is empty
// or the peer doesn't support ALPN, the connection will succeed and // or the peer doesn't support ALPN, the connection will succeed and
// ConnectionState.NegotiatedProtocol will be empty." // ConnectionState.NegotiatedProtocol will be empty.
NextProtos []string NextProtos []string
// ServerName is used to verify the hostname on the returned // ServerName is used to verify the hostname on the returned

View file

@ -189,7 +189,7 @@
When printing a struct, fmt cannot and therefore does not invoke When printing a struct, fmt cannot and therefore does not invoke
formatting methods such as Error or String on unexported fields. formatting methods such as Error or String on unexported fields.
Explicit argument indexes: Explicit argument indexes
In Printf, Sprintf, and Fprintf, the default behavior is for each In Printf, Sprintf, and Fprintf, the default behavior is for each
formatting verb to format successive arguments passed in the call. formatting verb to format successive arguments passed in the call.
@ -211,7 +211,7 @@
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17) fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11". will yield "16 17 0x10 0x11".
Format errors: Format errors
If an invalid argument is given for a verb, such as providing If an invalid argument is given for a verb, such as providing
a string to %d, the generated string will contain a a string to %d, the generated string will contain a

View file

@ -145,17 +145,14 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi
err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path) err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
case "$$B\n": case "$$B\n":
var data []byte var exportFormat byte
data, err = io.ReadAll(buf) exportFormat, err = buf.ReadByte()
if err != nil {
break
}
// The indexed export format starts with an 'i'; the older // The indexed export format starts with an 'i'; the older
// binary export format starts with a 'c', 'd', or 'v' // binary export format starts with a 'c', 'd', or 'v'
// (from "version"). Select appropriate importer. // (from "version"). Select appropriate importer.
if len(data) > 0 && data[0] == 'i' { if err == nil && exportFormat == 'i' {
_, pkg, err = iImportData(fset, packages, data[1:], id) pkg, err = iImportData(fset, packages, buf, id)
} else { } else {
err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path) err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
} }

View file

@ -8,6 +8,7 @@
package gcimporter package gcimporter
import ( import (
"bufio"
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
@ -20,7 +21,7 @@ import (
) )
type intReader struct { type intReader struct {
*bytes.Reader *bufio.Reader
path string path string
} }
@ -73,7 +74,7 @@ const (
// and returns the number of bytes consumed and a reference to the package. // and returns the number of bytes consumed and a reference to the package.
// If the export data version is not recognized or the format is otherwise // If the export data version is not recognized or the format is otherwise
// compromised, an error is returned. // compromised, an error is returned.
func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataReader *bufio.Reader, path string) (pkg *types.Package, err error) {
const currentVersion = iexportVersionCurrent const currentVersion = iexportVersionCurrent
version := int64(-1) version := int64(-1)
defer func() { defer func() {
@ -86,7 +87,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
} }
}() }()
r := &intReader{bytes.NewReader(data), path} r := &intReader{dataReader, path}
version = int64(r.uint64()) version = int64(r.uint64())
switch version { switch version {
@ -102,10 +103,12 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
sLen := int64(r.uint64()) sLen := int64(r.uint64())
dLen := int64(r.uint64()) dLen := int64(r.uint64())
whence, _ := r.Seek(0, io.SeekCurrent) data := make([]byte, sLen+dLen)
stringData := data[whence : whence+sLen] if _, err := io.ReadFull(r, data); err != nil {
declData := data[whence+sLen : whence+sLen+dLen] errorf("cannot read %d bytes of stringData and declData: %s", len(data), err)
r.Seek(sLen+dLen, io.SeekCurrent) }
stringData := data[:sLen]
declData := data[sLen:]
p := iimporter{ p := iimporter{
exportVersion: version, exportVersion: version,
@ -182,9 +185,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
// package was imported completely and without errors // package was imported completely and without errors
localpkg.MarkComplete() localpkg.MarkComplete()
return localpkg, nil
consumed, _ := r.Seek(0, io.SeekCurrent)
return int(consumed), localpkg, nil
} }
type iimporter struct { type iimporter struct {

View file

@ -588,6 +588,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _Add: case _Add:
// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer // unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
if !check.allowVersion(check.pkg, 1, 17) {
check.errorf(call.Fun, _InvalidUnsafeAdd, "unsafe.Add requires go1.17 or later")
return
}
check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add") check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
if x.mode == invalid { if x.mode == invalid {
return return
@ -684,6 +689,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _Slice: case _Slice:
// unsafe.Slice(ptr *T, len IntegerType) []T // unsafe.Slice(ptr *T, len IntegerType) []T
if !check.allowVersion(check.pkg, 1, 17) {
check.errorf(call.Fun, _InvalidUnsafeSlice, "unsafe.Slice requires go1.17 or later")
return
}
typ := asPointer(x.typ) typ := asPointer(x.typ)
if typ == nil { if typ == nil {
check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x) check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x)

View file

@ -19,10 +19,10 @@ type SubFS interface {
// Sub returns an FS corresponding to the subtree rooted at fsys's dir. // Sub returns an FS corresponding to the subtree rooted at fsys's dir.
// //
// If fs implements SubFS, Sub calls returns fsys.Sub(dir). // If dir is ".", Sub returns fsys unchanged.
// Otherwise, if dir is ".", Sub returns fsys unchanged. // Otherwise, if fs implements SubFS, Sub returns fsys.Sub(dir).
// Otherwise, Sub returns a new FS implementation sub that, // Otherwise, Sub returns a new FS implementation sub that,
// in effect, implements sub.Open(dir) as fsys.Open(path.Join(dir, name)). // in effect, implements sub.Open(name) as fsys.Open(path.Join(dir, name)).
// The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately. // The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately.
// //
// Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix") // Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix")

View file

@ -1898,61 +1898,62 @@ func TestCVE202133195(t *testing.T) {
// Change the default resolver to match our manipulated resolver // Change the default resolver to match our manipulated resolver
originalDefault := DefaultResolver originalDefault := DefaultResolver
DefaultResolver = &r DefaultResolver = &r
defer func() { defer func() { DefaultResolver = originalDefault }()
DefaultResolver = originalDefault // Redirect host file lookups.
}() defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
testHookHostsPath = "testdata/hosts"
_, err := r.LookupCNAME(context.Background(), "golang.org") _, err := r.LookupCNAME(context.Background(), "golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected)
} }
_, err = LookupCNAME("golang.org") _, err = LookupCNAME("golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected)
} }
_, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
_, _, err = LookupSRV("target", "tcp", "golang.org") _, _, err = LookupSRV("target", "tcp", "golang.org")
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
_, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org")
if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
_, _, err = LookupSRV("hdr", "tcp", "golang.org") _, _, err = LookupSRV("hdr", "tcp", "golang.org")
if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
_, err = r.LookupMX(context.Background(), "golang.org") _, err = r.LookupMX(context.Background(), "golang.org")
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected)
} }
_, err = LookupMX("golang.org") _, err = LookupMX("golang.org")
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected)
} }
_, err = r.LookupNS(context.Background(), "golang.org") _, err = r.LookupNS(context.Background(), "golang.org")
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected)
} }
_, err = LookupNS("golang.org") _, err = LookupNS("golang.org")
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected)
} }
_, err = r.LookupAddr(context.Background(), "1.2.3.4") _, err = r.LookupAddr(context.Background(), "192.0.2.42")
if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected)
} }
_, err = LookupAddr("1.2.3.4") _, err = LookupAddr("192.0.2.42")
if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected { if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected) t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected)
} }
} }

View file

@ -577,37 +577,17 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return io.CopyBuffer(writerOnly{w}, src, buf) return io.CopyBuffer(writerOnly{w}, src, buf)
} }
// sendfile path: // Copy the first sniffLen bytes before switching to ReadFrom.
// This ensures we don't start writing the response before the
// Do not start actually writing response until src is readable. // source is available (see golang.org/issue/5660) and provides
// If body length is <= sniffLen, sendfile/splice path will do // enough bytes to perform Content-Type sniffing when required.
// little anyway. This small read also satisfies sniffing the if !w.cw.wroteHeader {
// body in case Content-Type is missing. n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf)
nr, er := src.Read(buf[:sniffLen]) n += n0
atEOF := errors.Is(er, io.EOF) if err != nil || n0 < sniffLen {
n += int64(nr) return n, err
if nr > 0 {
// Write the small amount read normally.
nw, ew := w.Write(buf[:nr])
if ew != nil {
err = ew
} else if nr != nw {
err = io.ErrShortWrite
} }
} }
if err == nil && er != nil && !atEOF {
err = er
}
// Do not send StatusOK in the error case where nothing has been written.
if err == nil && !w.wroteHeader {
w.WriteHeader(StatusOK) // nr == 0, no error (or EOF)
}
if err != nil || atEOF {
return n, err
}
w.w.Flush() // get rid of any previous writes w.w.Flush() // get rid of any previous writes
w.cw.flush() // make sure Header is written; flush data to rwc w.cw.flush() // make sure Header is written; flush data to rwc
@ -620,7 +600,7 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return n, err return n, err
} }
n0, err := io.Copy(writerOnly{w}, src) n0, err := io.CopyBuffer(writerOnly{w}, src, buf)
n += n0 n += n0
return n, err return n, err
} }

View file

@ -157,9 +157,25 @@ func testServerIssue5953(t *testing.T, h2 bool) {
resp.Body.Close() resp.Body.Close()
} }
func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) } type byteAtATimeReader struct {
func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) } buf []byte
func testContentTypeWithCopy(t *testing.T, h2 bool) { }
func (b *byteAtATimeReader) Read(p []byte) (n int, err error) {
if len(p) < 1 {
return 0, nil
}
if len(b.buf) == 0 {
return 0, io.EOF
}
p[0] = b.buf[0]
b.buf = b.buf[1:]
return 1, nil
}
func TestContentTypeWithVariousSources_h1(t *testing.T) { testContentTypeWithVariousSources(t, h1Mode) }
func TestContentTypeWithVariousSources_h2(t *testing.T) { testContentTypeWithVariousSources(t, h2Mode) }
func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
defer afterTest(t) defer afterTest(t)
const ( const (
@ -167,30 +183,86 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
expected = "text/html; charset=utf-8" expected = "text/html; charset=utf-8"
) )
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { for _, test := range []struct {
// Use io.Copy from a bytes.Buffer to trigger ReadFrom. name string
buf := bytes.NewBuffer([]byte(input)) handler func(ResponseWriter, *Request)
n, err := io.Copy(w, buf) }{{
if int(n) != len(input) || err != nil { name: "write",
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input)) handler: func(w ResponseWriter, r *Request) {
} // Write the whole input at once.
})) n, err := w.Write([]byte(input))
defer cst.close() if int(n) != len(input) || err != nil {
t.Errorf("w.Write(%q) = %v, %v want %d, nil", input, n, err, len(input))
}
},
}, {
name: "write one byte at a time",
handler: func(w ResponseWriter, r *Request) {
// Write the input one byte at a time.
buf := []byte(input)
for i := range buf {
n, err := w.Write(buf[i : i+1])
if n != 1 || err != nil {
t.Errorf("w.Write(%q) = %v, %v want 1, nil", input, n, err)
}
}
},
}, {
name: "copy from Reader",
handler: func(w ResponseWriter, r *Request) {
// Use io.Copy from a plain Reader.
type readerOnly struct{ io.Reader }
buf := bytes.NewBuffer([]byte(input))
n, err := io.Copy(w, readerOnly{buf})
if int(n) != len(input) || err != nil {
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
}
},
}, {
name: "copy from bytes.Buffer",
handler: func(w ResponseWriter, r *Request) {
// Use io.Copy from a bytes.Buffer to trigger ReadFrom.
buf := bytes.NewBuffer([]byte(input))
n, err := io.Copy(w, buf)
if int(n) != len(input) || err != nil {
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
}
},
}, {
name: "copy one byte at a time",
handler: func(w ResponseWriter, r *Request) {
// Use io.Copy from a Reader that returns one byte at a time.
n, err := io.Copy(w, &byteAtATimeReader{[]byte(input)})
if int(n) != len(input) || err != nil {
t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
}
},
}} {
t.Run(test.name, func(t *testing.T) {
cst := newClientServerTest(t, h2, HandlerFunc(test.handler))
defer cst.close()
resp, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatalf("Get: %v", err)
}
if ct := resp.Header.Get("Content-Type"); ct != expected {
t.Errorf("Content-Type = %q, want %q", ct, expected)
}
if want, got := resp.Header.Get("Content-Length"), fmt.Sprint(len(input)); want != got {
t.Errorf("Content-Length = %q, want %q", want, got)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("reading body: %v", err)
} else if !bytes.Equal(data, []byte(input)) {
t.Errorf("data is %q, want %q", data, input)
}
resp.Body.Close()
})
resp, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatalf("Get: %v", err)
} }
if ct := resp.Header.Get("Content-Type"); ct != expected {
t.Errorf("Content-Type = %q, want %q", ct, expected)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("reading body: %v", err)
} else if !bytes.Equal(data, []byte(input)) {
t.Errorf("data is %q, want %q", data, input)
}
resp.Body.Close()
} }
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) } func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }

View file

@ -45,16 +45,6 @@ func (p *Process) wait() (ps *ProcessState, err error) {
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
} }
func terminateProcess(pid, exitcode int) error {
h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid))
if e != nil {
return NewSyscallError("OpenProcess", e)
}
defer syscall.CloseHandle(h)
e = syscall.TerminateProcess(h, uint32(exitcode))
return NewSyscallError("TerminateProcess", e)
}
func (p *Process) signal(sig Signal) error { func (p *Process) signal(sig Signal) error {
handle := atomic.LoadUintptr(&p.handle) handle := atomic.LoadUintptr(&p.handle)
if handle == uintptr(syscall.InvalidHandle) { if handle == uintptr(syscall.InvalidHandle) {
@ -64,16 +54,22 @@ func (p *Process) signal(sig Signal) error {
return ErrProcessDone return ErrProcessDone
} }
if sig == Kill { if sig == Kill {
err := terminateProcess(p.Pid, 1) var terminationHandle syscall.Handle
e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
if e != nil {
return NewSyscallError("DuplicateHandle", e)
}
runtime.KeepAlive(p) runtime.KeepAlive(p)
return err defer syscall.CloseHandle(terminationHandle)
e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
return NewSyscallError("TerminateProcess", e)
} }
// TODO(rsc): Handle Interrupt too? // TODO(rsc): Handle Interrupt too?
return syscall.Errno(syscall.EWINDOWS) return syscall.Errno(syscall.EWINDOWS)
} }
func (p *Process) release() error { func (p *Process) release() error {
handle := atomic.LoadUintptr(&p.handle) handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle))
if handle == uintptr(syscall.InvalidHandle) { if handle == uintptr(syscall.InvalidHandle) {
return syscall.EINVAL return syscall.EINVAL
} }
@ -81,7 +77,6 @@ func (p *Process) release() error {
if e != nil { if e != nil {
return NewSyscallError("CloseHandle", e) return NewSyscallError("CloseHandle", e)
} }
atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
// no need for a finalizer anymore // no need for a finalizer anymore
runtime.SetFinalizer(p, nil) runtime.SetFinalizer(p, nil)
return nil return nil

View file

@ -48,18 +48,21 @@ func main() {
if target == "nacl" { if target == "nacl" {
continue continue
} }
var buf bytes.Buffer var tags []string
fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n")
if target == "linux" { if target == "linux" {
fmt.Fprintf(&buf, "// +build !android\n") // must explicitly exclude android for linux tags = append(tags, "!android") // must explicitly exclude android for linux
} }
if target == "solaris" { if target == "solaris" {
fmt.Fprintf(&buf, "// +build !illumos\n") // must explicitly exclude illumos for solaris tags = append(tags, "!illumos") // must explicitly exclude illumos for solaris
} }
if target == "darwin" { if target == "darwin" {
fmt.Fprintf(&buf, "// +build !ios\n") // must explicitly exclude ios for darwin tags = append(tags, "!ios") // must explicitly exclude ios for darwin
} }
fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes tags = append(tags, target) // must explicitly include target for bootstrapping purposes
var buf bytes.Buffer
fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n")
fmt.Fprintf(&buf, "//go:build %s\n", strings.Join(tags, " && "))
fmt.Fprintf(&buf, "// +build %s\n\n", strings.Join(tags, ","))
fmt.Fprintf(&buf, "package sys\n\n") fmt.Fprintf(&buf, "package sys\n\n")
fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target) fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target)
for _, goos := range gooses { for _, goos := range gooses {
@ -81,6 +84,7 @@ func main() {
} }
var buf bytes.Buffer var buf bytes.Buffer
fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n") fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n")
fmt.Fprintf(&buf, "//go:build %s\n", target)
fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes
fmt.Fprintf(&buf, "package sys\n\n") fmt.Fprintf(&buf, "package sys\n\n")
fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target) fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target)

View file

@ -4071,8 +4071,16 @@ func exitsyscall0(gp *g) {
if schedEnabled(gp) { if schedEnabled(gp) {
_p_ = pidleget() _p_ = pidleget()
} }
var locked bool
if _p_ == nil { if _p_ == nil {
globrunqput(gp) globrunqput(gp)
// Below, we stoplockedm if gp is locked. globrunqput releases
// ownership of gp, so we must check if gp is locked prior to
// committing the release by unlocking sched.lock, otherwise we
// could race with another M transitioning gp from unlocked to
// locked.
locked = gp.lockedm != 0
} else if atomic.Load(&sched.sysmonwait) != 0 { } else if atomic.Load(&sched.sysmonwait) != 0 {
atomic.Store(&sched.sysmonwait, 0) atomic.Store(&sched.sysmonwait, 0)
notewakeup(&sched.sysmonnote) notewakeup(&sched.sysmonnote)
@ -4082,7 +4090,7 @@ func exitsyscall0(gp *g) {
acquirep(_p_) acquirep(_p_)
execute(gp, false) // Never returns. execute(gp, false) // Never returns.
} }
if gp.lockedm != 0 { if locked {
// Wait until another thread schedules gp and so m again. // Wait until another thread schedules gp and so m again.
// //
// N.B. lockedm must be this M, as this g was running on this M // N.B. lockedm must be this M, as this g was running on this M

View file

@ -313,6 +313,17 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
} }
} }
var maj, min, build uint32
rtlGetNtVersionNumbers(&maj, &min, &build)
isWin7 := maj < 6 || (maj == 6 && min <= 1)
// NT kernel handles are divisible by 4, with the bottom 3 bits left as
// a tag. The fully set tag correlates with the types of handles we're
// concerned about here. Except, the kernel will interpret some
// special handle values, like -1, -2, and so forth, so kernelbase.dll
// checks to see that those bottom three bits are checked, but that top
// bit is not checked.
isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 }
p, _ := GetCurrentProcess() p, _ := GetCurrentProcess()
parentProcess := p parentProcess := p
if sys.ParentProcess != 0 { if sys.ParentProcess != 0 {
@ -321,7 +332,15 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
fd := make([]Handle, len(attr.Files)) fd := make([]Handle, len(attr.Files))
for i := range attr.Files { for i := range attr.Files {
if attr.Files[i] > 0 { if attr.Files[i] > 0 {
err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) destinationProcessHandle := parentProcess
// On Windows 7, console handles aren't real handles, and can only be duplicated
// into the current process, not a parent one, which amounts to the same thing.
if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) {
destinationProcessHandle = p
}
err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
@ -351,19 +370,40 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
si.StdErr = fd[2] si.StdErr = fd[2]
fd = append(fd, sys.AdditionalInheritedHandles...) fd = append(fd, sys.AdditionalInheritedHandles...)
// On Windows 7, console handles aren't real handles, so don't pass them
// through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
for i := range fd {
if isLegacyWin7ConsoleHandle(fd[i]) {
fd[i] = 0
}
}
// The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST
// to treat the entire list as empty, so remove NULL handles.
j := 0
for i := range fd {
if fd[i] != 0 {
fd[j] = fd[i]
j++
}
}
fd = fd[:j]
// Do not accidentally inherit more than these handles. // Do not accidentally inherit more than these handles.
err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil) if len(fd) > 0 {
if err != nil { err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
return 0, 0, err if err != nil {
return 0, 0, err
}
} }
pi := new(ProcessInformation) pi := new(ProcessInformation)
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
if sys.Token != 0 { if sys.Token != 0 {
err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
} else { } else {
err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
} }
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err

View file

@ -198,6 +198,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys FreeLibrary(handle Handle) (err error) //sys FreeLibrary(handle Handle) (err error)
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) //sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
//sys GetVersion() (ver uint32, err error) //sys GetVersion() (ver uint32, err error)
//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW //sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32) //sys ExitProcess(exitcode uint32)
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW

View file

@ -43,6 +43,7 @@ var (
modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll"))
modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll"))
modntdll = NewLazyDLL(sysdll.Add("ntdll.dll"))
modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll"))
modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) modshell32 = NewLazyDLL(sysdll.Add("shell32.dll"))
moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) moduserenv = NewLazyDLL(sysdll.Add("userenv.dll"))
@ -167,6 +168,7 @@ var (
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
procTranslateNameW = modsecur32.NewProc("TranslateNameW") procTranslateNameW = modsecur32.NewProc("TranslateNameW")
procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
@ -1213,6 +1215,11 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by
return return
} }
func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) {
Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber)))
return
}
func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
if r1&0xff == 0 { if r1&0xff == 0 {

View file

@ -0,0 +1,14 @@
// errorcheck -lang=go1.16
// Copyright 2021 The Go Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package p
import "unsafe"
func main() {
_ = unsafe.Add(unsafe.Pointer(nil), 0) // ERROR "unsafe.Add requires go1.17 or later"
_ = unsafe.Slice(new(byte), 1) // ERROR "unsafe.Slice requires go1.17 or later"
}