mirror of
https://github.com/golang/go
synced 2024-09-24 15:20:16 -06:00
Merge "[dev.typeparams] all: merge master (8212707
) into dev.typeparams" into dev.typeparams
This commit is contained in:
commit
f0c97219a3
@ -224,12 +224,6 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
TODO: complete the Vet section
|
||||
</p>
|
||||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
|
||||
<p>
|
||||
TODO: complete the Runtime section
|
||||
</p>
|
||||
|
||||
<h2 id="compiler">Compiler</h2>
|
||||
|
||||
<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>
|
||||
<dd>
|
||||
<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>
|
||||
</dd>
|
||||
</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
|
||||
some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
|
||||
</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>
|
||||
</dl><!-- syscall -->
|
||||
|
||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
||||
<dd>
|
||||
<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><!-- CL 260577 -->
|
||||
The new
|
||||
<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><!-- 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><!-- 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><!-- CL 300996 -->
|
||||
TODO: <a href="https://golang.org/cl/300996">https://golang.org/cl/300996</a>: support "," 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><!-- CL 320252 -->
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of Apr 28, 2021",
|
||||
"Subtitle": "Version of Jun 2, 2021",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@ -4909,7 +4909,7 @@ if x := f(); x < y {
|
||||
|
||||
<p>
|
||||
"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
|
||||
to execute.
|
||||
</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
|
||||
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>
|
||||
using the reserved word <code>type</code> rather than an actual type:
|
||||
using the keyword <code>type</code> rather than an actual type:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
@ -40,7 +40,8 @@ func check(t *testing.T, file string) {
|
||||
if len(frags) == 1 {
|
||||
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 {
|
||||
t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
|
||||
continue
|
||||
|
12
misc/cgo/errors/testdata/err2.go
vendored
12
misc/cgo/errors/testdata/err2.go
vendored
@ -40,15 +40,15 @@ func main() {
|
||||
C.foop = x // ERROR HERE
|
||||
|
||||
// issue 13129: used to output error about C.unsignedshort with CC=clang
|
||||
var x C.ushort
|
||||
x = int(0) // ERROR HERE: C\.ushort
|
||||
var x1 C.ushort
|
||||
x1 = int(0) // ERROR HERE: C\.ushort
|
||||
|
||||
// issue 13423
|
||||
_ = C.fopen() // ERROR HERE
|
||||
|
||||
// issue 13467
|
||||
var x rune = '✈'
|
||||
var _ rune = C.transform(x) // ERROR HERE: C\.int
|
||||
var x2 rune = '✈'
|
||||
var _ rune = C.transform(x2) // ERROR HERE: C\.int
|
||||
|
||||
// issue 13635: used to output error about C.unsignedchar.
|
||||
// This test tests all such types.
|
||||
@ -91,10 +91,10 @@ func main() {
|
||||
|
||||
// issue 26745
|
||||
_ = func(i int) int {
|
||||
return C.i + 1 // ERROR HERE: :13
|
||||
return C.i + 1 // ERROR HERE: 14
|
||||
}
|
||||
_ = func(i int) {
|
||||
C.fi(i) // ERROR HERE: :6
|
||||
C.fi(i) // ERROR HERE: 7
|
||||
}
|
||||
|
||||
C.fi = C.fi // ERROR HERE
|
||||
|
@ -1638,6 +1638,8 @@ func (p *Package) gccCmd() []string {
|
||||
c = append(c, "-maix64")
|
||||
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
|
||||
return c
|
||||
}
|
||||
|
@ -168,8 +168,18 @@ func (p *Package) writeDefs() {
|
||||
if *gccgo {
|
||||
fmt.Fprintf(fc, "extern byte *%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)
|
||||
// Force a reference to all symbols so that
|
||||
// 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:cgo_import_static %s\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.
|
||||
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" {
|
||||
// Write results back to frame.
|
||||
|
@ -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)
|
||||
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 {
|
||||
parameterUpdateMu.Lock()
|
||||
defer parameterUpdateMu.Unlock()
|
||||
|
@ -886,9 +886,6 @@ func (p *noder) typeExpr(typ syntax.Expr) ir.Ntype {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := n.(ir.Ntype); !ok {
|
||||
ir.Dump("NOT NTYPE", n)
|
||||
}
|
||||
return n.(ir.Ntype)
|
||||
}
|
||||
|
||||
|
@ -999,6 +999,12 @@ func tcRecover(n *ir.CallExpr) ir.Node {
|
||||
|
||||
// tcUnsafeAdd typechecks an OUNSAFEADD node.
|
||||
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.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT])
|
||||
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.
|
||||
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.Y = Expr(n.Y)
|
||||
if n.X.Type() == nil || n.Y.Type() == nil {
|
||||
|
@ -579,6 +579,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
|
||||
case _Add:
|
||||
// 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")
|
||||
if x.mode == invalid {
|
||||
return
|
||||
@ -675,6 +680,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
|
||||
case _Slice:
|
||||
// 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)
|
||||
if typ == nil {
|
||||
check.errorf(x, invalidArg+"%s is not a pointer", x)
|
||||
|
29
src/cmd/dist/test.go
vendored
29
src/cmd/dist/test.go
vendored
@ -722,14 +722,29 @@ func (t *tester) registerTests() {
|
||||
},
|
||||
})
|
||||
if t.hasCxx() {
|
||||
t.tests = append(t.tests, distTest{
|
||||
name: "swig_callback",
|
||||
heading: "../misc/swig/callback",
|
||||
fn: func(dt *distTest) error {
|
||||
t.addCmd(dt, "misc/swig/callback", t.goTest())
|
||||
return nil
|
||||
t.tests = append(t.tests,
|
||||
distTest{
|
||||
name: "swig_callback",
|
||||
heading: "../misc/swig/callback",
|
||||
fn: func(dt *distTest) error {
|
||||
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
141
src/cmd/link/cgo_test.go
Normal 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")
|
||||
}
|
||||
}
|
@ -124,6 +124,10 @@ func hostArchive(ctxt *Link, name string) {
|
||||
|
||||
libgcc := sym.Library{Pkg: "libgcc"}
|
||||
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)
|
||||
h.ld(ctxt, f, h.pkg, h.length, h.pn)
|
||||
}
|
||||
|
@ -241,6 +241,10 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
|
||||
return true, "dynamically linking with a shared library"
|
||||
}
|
||||
|
||||
if unknownObjFormat {
|
||||
return true, "some input objects have an unrecognized file format"
|
||||
}
|
||||
|
||||
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,
|
||||
// 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) {
|
||||
extNeeded, extReason := mustLinkExternal(ctxt)
|
||||
via := ""
|
||||
|
@ -343,10 +343,16 @@ var (
|
||||
const pkgdef = "__.PKGDEF"
|
||||
|
||||
var (
|
||||
// Set if we see an object compiled by the host compiler that is not
|
||||
// from a package that is known to support internal linking mode.
|
||||
// externalobj is set to true if we see an object compiled by
|
||||
// the host compiler that is not from a package that is known
|
||||
// to support internal linking mode.
|
||||
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) {
|
||||
@ -1065,6 +1071,10 @@ func hostobjs(ctxt *Link) {
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
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 */
|
||||
line, err := f.ReadString('\n')
|
||||
if err != nil {
|
||||
@ -1874,7 +1892,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -475,7 +475,7 @@ func (f *peFile) addDWARFSection(name string, size int) *peSection {
|
||||
off := f.stringTable.add(name)
|
||||
h := f.addSection(name, size, size)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -455,7 +455,7 @@ func initP384() {
|
||||
// Multiple invocations of this function will return the same value, so it can
|
||||
// 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 {
|
||||
initonce.Do(initAll)
|
||||
return p256
|
||||
@ -479,7 +479,7 @@ func P384() Curve {
|
||||
// Multiple invocations of this function will return the same value, so it can
|
||||
// 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 {
|
||||
initonce.Do(initAll)
|
||||
return p521
|
||||
|
@ -619,7 +619,7 @@ type Config struct {
|
||||
// protocol will be one from this list, and the connection will fail
|
||||
// if there is no mutually supported protocol. If NextProtos is empty
|
||||
// or the peer doesn't support ALPN, the connection will succeed and
|
||||
// ConnectionState.NegotiatedProtocol will be empty."
|
||||
// ConnectionState.NegotiatedProtocol will be empty.
|
||||
NextProtos []string
|
||||
|
||||
// ServerName is used to verify the hostname on the returned
|
||||
|
@ -189,7 +189,7 @@
|
||||
When printing a struct, fmt cannot and therefore does not invoke
|
||||
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
|
||||
formatting verb to format successive arguments passed in the call.
|
||||
@ -211,7 +211,7 @@
|
||||
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
|
||||
will yield "16 17 0x10 0x11".
|
||||
|
||||
Format errors:
|
||||
Format errors
|
||||
|
||||
If an invalid argument is given for a verb, such as providing
|
||||
a string to %d, the generated string will contain a
|
||||
|
@ -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)
|
||||
|
||||
case "$$B\n":
|
||||
var data []byte
|
||||
data, err = io.ReadAll(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
var exportFormat byte
|
||||
exportFormat, err = buf.ReadByte()
|
||||
|
||||
// The indexed export format starts with an 'i'; the older
|
||||
// binary export format starts with a 'c', 'd', or 'v'
|
||||
// (from "version"). Select appropriate importer.
|
||||
if len(data) > 0 && data[0] == 'i' {
|
||||
_, pkg, err = iImportData(fset, packages, data[1:], id)
|
||||
if err == nil && exportFormat == 'i' {
|
||||
pkg, err = iImportData(fset, packages, buf, id)
|
||||
} else {
|
||||
err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
@ -20,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
type intReader struct {
|
||||
*bytes.Reader
|
||||
*bufio.Reader
|
||||
path string
|
||||
}
|
||||
|
||||
@ -73,7 +74,7 @@ const (
|
||||
// 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
|
||||
// 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
|
||||
version := int64(-1)
|
||||
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())
|
||||
switch version {
|
||||
@ -102,10 +103,12 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
||||
sLen := int64(r.uint64())
|
||||
dLen := int64(r.uint64())
|
||||
|
||||
whence, _ := r.Seek(0, io.SeekCurrent)
|
||||
stringData := data[whence : whence+sLen]
|
||||
declData := data[whence+sLen : whence+sLen+dLen]
|
||||
r.Seek(sLen+dLen, io.SeekCurrent)
|
||||
data := make([]byte, sLen+dLen)
|
||||
if _, err := io.ReadFull(r, data); err != nil {
|
||||
errorf("cannot read %d bytes of stringData and declData: %s", len(data), err)
|
||||
}
|
||||
stringData := data[:sLen]
|
||||
declData := data[sLen:]
|
||||
|
||||
p := iimporter{
|
||||
exportVersion: version,
|
||||
@ -182,9 +185,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
||||
|
||||
// package was imported completely and without errors
|
||||
localpkg.MarkComplete()
|
||||
|
||||
consumed, _ := r.Seek(0, io.SeekCurrent)
|
||||
return int(consumed), localpkg, nil
|
||||
return localpkg, nil
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
|
@ -588,6 +588,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
|
||||
case _Add:
|
||||
// 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")
|
||||
if x.mode == invalid {
|
||||
return
|
||||
@ -684,6 +689,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
|
||||
case _Slice:
|
||||
// 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)
|
||||
if typ == nil {
|
||||
check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x)
|
||||
|
@ -19,10 +19,10 @@ type SubFS interface {
|
||||
|
||||
// Sub returns an FS corresponding to the subtree rooted at fsys's dir.
|
||||
//
|
||||
// If fs implements SubFS, Sub calls returns fsys.Sub(dir).
|
||||
// Otherwise, if dir is ".", Sub returns fsys unchanged.
|
||||
// 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,
|
||||
// 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.
|
||||
//
|
||||
// Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix")
|
||||
|
@ -1898,61 +1898,62 @@ func TestCVE202133195(t *testing.T) {
|
||||
// Change the default resolver to match our manipulated resolver
|
||||
originalDefault := DefaultResolver
|
||||
DefaultResolver = &r
|
||||
defer func() {
|
||||
DefaultResolver = originalDefault
|
||||
}()
|
||||
defer func() { DefaultResolver = originalDefault }()
|
||||
// Redirect host file lookups.
|
||||
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
|
||||
testHookHostsPath = "testdata/hosts"
|
||||
|
||||
_, err := r.LookupCNAME(context.Background(), "golang.org")
|
||||
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, err = LookupCNAME("golang.org")
|
||||
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
|
||||
_, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
|
||||
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, _, err = LookupSRV("target", "tcp", "golang.org")
|
||||
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
|
||||
_, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org")
|
||||
if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, _, err = LookupSRV("hdr", "tcp", "golang.org")
|
||||
if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
|
||||
_, err = r.LookupMX(context.Background(), "golang.org")
|
||||
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, err = LookupMX("golang.org")
|
||||
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
|
||||
_, err = r.LookupNS(context.Background(), "golang.org")
|
||||
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, err = LookupNS("golang.org")
|
||||
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
|
||||
_, err = r.LookupAddr(context.Background(), "1.2.3.4")
|
||||
if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
_, err = r.LookupAddr(context.Background(), "192.0.2.42")
|
||||
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
_, err = LookupAddr("1.2.3.4")
|
||||
if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
|
||||
_, err = LookupAddr("192.0.2.42")
|
||||
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
|
||||
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected)
|
||||
}
|
||||
}
|
||||
|
@ -577,37 +577,17 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
|
||||
return io.CopyBuffer(writerOnly{w}, src, buf)
|
||||
}
|
||||
|
||||
// sendfile path:
|
||||
|
||||
// Do not start actually writing response until src is readable.
|
||||
// If body length is <= sniffLen, sendfile/splice path will do
|
||||
// little anyway. This small read also satisfies sniffing the
|
||||
// body in case Content-Type is missing.
|
||||
nr, er := src.Read(buf[:sniffLen])
|
||||
atEOF := errors.Is(er, io.EOF)
|
||||
n += int64(nr)
|
||||
|
||||
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
|
||||
// Copy the first sniffLen bytes before switching to ReadFrom.
|
||||
// This ensures we don't start writing the response before the
|
||||
// source is available (see golang.org/issue/5660) and provides
|
||||
// enough bytes to perform Content-Type sniffing when required.
|
||||
if !w.cw.wroteHeader {
|
||||
n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf)
|
||||
n += n0
|
||||
if err != nil || n0 < sniffLen {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
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.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
|
||||
}
|
||||
|
||||
n0, err := io.Copy(writerOnly{w}, src)
|
||||
n0, err := io.CopyBuffer(writerOnly{w}, src, buf)
|
||||
n += n0
|
||||
return n, err
|
||||
}
|
||||
|
@ -157,9 +157,25 @@ func testServerIssue5953(t *testing.T, h2 bool) {
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) }
|
||||
func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) }
|
||||
func testContentTypeWithCopy(t *testing.T, h2 bool) {
|
||||
type byteAtATimeReader struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
const (
|
||||
@ -167,30 +183,86 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
|
||||
expected = "text/html; charset=utf-8"
|
||||
)
|
||||
|
||||
cst := newClientServerTest(t, h2, HandlerFunc(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))
|
||||
}
|
||||
}))
|
||||
defer cst.close()
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
handler func(ResponseWriter, *Request)
|
||||
}{{
|
||||
name: "write",
|
||||
handler: func(w ResponseWriter, r *Request) {
|
||||
// Write the whole input at once.
|
||||
n, err := w.Write([]byte(input))
|
||||
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) }
|
||||
|
@ -45,16 +45,6 @@ func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
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 {
|
||||
handle := atomic.LoadUintptr(&p.handle)
|
||||
if handle == uintptr(syscall.InvalidHandle) {
|
||||
@ -64,16 +54,22 @@ func (p *Process) signal(sig Signal) error {
|
||||
return ErrProcessDone
|
||||
}
|
||||
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)
|
||||
return err
|
||||
defer syscall.CloseHandle(terminationHandle)
|
||||
e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
|
||||
return NewSyscallError("TerminateProcess", e)
|
||||
}
|
||||
// TODO(rsc): Handle Interrupt too?
|
||||
return syscall.Errno(syscall.EWINDOWS)
|
||||
}
|
||||
|
||||
func (p *Process) release() error {
|
||||
handle := atomic.LoadUintptr(&p.handle)
|
||||
handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle))
|
||||
if handle == uintptr(syscall.InvalidHandle) {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
@ -81,7 +77,6 @@ func (p *Process) release() error {
|
||||
if e != nil {
|
||||
return NewSyscallError("CloseHandle", e)
|
||||
}
|
||||
atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
|
||||
// no need for a finalizer anymore
|
||||
runtime.SetFinalizer(p, nil)
|
||||
return nil
|
||||
|
@ -48,18 +48,21 @@ func main() {
|
||||
if target == "nacl" {
|
||||
continue
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n")
|
||||
var tags []string
|
||||
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" {
|
||||
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" {
|
||||
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, "const GOOS = `%s`\n\n", target)
|
||||
for _, goos := range gooses {
|
||||
@ -81,6 +84,7 @@ func main() {
|
||||
}
|
||||
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", target)
|
||||
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, "const GOARCH = `%s`\n\n", target)
|
||||
|
@ -4071,8 +4071,16 @@ func exitsyscall0(gp *g) {
|
||||
if schedEnabled(gp) {
|
||||
_p_ = pidleget()
|
||||
}
|
||||
var locked bool
|
||||
if _p_ == nil {
|
||||
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 {
|
||||
atomic.Store(&sched.sysmonwait, 0)
|
||||
notewakeup(&sched.sysmonnote)
|
||||
@ -4082,7 +4090,7 @@ func exitsyscall0(gp *g) {
|
||||
acquirep(_p_)
|
||||
execute(gp, false) // Never returns.
|
||||
}
|
||||
if gp.lockedm != 0 {
|
||||
if locked {
|
||||
// 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
|
||||
|
@ -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()
|
||||
parentProcess := p
|
||||
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))
|
||||
for i := range attr.Files {
|
||||
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 {
|
||||
return 0, 0, err
|
||||
}
|
||||
@ -351,19 +370,40 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
|
||||
si.StdErr = fd[2]
|
||||
|
||||
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.
|
||||
err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
if len(fd) > 0 {
|
||||
err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
pi := new(ProcessInformation)
|
||||
|
||||
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
|
||||
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 {
|
||||
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 {
|
||||
return 0, 0, err
|
||||
|
@ -198,6 +198,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys FreeLibrary(handle Handle) (err error)
|
||||
//sys GetProcAddress(module Handle, procname string) (proc uintptr, 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 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
|
||||
|
@ -43,6 +43,7 @@ var (
|
||||
modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
|
||||
modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll"))
|
||||
modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll"))
|
||||
modntdll = NewLazyDLL(sysdll.Add("ntdll.dll"))
|
||||
modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll"))
|
||||
modshell32 = NewLazyDLL(sysdll.Add("shell32.dll"))
|
||||
moduserenv = NewLazyDLL(sysdll.Add("userenv.dll"))
|
||||
@ -167,6 +168,7 @@ var (
|
||||
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
|
||||
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
|
||||
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
|
||||
procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
|
||||
procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
|
||||
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
||||
procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
|
||||
@ -1213,6 +1215,11 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by
|
||||
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) {
|
||||
r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
|
||||
if r1&0xff == 0 {
|
||||
|
14
test/fixedbugs/issue46525.go
Normal file
14
test/fixedbugs/issue46525.go
Normal 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"
|
||||
}
|
Loading…
Reference in New Issue
Block a user