]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge master (8212707) into dev.typeparams
authorMatthew Dempsky <mdempsky@google.com>
Mon, 7 Jun 2021 19:27:24 +0000 (12:27 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 7 Jun 2021 19:27:36 +0000 (12:27 -0700)
Conflicts:

- src/go/internal/gcimporter/iimport.go

  CL 325429 and CL 319931 made unrelated changes to adjacent lines

Merge List:

+ 2021-06-07 8212707871 crypto/elliptic: update P-521 docs to say it's constant-time
+ 2021-06-07 7406180012 fmt: split package documentation into more sections
+ 2021-06-07 e3176bbc3e crypto/tls: fix typo in Config.NextProtos docs
+ 2021-06-05 e1fa26026d spec: improve wording consistency by eliminating "specifier"
+ 2021-06-05 f490134126 spec: improve wording by choosing an official term "keyword"
+ 2021-06-05 e3cb381704 go/internal/gcimporter: don't waste CPU copying bytes in `io.ReadAll`
+ 2021-06-05 9d669ed47a misc/cgo/errors: use expected column numbers
+ 2021-06-04 95939e8de7 cmd/compile/internal/abi: fix typo in comment
+ 2021-06-04 831f9376d8 net/http: fix ResponseWriter.ReadFrom with short reads
+ 2021-06-04 3a9d906edc os: avoid finalizer race in windows process object
+ 2021-06-04 105c5b50e0 os: terminate windows processes via handle directly
+ 2021-06-04 79cd407f88 syscall: regenerate zsyscall_windows.go
+ 2021-06-04 c6b6211229 doc/go1.17: document testing changes for Go 1.17
+ 2021-06-04 0214440075 syscall: do not pass console handles to PROC_THREAD_ATTRIBUTE_HANDLE_LIST on Windows 7
+ 2021-06-04 962d5c997a cmd/compile,go/types: restrict use of unsafe.{Add,Slice} to go1.17 or newer
+ 2021-06-04 b29b123e07 cmd/compile: remove spurious ir.Dump
+ 2021-06-03 6d98301114 cmd/link: use correct alignment in PE DWARF sections
+ 2021-06-03 e0d029f758 runtime: avoid gp.lockedm race in exitsyscall0
+ 2021-06-02 dd7ba3ba2c net: don't rely on system hosts in TestCVE202133195
+ 2021-06-02 4f572d7076 io/fs: minor corrections to Sub docs
+ 2021-06-02 e11d14225c doc/go1.17: remove runtime section
+ 2021-06-02 6e189afd3e doc/go1.17: mention SYS_WAIT6/WEXITED on NetBSD
+ 2021-06-02 ff9f5fb859 cmd/link: recognize clang linker error in testCGOLTO
+ 2021-06-02 1c6a2ea2ea doc/go1.17: document time changes for Go1.17
+ 2021-06-02 d743e67e06 doc/go1.17: document flag changes for Go 1.17
+ 2021-06-02 dc8f87b749 runtime/internal/sys: generate //go:build lines in gengoos.go
+ 2021-06-02 84c0e5d47f cmd/link: move issue 43830 tests out of TestScript
+ 2021-06-02 cae68700cc runtime: fix formatting
+ 2021-06-01 567ee865f6 cmd/go: add declaration to cgo_lto_issue43830 test
+ 2021-06-01 24e9707cbf cmd/link, cmd/cgo: support -flto in CFLAGS

Change-Id: I9ef88e7de0f8b1841ed9604b613b41672df67e71

33 files changed:
doc/go1.17.html
doc/go_spec.html
misc/cgo/errors/errors_test.go
misc/cgo/errors/testdata/err2.go
src/cmd/cgo/gcc.go
src/cmd/cgo/out.go
src/cmd/compile/internal/abi/abiutils.go
src/cmd/compile/internal/noder/noder.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/types2/builtins.go
src/cmd/dist/test.go
src/cmd/link/cgo_test.go [new file with mode: 0644]
src/cmd/link/internal/ld/ar.go
src/cmd/link/internal/ld/config.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/pe.go
src/crypto/elliptic/elliptic.go
src/crypto/tls/common.go
src/fmt/doc.go
src/go/internal/gcimporter/gcimporter.go
src/go/internal/gcimporter/iimport.go
src/go/types/builtins.go
src/io/fs/sub.go
src/net/dnsclient_unix_test.go
src/net/http/server.go
src/net/http/sniff_test.go
src/os/exec_windows.go
src/runtime/internal/sys/gengoos.go
src/runtime/proc.go
src/syscall/exec_windows.go
src/syscall/syscall_windows.go
src/syscall/zsyscall_windows.go
test/fixedbugs/issue46525.go [new file with mode: 0644]

index ee498f76035ce1b72617fb5d7f886385cd2d8e08..7438d894fe3feacf50e116d4a17abafd94640c77 100644 (file)
@@ -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 &#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><!-- CL 320252 -->
index e59b3554f288e087efe281f3f074b495ae4d899e..561d44271a258035df266806249e20f845ed5fcc 100644 (file)
@@ -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 &lt; 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>
index a077b5947862134295016c79b59ee1a5e55087bd..68a30a44fe427d434df9dc634f702fc38552aa5e 100644 (file)
@@ -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
index 1d22401aee53a6e0783b3dc16d7a1555d67d4180..a90598fe35b6304434bba7253c29b1d62173dcc4 100644 (file)
@@ -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
index ae61725bc751d02f67e8aced126488bc92c52e7d..a73e998877af812762afcc4716c17b78adf7f065 100644 (file)
@@ -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
 }
