Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
716e5b5d05 | ||
|
|
bd5ec5d0e7 | ||
|
|
d5722222f1 | ||
|
|
cf3a4d4bb9 | ||
|
|
f9b11597fa | ||
|
|
289b9e3aad | ||
|
|
51ae6d6612 |
21
README.md
21
README.md
@@ -27,6 +27,7 @@ Every release includes the following modifications:
|
||||
- Added back LoadLibraryA fallback to load system libraries (reverted [a17d959](https://github.com/golang/go/commit/a17d959debdb04cd550016a3501dd09d50cd62e7))
|
||||
- Added back sysSocket fallback for socket syscalls (reverted [7c1157f](https://github.com/golang/go/commit/7c1157f9544922e96945196b47b95664b1e39108))
|
||||
- Added back Windows 7 console handle workaround (reverted [48042aa](https://github.com/golang/go/commit/48042aa09c2f878c4faa576948b07fe625c4707a))
|
||||
- Added back 5ms sleep on Windows 7/8 in (\*Process).Wait (reverted [f0894a0](https://github.com/golang/go/commit/f0894a00f4b756d4b9b4078af2e686b359493583))
|
||||
- Restored deprecated `go get` behavior for use outside modules (reverted [de4d503](https://github.com/golang/go/commit/de4d50316fb5c6d1529aa5377dc93b26021ee843))
|
||||
- Includes all improvements and bug fixes from the corresponding upstream Go release
|
||||
|
||||
@@ -64,20 +65,14 @@ Binary distributions are **available at the [release page](https://github.com/th
|
||||
|
||||
3. Add the following to your shell configuration file:
|
||||
|
||||
- For bash (add to `~/.bash_profile` or `~/.bashrc`):
|
||||
- For bash, add to `~/.bash_profile` or `~/.bashrc`
|
||||
- For zsh, add to `~/.zshrc`
|
||||
|
||||
```bash
|
||||
export GOROOT=/usr/local/go-legacy-win7
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
||||
```
|
||||
|
||||
- For zsh (add to `~/.zshrc`):
|
||||
```zsh
|
||||
export GOROOT=/usr/local/go-legacy-win7
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
||||
```
|
||||
```bash
|
||||
export GOROOT=/usr/local/go-legacy-win7
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
||||
```
|
||||
|
||||
4. Apply the changes:
|
||||
|
||||
|
||||
4
VERSION
4
VERSION
@@ -1,2 +1,2 @@
|
||||
go1.23.3
|
||||
time 2024-11-06T18:46:45Z
|
||||
go1.23.5
|
||||
time 2025-01-10T16:44:59Z
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
From ed249cf4dbfe31b9cea185100b74c38e5c6e3bd9 Mon Sep 17 00:00:00 2001
|
||||
From 3e1a3a3c96117fd4d655dd85d2e2c807e691104e Mon Sep 17 00:00:00 2001
|
||||
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
|
||||
Date: Sat, 9 Nov 2024 18:54:55 +1100
|
||||
Date: Tue, 24 Dec 2024 19:31:25 +0700
|
||||
Subject: [PATCH] Add back LoadLibraryA fallback
|
||||
|
||||
---
|
||||
@@ -14,7 +14,7 @@ Subject: [PATCH] Add back LoadLibraryA fallback
|
||||
7 files changed, 136 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go
|
||||
index 4880e62a55..8bfff0bc93 100644
|
||||
index 4880e62..8bfff0b 100644
|
||||
--- a/src/runtime/export_windows_test.go
|
||||
+++ b/src/runtime/export_windows_test.go
|
||||
@@ -36,3 +36,7 @@ func NewContextStub() *ContextStub {
|
||||
@@ -26,7 +26,7 @@ index 4880e62a55..8bfff0bc93 100644
|
||||
+ return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
|
||||
+}
|
||||
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
|
||||
index 02735802d4..c76df9da22 100644
|
||||
index 0273580..c76df9d 100644
|
||||
--- a/src/runtime/os_windows.go
|
||||
+++ b/src/runtime/os_windows.go
|
||||
@@ -41,6 +41,7 @@ const (
|
||||
@@ -139,7 +139,7 @@ index 02735802d4..c76df9da22 100644
|
||||
|
||||
// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
|
||||
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
|
||||
index 85b1b8c902..eb808feea5 100644
|
||||
index 85b1b8c..eb808fe 100644
|
||||
--- a/src/runtime/syscall_windows.go
|
||||
+++ b/src/runtime/syscall_windows.go
|
||||
@@ -413,10 +413,23 @@ func callbackWrap(a *callbackArgs) {
|
||||
@@ -169,7 +169,7 @@ index 85b1b8c902..eb808feea5 100644
|
||||
err = 0
|
||||
}
|
||||
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
|
||||
index 156cf3eb8e..2db5b61a9b 100644
|
||||
index 156cf3e..2db5b61 100644
|
||||
--- a/src/runtime/syscall_windows_test.go
|
||||
+++ b/src/runtime/syscall_windows_test.go
|
||||
@@ -1166,7 +1166,10 @@ uintptr_t cfunc(void) {
|
||||
@@ -210,11 +210,11 @@ index 156cf3eb8e..2db5b61a9b 100644
|
||||
modwinmm = syscall.NewLazyDLL("winmm.dll")
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
|
||||
index 81134cb0bd..b3554d349b 100644
|
||||
index a7873e6..bd82b51 100644
|
||||
--- a/src/syscall/dll_windows.go
|
||||
+++ b/src/syscall/dll_windows.go
|
||||
@@ -44,7 +44,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
|
||||
|
||||
@@ -45,7 +45,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
|
||||
//go:noescape
|
||||
func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
-func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
@@ -222,7 +222,7 @@ index 81134cb0bd..b3554d349b 100644
|
||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
||||
|
||||
// A DLL implements access to a single DLL.
|
||||
@@ -53,6 +53,26 @@ type DLL struct {
|
||||
@@ -54,6 +54,26 @@ type DLL struct {
|
||||
Handle Handle
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ index 81134cb0bd..b3554d349b 100644
|
||||
// LoadDLL loads the named DLL file into memory.
|
||||
//
|
||||
// If name is not an absolute path and is not a known system DLL used by
|
||||
@@ -69,7 +89,11 @@ func LoadDLL(name string) (*DLL, error) {
|
||||
@@ -70,7 +90,11 @@ func LoadDLL(name string) (*DLL, error) {
|
||||
var h uintptr
|
||||
var e Errno
|
||||
if sysdll.IsSystemDLL[name] {
|
||||
@@ -263,7 +263,7 @@ index 81134cb0bd..b3554d349b 100644
|
||||
h, e = loadlibrary(namep)
|
||||
}
|
||||
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
|
||||
index 4e988c418a..45b1908b71 100644
|
||||
index 4e988c4..45b1908 100644
|
||||
--- a/src/syscall/security_windows.go
|
||||
+++ b/src/syscall/security_windows.go
|
||||
@@ -290,6 +290,7 @@ type Tokenprimarygroup struct {
|
||||
@@ -275,7 +275,7 @@ index 4e988c418a..45b1908b71 100644
|
||||
// An access token contains the security information for a logon session.
|
||||
// The system creates an access token when a user logs on, and every
|
||||
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
|
||||
index d8d8594a55..28369e3b91 100644
|
||||
index d8d8594..28369e3 100644
|
||||
--- a/src/syscall/zsyscall_windows.go
|
||||
+++ b/src/syscall/zsyscall_windows.go
|
||||
@@ -128,6 +128,7 @@ var (
|
||||
@@ -303,5 +303,5 @@ index d8d8594a55..28369e3b91 100644
|
||||
Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
|
||||
return
|
||||
--
|
||||
2.47.0
|
||||
2.39.5
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
From cf3a4d4bb96092dcc87454133a9a77ea4454a60d Mon Sep 17 00:00:00 2001
|
||||
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
|
||||
Date: Wed, 25 Dec 2024 14:16:56 +0700
|
||||
Subject: [PATCH] Add 5ms sleep on Windows 7/8 in (*Process).Wait
|
||||
|
||||
---
|
||||
src/os/exec_windows.go | 11 +++++++++++
|
||||
src/syscall/exec_windows.go | 16 ++++++++++++----
|
||||
2 files changed, 23 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
|
||||
index ab2dae1..a2d7d34 100644
|
||||
--- a/src/os/exec_windows.go
|
||||
+++ b/src/os/exec_windows.go
|
||||
@@ -44,6 +44,17 @@ func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("GetProcessTimes", e)
|
||||
}
|
||||
+
|
||||
+ // NOTE(brainman): It seems that sometimes process is not dead
|
||||
+ // when WaitForSingleObject returns. But we do not know any
|
||||
+ // other way to wait for it. Sleeping for a while seems to do
|
||||
+ // the trick sometimes.
|
||||
+ // See https://golang.org/issue/25965 for details.
|
||||
+ _, isWin10AndAbove := syscall.WindowsVersion()
|
||||
+ if !isWin10AndAbove {
|
||||
+ defer time.Sleep(5 * time.Millisecond)
|
||||
+ }
|
||||
+
|
||||
defer p.Release()
|
||||
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
|
||||
}
|
||||
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
|
||||
index f099a6f..27b4303 100644
|
||||
--- a/src/syscall/exec_windows.go
|
||||
+++ b/src/syscall/exec_windows.go
|
||||
@@ -253,6 +253,16 @@ type SysProcAttr struct {
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
+// WindowsVersion returns whether the OS is Windows 7 (or earlier) and Windows 10 (or later)
|
||||
+func WindowsVersion() (isWin7, isWin10AndAbove bool) {
|
||||
+ info := _OSVERSIONINFOW{}
|
||||
+ info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||
+ rtlGetVersion(&info)
|
||||
+ isWin7 = info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1)
|
||||
+ isWin10AndAbove = info.majorVersion >= 10
|
||||
+ return
|
||||
+}
|
||||
+
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
if len(argv0) == 0 {
|
||||
return 0, 0, EWINDOWS
|
||||
@@ -316,10 +326,8 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
|
||||
}
|
||||
}
|
||||
|
||||
- info := _OSVERSIONINFOW{}
|
||||
- info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||
- rtlGetVersion(&info)
|
||||
- isWin7 := info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1)
|
||||
+ isWin7, _ := WindowsVersion()
|
||||
+
|
||||
// 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
|
||||
--
|
||||
2.39.5
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var globalSkip = func(t *testing.T) {}
|
||||
var globalSkip = func(t testing.TB) {}
|
||||
|
||||
// Program to run.
|
||||
var bin []string
|
||||
@@ -59,12 +59,12 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func testMain(m *testing.M) int {
|
||||
if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
|
||||
globalSkip = func(t *testing.T) { t.Skip("short mode and $GO_BUILDER_NAME not set") }
|
||||
globalSkip = func(t testing.TB) { t.Skip("short mode and $GO_BUILDER_NAME not set") }
|
||||
return m.Run()
|
||||
}
|
||||
if runtime.GOOS == "linux" {
|
||||
if _, err := os.Stat("/etc/alpine-release"); err == nil {
|
||||
globalSkip = func(t *testing.T) { t.Skip("skipping failing test on alpine - go.dev/issue/19938") }
|
||||
globalSkip = func(t testing.TB) { t.Skip("skipping failing test on alpine - go.dev/issue/19938") }
|
||||
return m.Run()
|
||||
}
|
||||
}
|
||||
@@ -1291,8 +1291,8 @@ func TestPreemption(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 59294. Test calling Go function from C after using some
|
||||
// stack space.
|
||||
// Issue 59294 and 68285. Test calling Go function from C after with
|
||||
// various stack space.
|
||||
func TestDeepStack(t *testing.T) {
|
||||
globalSkip(t)
|
||||
testenv.MustHaveGoBuild(t)
|
||||
@@ -1350,6 +1350,53 @@ func TestDeepStack(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCgoCallbackMainThread(b *testing.B) {
|
||||
// Benchmark for calling into Go fron C main thread.
|
||||
// See issue #68587.
|
||||
//
|
||||
// It uses a subprocess, which is a C binary that calls
|
||||
// Go on the main thread b.N times. There is some overhead
|
||||
// for launching the subprocess. It is probably fine when
|
||||
// b.N is large.
|
||||
|
||||
globalSkip(b)
|
||||
testenv.MustHaveGoBuild(b)
|
||||
testenv.MustHaveCGO(b)
|
||||
testenv.MustHaveBuildMode(b, "c-archive")
|
||||
|
||||
if !testWork {
|
||||
defer func() {
|
||||
os.Remove("testp10" + exeSuffix)
|
||||
os.Remove("libgo10.a")
|
||||
os.Remove("libgo10.h")
|
||||
}()
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo10.a", "./libgo10")
|
||||
out, err := cmd.CombinedOutput()
|
||||
b.Logf("%v\n%s", cmd.Args, out)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
ccArgs := append(cc, "-o", "testp10"+exeSuffix, "main10.c", "libgo10.a")
|
||||
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
||||
b.Logf("%v\n%s", ccArgs, out)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
argv := cmdToRun("./testp10")
|
||||
argv = append(argv, fmt.Sprint(b.N))
|
||||
cmd = exec.Command(argv[0], argv[1:]...)
|
||||
|
||||
b.ResetTimer()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedObject(t *testing.T) {
|
||||
// Test that we can put a Go c-archive into a C shared object.
|
||||
globalSkip(t)
|
||||
|
||||
12
src/cmd/cgo/internal/testcarchive/testdata/libgo10/a.go
vendored
Normal file
12
src/cmd/cgo/internal/testcarchive/testdata/libgo10/a.go
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2024 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 "C"
|
||||
|
||||
//export GoF
|
||||
func GoF() {}
|
||||
|
||||
func main() {}
|
||||
@@ -6,9 +6,29 @@ package main
|
||||
|
||||
import "runtime"
|
||||
|
||||
// extern void callGoWithVariousStack(int);
|
||||
import "C"
|
||||
|
||||
func main() {}
|
||||
|
||||
//export GoF
|
||||
func GoF() { runtime.GC() }
|
||||
func GoF(p int32) {
|
||||
runtime.GC()
|
||||
if p != 0 {
|
||||
panic("panic")
|
||||
}
|
||||
}
|
||||
|
||||
//export callGoWithVariousStackAndGoFrame
|
||||
func callGoWithVariousStackAndGoFrame(p int32) {
|
||||
if p != 0 {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e == nil {
|
||||
panic("did not panic")
|
||||
}
|
||||
runtime.GC()
|
||||
}()
|
||||
}
|
||||
C.callGoWithVariousStack(C.int(p));
|
||||
}
|
||||
|
||||
22
src/cmd/cgo/internal/testcarchive/testdata/main10.c
vendored
Normal file
22
src/cmd/cgo/internal/testcarchive/testdata/main10.c
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libgo10.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int n, i;
|
||||
|
||||
if (argc != 2) {
|
||||
perror("wrong arg");
|
||||
return 2;
|
||||
}
|
||||
n = atoi(argv[1]);
|
||||
for (i = 0; i < n; i++)
|
||||
GoF();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -6,19 +6,27 @@
|
||||
|
||||
void use(int *x) { (*x)++; }
|
||||
|
||||
void callGoFWithDeepStack() {
|
||||
void callGoFWithDeepStack(int p) {
|
||||
int x[10000];
|
||||
|
||||
use(&x[0]);
|
||||
use(&x[9999]);
|
||||
|
||||
GoF();
|
||||
GoF(p);
|
||||
|
||||
use(&x[0]);
|
||||
use(&x[9999]);
|
||||
}
|
||||
|
||||
int main() {
|
||||
GoF(); // call GoF without using much stack
|
||||
callGoFWithDeepStack(); // call GoF with a deep stack
|
||||
void callGoWithVariousStack(int p) {
|
||||
GoF(0); // call GoF without using much stack
|
||||
callGoFWithDeepStack(p); // call GoF with a deep stack
|
||||
GoF(0); // again on a shallow stack
|
||||
}
|
||||
|
||||
int main() {
|
||||
callGoWithVariousStack(0);
|
||||
|
||||
callGoWithVariousStackAndGoFrame(0); // normal execution
|
||||
callGoWithVariousStackAndGoFrame(1); // panic and recover
|
||||
}
|
||||
|
||||
@@ -318,9 +318,10 @@ func containsClosure(f, c *ir.Func) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Closures within function Foo are named like "Foo.funcN..." or "Foo-rangeN".
|
||||
// TODO(mdempsky): Better way to recognize this.
|
||||
fn := f.Sym().Name
|
||||
cn := c.Sym().Name
|
||||
return len(cn) > len(fn) && cn[:len(fn)] == fn && (cn[len(fn)] == '.' || cn[len(fn)] == '-')
|
||||
for p := c.ClosureParent; p != nil; p = p.ClosureParent {
|
||||
if p == f {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -582,6 +582,23 @@ func TestIssue25596(t *testing.T) {
|
||||
compileAndImportPkg(t, "issue25596")
|
||||
}
|
||||
|
||||
func TestIssue70394(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// This package only handles gc export data.
|
||||
if runtime.Compiler != "gc" {
|
||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||
}
|
||||
|
||||
pkg := compileAndImportPkg(t, "alias")
|
||||
obj := lookupObj(t, pkg.Scope(), "A")
|
||||
|
||||
typ := obj.Type()
|
||||
if _, ok := typ.(*types2.Alias); !ok {
|
||||
t.Fatalf("type of %s is %s, wanted an alias", obj, typ)
|
||||
}
|
||||
}
|
||||
|
||||
func importPkg(t *testing.T, path, srcDir string) *types2.Package {
|
||||
pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
|
||||
if err != nil {
|
||||
|
||||
7
src/cmd/compile/internal/importer/testdata/alias.go
vendored
Normal file
7
src/cmd/compile/internal/importer/testdata/alias.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2024 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 testdata
|
||||
|
||||
type A = int32
|
||||
@@ -29,11 +29,9 @@ func ReadPackage(ctxt *types2.Context, imports map[string]*types2.Package, input
|
||||
pr := pkgReader{
|
||||
PkgDecoder: input,
|
||||
|
||||
ctxt: ctxt,
|
||||
imports: imports,
|
||||
// Currently, the compiler panics when using Alias types.
|
||||
// TODO(gri) set to true once this is fixed (issue #66873)
|
||||
enableAlias: false,
|
||||
ctxt: ctxt,
|
||||
imports: imports,
|
||||
enableAlias: true,
|
||||
|
||||
posBases: make([]*syntax.PosBase, input.NumElems(pkgbits.RelocPosBase)),
|
||||
pkgs: make([]*types2.Package, input.NumElems(pkgbits.RelocPkg)),
|
||||
|
||||
@@ -51,6 +51,8 @@ import (
|
||||
// the generated ODCLFUNC, but there is no
|
||||
// pointer from the Func back to the OMETHVALUE.
|
||||
type Func struct {
|
||||
// if you add or remove a field, don't forget to update sizeof_test.go
|
||||
|
||||
miniNode
|
||||
Body Nodes
|
||||
|
||||
@@ -76,6 +78,9 @@ type Func struct {
|
||||
// Populated during walk.
|
||||
Closures []*Func
|
||||
|
||||
// Parent of a closure
|
||||
ClosureParent *Func
|
||||
|
||||
// Parents records the parent scope of each scope within a
|
||||
// function. The root scope (0) has no parent, so the i'th
|
||||
// scope's parent is stored at Parents[i-1].
|
||||
@@ -512,6 +517,7 @@ func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func,
|
||||
|
||||
fn.Nname.Defn = fn
|
||||
pkg.Funcs = append(pkg.Funcs, fn)
|
||||
fn.ClosureParent = outerfn
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
|
||||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Func{}, 176, 296},
|
||||
{Func{}, 180, 304},
|
||||
{Name{}, 96, 168},
|
||||
}
|
||||
|
||||
|
||||
@@ -2099,3 +2099,27 @@ func TestTwoLevelReturnCheck(t *testing.T) {
|
||||
t.Errorf("Expected y=3, got y=%d\n", y)
|
||||
}
|
||||
}
|
||||
|
||||
func Bug70035(s1, s2, s3 []string) string {
|
||||
var c1 string
|
||||
for v1 := range slices.Values(s1) {
|
||||
var c2 string
|
||||
for v2 := range slices.Values(s2) {
|
||||
var c3 string
|
||||
for v3 := range slices.Values(s3) {
|
||||
c3 = c3 + v3
|
||||
}
|
||||
c2 = c2 + v2 + c3
|
||||
}
|
||||
c1 = c1 + v1 + c2
|
||||
}
|
||||
return c1
|
||||
}
|
||||
|
||||
func Test70035(t *testing.T) {
|
||||
got := Bug70035([]string{"1", "2", "3"}, []string{"a", "b", "c"}, []string{"A", "B", "C"})
|
||||
want := "1aABCbABCcABC2aABCbABCcABC3aABCbABCcABC"
|
||||
if got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,6 +252,7 @@ func writebarrier(f *Func) {
|
||||
var start, end int
|
||||
var nonPtrStores int
|
||||
values := b.Values
|
||||
hasMove := false
|
||||
FindSeq:
|
||||
for i := len(values) - 1; i >= 0; i-- {
|
||||
w := values[i]
|
||||
@@ -263,6 +264,9 @@ func writebarrier(f *Func) {
|
||||
end = i + 1
|
||||
}
|
||||
nonPtrStores = 0
|
||||
if w.Op == OpMoveWB {
|
||||
hasMove = true
|
||||
}
|
||||
case OpVarDef, OpVarLive:
|
||||
continue
|
||||
case OpStore:
|
||||
@@ -273,6 +277,17 @@ func writebarrier(f *Func) {
|
||||
if nonPtrStores > 2 {
|
||||
break FindSeq
|
||||
}
|
||||
if hasMove {
|
||||
// We need to ensure that this store happens
|
||||
// before we issue a wbMove, as the wbMove might
|
||||
// use the result of this store as its source.
|
||||
// Even though this store is not write-barrier
|
||||
// eligible, it might nevertheless be the store
|
||||
// of a pointer to the stack, which is then the
|
||||
// source of the move.
|
||||
// See issue 71228.
|
||||
break FindSeq
|
||||
}
|
||||
default:
|
||||
if last == nil {
|
||||
continue
|
||||
|
||||
@@ -662,7 +662,21 @@ func (r *gitRepo) statLocal(ctx context.Context, version, rev string) (*RevInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Strings(info.Tags)
|
||||
|
||||
// Git 2.47.1 does not send the tags during shallow clone anymore
|
||||
// (perhaps the exact version that changed behavior is an earlier one),
|
||||
// so we have to also add tags from the refs list we fetched with ls-remote.
|
||||
if refs, err := r.loadRefs(ctx); err == nil {
|
||||
for ref, h := range refs {
|
||||
if h == hash {
|
||||
if tag, found := strings.CutPrefix(ref, "refs/tags/"); found {
|
||||
info.Tags = append(info.Tags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
slices.Sort(info.Tags)
|
||||
info.Tags = slices.Compact(info.Tags)
|
||||
|
||||
// Used hash as info.Version above.
|
||||
// Use caller's suggested version if it appears in the tag list
|
||||
|
||||
@@ -257,6 +257,10 @@ func (gs *gState[R]) stop(ts trace.Time, stack trace.Stack, ctx *traceContext) {
|
||||
if gs.lastStopStack != trace.NoStack {
|
||||
stk = ctx.Stack(viewerFrames(gs.lastStopStack))
|
||||
}
|
||||
var endStk int
|
||||
if stack != trace.NoStack {
|
||||
endStk = ctx.Stack(viewerFrames(stack))
|
||||
}
|
||||
// Check invariants.
|
||||
if gs.startRunningTime == 0 {
|
||||
panic("silently broken trace or generator invariant (startRunningTime != 0) not held")
|
||||
@@ -270,6 +274,7 @@ func (gs *gState[R]) stop(ts trace.Time, stack trace.Stack, ctx *traceContext) {
|
||||
Dur: ts.Sub(gs.startRunningTime),
|
||||
Resource: uint64(gs.executing),
|
||||
Stack: stk,
|
||||
EndStack: endStk,
|
||||
})
|
||||
|
||||
// Flush completed ranges.
|
||||
|
||||
@@ -852,6 +852,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
Time: testTime,
|
||||
}
|
||||
|
||||
issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
|
||||
@@ -868,6 +869,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
Time: testTime,
|
||||
}
|
||||
|
||||
testResumeState := func(test string, didResume bool) {
|
||||
@@ -914,7 +916,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// An old session ticket is replaced with a ticket encrypted with a fresh key.
|
||||
ticket = getTicket()
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithOldTicket", true)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("old first ticket matches the fresh one")
|
||||
@@ -922,13 +924,13 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// Once the session master secret is expired, a full handshake should occur.
|
||||
ticket = getTicket()
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithExpiredTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("expired first ticket matches the fresh one")
|
||||
}
|
||||
|
||||
serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
|
||||
serverConfig.Time = testTime // reset the time back
|
||||
key1 := randomKey()
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key1})
|
||||
|
||||
@@ -945,11 +947,11 @@ func testResumption(t *testing.T, version uint16) {
|
||||
testResumeState("KeyChangeFinish", true)
|
||||
|
||||
// Age the session ticket a bit, but not yet expired.
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("OldSessionTicket", true)
|
||||
ticket = getTicket()
|
||||
// Expire the session ticket, which would force a full handshake.
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) }
|
||||
testResumeState("ExpiredSessionTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("new ticket wasn't provided after old ticket expired")
|
||||
@@ -957,7 +959,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// Age the session ticket a bit at a time, but don't expire it.
|
||||
d := 0 * time.Hour
|
||||
serverConfig.Time = func() time.Time { return time.Now().Add(d) }
|
||||
serverConfig.Time = func() time.Time { return testTime().Add(d) }
|
||||
deleteTicket()
|
||||
testResumeState("GetFreshSessionTicket", false)
|
||||
for i := 0; i < 13; i++ {
|
||||
@@ -968,7 +970,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
// handshake occurs for TLS 1.2. Resumption should still occur for
|
||||
// TLS 1.3 since the client should be using a fresh ticket sent over
|
||||
// by the server.
|
||||
d += 12 * time.Hour
|
||||
d += 12*time.Hour + time.Minute
|
||||
if version == VersionTLS13 {
|
||||
testResumeState("ExpiredSessionTicket", true)
|
||||
} else {
|
||||
@@ -984,6 +986,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
Time: testTime,
|
||||
}
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key2})
|
||||
|
||||
@@ -1009,6 +1012,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
|
||||
MaxVersion: version,
|
||||
Certificates: testConfig.Certificates,
|
||||
Time: testTime,
|
||||
}
|
||||
testResumeState("InitialHandshake", false)
|
||||
testResumeState("WithHelloRetryRequest", true)
|
||||
@@ -1018,6 +1022,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
Time: testTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1736,6 +1741,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
||||
serverConfig := &Config{
|
||||
MaxVersion: version,
|
||||
Certificates: []Certificate{testConfig.Certificates[0]},
|
||||
Time: testTime,
|
||||
ClientCAs: rootCAs,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
@@ -1749,6 +1755,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
||||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
Certificates: []Certificate{testConfig.Certificates[0]},
|
||||
Time: testTime,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
test.configureClient(clientConfig, &clientCalled)
|
||||
@@ -1791,8 +1798,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AddCert(issuer)
|
||||
|
||||
now := func() time.Time { return time.Unix(1476984729, 0) }
|
||||
|
||||
sentinelErr := errors.New("TestVerifyPeerCertificate")
|
||||
|
||||
verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
|
||||
@@ -2038,7 +2043,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
config.ServerName = "example.golang"
|
||||
config.ClientAuth = RequireAndVerifyClientCert
|
||||
config.ClientCAs = rootCAs
|
||||
config.Time = now
|
||||
config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
config.Certificates = make([]Certificate, 1)
|
||||
config.Certificates[0].Certificate = [][]byte{testRSACertificate}
|
||||
@@ -2055,7 +2060,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
config := testConfig.Clone()
|
||||
config.ServerName = "example.golang"
|
||||
config.RootCAs = rootCAs
|
||||
config.Time = now
|
||||
config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
test.configureClient(config, &clientCalled)
|
||||
clientErr := Client(c, config).Handshake()
|
||||
@@ -2368,7 +2373,7 @@ func testGetClientCertificate(t *testing.T, version uint16) {
|
||||
serverConfig.RootCAs = x509.NewCertPool()
|
||||
serverConfig.RootCAs.AddCert(issuer)
|
||||
serverConfig.ClientCAs = serverConfig.RootCAs
|
||||
serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
serverConfig.Time = testTime
|
||||
serverConfig.MaxVersion = version
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
@@ -2539,6 +2544,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
ServerName: "example.golang",
|
||||
RootCAs: roots,
|
||||
Time: testTime,
|
||||
}
|
||||
serverConfig := testConfig.Clone()
|
||||
serverConfig.MaxVersion = ver
|
||||
|
||||
@@ -501,6 +501,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
|
||||
serverConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
Time: testTime,
|
||||
}
|
||||
clientConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
|
||||
@@ -508,6 +509,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(1),
|
||||
ServerName: "servername",
|
||||
MinVersion: VersionTLS12,
|
||||
Time: testTime,
|
||||
}
|
||||
|
||||
// Establish a session at TLS 1.3.
|
||||
|
||||
@@ -519,6 +519,11 @@ func fromHex(s string) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// testTime is 2016-10-20T17:32:09.000Z, which is within the validity period of
|
||||
// [testRSACertificate], [testRSACertificateIssuer], [testRSA2048Certificate],
|
||||
// [testRSA2048CertificateIssuer], and [testECDSACertificate].
|
||||
var testTime = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
|
||||
var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
|
||||
|
||||
var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76")
|
||||
|
||||
@@ -1112,8 +1112,6 @@ func TestConnectionState(t *testing.T) {
|
||||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AddCert(issuer)
|
||||
|
||||
now := func() time.Time { return time.Unix(1476984729, 0) }
|
||||
|
||||
const alpnProtocol = "golang"
|
||||
const serverName = "example.golang"
|
||||
var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
|
||||
@@ -1129,7 +1127,7 @@ func TestConnectionState(t *testing.T) {
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
config := &Config{
|
||||
Time: now,
|
||||
Time: testTime,
|
||||
Rand: zeroSource{},
|
||||
Certificates: make([]Certificate, 1),
|
||||
MaxVersion: v,
|
||||
@@ -1760,7 +1758,7 @@ func testVerifyCertificates(t *testing.T, version uint16) {
|
||||
var serverVerifyPeerCertificates, clientVerifyPeerCertificates bool
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
clientConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
clientConfig.Time = testTime
|
||||
clientConfig.MaxVersion = version
|
||||
clientConfig.MinVersion = version
|
||||
clientConfig.RootCAs = rootCAs
|
||||
|
||||
@@ -1607,6 +1607,23 @@ var nameConstraintsTests = []nameConstraintsTest{
|
||||
leaf: leafSpec{sans: []string{"dns:.example.com"}},
|
||||
expectedError: "cannot parse dnsName \".example.com\"",
|
||||
},
|
||||
// #86: URIs with IPv6 addresses with zones and ports are rejected
|
||||
{
|
||||
roots: []constraintsSpec{
|
||||
{
|
||||
ok: []string{"uri:example.com"},
|
||||
},
|
||||
},
|
||||
intermediates: [][]constraintsSpec{
|
||||
{
|
||||
{},
|
||||
},
|
||||
},
|
||||
leaf: leafSpec{
|
||||
sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
|
||||
},
|
||||
expectedError: "URI with IP",
|
||||
},
|
||||
}
|
||||
|
||||
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -434,8 +435,10 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
|
||||
net.ParseIP(host) != nil {
|
||||
// netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we
|
||||
// check if _either_ the string parses as an IP, or if it is enclosed in
|
||||
// square brackets.
|
||||
if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) {
|
||||
return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,6 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error,
|
||||
if err == syscall.EAGAIN {
|
||||
err = nil
|
||||
}
|
||||
handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL)
|
||||
handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL && err != syscall.EOPNOTSUPP && err != syscall.ENOTSUP)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -613,8 +613,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
||||
reqBodyClosed = false // have we closed the current req.Body?
|
||||
|
||||
// Redirect behavior:
|
||||
redirectMethod string
|
||||
includeBody bool
|
||||
redirectMethod string
|
||||
includeBody = true
|
||||
stripSensitiveHeaders = false
|
||||
)
|
||||
uerr := func(err error) error {
|
||||
// the body may have been closed already by c.send()
|
||||
@@ -681,7 +682,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
||||
// in case the user set Referer on their first request.
|
||||
// If they really want to override, they can do it in
|
||||
// their CheckRedirect func.
|
||||
copyHeaders(req)
|
||||
if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host {
|
||||
if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) {
|
||||
stripSensitiveHeaders = true
|
||||
}
|
||||
}
|
||||
copyHeaders(req, stripSensitiveHeaders)
|
||||
|
||||
// Add the Referer header from the most recent
|
||||
// request URL to the new one, if it's not https->http:
|
||||
@@ -744,7 +750,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
||||
// makeHeadersCopier makes a function that copies headers from the
|
||||
// initial Request, ireq. For every redirect, this function must be called
|
||||
// so that it can copy headers into the upcoming Request.
|
||||
func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
|
||||
func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) {
|
||||
// The headers to copy are from the very initial request.
|
||||
// We use a closured callback to keep a reference to these original headers.
|
||||
var (
|
||||
@@ -758,8 +764,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
|
||||
}
|
||||
}
|
||||
|
||||
preq := ireq // The previous request
|
||||
return func(req *Request) {
|
||||
return func(req *Request, stripSensitiveHeaders bool) {
|
||||
// If Jar is present and there was some initial cookies provided
|
||||
// via the request header, then we may need to alter the initial
|
||||
// cookies as we follow redirects since each redirect may end up
|
||||
@@ -796,12 +801,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
|
||||
// Copy the initial request's Header values
|
||||
// (at least the safe ones).
|
||||
for k, vv := range ireqhdr {
|
||||
if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
|
||||
sensitive := false
|
||||
switch CanonicalHeaderKey(k) {
|
||||
case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
|
||||
sensitive = true
|
||||
}
|
||||
if !(sensitive && stripSensitiveHeaders) {
|
||||
req.Header[k] = vv
|
||||
}
|
||||
}
|
||||
|
||||
preq = req // Update previous Request with the current request
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,28 +985,23 @@ func (b *cancelTimerBody) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
|
||||
switch CanonicalHeaderKey(headerKey) {
|
||||
case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
|
||||
// Permit sending auth/cookie headers from "foo.com"
|
||||
// to "sub.foo.com".
|
||||
func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool {
|
||||
// Permit sending auth/cookie headers from "foo.com"
|
||||
// to "sub.foo.com".
|
||||
|
||||
// Note that we don't send all cookies to subdomains
|
||||
// automatically. This function is only used for
|
||||
// Cookies set explicitly on the initial outgoing
|
||||
// client request. Cookies automatically added via the
|
||||
// CookieJar mechanism continue to follow each
|
||||
// cookie's scope as set by Set-Cookie. But for
|
||||
// outgoing requests with the Cookie header set
|
||||
// directly, we don't know their scope, so we assume
|
||||
// it's for *.domain.com.
|
||||
// Note that we don't send all cookies to subdomains
|
||||
// automatically. This function is only used for
|
||||
// Cookies set explicitly on the initial outgoing
|
||||
// client request. Cookies automatically added via the
|
||||
// CookieJar mechanism continue to follow each
|
||||
// cookie's scope as set by Set-Cookie. But for
|
||||
// outgoing requests with the Cookie header set
|
||||
// directly, we don't know their scope, so we assume
|
||||
// it's for *.domain.com.
|
||||
|
||||
ihost := idnaASCIIFromURL(initial)
|
||||
dhost := idnaASCIIFromURL(dest)
|
||||
return isDomainOrSubdomain(dhost, ihost)
|
||||
}
|
||||
// All other headers are copied:
|
||||
return true
|
||||
ihost := idnaASCIIFromURL(initial)
|
||||
dhost := idnaASCIIFromURL(dest)
|
||||
return isDomainOrSubdomain(dhost, ihost)
|
||||
}
|
||||
|
||||
// isDomainOrSubdomain reports whether sub is a subdomain (or exact
|
||||
|
||||
@@ -1536,6 +1536,55 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #70530: Once we strip a header on a redirect to a different host,
|
||||
// the header should stay stripped across any further redirects.
|
||||
func TestClientStripHeadersOnRepeatedRedirect(t *testing.T) {
|
||||
run(t, testClientStripHeadersOnRepeatedRedirect)
|
||||
}
|
||||
func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) {
|
||||
var proto string
|
||||
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
if r.Host+r.URL.Path != "a.example.com/" {
|
||||
if h := r.Header.Get("Authorization"); h != "" {
|
||||
t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h)
|
||||
}
|
||||
}
|
||||
// Follow a chain of redirects from a to b and back to a.
|
||||
// The Authorization header is stripped on the first redirect to b,
|
||||
// and stays stripped even if we're sent back to a.
|
||||
switch r.Host + r.URL.Path {
|
||||
case "a.example.com/":
|
||||
Redirect(w, r, proto+"://b.example.com/", StatusFound)
|
||||
case "b.example.com/":
|
||||
Redirect(w, r, proto+"://b.example.com/redirect", StatusFound)
|
||||
case "b.example.com/redirect":
|
||||
Redirect(w, r, proto+"://a.example.com/redirect", StatusFound)
|
||||
case "a.example.com/redirect":
|
||||
w.Header().Set("X-Done", "true")
|
||||
default:
|
||||
t.Errorf("unexpected request to %v", r.URL)
|
||||
}
|
||||
})).ts
|
||||
proto, _, _ = strings.Cut(ts.URL, ":")
|
||||
|
||||
c := ts.Client()
|
||||
c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) {
|
||||
return net.Dial("tcp", ts.Listener.Addr().String())
|
||||
}
|
||||
|
||||
req, _ := NewRequest("GET", proto+"://a.example.com/", nil)
|
||||
req.Header.Add("Cookie", "foo=bar")
|
||||
req.Header.Add("Authorization", "secretpassword")
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.Header.Get("X-Done") != "true" {
|
||||
t.Fatalf("response missing expected header: X-Done=true")
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 22233: copy host when Client follows a relative redirect.
|
||||
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) }
|
||||
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) {
|
||||
@@ -1702,43 +1751,39 @@ func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) {
|
||||
// Part of Issue 4800
|
||||
func TestShouldCopyHeaderOnRedirect(t *testing.T) {
|
||||
tests := []struct {
|
||||
header string
|
||||
initialURL string
|
||||
destURL string
|
||||
want bool
|
||||
}{
|
||||
{"User-Agent", "http://foo.com/", "http://bar.com/", true},
|
||||
{"X-Foo", "http://foo.com/", "http://bar.com/", true},
|
||||
|
||||
// Sensitive headers:
|
||||
{"cookie", "http://foo.com/", "http://bar.com/", false},
|
||||
{"cookie2", "http://foo.com/", "http://bar.com/", false},
|
||||
{"authorization", "http://foo.com/", "http://bar.com/", false},
|
||||
{"authorization", "http://foo.com/", "https://foo.com/", true},
|
||||
{"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true},
|
||||
{"www-authenticate", "http://foo.com/", "http://bar.com/", false},
|
||||
{"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false},
|
||||
{"http://foo.com/", "http://bar.com/", false},
|
||||
{"http://foo.com/", "http://bar.com/", false},
|
||||
{"http://foo.com/", "http://bar.com/", false},
|
||||
{"http://foo.com/", "https://foo.com/", true},
|
||||
{"http://foo.com:1234/", "http://foo.com:4321/", true},
|
||||
{"http://foo.com/", "http://bar.com/", false},
|
||||
{"http://foo.com/", "http://[::1%25.foo.com]/", false},
|
||||
|
||||
// But subdomains should work:
|
||||
{"www-authenticate", "http://foo.com/", "http://foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
|
||||
{"www-authenticate", "http://foo.com/", "https://foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com:443/", "https://foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
{"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true},
|
||||
{"http://foo.com/", "http://foo.com/", true},
|
||||
{"http://foo.com/", "http://sub.foo.com/", true},
|
||||
{"http://foo.com/", "http://notfoo.com/", false},
|
||||
{"http://foo.com/", "https://foo.com/", true},
|
||||
{"http://foo.com:80/", "http://foo.com/", true},
|
||||
{"http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
{"http://foo.com:443/", "https://foo.com/", true},
|
||||
{"http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
{"http://foo.com:1234/", "http://foo.com/", true},
|
||||
|
||||
{"authorization", "http://foo.com/", "http://foo.com/", true},
|
||||
{"authorization", "http://foo.com/", "http://sub.foo.com/", true},
|
||||
{"authorization", "http://foo.com/", "http://notfoo.com/", false},
|
||||
{"authorization", "http://foo.com/", "https://foo.com/", true},
|
||||
{"authorization", "http://foo.com:80/", "http://foo.com/", true},
|
||||
{"authorization", "http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
{"authorization", "http://foo.com:443/", "https://foo.com/", true},
|
||||
{"authorization", "http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
{"authorization", "http://foo.com:1234/", "http://foo.com/", true},
|
||||
{"http://foo.com/", "http://foo.com/", true},
|
||||
{"http://foo.com/", "http://sub.foo.com/", true},
|
||||
{"http://foo.com/", "http://notfoo.com/", false},
|
||||
{"http://foo.com/", "https://foo.com/", true},
|
||||
{"http://foo.com:80/", "http://foo.com/", true},
|
||||
{"http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
{"http://foo.com:443/", "https://foo.com/", true},
|
||||
{"http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
{"http://foo.com:1234/", "http://foo.com/", true},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
u0, err := url.Parse(tt.initialURL)
|
||||
@@ -1751,10 +1796,10 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
|
||||
t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err)
|
||||
continue
|
||||
}
|
||||
got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1)
|
||||
got := Export_shouldCopyHeaderOnRedirect(u0, u1)
|
||||
if got != tt.want {
|
||||
t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
|
||||
i, tt.header, tt.initialURL, tt.destURL, got, tt.want)
|
||||
t.Errorf("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v",
|
||||
i, tt.initialURL, tt.destURL, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,56 +10,56 @@ import "strings"
|
||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
|
||||
// generated from src/crypto/tls:
|
||||
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||
MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
|
||||
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
|
||||
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
|
||||
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
|
||||
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
|
||||
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
|
||||
MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u
|
||||
FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/
|
||||
jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH
|
||||
DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD
|
||||
qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl
|
||||
U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE
|
||||
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
|
||||
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
|
||||
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
|
||||
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
|
||||
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
|
||||
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
|
||||
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
|
||||
WkBKOclmOV2xlTVuPw==
|
||||
DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv
|
||||
bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu
|
||||
LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR
|
||||
Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5
|
||||
2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO
|
||||
6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL
|
||||
rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
// LocalhostKey is the private key for LocalhostCert.
|
||||
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
||||
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
||||
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
||||
URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
|
||||
AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
|
||||
VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
|
||||
x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
|
||||
lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
|
||||
dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
|
||||
EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
|
||||
XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
|
||||
6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
|
||||
3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
|
||||
uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
|
||||
Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
|
||||
w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
|
||||
+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
|
||||
OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
|
||||
brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
|
||||
m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
|
||||
LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
|
||||
/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
|
||||
s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
|
||||
Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
|
||||
xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
|
||||
ZboOWVe3icTy64BT3OQhmg==
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34
|
||||
wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu
|
||||
pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O
|
||||
pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs
|
||||
xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde
|
||||
o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF
|
||||
GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr
|
||||
/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE
|
||||
sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa
|
||||
7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc
|
||||
k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT
|
||||
gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u
|
||||
7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5
|
||||
5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w
|
||||
HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo
|
||||
VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p
|
||||
hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd
|
||||
tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY
|
||||
JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB
|
||||
PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl
|
||||
zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY
|
||||
M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr
|
||||
Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn
|
||||
nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU
|
||||
supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ
|
||||
jel6uj2FOP9g54s+GzlSVg/T
|
||||
-----END RSA TESTING KEY-----`))
|
||||
|
||||
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
|
||||
|
||||
@@ -53,6 +53,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
||||
if err != nil {
|
||||
return 0, err, false
|
||||
}
|
||||
if fi.Mode()&(fs.ModeSymlink|fs.ModeDevice|fs.ModeCharDevice|fs.ModeIrregular) != 0 {
|
||||
return 0, nil, false
|
||||
}
|
||||
|
||||
remain = fi.Size()
|
||||
}
|
||||
|
||||
86
src/net/sendfile_unix_test.go
Normal file
86
src/net/sendfile_unix_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"internal/testpty"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Issue 70763: test that we don't fail on sendfile from a tty.
|
||||
func TestCopyFromTTY(t *testing.T) {
|
||||
pty, ttyName, err := testpty.Open()
|
||||
if err != nil {
|
||||
t.Skipf("skipping test because pty open failed: %v", err)
|
||||
}
|
||||
defer pty.Close()
|
||||
|
||||
// Use syscall.Open so that the tty is blocking.
|
||||
ttyFD, err := syscall.Open(ttyName, syscall.O_RDWR, 0)
|
||||
if err != nil {
|
||||
t.Skipf("skipping test because tty open failed: %v", err)
|
||||
}
|
||||
defer syscall.Close(ttyFD)
|
||||
|
||||
tty := os.NewFile(uintptr(ttyFD), "tty")
|
||||
defer tty.Close()
|
||||
|
||||
ln := newLocalListener(t, "tcp")
|
||||
defer ln.Close()
|
||||
|
||||
ch := make(chan bool)
|
||||
|
||||
const data = "data\n"
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
buf := make([]byte, len(data))
|
||||
if _, err := io.ReadFull(conn, buf); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ch <- true
|
||||
}()
|
||||
|
||||
conn, err := Dial("tcp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if _, err := pty.Write([]byte(data)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
<-ch
|
||||
if err := pty.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
lr := io.LimitReader(tty, int64(len(data)))
|
||||
if _, err := io.Copy(conn, lr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,17 @@ func (p *Process) wait() (ps *ProcessState, err error) {
|
||||
if e != nil {
|
||||
return nil, NewSyscallError("GetProcessTimes", e)
|
||||
}
|
||||
|
||||
// NOTE(brainman): It seems that sometimes process is not dead
|
||||
// when WaitForSingleObject returns. But we do not know any
|
||||
// other way to wait for it. Sleeping for a while seems to do
|
||||
// the trick sometimes.
|
||||
// See https://golang.org/issue/25965 for details.
|
||||
_, isWin10AndAbove := syscall.WindowsVersion()
|
||||
if !isWin10AndAbove {
|
||||
defer time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
|
||||
defer p.Release()
|
||||
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ x_cgo_getstackbound(uintptr bounds[2])
|
||||
pthread_attr_get_np(pthread_self(), &attr);
|
||||
pthread_attr_getstack(&attr, &addr, &size); // low address
|
||||
#else
|
||||
// We don't know how to get the current stacks, so assume they are the
|
||||
// same as the default stack bounds.
|
||||
pthread_attr_getstacksize(&attr, &size);
|
||||
addr = __builtin_frame_address(0) + 4096 - size;
|
||||
// We don't know how to get the current stacks, leave it as
|
||||
// 0 and the caller will use an estimate based on the current
|
||||
// SP.
|
||||
addr = 0;
|
||||
size = 0;
|
||||
#endif
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
|
||||
@@ -231,34 +231,6 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
|
||||
func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) {
|
||||
g0 := mp.g0
|
||||
|
||||
inBound := sp > g0.stack.lo && sp <= g0.stack.hi
|
||||
if mp.ncgo > 0 && !inBound {
|
||||
// ncgo > 0 indicates that this M was in Go further up the stack
|
||||
// (it called C and is now receiving a callback).
|
||||
//
|
||||
// !inBound indicates that we were called with SP outside the
|
||||
// expected system stack bounds (C changed the stack out from
|
||||
// under us between the cgocall and cgocallback?).
|
||||
//
|
||||
// It is not safe for the C call to change the stack out from
|
||||
// under us, so throw.
|
||||
|
||||
// Note that this case isn't possible for signal == true, as
|
||||
// that is always passing a new M from needm.
|
||||
|
||||
// Stack is bogus, but reset the bounds anyway so we can print.
|
||||
hi := g0.stack.hi
|
||||
lo := g0.stack.lo
|
||||
g0.stack.hi = sp + 1024
|
||||
g0.stack.lo = sp - 32*1024
|
||||
g0.stackguard0 = g0.stack.lo + stackGuard
|
||||
g0.stackguard1 = g0.stackguard0
|
||||
|
||||
print("M ", mp.id, " procid ", mp.procid, " runtime: cgocallback with sp=", hex(sp), " out of bounds [", hex(lo), ", ", hex(hi), "]")
|
||||
print("\n")
|
||||
exit(2)
|
||||
}
|
||||
|
||||
if !mp.isextra {
|
||||
// We allocated the stack for standard Ms. Don't replace the
|
||||
// stack bounds with estimated ones when we already initialized
|
||||
@@ -266,26 +238,37 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// This M does not have Go further up the stack. However, it may have
|
||||
// previously called into Go, initializing the stack bounds. Between
|
||||
// that call returning and now the stack may have changed (perhaps the
|
||||
// C thread is running a coroutine library). We need to update the
|
||||
// stack bounds for this case.
|
||||
inBound := sp > g0.stack.lo && sp <= g0.stack.hi
|
||||
if inBound && mp.g0StackAccurate {
|
||||
// This M has called into Go before and has the stack bounds
|
||||
// initialized. We have the accurate stack bounds, and the SP
|
||||
// is in bounds. We expect it continues to run within the same
|
||||
// bounds.
|
||||
return
|
||||
}
|
||||
|
||||
// We don't have an accurate stack bounds (either it never calls
|
||||
// into Go before, or we couldn't get the accurate bounds), or the
|
||||
// current SP is not within the previous bounds (the stack may have
|
||||
// changed between calls). We need to update the stack bounds.
|
||||
//
|
||||
// N.B. we need to update the stack bounds even if SP appears to
|
||||
// already be in bounds. Our "bounds" may actually be estimated dummy
|
||||
// bounds (below). The actual stack bounds could have shifted but still
|
||||
// have partial overlap with our dummy bounds. If we failed to update
|
||||
// in that case, we could find ourselves seemingly called near the
|
||||
// bottom of the stack bounds, where we quickly run out of space.
|
||||
// already be in bounds, if our bounds are estimated dummy bounds
|
||||
// (below). We may be in a different region within the same actual
|
||||
// stack bounds, but our estimates were not accurate. Or the actual
|
||||
// stack bounds could have shifted but still have partial overlap with
|
||||
// our dummy bounds. If we failed to update in that case, we could find
|
||||
// ourselves seemingly called near the bottom of the stack bounds, where
|
||||
// we quickly run out of space.
|
||||
|
||||
// Set the stack bounds to match the current stack. If we don't
|
||||
// actually know how big the stack is, like we don't know how big any
|
||||
// scheduling stack is, but we assume there's at least 32 kB. If we
|
||||
// can get a more accurate stack bound from pthread, use that, provided
|
||||
// it actually contains SP..
|
||||
// it actually contains SP.
|
||||
g0.stack.hi = sp + 1024
|
||||
g0.stack.lo = sp - 32*1024
|
||||
mp.g0StackAccurate = false
|
||||
if !signal && _cgo_getstackbound != nil {
|
||||
// Don't adjust if called from the signal handler.
|
||||
// We are on the signal stack, not the pthread stack.
|
||||
@@ -296,12 +279,16 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) {
|
||||
asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds))
|
||||
// getstackbound is an unsupported no-op on Windows.
|
||||
//
|
||||
// On Unix systems, if the API to get accurate stack bounds is
|
||||
// not available, it returns zeros.
|
||||
//
|
||||
// Don't use these bounds if they don't contain SP. Perhaps we
|
||||
// were called by something not using the standard thread
|
||||
// stack.
|
||||
if bounds[0] != 0 && sp > bounds[0] && sp <= bounds[1] {
|
||||
g0.stack.lo = bounds[0]
|
||||
g0.stack.hi = bounds[1]
|
||||
mp.g0StackAccurate = true
|
||||
}
|
||||
}
|
||||
g0.stackguard0 = g0.stack.lo + stackGuard
|
||||
@@ -319,6 +306,8 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
||||
}
|
||||
|
||||
sp := gp.m.g0.sched.sp // system sp saved by cgocallback.
|
||||
oldStack := gp.m.g0.stack
|
||||
oldAccurate := gp.m.g0StackAccurate
|
||||
callbackUpdateSystemStack(gp.m, sp, false)
|
||||
|
||||
// The call from C is on gp.m's g0 stack, so we must ensure
|
||||
@@ -380,6 +369,12 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
||||
reentersyscall(savedpc, uintptr(savedsp), uintptr(savedbp))
|
||||
|
||||
gp.m.winsyscall = winsyscall
|
||||
|
||||
// Restore the old g0 stack bounds
|
||||
gp.m.g0.stack = oldStack
|
||||
gp.m.g0.stackguard0 = oldStack.lo + stackGuard
|
||||
gp.m.g0.stackguard1 = gp.m.g0.stackguard0
|
||||
gp.m.g0StackAccurate = oldAccurate
|
||||
}
|
||||
|
||||
func cgocallbackg1(fn, frame unsafe.Pointer, ctxt uintptr) {
|
||||
|
||||
@@ -1886,3 +1886,30 @@ func (m *TraceMap) PutString(s string) (uint64, bool) {
|
||||
func (m *TraceMap) Reset() {
|
||||
m.traceMap.reset()
|
||||
}
|
||||
|
||||
func SetSpinInGCMarkDone(spin bool) {
|
||||
gcDebugMarkDone.spinAfterRaggedBarrier.Store(spin)
|
||||
}
|
||||
|
||||
func GCMarkDoneRestarted() bool {
|
||||
// Only read this outside of the GC. If we're running during a GC, just report false.
|
||||
mp := acquirem()
|
||||
if gcphase != _GCoff {
|
||||
releasem(mp)
|
||||
return false
|
||||
}
|
||||
restarted := gcDebugMarkDone.restartedDueTo27993
|
||||
releasem(mp)
|
||||
return restarted
|
||||
}
|
||||
|
||||
func GCMarkDoneResetRestartFlag() {
|
||||
mp := acquirem()
|
||||
for gcphase != _GCoff {
|
||||
releasem(mp)
|
||||
Gosched()
|
||||
mp = acquirem()
|
||||
}
|
||||
gcDebugMarkDone.restartedDueTo27993 = false
|
||||
releasem(mp)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ package runtime_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"internal/weak"
|
||||
"math/bits"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -787,3 +789,78 @@ func TestMemoryLimitNoGCPercent(t *testing.T) {
|
||||
func TestMyGenericFunc(t *testing.T) {
|
||||
runtime.MyGenericFunc[int]()
|
||||
}
|
||||
|
||||
func TestWeakToStrongMarkTermination(t *testing.T) {
|
||||
testenv.MustHaveParallelism(t)
|
||||
|
||||
type T struct {
|
||||
a *int
|
||||
b int
|
||||
}
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
|
||||
defer debug.SetGCPercent(debug.SetGCPercent(-1))
|
||||
w := make([]weak.Pointer[T], 2048)
|
||||
|
||||
// Make sure there's no out-standing GC from a previous test.
|
||||
runtime.GC()
|
||||
|
||||
// Create many objects with a weak pointers to them.
|
||||
for i := range w {
|
||||
x := new(T)
|
||||
x.a = new(int)
|
||||
w[i] = weak.Make(x)
|
||||
}
|
||||
|
||||
// Reset the restart flag.
|
||||
runtime.GCMarkDoneResetRestartFlag()
|
||||
|
||||
// Prevent mark termination from completing.
|
||||
runtime.SetSpinInGCMarkDone(true)
|
||||
|
||||
// Start a GC, and wait a little bit to get something spinning in mark termination.
|
||||
// Simultaneously, fire off another goroutine to disable spinning. If everything's
|
||||
// working correctly, then weak.Strong will block, so we need to make sure something
|
||||
// prevents the GC from continuing to spin.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
runtime.GC()
|
||||
done <- struct{}{}
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Let mark termination continue.
|
||||
runtime.SetSpinInGCMarkDone(false)
|
||||
}()
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// Perform many weak->strong conversions in the critical window.
|
||||
var wg sync.WaitGroup
|
||||
for _, wp := range w {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wp.Strong()
|
||||
}()
|
||||
}
|
||||
|
||||
// Make sure the GC completes.
|
||||
<-done
|
||||
|
||||
// Make sure all the weak->strong conversions finish.
|
||||
wg.Wait()
|
||||
|
||||
// The bug is triggered if there's still mark work after gcMarkDone stops the world.
|
||||
//
|
||||
// This can manifest in one of two ways today:
|
||||
// - An exceedingly rare crash in mark termination.
|
||||
// - gcMarkDone restarts, as if issue #27993 is at play.
|
||||
//
|
||||
// Check for the latter. This is a fairly controlled environment, so #27993 is very
|
||||
// unlikely to happen (it's already rare to begin with) but we'll always _appear_ to
|
||||
// trigger the same bug if weak->strong conversions aren't properly coordinated with
|
||||
// mark termination.
|
||||
if runtime.GCMarkDoneRestarted() {
|
||||
t.Errorf("gcMarkDone restarted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ const (
|
||||
lockRankDefer
|
||||
lockRankSweepWaiters
|
||||
lockRankAssistQueue
|
||||
lockRankStrongFromWeakQueue
|
||||
lockRankSweep
|
||||
lockRankTestR
|
||||
lockRankTestW
|
||||
@@ -84,64 +85,65 @@ const lockRankLeafRank lockRank = 1000
|
||||
|
||||
// lockNames gives the names associated with each of the above ranks.
|
||||
var lockNames = []string{
|
||||
lockRankSysmon: "sysmon",
|
||||
lockRankScavenge: "scavenge",
|
||||
lockRankForcegc: "forcegc",
|
||||
lockRankDefer: "defer",
|
||||
lockRankSweepWaiters: "sweepWaiters",
|
||||
lockRankAssistQueue: "assistQueue",
|
||||
lockRankSweep: "sweep",
|
||||
lockRankTestR: "testR",
|
||||
lockRankTestW: "testW",
|
||||
lockRankTimerSend: "timerSend",
|
||||
lockRankAllocmW: "allocmW",
|
||||
lockRankExecW: "execW",
|
||||
lockRankCpuprof: "cpuprof",
|
||||
lockRankPollCache: "pollCache",
|
||||
lockRankPollDesc: "pollDesc",
|
||||
lockRankWakeableSleep: "wakeableSleep",
|
||||
lockRankHchan: "hchan",
|
||||
lockRankAllocmR: "allocmR",
|
||||
lockRankExecR: "execR",
|
||||
lockRankSched: "sched",
|
||||
lockRankAllg: "allg",
|
||||
lockRankAllp: "allp",
|
||||
lockRankNotifyList: "notifyList",
|
||||
lockRankSudog: "sudog",
|
||||
lockRankTimers: "timers",
|
||||
lockRankTimer: "timer",
|
||||
lockRankNetpollInit: "netpollInit",
|
||||
lockRankRoot: "root",
|
||||
lockRankItab: "itab",
|
||||
lockRankReflectOffs: "reflectOffs",
|
||||
lockRankUserArenaState: "userArenaState",
|
||||
lockRankTraceBuf: "traceBuf",
|
||||
lockRankTraceStrings: "traceStrings",
|
||||
lockRankFin: "fin",
|
||||
lockRankSpanSetSpine: "spanSetSpine",
|
||||
lockRankMspanSpecial: "mspanSpecial",
|
||||
lockRankTraceTypeTab: "traceTypeTab",
|
||||
lockRankGcBitsArenas: "gcBitsArenas",
|
||||
lockRankProfInsert: "profInsert",
|
||||
lockRankProfBlock: "profBlock",
|
||||
lockRankProfMemActive: "profMemActive",
|
||||
lockRankProfMemFuture: "profMemFuture",
|
||||
lockRankGscan: "gscan",
|
||||
lockRankStackpool: "stackpool",
|
||||
lockRankStackLarge: "stackLarge",
|
||||
lockRankHchanLeaf: "hchanLeaf",
|
||||
lockRankWbufSpans: "wbufSpans",
|
||||
lockRankMheap: "mheap",
|
||||
lockRankMheapSpecial: "mheapSpecial",
|
||||
lockRankGlobalAlloc: "globalAlloc",
|
||||
lockRankTrace: "trace",
|
||||
lockRankTraceStackTab: "traceStackTab",
|
||||
lockRankPanic: "panic",
|
||||
lockRankDeadlock: "deadlock",
|
||||
lockRankRaceFini: "raceFini",
|
||||
lockRankAllocmRInternal: "allocmRInternal",
|
||||
lockRankExecRInternal: "execRInternal",
|
||||
lockRankTestRInternal: "testRInternal",
|
||||
lockRankSysmon: "sysmon",
|
||||
lockRankScavenge: "scavenge",
|
||||
lockRankForcegc: "forcegc",
|
||||
lockRankDefer: "defer",
|
||||
lockRankSweepWaiters: "sweepWaiters",
|
||||
lockRankAssistQueue: "assistQueue",
|
||||
lockRankStrongFromWeakQueue: "strongFromWeakQueue",
|
||||
lockRankSweep: "sweep",
|
||||
lockRankTestR: "testR",
|
||||
lockRankTestW: "testW",
|
||||
lockRankTimerSend: "timerSend",
|
||||
lockRankAllocmW: "allocmW",
|
||||
lockRankExecW: "execW",
|
||||
lockRankCpuprof: "cpuprof",
|
||||
lockRankPollCache: "pollCache",
|
||||
lockRankPollDesc: "pollDesc",
|
||||
lockRankWakeableSleep: "wakeableSleep",
|
||||
lockRankHchan: "hchan",
|
||||
lockRankAllocmR: "allocmR",
|
||||
lockRankExecR: "execR",
|
||||
lockRankSched: "sched",
|
||||
lockRankAllg: "allg",
|
||||
lockRankAllp: "allp",
|
||||
lockRankNotifyList: "notifyList",
|
||||
lockRankSudog: "sudog",
|
||||
lockRankTimers: "timers",
|
||||
lockRankTimer: "timer",
|
||||
lockRankNetpollInit: "netpollInit",
|
||||
lockRankRoot: "root",
|
||||
lockRankItab: "itab",
|
||||
lockRankReflectOffs: "reflectOffs",
|
||||
lockRankUserArenaState: "userArenaState",
|
||||
lockRankTraceBuf: "traceBuf",
|
||||
lockRankTraceStrings: "traceStrings",
|
||||
lockRankFin: "fin",
|
||||
lockRankSpanSetSpine: "spanSetSpine",
|
||||
lockRankMspanSpecial: "mspanSpecial",
|
||||
lockRankTraceTypeTab: "traceTypeTab",
|
||||
lockRankGcBitsArenas: "gcBitsArenas",
|
||||
lockRankProfInsert: "profInsert",
|
||||
lockRankProfBlock: "profBlock",
|
||||
lockRankProfMemActive: "profMemActive",
|
||||
lockRankProfMemFuture: "profMemFuture",
|
||||
lockRankGscan: "gscan",
|
||||
lockRankStackpool: "stackpool",
|
||||
lockRankStackLarge: "stackLarge",
|
||||
lockRankHchanLeaf: "hchanLeaf",
|
||||
lockRankWbufSpans: "wbufSpans",
|
||||
lockRankMheap: "mheap",
|
||||
lockRankMheapSpecial: "mheapSpecial",
|
||||
lockRankGlobalAlloc: "globalAlloc",
|
||||
lockRankTrace: "trace",
|
||||
lockRankTraceStackTab: "traceStackTab",
|
||||
lockRankPanic: "panic",
|
||||
lockRankDeadlock: "deadlock",
|
||||
lockRankRaceFini: "raceFini",
|
||||
lockRankAllocmRInternal: "allocmRInternal",
|
||||
lockRankExecRInternal: "execRInternal",
|
||||
lockRankTestRInternal: "testRInternal",
|
||||
}
|
||||
|
||||
func (rank lockRank) String() string {
|
||||
@@ -163,62 +165,63 @@ func (rank lockRank) String() string {
|
||||
//
|
||||
// Lock ranks that allow self-cycles list themselves.
|
||||
var lockPartialOrder [][]lockRank = [][]lockRank{
|
||||
lockRankSysmon: {},
|
||||
lockRankScavenge: {lockRankSysmon},
|
||||
lockRankForcegc: {lockRankSysmon},
|
||||
lockRankDefer: {},
|
||||
lockRankSweepWaiters: {},
|
||||
lockRankAssistQueue: {},
|
||||
lockRankSweep: {},
|
||||
lockRankTestR: {},
|
||||
lockRankTestW: {},
|
||||
lockRankTimerSend: {},
|
||||
lockRankAllocmW: {},
|
||||
lockRankExecW: {},
|
||||
lockRankCpuprof: {},
|
||||
lockRankPollCache: {},
|
||||
lockRankPollDesc: {},
|
||||
lockRankWakeableSleep: {},
|
||||
lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR},
|
||||
lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
|
||||
lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
|
||||
lockRankNotifyList: {},
|
||||
lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList},
|
||||
lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
|
||||
lockRankTimer: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
|
||||
lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers, lockRankTimer},
|
||||
lockRankRoot: {},
|
||||
lockRankItab: {},
|
||||
lockRankReflectOffs: {lockRankItab},
|
||||
lockRankUserArenaState: {},
|
||||
lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
|
||||
lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf},
|
||||
lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial},
|
||||
lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive},
|
||||
lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture},
|
||||
lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf},
|
||||
lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans},
|
||||
lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
|
||||
lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial},
|
||||
lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
|
||||
lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace},
|
||||
lockRankPanic: {},
|
||||
lockRankDeadlock: {lockRankPanic, lockRankDeadlock},
|
||||
lockRankRaceFini: {lockRankPanic},
|
||||
lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR},
|
||||
lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR},
|
||||
lockRankTestRInternal: {lockRankTestR, lockRankTestW},
|
||||
lockRankSysmon: {},
|
||||
lockRankScavenge: {lockRankSysmon},
|
||||
lockRankForcegc: {lockRankSysmon},
|
||||
lockRankDefer: {},
|
||||
lockRankSweepWaiters: {},
|
||||
lockRankAssistQueue: {},
|
||||
lockRankStrongFromWeakQueue: {},
|
||||
lockRankSweep: {},
|
||||
lockRankTestR: {},
|
||||
lockRankTestW: {},
|
||||
lockRankTimerSend: {},
|
||||
lockRankAllocmW: {},
|
||||
lockRankExecW: {},
|
||||
lockRankCpuprof: {},
|
||||
lockRankPollCache: {},
|
||||
lockRankPollDesc: {},
|
||||
lockRankWakeableSleep: {},
|
||||
lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan},
|
||||
lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR},
|
||||
lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
|
||||
lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched},
|
||||
lockRankNotifyList: {},
|
||||
lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList},
|
||||
lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
|
||||
lockRankTimer: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers},
|
||||
lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers, lockRankTimer},
|
||||
lockRankRoot: {},
|
||||
lockRankItab: {},
|
||||
lockRankReflectOffs: {lockRankItab},
|
||||
lockRankUserArenaState: {},
|
||||
lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
|
||||
lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf},
|
||||
lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial},
|
||||
lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings},
|
||||
lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive},
|
||||
lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture},
|
||||
lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf},
|
||||
lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan},
|
||||
lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans},
|
||||
lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
|
||||
lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial},
|
||||
lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap},
|
||||
lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace},
|
||||
lockRankPanic: {},
|
||||
lockRankDeadlock: {lockRankPanic, lockRankDeadlock},
|
||||
lockRankRaceFini: {lockRankPanic},
|
||||
lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR},
|
||||
lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR},
|
||||
lockRankTestRInternal: {lockRankTestR, lockRankTestW},
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ func gcinit() {
|
||||
work.markDoneSema = 1
|
||||
lockInit(&work.sweepWaiters.lock, lockRankSweepWaiters)
|
||||
lockInit(&work.assistQueue.lock, lockRankAssistQueue)
|
||||
lockInit(&work.strongFromWeak.lock, lockRankStrongFromWeakQueue)
|
||||
lockInit(&work.wbufSpans.lock, lockRankWbufSpans)
|
||||
}
|
||||
|
||||
@@ -418,6 +419,26 @@ type workType struct {
|
||||
list gList
|
||||
}
|
||||
|
||||
// strongFromWeak controls how the GC interacts with weak->strong
|
||||
// pointer conversions.
|
||||
strongFromWeak struct {
|
||||
// block is a flag set during mark termination that prevents
|
||||
// new weak->strong conversions from executing by blocking the
|
||||
// goroutine and enqueuing it onto q.
|
||||
//
|
||||
// Mutated only by one goroutine at a time in gcMarkDone,
|
||||
// with globally-synchronizing events like forEachP and
|
||||
// stopTheWorld.
|
||||
block bool
|
||||
|
||||
// q is a queue of goroutines that attempted to perform a
|
||||
// weak->strong conversion during mark termination.
|
||||
//
|
||||
// Protected by lock.
|
||||
lock mutex
|
||||
q gQueue
|
||||
}
|
||||
|
||||
// cycles is the number of completed GC cycles, where a GC
|
||||
// cycle is sweep termination, mark, mark termination, and
|
||||
// sweep. This differs from memstats.numgc, which is
|
||||
@@ -800,6 +821,19 @@ func gcStart(trigger gcTrigger) {
|
||||
// This is protected by markDoneSema.
|
||||
var gcMarkDoneFlushed uint32
|
||||
|
||||
// gcDebugMarkDone contains fields used to debug/test mark termination.
|
||||
var gcDebugMarkDone struct {
|
||||
// spinAfterRaggedBarrier forces gcMarkDone to spin after it executes
|
||||
// the ragged barrier.
|
||||
spinAfterRaggedBarrier atomic.Bool
|
||||
|
||||
// restartedDueTo27993 indicates that we restarted mark termination
|
||||
// due to the bug described in issue #27993.
|
||||
//
|
||||
// Protected by worldsema.
|
||||
restartedDueTo27993 bool
|
||||
}
|
||||
|
||||
// gcMarkDone transitions the GC from mark to mark termination if all
|
||||
// reachable objects have been marked (that is, there are no grey
|
||||
// objects and can be no more in the future). Otherwise, it flushes
|
||||
@@ -842,6 +876,10 @@ top:
|
||||
// stop the world later, so acquire worldsema now.
|
||||
semacquire(&worldsema)
|
||||
|
||||
// Prevent weak->strong conversions from generating additional
|
||||
// GC work. forEachP will guarantee that it is observed globally.
|
||||
work.strongFromWeak.block = true
|
||||
|
||||
// Flush all local buffers and collect flushedWork flags.
|
||||
gcMarkDoneFlushed = 0
|
||||
forEachP(waitReasonGCMarkTermination, func(pp *p) {
|
||||
@@ -872,6 +910,10 @@ top:
|
||||
goto top
|
||||
}
|
||||
|
||||
// For debugging/testing.
|
||||
for gcDebugMarkDone.spinAfterRaggedBarrier.Load() {
|
||||
}
|
||||
|
||||
// There was no global work, no local work, and no Ps
|
||||
// communicated work since we took markDoneSema. Therefore
|
||||
// there are no grey objects and no more objects can be
|
||||
@@ -910,6 +952,8 @@ top:
|
||||
}
|
||||
})
|
||||
if restart {
|
||||
gcDebugMarkDone.restartedDueTo27993 = true
|
||||
|
||||
getg().m.preemptoff = ""
|
||||
systemstack(func() {
|
||||
// Accumulate the time we were stopped before we had to start again.
|
||||
@@ -936,6 +980,11 @@ top:
|
||||
// start the world again.
|
||||
gcWakeAllAssists()
|
||||
|
||||
// Wake all blocked weak->strong conversions. These will run
|
||||
// when we start the world again.
|
||||
work.strongFromWeak.block = false
|
||||
gcWakeAllStrongFromWeak()
|
||||
|
||||
// Likewise, release the transition lock. Blocked
|
||||
// workers and assists will run when we start the
|
||||
// world again.
|
||||
|
||||
@@ -2049,8 +2049,19 @@ func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer
|
||||
func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
|
||||
handle := (*atomic.Uintptr)(u)
|
||||
|
||||
// Prevent preemption. We want to make sure that another GC cycle can't start.
|
||||
// Prevent preemption. We want to make sure that another GC cycle can't start
|
||||
// and that work.strongFromWeak.block can't change out from under us.
|
||||
mp := acquirem()
|
||||
|
||||
// Yield to the GC if necessary.
|
||||
if work.strongFromWeak.block {
|
||||
releasem(mp)
|
||||
|
||||
// Try to park and wait for mark termination.
|
||||
// N.B. gcParkStrongFromWeak calls acquirem before returning.
|
||||
mp = gcParkStrongFromWeak()
|
||||
}
|
||||
|
||||
p := handle.Load()
|
||||
if p == 0 {
|
||||
releasem(mp)
|
||||
@@ -2092,6 +2103,41 @@ func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
|
||||
return ptr
|
||||
}
|
||||
|
||||
// gcParkStrongFromWeak puts the current goroutine on the weak->strong queue and parks.
|
||||
func gcParkStrongFromWeak() *m {
|
||||
// Prevent preemption as we check strongFromWeak, so it can't change out from under us.
|
||||
mp := acquirem()
|
||||
|
||||
for work.strongFromWeak.block {
|
||||
lock(&work.strongFromWeak.lock)
|
||||
releasem(mp) // N.B. Holding the lock prevents preemption.
|
||||
|
||||
// Queue ourselves up.
|
||||
work.strongFromWeak.q.pushBack(getg())
|
||||
|
||||
// Park.
|
||||
goparkunlock(&work.strongFromWeak.lock, waitReasonGCWeakToStrongWait, traceBlockGCWeakToStrongWait, 2)
|
||||
|
||||
// Re-acquire the current M since we're going to check the condition again.
|
||||
mp = acquirem()
|
||||
|
||||
// Re-check condition. We may have awoken in the next GC's mark termination phase.
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
// gcWakeAllStrongFromWeak wakes all currently blocked weak->strong
|
||||
// conversions. This is used at the end of a GC cycle.
|
||||
//
|
||||
// work.strongFromWeak.block must be false to prevent woken goroutines
|
||||
// from immediately going back to sleep.
|
||||
func gcWakeAllStrongFromWeak() {
|
||||
lock(&work.strongFromWeak.lock)
|
||||
list := work.strongFromWeak.q.popList()
|
||||
injectglist(&list)
|
||||
unlock(&work.strongFromWeak.lock)
|
||||
}
|
||||
|
||||
// Retrieves or creates a weak pointer handle for the object p.
|
||||
func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
|
||||
// First try to retrieve without allocating.
|
||||
@@ -2126,8 +2172,14 @@ func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
|
||||
|
||||
// Keep p alive for the duration of the function to ensure
|
||||
// that it cannot die while we're trying to do this.
|
||||
//
|
||||
// Same for handle, which is only stored in the special.
|
||||
// There's a window where it might die if we don't keep it
|
||||
// alive explicitly. Returning it here is probably good enough,
|
||||
// but let's be defensive and explicit. See #70455.
|
||||
KeepAlive(p)
|
||||
return s.handle
|
||||
KeepAlive(handle)
|
||||
return handle
|
||||
}
|
||||
|
||||
// There was an existing handle. Free the special
|
||||
@@ -2147,7 +2199,10 @@ func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr {
|
||||
|
||||
// Keep p alive for the duration of the function to ensure
|
||||
// that it cannot die while we're trying to do this.
|
||||
//
|
||||
// Same for handle, just to be defensive.
|
||||
KeepAlive(p)
|
||||
KeepAlive(handle)
|
||||
return handle
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ NONE < defer;
|
||||
NONE <
|
||||
sweepWaiters,
|
||||
assistQueue,
|
||||
strongFromWeakQueue,
|
||||
sweep;
|
||||
|
||||
# Test only
|
||||
@@ -66,6 +67,7 @@ assistQueue,
|
||||
hchan,
|
||||
pollDesc, # pollDesc can interact with timers, which can lock sched.
|
||||
scavenge,
|
||||
strongFromWeakQueue,
|
||||
sweep,
|
||||
sweepWaiters,
|
||||
testR,
|
||||
|
||||
@@ -2539,6 +2539,7 @@ func dropm() {
|
||||
g0.stack.lo = 0
|
||||
g0.stackguard0 = 0
|
||||
g0.stackguard1 = 0
|
||||
mp.g0StackAccurate = false
|
||||
|
||||
putExtraM(mp)
|
||||
|
||||
@@ -3872,23 +3873,23 @@ func injectglist(glist *gList) {
|
||||
if glist.empty() {
|
||||
return
|
||||
}
|
||||
trace := traceAcquire()
|
||||
if trace.ok() {
|
||||
for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() {
|
||||
trace.GoUnpark(gp, 0)
|
||||
}
|
||||
traceRelease(trace)
|
||||
}
|
||||
|
||||
// Mark all the goroutines as runnable before we put them
|
||||
// on the run queues.
|
||||
head := glist.head.ptr()
|
||||
var tail *g
|
||||
qsize := 0
|
||||
trace := traceAcquire()
|
||||
for gp := head; gp != nil; gp = gp.schedlink.ptr() {
|
||||
tail = gp
|
||||
qsize++
|
||||
casgstatus(gp, _Gwaiting, _Grunnable)
|
||||
if trace.ok() {
|
||||
trace.GoUnpark(gp, 0)
|
||||
}
|
||||
}
|
||||
if trace.ok() {
|
||||
traceRelease(trace)
|
||||
}
|
||||
|
||||
// Turn the gList into a gQueue.
|
||||
|
||||
@@ -556,47 +556,48 @@ type m struct {
|
||||
_ uint32 // align next field to 8 bytes
|
||||
|
||||
// Fields not known to debuggers.
|
||||
procid uint64 // for debuggers, but offset not hard-coded
|
||||
gsignal *g // signal-handling g
|
||||
goSigStack gsignalStack // Go-allocated signal handling stack
|
||||
sigmask sigset // storage for saved signal mask
|
||||
tls [tlsSlots]uintptr // thread-local storage (for x86 extern register)
|
||||
mstartfn func()
|
||||
curg *g // current running goroutine
|
||||
caughtsig guintptr // goroutine running during fatal signal
|
||||
p puintptr // attached p for executing go code (nil if not executing go code)
|
||||
nextp puintptr
|
||||
oldp puintptr // the p that was attached before executing a syscall
|
||||
id int64
|
||||
mallocing int32
|
||||
throwing throwType
|
||||
preemptoff string // if != "", keep curg running on this m
|
||||
locks int32
|
||||
dying int32
|
||||
profilehz int32
|
||||
spinning bool // m is out of work and is actively looking for work
|
||||
blocked bool // m is blocked on a note
|
||||
newSigstack bool // minit on C thread called sigaltstack
|
||||
printlock int8
|
||||
incgo bool // m is executing a cgo call
|
||||
isextra bool // m is an extra m
|
||||
isExtraInC bool // m is an extra m that is not executing Go code
|
||||
isExtraInSig bool // m is an extra m in a signal handler
|
||||
freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
|
||||
needextram bool
|
||||
traceback uint8
|
||||
ncgocall uint64 // number of cgo calls in total
|
||||
ncgo int32 // number of cgo calls currently in progress
|
||||
cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily
|
||||
cgoCallers *cgoCallers // cgo traceback if crashing in cgo call
|
||||
park note
|
||||
alllink *m // on allm
|
||||
schedlink muintptr
|
||||
lockedg guintptr
|
||||
createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it.
|
||||
lockedExt uint32 // tracking for external LockOSThread
|
||||
lockedInt uint32 // tracking for internal lockOSThread
|
||||
nextwaitm muintptr // next m waiting for lock
|
||||
procid uint64 // for debuggers, but offset not hard-coded
|
||||
gsignal *g // signal-handling g
|
||||
goSigStack gsignalStack // Go-allocated signal handling stack
|
||||
sigmask sigset // storage for saved signal mask
|
||||
tls [tlsSlots]uintptr // thread-local storage (for x86 extern register)
|
||||
mstartfn func()
|
||||
curg *g // current running goroutine
|
||||
caughtsig guintptr // goroutine running during fatal signal
|
||||
p puintptr // attached p for executing go code (nil if not executing go code)
|
||||
nextp puintptr
|
||||
oldp puintptr // the p that was attached before executing a syscall
|
||||
id int64
|
||||
mallocing int32
|
||||
throwing throwType
|
||||
preemptoff string // if != "", keep curg running on this m
|
||||
locks int32
|
||||
dying int32
|
||||
profilehz int32
|
||||
spinning bool // m is out of work and is actively looking for work
|
||||
blocked bool // m is blocked on a note
|
||||
newSigstack bool // minit on C thread called sigaltstack
|
||||
printlock int8
|
||||
incgo bool // m is executing a cgo call
|
||||
isextra bool // m is an extra m
|
||||
isExtraInC bool // m is an extra m that is not executing Go code
|
||||
isExtraInSig bool // m is an extra m in a signal handler
|
||||
freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
|
||||
needextram bool
|
||||
g0StackAccurate bool // whether the g0 stack has accurate bounds
|
||||
traceback uint8
|
||||
ncgocall uint64 // number of cgo calls in total
|
||||
ncgo int32 // number of cgo calls currently in progress
|
||||
cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily
|
||||
cgoCallers *cgoCallers // cgo traceback if crashing in cgo call
|
||||
park note
|
||||
alllink *m // on allm
|
||||
schedlink muintptr
|
||||
lockedg guintptr
|
||||
createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it.
|
||||
lockedExt uint32 // tracking for external LockOSThread
|
||||
lockedInt uint32 // tracking for internal lockOSThread
|
||||
nextwaitm muintptr // next m waiting for lock
|
||||
|
||||
mLockProfile mLockProfile // fields relating to runtime.lock contention
|
||||
profStack []uintptr // used for memory/block/mutex stack traces
|
||||
@@ -1095,6 +1096,7 @@ const (
|
||||
waitReasonTraceProcStatus // "trace proc status"
|
||||
waitReasonPageTraceFlush // "page trace flush"
|
||||
waitReasonCoroutine // "coroutine"
|
||||
waitReasonGCWeakToStrongWait // "GC weak to strong wait"
|
||||
)
|
||||
|
||||
var waitReasonStrings = [...]string{
|
||||
@@ -1135,6 +1137,7 @@ var waitReasonStrings = [...]string{
|
||||
waitReasonTraceProcStatus: "trace proc status",
|
||||
waitReasonPageTraceFlush: "page trace flush",
|
||||
waitReasonCoroutine: "coroutine",
|
||||
waitReasonGCWeakToStrongWait: "GC weak to strong wait",
|
||||
}
|
||||
|
||||
func (w waitReason) String() string {
|
||||
|
||||
@@ -69,7 +69,7 @@ const (
|
||||
// to each stack below the usual guard area for OS-specific
|
||||
// purposes like signal handling. Used on Windows, Plan 9,
|
||||
// and iOS because they do not use a separate stack.
|
||||
stackSystem = goos.IsWindows*512*goarch.PtrSize + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024
|
||||
stackSystem = goos.IsWindows*4096 + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024
|
||||
|
||||
// The minimum size of stack used by Go code
|
||||
stackMin = 2048
|
||||
@@ -1330,7 +1330,7 @@ func morestackc() {
|
||||
}
|
||||
|
||||
// startingStackSize is the amount of stack that new goroutines start with.
|
||||
// It is a power of 2, and between _FixedStack and maxstacksize, inclusive.
|
||||
// It is a power of 2, and between fixedStack and maxstacksize, inclusive.
|
||||
// startingStackSize is updated every GC by tracking the average size of
|
||||
// stacks scanned during the GC.
|
||||
var startingStackSize uint32 = fixedStack
|
||||
|
||||
@@ -99,24 +99,26 @@ const (
|
||||
traceBlockDebugCall
|
||||
traceBlockUntilGCEnds
|
||||
traceBlockSleep
|
||||
traceBlockGCWeakToStrongWait
|
||||
)
|
||||
|
||||
var traceBlockReasonStrings = [...]string{
|
||||
traceBlockGeneric: "unspecified",
|
||||
traceBlockForever: "forever",
|
||||
traceBlockNet: "network",
|
||||
traceBlockSelect: "select",
|
||||
traceBlockCondWait: "sync.(*Cond).Wait",
|
||||
traceBlockSync: "sync",
|
||||
traceBlockChanSend: "chan send",
|
||||
traceBlockChanRecv: "chan receive",
|
||||
traceBlockGCMarkAssist: "GC mark assist wait for work",
|
||||
traceBlockGCSweep: "GC background sweeper wait",
|
||||
traceBlockSystemGoroutine: "system goroutine wait",
|
||||
traceBlockPreempted: "preempted",
|
||||
traceBlockDebugCall: "wait for debug call",
|
||||
traceBlockUntilGCEnds: "wait until GC ends",
|
||||
traceBlockSleep: "sleep",
|
||||
traceBlockGeneric: "unspecified",
|
||||
traceBlockForever: "forever",
|
||||
traceBlockNet: "network",
|
||||
traceBlockSelect: "select",
|
||||
traceBlockCondWait: "sync.(*Cond).Wait",
|
||||
traceBlockSync: "sync",
|
||||
traceBlockChanSend: "chan send",
|
||||
traceBlockChanRecv: "chan receive",
|
||||
traceBlockGCMarkAssist: "GC mark assist wait for work",
|
||||
traceBlockGCSweep: "GC background sweeper wait",
|
||||
traceBlockSystemGoroutine: "system goroutine wait",
|
||||
traceBlockPreempted: "preempted",
|
||||
traceBlockDebugCall: "wait for debug call",
|
||||
traceBlockUntilGCEnds: "wait until GC ends",
|
||||
traceBlockSleep: "sleep",
|
||||
traceBlockGCWeakToStrongWait: "GC weak to strong wait",
|
||||
}
|
||||
|
||||
// traceGoStopReason is an enumeration of reasons a goroutine might yield.
|
||||
|
||||
@@ -42,6 +42,7 @@ func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
|
||||
// Deprecated: Use [SyscallN] instead.
|
||||
func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
|
||||
|
||||
//go:noescape
|
||||
func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||
func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
|
||||
|
||||
@@ -253,6 +253,16 @@ type SysProcAttr struct {
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
// WindowsVersion returns whether the OS is Windows 7 (or earlier) and Windows 10 (or later)
|
||||
func WindowsVersion() (isWin7, isWin10AndAbove bool) {
|
||||
info := _OSVERSIONINFOW{}
|
||||
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||
rtlGetVersion(&info)
|
||||
isWin7 = info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1)
|
||||
isWin10AndAbove = info.majorVersion >= 10
|
||||
return
|
||||
}
|
||||
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
if len(argv0) == 0 {
|
||||
return 0, 0, EWINDOWS
|
||||
@@ -316,10 +326,8 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
|
||||
}
|
||||
}
|
||||
|
||||
info := _OSVERSIONINFOW{}
|
||||
info.osVersionInfoSize = uint32(unsafe.Sizeof(info))
|
||||
rtlGetVersion(&info)
|
||||
isWin7 := info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1)
|
||||
isWin7, _ := WindowsVersion()
|
||||
|
||||
// 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
|
||||
|
||||
@@ -213,6 +213,51 @@ func TestGetStartupInfo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyscallAllocations(t *testing.T) {
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
|
||||
// Test that syscall.SyscallN arguments do not escape.
|
||||
// The function used (in this case GetVersion) doesn't matter
|
||||
// as long as it is always available and doesn't panic.
|
||||
h, err := syscall.LoadLibrary("kernel32.dll")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer syscall.FreeLibrary(h)
|
||||
proc, err := syscall.GetProcAddress(h, "GetVersion")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testAllocs := func(t *testing.T, name string, fn func() error) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
n := int(testing.AllocsPerRun(10, func() {
|
||||
if err := fn(); err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
}))
|
||||
if n > 0 {
|
||||
t.Errorf("allocs = %d, want 0", n)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
testAllocs(t, "SyscallN", func() error {
|
||||
r0, _, e1 := syscall.SyscallN(proc, 0, 0, 0)
|
||||
if r0 == 0 {
|
||||
return syscall.Errno(e1)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
testAllocs(t, "Syscall", func() error {
|
||||
r0, _, e1 := syscall.Syscall(proc, 3, 0, 0, 0)
|
||||
if r0 == 0 {
|
||||
return syscall.Errno(e1)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzUTF16FromString(f *testing.F) {
|
||||
f.Add("hi") // ASCII
|
||||
f.Add("â") // latin1
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -1084,10 +1085,15 @@ func TestLoadFixed(t *testing.T) {
|
||||
// So GMT+1 corresponds to -3600 in the Go zone, not +3600.
|
||||
name, offset := Now().In(loc).Zone()
|
||||
// The zone abbreviation is "-01" since tzdata-2016g, and "GMT+1"
|
||||
// on earlier versions; we accept both. (Issue #17276).
|
||||
if !(name == "GMT+1" || name == "-01") || offset != -1*60*60 {
|
||||
t.Errorf("Now().In(loc).Zone() = %q, %d, want %q or %q, %d",
|
||||
name, offset, "GMT+1", "-01", -1*60*60)
|
||||
// on earlier versions; we accept both. (Issue 17276.)
|
||||
wantName := []string{"GMT+1", "-01"}
|
||||
// The zone abbreviation may be "+01" on OpenBSD. (Issue 69840.)
|
||||
if runtime.GOOS == "openbsd" {
|
||||
wantName = append(wantName, "+01")
|
||||
}
|
||||
if !slices.Contains(wantName, name) || offset != -1*60*60 {
|
||||
t.Errorf("Now().In(loc).Zone() = %q, %d, want %q (one of), %d",
|
||||
name, offset, wantName, -1*60*60)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,3 +53,28 @@ func combine4slice(p *[4][]byte, a, b, c, d []byte) {
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[3] = d
|
||||
}
|
||||
|
||||
type S struct {
|
||||
a, b string
|
||||
c *int
|
||||
}
|
||||
|
||||
var g1, g2 *int
|
||||
|
||||
func issue71228(dst *S, ptr *int) {
|
||||
// Make sure that the non-write-barrier write.
|
||||
// "sp.c = ptr" happens before the large write
|
||||
// barrier "*dst = *sp". We approximate testing
|
||||
// that by ensuring that two global variable write
|
||||
// barriers aren't combined.
|
||||
_ = *dst
|
||||
var s S
|
||||
sp := &s
|
||||
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
g1 = nil
|
||||
sp.c = ptr // outside of any write barrier
|
||||
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
g2 = nil
|
||||
//amd64:`.*runtime[.]wbMove`
|
||||
*dst = *sp
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user