index 8c31d5b7941759da83701cbfb7983a66c48990d8..94152f4278cb04b44325a936c50d8d11887f4b3d 100644 (file)
@@ -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.
index cb8e9d7b0fe0a2040859e37d4bc55a2dc7c87b23..b8ea1955d13be363dbb500dc1152bff9b6a52ae3 100644 (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)
 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()
index 2fb852b18432b007fd77e75cc5cb403c3adb6945..08c05a69bea70b3d57ee204b42cc107ebe2f0277 100644 (file)
@@ -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)
 }
 
index f9ee686f9e9f442a78801130bbebdd81f55c27cf..15756a47e4860883699f46a1f3396208ad4ff135 100644 (file)
@@ -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 {
index 8e13b0ff187f0c6e277b9d320a92d5cb1e052cd8..8f2d849ef52d60624ba1ce71ca26c58f860c15b4 100644 (file)
@@ -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)
index 50bf80ba5960bd084f3f9d4453ff99c1283db57f..bc49c6d80402e37389dcd51cc0c660727d4d65fe 100644 (file)
@@ -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
+                                               },
                                        },
-                               })
+                               )
                        }
                }
        }
diff --git a/src/cmd/link/cgo_test.go b/src/cmd/link/cgo_test.go
new file mode 100644 (file)
index 0000000..26ab802
--- /dev/null
@@ -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")
+       }
+}
index 22f53a4df2ee369ce71df17390178ac1b94d04ff..23915f90329a0a81e74736815c678b1de876de75 100644 (file)
@@ -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)
                }
index ae0d7520ebc0790360d3f399c9a0e517f449556c..20f1d0b8c12c6848fd68f83a7e4b41cd1c9f2b7a 100644 (file)
@@ -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 := ""
index e8f001ba8ec095f5e3e73a363db3b4537ee025a3..644faeb2fbc2fd039b65681621a296cc700d2e53 100644 (file)
@@ -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
        }
 
index 3540c07da104e5e257eaf26b15680f23baefba0d..8eb4231c3ab2895f095e2b1197e92d60659eb177 100644 (file)
@@ -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
 }
 
index b8e5a3097d261f2312e6042cb72a94be371475f1..f072960bfeddf83ce69d6a6ec1c701b99a2a6d9b 100644 (file)
@@ -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
index 77957ef82bd9d3752e31a422314be9d932a65d64..d561e61707edd979576c9c21ec8224aa2228c447 100644 (file)
@@ -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
index d05ee519c3db471c384bae5bfe05de56914b0dcc..c584cc9465e57364b27143529040d6f4dcce9434 100644 (file)
        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.
                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
index b74daca246374542f6fa60362eb7f820930cedf9..73cf6334fd65e681aafe7d97b986de0b5dd8ed29 100644 (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)
 
        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)
                }
index e003dc9767a387c384bee6968d8c6aec4c0a84e7..b300860e94074a0c24a7e5c7fcec4db38fbe6bc5 100644 (file)
@@ -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 {
index 739051cc611b3c68488f1c6f8f55bbc4d307a217..2a2d54da88227a60bcb6f5c3dfbf019db61faed4 100644 (file)
@@ -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)
index 7822e555eaa0eb35ebeba07f4b669c9696aa4829..ae20e030a93de2f761e00744d14992065b0dfb66 100644 (file)
@@ -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")
index a718e75a726af486d621d48edd14d888ab6cc834..a59be7fea0d7a0d1cf3d2a8e3a8a35c2af23da16 100644 (file)
@@ -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)
        }
 }
index 4e73508973a1fe0993b6c4e4f91e955d0b84cbbb..430019de509bc17ea9bdfe790bacd05ef5fb9905 100644 (file)
@@ -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
 }
index 8d5350374ddb61040af7c0d6b2a00e88436dd64c..e91335729af16171cfe4df274eb3298bfcc91903 100644 (file)
@@ -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) }
index 5710401acdb92d44dca834d2ac9c42fe09b9b2d7..239bed198f7fd020f25de0d3f240d1ed7428d1ef 100644 (file)
@@ -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
index 51f64a6e5c667976b9c6f81a757d0e8218980687..ffe962f71df61c89cba3261d7e017c5de4e432b2 100644 (file)
@@ -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)
index 63eeb6c9c75625c2a4b55469972ef282b842a73e..24566e5efa2dd1c56dc234987928ddaef31e43c5 100644 (file)
@@ -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
index 253e9e8c1f9604997f8de7c24d6adcd57fee0907..18d15028c3d3bba9812e58ea0555f618f6e5a07c 100644 (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()
        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
index fc734effbbeeda8953c31e2e5237820624f938b2..660179ae9e8cf32ddccb2e09b3ac45dbf136f860 100644 (file)
@@ -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
index 10d0f54e8c71c0e59b1a1c9d2cff5bab0339f536..7bfff16be6ac325fa9a406f98b76aa0542b39948 100644 (file)
@@ -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 {
diff --git a/test/fixedbugs/issue46525.go b/test/fixedbugs/issue46525.go
new file mode 100644 (file)
index 0000000..164e147
--- /dev/null
@@ -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"
+}