diff options
author | hiddenpath <hiddenpath@yandex-team.com> | 2024-01-26 19:49:19 +0300 |
---|---|---|
committer | hiddenpath <hiddenpath@yandex-team.com> | 2024-01-26 20:08:56 +0300 |
commit | f6d7ec162ce757a854f4a619d6b0c7084ad48f3e (patch) | |
tree | d3176e091caaa7b6cdebda4944ac265de533a6da /contrib | |
parent | 27b1811df443f5a3d16e2ae0f1744f39b348109d (diff) | |
download | ydb-f6d7ec162ce757a854f4a619d6b0c7084ad48f3e.tar.gz |
Update golang to 1.21.6
Diffstat (limited to 'contrib')
40 files changed, 462 insertions, 329 deletions
diff --git a/contrib/go/_std_1.21/src/crypto/internal/boring/notboring.go b/contrib/go/_std_1.21/src/crypto/internal/boring/notboring.go index 1c5e4c742d..e478791217 100644 --- a/contrib/go/_std_1.21/src/crypto/internal/boring/notboring.go +++ b/contrib/go/_std_1.21/src/crypto/internal/boring/notboring.go @@ -50,6 +50,7 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: no func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") } func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") } +func NewGCMTLS13(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") } type PublicKeyECDSA struct{ _ int } type PrivateKeyECDSA struct{ _ int } diff --git a/contrib/go/_std_1.21/src/crypto/rand/rand.go b/contrib/go/_std_1.21/src/crypto/rand/rand.go index 62738e2cb1..d0dcc7cc71 100644 --- a/contrib/go/_std_1.21/src/crypto/rand/rand.go +++ b/contrib/go/_std_1.21/src/crypto/rand/rand.go @@ -15,7 +15,7 @@ import "io" // available, /dev/urandom otherwise. // On OpenBSD and macOS, Reader uses getentropy(2). // On other Unix-like systems, Reader reads from /dev/urandom. -// On Windows systems, Reader uses the RtlGenRandom API. +// On Windows systems, Reader uses the ProcessPrng API. // On JS/Wasm, Reader uses the Web Crypto API. // On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1. var Reader io.Reader diff --git a/contrib/go/_std_1.21/src/crypto/rand/rand_windows.go b/contrib/go/_std_1.21/src/crypto/rand/rand_windows.go index 6c0655c72b..7380f1f0f1 100644 --- a/contrib/go/_std_1.21/src/crypto/rand/rand_windows.go +++ b/contrib/go/_std_1.21/src/crypto/rand/rand_windows.go @@ -15,11 +15,8 @@ func init() { Reader = &rngReader{} } type rngReader struct{} -func (r *rngReader) Read(b []byte) (n int, err error) { - // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at - // most 1<<31-1 bytes at a time so that this works the same on 32-bit - // and 64-bit systems. - if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { +func (r *rngReader) Read(b []byte) (int, error) { + if err := windows.ProcessPrng(b); err != nil { return 0, err } return len(b), nil diff --git a/contrib/go/_std_1.21/src/crypto/tls/cipher_suites.go b/contrib/go/_std_1.21/src/crypto/tls/cipher_suites.go index 589e8b6faf..fd538da0f7 100644 --- a/contrib/go/_std_1.21/src/crypto/tls/cipher_suites.go +++ b/contrib/go/_std_1.21/src/crypto/tls/cipher_suites.go @@ -532,7 +532,13 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead { if err != nil { panic(err) } - aead, err := cipher.NewGCM(aes) + var aead cipher.AEAD + if boring.Enabled { + aead, err = boring.NewGCMTLS13(aes) + } else { + boring.Unreachable() + aead, err = cipher.NewGCM(aes) + } if err != nil { panic(err) } diff --git a/contrib/go/_std_1.21/src/crypto/tls/handshake_client.go b/contrib/go/_std_1.21/src/crypto/tls/handshake_client.go index 4649f36dea..e81764a912 100644 --- a/contrib/go/_std_1.21/src/crypto/tls/handshake_client.go +++ b/contrib/go/_std_1.21/src/crypto/tls/handshake_client.go @@ -139,7 +139,9 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { if len(hello.supportedVersions) == 1 { hello.cipherSuites = nil } - if hasAESGCMHardwareSupport { + if needFIPS() { + hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...) + } else if hasAESGCMHardwareSupport { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) } else { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) diff --git a/contrib/go/_std_1.21/src/crypto/tls/handshake_client_tls13.go b/contrib/go/_std_1.21/src/crypto/tls/handshake_client_tls13.go index 2f59f6888c..a84cede1b0 100644 --- a/contrib/go/_std_1.21/src/crypto/tls/handshake_client_tls13.go +++ b/contrib/go/_std_1.21/src/crypto/tls/handshake_client_tls13.go @@ -41,10 +41,6 @@ type clientHandshakeStateTLS13 struct { func (hs *clientHandshakeStateTLS13) handshake() error { c := hs.c - if needFIPS() { - return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") - } - // The server must not select TLS 1.3 in a renegotiation. See RFC 8446, // sections 4.1.2 and 4.1.3. if c.handshakes > 0 { diff --git a/contrib/go/_std_1.21/src/crypto/tls/handshake_server_tls13.go b/contrib/go/_std_1.21/src/crypto/tls/handshake_server_tls13.go index 07b1a3851e..dd5298b728 100644 --- a/contrib/go/_std_1.21/src/crypto/tls/handshake_server_tls13.go +++ b/contrib/go/_std_1.21/src/crypto/tls/handshake_server_tls13.go @@ -45,10 +45,6 @@ type serverHandshakeStateTLS13 struct { func (hs *serverHandshakeStateTLS13) handshake() error { c := hs.c - if needFIPS() { - return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") - } - // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. if err := hs.processClientHello(); err != nil { return err @@ -163,6 +159,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { preferenceList = defaultCipherSuitesTLS13NoAES } + if needFIPS() { + preferenceList = defaultCipherSuitesTLS13FIPS + } for _, suiteID := range preferenceList { hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) if hs.suite != nil { diff --git a/contrib/go/_std_1.21/src/crypto/tls/notboring.go b/contrib/go/_std_1.21/src/crypto/tls/notboring.go index 7d85b39c59..edccb44d87 100644 --- a/contrib/go/_std_1.21/src/crypto/tls/notboring.go +++ b/contrib/go/_std_1.21/src/crypto/tls/notboring.go @@ -18,3 +18,5 @@ func fipsCurvePreferences(c *Config) []CurveID { panic("fipsCurvePreferences") } func fipsCipherSuites(c *Config) []uint16 { panic("fipsCipherSuites") } var fipsSupportedSignatureAlgorithms []SignatureScheme + +var defaultCipherSuitesTLS13FIPS []uint16 diff --git a/contrib/go/_std_1.21/src/go/types/call.go b/contrib/go/_std_1.21/src/go/types/call.go index 8a3cec7309..f00290a74f 100644 --- a/contrib/go/_std_1.21/src/go/types/call.go +++ b/contrib/go/_std_1.21/src/go/types/call.go @@ -571,6 +571,14 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type for i, arg := range args { // generic arguments cannot have a defined (*Named) type - no need for underlying type below if asig, _ := arg.typ.(*Signature); asig != nil && asig.TypeParams().Len() > 0 { + // The argument type is a generic function signature. This type is + // pointer-identical with (it's copied from) the type of the generic + // function argument and thus the function object. + // Before we change the type (type parameter renaming, below), make + // a clone of it as otherwise we implicitly modify the object's type + // (go.dev/issues/63260). + clone := *asig + asig = &clone // Rename type parameters for cases like f(g, g); this gives each // generic function argument a unique type identity (go.dev/issues/59956). // TODO(gri) Consider only doing this if a function argument appears diff --git a/contrib/go/_std_1.21/src/internal/buildcfg/zbootstrap.go b/contrib/go/_std_1.21/src/internal/buildcfg/zbootstrap.go index f5b4f3486b..b83b3ead43 100644 --- a/contrib/go/_std_1.21/src/internal/buildcfg/zbootstrap.go +++ b/contrib/go/_std_1.21/src/internal/buildcfg/zbootstrap.go @@ -13,6 +13,6 @@ const defaultGOPPC64 = `power8` const defaultGOEXPERIMENT = `` const defaultGO_EXTLINK_ENABLED = `` const defaultGO_LDSO = `` -const version = `go1.21.3` +const version = `go1.21.6` const defaultGOOS = runtime.GOOS const defaultGOARCH = runtime.GOARCH diff --git a/contrib/go/_std_1.21/src/internal/poll/splice_linux.go b/contrib/go/_std_1.21/src/internal/poll/splice_linux.go index 9505c5dcfc..72cca34fe4 100644 --- a/contrib/go/_std_1.21/src/internal/poll/splice_linux.go +++ b/contrib/go/_std_1.21/src/internal/poll/splice_linux.go @@ -13,6 +13,12 @@ import ( ) const ( + // spliceNonblock doesn't make the splice itself necessarily nonblocking + // (because the actual file descriptors that are spliced from/to may block + // unless they have the O_NONBLOCK flag set), but it makes the splice pipe + // operations nonblocking. + spliceNonblock = 0x2 + // maxSpliceSize is the maximum amount of data Splice asks // the kernel to move in a single call to splice(2). // We use 1MB as Splice writes data through a pipe, and 1MB is the default maximum pipe buffer size, @@ -89,7 +95,11 @@ func spliceDrain(pipefd int, sock *FD, max int) (int, error) { return 0, err } for { - n, err := splice(pipefd, sock.Sysfd, max, 0) + // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, + // because it could return EAGAIN ceaselessly when the write end of the pipe is full, + // but this shouldn't be a concern here, since the pipe buffer must be sufficient for + // this data transmission on the basis of the workflow in Splice. + n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock) if err == syscall.EINTR { continue } @@ -127,7 +137,14 @@ func splicePump(sock *FD, pipefd int, inPipe int) (int, error) { } written := 0 for inPipe > 0 { - n, err := splice(sock.Sysfd, pipefd, inPipe, 0) + // In theory calling splice(2) with SPLICE_F_NONBLOCK could end up an infinite loop here, + // because it could return EAGAIN ceaselessly when the read end of the pipe is empty, + // but this shouldn't be a concern here, since the pipe buffer must contain inPipe size of + // data on the basis of the workflow in Splice. + n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock) + if err == syscall.EINTR { + continue + } // Here, the condition n == 0 && err == nil should never be // observed, since Splice controls the write side of the pipe. if n > 0 { diff --git a/contrib/go/_std_1.21/src/internal/safefilepath/path_windows.go b/contrib/go/_std_1.21/src/internal/safefilepath/path_windows.go index 909c150edc..7cfd6ce2ea 100644 --- a/contrib/go/_std_1.21/src/internal/safefilepath/path_windows.go +++ b/contrib/go/_std_1.21/src/internal/safefilepath/path_windows.go @@ -20,15 +20,10 @@ func fromFS(path string) (string, error) { for p := path; p != ""; { // Find the next path element. i := 0 - dot := -1 for i < len(p) && p[i] != '/' { switch p[i] { case 0, '\\', ':': return "", errInvalidPath - case '.': - if dot < 0 { - dot = i - } } i++ } @@ -39,22 +34,8 @@ func fromFS(path string) (string, error) { } else { p = "" } - // Trim the extension and look for a reserved name. - base := part - if dot >= 0 { - base = part[:dot] - } - if isReservedName(base) { - if dot < 0 { - return "", errInvalidPath - } - // The path element is a reserved name with an extension. - // Some Windows versions consider this a reserved name, - // while others do not. Use FullPath to see if the name is - // reserved. - if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { - return "", errInvalidPath - } + if IsReservedName(part) { + return "", errInvalidPath } } if containsSlash { @@ -70,23 +51,88 @@ func fromFS(path string) (string, error) { return path, nil } -// isReservedName reports if name is a Windows reserved device name. +// IsReservedName reports if name is a Windows reserved device name. // It does not detect names with an extension, which are also reserved on some Windows versions. // // For details, search for PRN in // https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. -func isReservedName(name string) bool { - if 3 <= len(name) && len(name) <= 4 { +func IsReservedName(name string) bool { + // Device names can have arbitrary trailing characters following a dot or colon. + base := name + for i := 0; i < len(base); i++ { + switch base[i] { + case ':', '.': + base = base[:i] + } + } + // Trailing spaces in the last path element are ignored. + for len(base) > 0 && base[len(base)-1] == ' ' { + base = base[:len(base)-1] + } + if !isReservedBaseName(base) { + return false + } + if len(base) == len(name) { + return true + } + // The path element is a reserved name with an extension. + // Some Windows versions consider this a reserved name, + // while others do not. Use FullPath to see if the name is + // reserved. + if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { + return true + } + return false +} + +func isReservedBaseName(name string) bool { + if len(name) == 3 { switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { case "CON", "PRN", "AUX", "NUL": - return len(name) == 3 + return true + } + } + if len(name) >= 4 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { case "COM", "LPT": - return len(name) == 4 && '1' <= name[3] && name[3] <= '9' + if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { + return true + } + // Superscript ¹, ², and ³ are considered numbers as well. + switch name[3:] { + case "\u00b2", "\u00b3", "\u00b9": + return true + } + return false } } + + // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles + // + // While CONIN$ and CONOUT$ aren't documented as being files, + // they behave the same as CON. For example, ./CONIN$ also opens the console input. + if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { + return true + } + if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { + return true + } return false } +func equalFold(a, b string) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if toUpper(a[i]) != toUpper(b[i]) { + return false + } + } + return true +} + func toUpper(c byte) byte { if 'a' <= c && c <= 'z' { return c - ('a' - 'A') diff --git a/contrib/go/_std_1.21/src/internal/syscall/windows/reparse_windows.go b/contrib/go/_std_1.21/src/internal/syscall/windows/reparse_windows.go index 6e111392f0..6caf47e867 100644 --- a/contrib/go/_std_1.21/src/internal/syscall/windows/reparse_windows.go +++ b/contrib/go/_std_1.21/src/internal/syscall/windows/reparse_windows.go @@ -12,6 +12,7 @@ import ( const ( FSCTL_SET_REPARSE_POINT = 0x000900A4 IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 + IO_REPARSE_TAG_DEDUP = 0x80000013 SYMLINK_FLAG_RELATIVE = 1 ) diff --git a/contrib/go/_std_1.21/src/internal/syscall/windows/syscall_windows.go b/contrib/go/_std_1.21/src/internal/syscall/windows/syscall_windows.go index 892b878d16..e9390b07cd 100644 --- a/contrib/go/_std_1.21/src/internal/syscall/windows/syscall_windows.go +++ b/contrib/go/_std_1.21/src/internal/syscall/windows/syscall_windows.go @@ -373,7 +373,7 @@ func ErrorLoadingGetTempPath2() error { //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW -//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 +//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng //sys RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table *byte) (ret uintptr) = kernel32.RtlLookupFunctionEntry //sys RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry uintptr, ctxt uintptr, data *uintptr, frame *uintptr, ctxptrs *byte) (ret uintptr) = kernel32.RtlVirtualUnwind diff --git a/contrib/go/_std_1.21/src/internal/syscall/windows/zsyscall_windows.go b/contrib/go/_std_1.21/src/internal/syscall/windows/zsyscall_windows.go index a5c246b773..26ec290e02 100644 --- a/contrib/go/_std_1.21/src/internal/syscall/windows/zsyscall_windows.go +++ b/contrib/go/_std_1.21/src/internal/syscall/windows/zsyscall_windows.go @@ -37,13 +37,14 @@ func errnoErr(e syscall.Errno) error { } var ( - modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) - modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) - modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) - modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) - modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) - moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) - modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) + modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) + modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) + modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) + modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) + modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) + moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) + modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") @@ -52,7 +53,7 @@ var ( procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") procRevertToSelf = modadvapi32.NewProc("RevertToSelf") procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") - procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") + procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") procCreateEventW = modkernel32.NewProc("CreateEventW") procGetACP = modkernel32.NewProc("GetACP") @@ -148,12 +149,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32 return } -func RtlGenRandom(buf []byte) (err error) { +func ProcessPrng(buf []byte) (err error) { var _p0 *byte if len(buf) > 0 { _p0 = &buf[0] } - r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) + r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) if r1 == 0 { err = errnoErr(e1) } diff --git a/contrib/go/_std_1.21/src/net/http/h2_bundle.go b/contrib/go/_std_1.21/src/net/http/h2_bundle.go index 9cd6a3490f..dd59e1f4f2 100644 --- a/contrib/go/_std_1.21/src/net/http/h2_bundle.go +++ b/contrib/go/_std_1.21/src/net/http/h2_bundle.go @@ -7012,6 +7012,7 @@ func (sc *http2serverConn) startPush(msg *http2startPushRequest) { panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err)) } + sc.curHandlers++ go sc.runHandler(rw, req, sc.handler.ServeHTTP) return promisedID, nil } diff --git a/contrib/go/_std_1.21/src/net/http/internal/chunked.go b/contrib/go/_std_1.21/src/net/http/internal/chunked.go index 5a174415dc..aad8e5aa09 100644 --- a/contrib/go/_std_1.21/src/net/http/internal/chunked.go +++ b/contrib/go/_std_1.21/src/net/http/internal/chunked.go @@ -39,7 +39,8 @@ type chunkedReader struct { n uint64 // unread bytes in chunk err error buf [2]byte - checkEnd bool // whether need to check for \r\n chunk footer + checkEnd bool // whether need to check for \r\n chunk footer + excess int64 // "excessive" chunk overhead, for malicious sender detection } func (cr *chunkedReader) beginChunk() { @@ -49,10 +50,36 @@ func (cr *chunkedReader) beginChunk() { if cr.err != nil { return } + cr.excess += int64(len(line)) + 2 // header, plus \r\n after the chunk data + line = trimTrailingWhitespace(line) + line, cr.err = removeChunkExtension(line) + if cr.err != nil { + return + } cr.n, cr.err = parseHexUint(line) if cr.err != nil { return } + // A sender who sends one byte per chunk will send 5 bytes of overhead + // for every byte of data. ("1\r\nX\r\n" to send "X".) + // We want to allow this, since streaming a byte at a time can be legitimate. + // + // A sender can use chunk extensions to add arbitrary amounts of additional + // data per byte read. ("1;very long extension\r\nX\r\n" to send "X".) + // We don't want to disallow extensions (although we discard them), + // but we also don't want to allow a sender to reduce the signal/noise ratio + // arbitrarily. + // + // We track the amount of excess overhead read, + // and produce an error if it grows too large. + // + // Currently, we say that we're willing to accept 16 bytes of overhead per chunk, + // plus twice the amount of real data in the chunk. + cr.excess -= 16 + (2 * int64(cr.n)) + cr.excess = max(cr.excess, 0) + if cr.excess > 16*1024 { + cr.err = errors.New("chunked encoding contains too much non-data") + } if cr.n == 0 { cr.err = io.EOF } @@ -140,11 +167,6 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { if len(p) >= maxLineLength { return nil, ErrLineTooLong } - p = trimTrailingWhitespace(p) - p, err = removeChunkExtension(p) - if err != nil { - return nil, err - } return p, nil } diff --git a/contrib/go/_std_1.21/src/os/rlimit.go b/contrib/go/_std_1.21/src/os/rlimit.go deleted file mode 100644 index e0d0ef9b62..0000000000 --- a/contrib/go/_std_1.21/src/os/rlimit.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix - -package os - -import "syscall" - -// Some systems set an artificially low soft limit on open file count, for compatibility -// with code that uses select and its hard-coded maximum file descriptor -// (limited by the size of fd_set). -// -// Go does not use select, so it should not be subject to these limits. -// On some systems the limit is 256, which is very easy to run into, -// even in simple programs like gofmt when they parallelize walking -// a file tree. -// -// After a long discussion on go.dev/issue/46279, we decided the -// best approach was for Go to raise the limit unconditionally for itself, -// and then leave old software to set the limit back as needed. -// Code that really wants Go to leave the limit alone can set the hard limit, -// which Go of course has no choice but to respect. -func init() { - var lim syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err == nil && lim.Cur != lim.Max { - lim.Cur = lim.Max - adjustFileLimit(&lim) - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim) - } -} diff --git a/contrib/go/_std_1.21/src/os/rlimit_darwin.go b/contrib/go/_std_1.21/src/os/rlimit_darwin.go deleted file mode 100644 index b28982a83a..0000000000 --- a/contrib/go/_std_1.21/src/os/rlimit_darwin.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin - -package os - -import "syscall" - -// adjustFileLimit adds per-OS limitations on the Rlimit used for RLIMIT_NOFILE. See rlimit.go. -func adjustFileLimit(lim *syscall.Rlimit) { - // On older macOS, setrlimit(RLIMIT_NOFILE, lim) with lim.Cur = infinity fails. - // Set to the value of kern.maxfilesperproc instead. - n, err := syscall.SysctlUint32("kern.maxfilesperproc") - if err != nil { - return - } - if lim.Cur > uint64(n) { - lim.Cur = uint64(n) - } -} diff --git a/contrib/go/_std_1.21/src/os/rlimit_stub.go b/contrib/go/_std_1.21/src/os/rlimit_stub.go deleted file mode 100644 index cbe28400c5..0000000000 --- a/contrib/go/_std_1.21/src/os/rlimit_stub.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || dragonfly || freebsd || linux || netbsd || openbsd || solaris - -package os - -import "syscall" - -// adjustFileLimit adds per-OS limitations on the Rlimit used for RLIMIT_NOFILE. See rlimit.go. -func adjustFileLimit(lim *syscall.Rlimit) {} diff --git a/contrib/go/_std_1.21/src/os/types_windows.go b/contrib/go/_std_1.21/src/os/types_windows.go index 9a3d508783..effb0148df 100644 --- a/contrib/go/_std_1.21/src/os/types_windows.go +++ b/contrib/go/_std_1.21/src/os/types_windows.go @@ -141,7 +141,23 @@ func (fs *fileStat) Mode() (m FileMode) { m |= ModeDevice | ModeCharDevice } if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && m&ModeType == 0 { - m |= ModeIrregular + if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { + // If the Data Deduplication service is enabled on Windows Server, its + // Optimization job may convert regular files to IO_REPARSE_TAG_DEDUP + // whenever that job runs. + // + // However, DEDUP reparse points remain similar in most respects to + // regular files: they continue to support random-access reads and writes + // of persistent data, and they shouldn't add unexpected latency or + // unavailability in the way that a network filesystem might. + // + // Go programs may use ModeIrregular to filter out unusual files (such as + // raw device files on Linux, POSIX FIFO special files, and so on), so + // to avoid files changing unpredictably from regular to irregular we will + // consider DEDUP files to be close enough to regular to treat as such. + } else { + m |= ModeIrregular + } } return m } diff --git a/contrib/go/_std_1.21/src/os/ya.make b/contrib/go/_std_1.21/src/os/ya.make index dc812bdd07..8c4c417f82 100644 --- a/contrib/go/_std_1.21/src/os/ya.make +++ b/contrib/go/_std_1.21/src/os/ya.make @@ -29,8 +29,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64) rawconn.go readfrom_linux.go removeall_at.go - rlimit.go - rlimit_stub.go stat.go stat_linux.go stat_unix.go @@ -71,8 +69,6 @@ ELSEIF (OS_LINUX AND ARCH_ARM64) rawconn.go readfrom_linux.go removeall_at.go - rlimit.go - rlimit_stub.go stat.go stat_linux.go stat_unix.go @@ -113,8 +109,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64) rawconn.go readfrom_linux.go removeall_at.go - rlimit.go - rlimit_stub.go stat.go stat_linux.go stat_unix.go @@ -154,8 +148,6 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64) rawconn.go readfrom_stub.go removeall_at.go - rlimit.go - rlimit_darwin.go stat.go stat_darwin.go stat_unix.go @@ -195,8 +187,6 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64) rawconn.go readfrom_stub.go removeall_at.go - rlimit.go - rlimit_darwin.go stat.go stat_darwin.go stat_unix.go @@ -236,8 +226,6 @@ ELSEIF (OS_DARWIN AND ARCH_AARCH64) rawconn.go readfrom_stub.go removeall_at.go - rlimit.go - rlimit_darwin.go stat.go stat_darwin.go stat_unix.go diff --git a/contrib/go/_std_1.21/src/path/filepath/path.go b/contrib/go/_std_1.21/src/path/filepath/path.go index ca1d8b3116..3bf3ff6b89 100644 --- a/contrib/go/_std_1.21/src/path/filepath/path.go +++ b/contrib/go/_std_1.21/src/path/filepath/path.go @@ -15,7 +15,6 @@ import ( "errors" "io/fs" "os" - "runtime" "sort" "strings" ) @@ -167,21 +166,7 @@ func Clean(path string) string { out.append('.') } - if runtime.GOOS == "windows" && out.volLen == 0 && out.buf != nil { - // If a ':' appears in the path element at the start of a Windows path, - // insert a .\ at the beginning to avoid converting relative paths - // like a/../c: into c:. - for _, c := range out.buf { - if os.IsPathSeparator(c) { - break - } - if c == ':' { - out.prepend('.', Separator) - break - } - } - } - + postClean(&out) // avoid creating absolute paths on Windows return FromSlash(out.string()) } diff --git a/contrib/go/_std_1.21/src/path/filepath/path_nonwindows.go b/contrib/go/_std_1.21/src/path/filepath/path_nonwindows.go new file mode 100644 index 0000000000..db69f0228b --- /dev/null +++ b/contrib/go/_std_1.21/src/path/filepath/path_nonwindows.go @@ -0,0 +1,9 @@ +// Copyright 2023 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 !windows + +package filepath + +func postClean(out *lazybuf) {} diff --git a/contrib/go/_std_1.21/src/path/filepath/path_windows.go b/contrib/go/_std_1.21/src/path/filepath/path_windows.go index 4dca9e0f55..eacab0e5ce 100644 --- a/contrib/go/_std_1.21/src/path/filepath/path_windows.go +++ b/contrib/go/_std_1.21/src/path/filepath/path_windows.go @@ -5,6 +5,8 @@ package filepath import ( + "internal/safefilepath" + "os" "strings" "syscall" ) @@ -20,34 +22,6 @@ func toUpper(c byte) byte { return c } -// isReservedName reports if name is a Windows reserved device name or a console handle. -// It does not detect names with an extension, which are also reserved on some Windows versions. -// -// For details, search for PRN in -// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. -func isReservedName(name string) bool { - if 3 <= len(name) && len(name) <= 4 { - switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { - case "CON", "PRN", "AUX", "NUL": - return len(name) == 3 - case "COM", "LPT": - return len(name) == 4 && '1' <= name[3] && name[3] <= '9' - } - } - // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles - // - // While CONIN$ and CONOUT$ aren't documented as being files, - // they behave the same as CON. For example, ./CONIN$ also opens the console input. - if len(name) == 6 && name[5] == '$' && strings.EqualFold(name, "CONIN$") { - return true - } - if len(name) == 7 && name[6] == '$' && strings.EqualFold(name, "CONOUT$") { - return true - } - return false -} - func isLocal(path string) bool { if path == "" { return false @@ -68,25 +42,8 @@ func isLocal(path string) bool { if part == "." || part == ".." { hasDots = true } - // Trim the extension and look for a reserved name. - base, _, hasExt := strings.Cut(part, ".") - if isReservedName(base) { - if !hasExt { - return false - } - // The path element is a reserved name with an extension. Some Windows - // versions consider this a reserved name, while others do not. Use - // FullPath to see if the name is reserved. - // - // FullPath will convert references to reserved device names to their - // canonical form: \\.\${DEVICE_NAME} - // - // FullPath does not perform this conversion for paths which contain - // a reserved device name anywhere other than in the last element, - // so check the part rather than the full path. - if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { - return false - } + if safefilepath.IsReservedName(part) { + return false } } if hasDots { @@ -118,40 +75,93 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. // -// See: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats +// See: +// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats +// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html func volumeNameLen(path string) int { - if len(path) < 2 { - return 0 - } - // with drive letter - c := path[0] - if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { + switch { + case len(path) >= 2 && path[1] == ':': + // Path starts with a drive letter. + // + // Not all Windows functions necessarily enforce the requirement that + // drive letters be in the set A-Z, and we don't try to here. + // + // We don't handle the case of a path starting with a non-ASCII character, + // in which case the "drive letter" might be multiple bytes long. return 2 - } - // UNC and DOS device paths start with two slashes. - if !isSlash(path[0]) || !isSlash(path[1]) { + + case len(path) == 0 || !isSlash(path[0]): + // Path does not have a volume component. return 0 + + case pathHasPrefixFold(path, `\\.\UNC`): + // We're going to treat the UNC host and share as part of the volume + // prefix for historical reasons, but this isn't really principled; + // Windows's own GetFullPathName will happily remove the first + // component of the path in this space, converting + // \\.\unc\a\b\..\c into \\.\unc\a\c. + return uncLen(path, len(`\\.\UNC\`)) + + case pathHasPrefixFold(path, `\\.`) || + pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`): + // Path starts with \\.\, and is a Local Device path; or + // path starts with \\?\ or \??\ and is a Root Local Device path. + // + // We treat the next component after the \\.\ prefix as + // part of the volume name, which means Clean(`\\?\c:\`) + // won't remove the trailing \. (See #64028.) + if len(path) == 3 { + return 3 // exactly \\. + } + _, rest, ok := cutPath(path[4:]) + if !ok { + return len(path) + } + return len(path) - len(rest) - 1 + + case len(path) >= 2 && isSlash(path[1]): + // Path starts with \\, and is a UNC path. + return uncLen(path, 2) } - rest := path[2:] - p1, rest, _ := cutPath(rest) - p2, rest, ok := cutPath(rest) - if !ok { - return len(path) + return 0 +} + +// pathHasPrefixFold tests whether the path s begins with prefix, +// ignoring case and treating all path separators as equivalent. +// If s is longer than prefix, then s[len(prefix)] must be a path separator. +func pathHasPrefixFold(s, prefix string) bool { + if len(s) < len(prefix) { + return false } - if p1 != "." && p1 != "?" { - // This is a UNC path: \\${HOST}\${SHARE}\ - return len(path) - len(rest) - 1 + for i := 0; i < len(prefix); i++ { + if isSlash(prefix[i]) { + if !isSlash(s[i]) { + return false + } + } else if toUpper(prefix[i]) != toUpper(s[i]) { + return false + } } - // This is a DOS device path. - if len(p2) == 3 && toUpper(p2[0]) == 'U' && toUpper(p2[1]) == 'N' && toUpper(p2[2]) == 'C' { - // This is a DOS device path that links to a UNC: \\.\UNC\${HOST}\${SHARE}\ - _, rest, _ = cutPath(rest) // host - _, rest, ok = cutPath(rest) // share - if !ok { - return len(path) + if len(s) > len(prefix) && !isSlash(s[len(prefix)]) { + return false + } + return true +} + +// uncLen returns the length of the volume prefix of a UNC path. +// prefixLen is the prefix prior to the start of the UNC host; +// for example, for "//host/share", the prefixLen is len("//")==2. +func uncLen(path string, prefixLen int) int { + count := 0 + for i := prefixLen; i < len(path); i++ { + if isSlash(path[i]) { + count++ + if count == 2 { + return i + } } } - return len(path) - len(rest) - 1 + return len(path) } // cutPath slices path around the first path separator. @@ -238,6 +248,12 @@ func join(elem []string) string { for len(e) > 0 && isSlash(e[0]) { e = e[1:] } + // If the path is \ and the next path element is ??, + // add an extra .\ to create \.\?? rather than \??\ + // (a Root Local Device path). + if b.Len() == 1 && pathHasPrefixFold(e, "??") { + b.WriteString(`.\`) + } case lastChar == ':': // If the path ends in a colon, keep the path relative to the current directory // on a drive and don't add a separator. Preserve leading slashes in the next @@ -304,3 +320,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) } + +// postClean adjusts the results of Clean to avoid turning a relative path +// into an absolute or rooted one. +func postClean(out *lazybuf) { + if out.volLen != 0 || out.buf == nil { + return + } + // If a ':' appears in the path element at the start of a path, + // insert a .\ at the beginning to avoid converting relative paths + // like a/../c: into c:. + for _, c := range out.buf { + if os.IsPathSeparator(c) { + break + } + if c == ':' { + out.prepend('.', Separator) + return + } + } + // If a path begins with \??\, insert a \. at the beginning + // to avoid converting paths like \a\..\??\c:\x into \??\c:\x + // (equivalent to c:\x). + if len(out.buf) >= 3 && os.IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { + out.prepend(Separator, '.') + } +} diff --git a/contrib/go/_std_1.21/src/path/filepath/ya.make b/contrib/go/_std_1.21/src/path/filepath/ya.make index 4b6a0333a7..9d04957bac 100644 --- a/contrib/go/_std_1.21/src/path/filepath/ya.make +++ b/contrib/go/_std_1.21/src/path/filepath/ya.make @@ -6,6 +6,7 @@ ELSEIF (OS_LINUX AND ARCH_X86_64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go @@ -14,6 +15,7 @@ ELSEIF (OS_LINUX AND ARCH_ARM64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go @@ -22,6 +24,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go @@ -30,6 +33,7 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go @@ -38,6 +42,7 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go @@ -46,6 +51,7 @@ ELSEIF (OS_DARWIN AND ARCH_AARCH64) SRCS( match.go path.go + path_nonwindows.go path_unix.go symlink.go symlink_unix.go diff --git a/contrib/go/_std_1.21/src/runtime/cgo/asm_amd64.s b/contrib/go/_std_1.21/src/runtime/cgo/asm_amd64.s index f254622f23..e319094a45 100644 --- a/contrib/go/_std_1.21/src/runtime/cgo/asm_amd64.s +++ b/contrib/go/_std_1.21/src/runtime/cgo/asm_amd64.s @@ -7,12 +7,17 @@ // Set the x_crosscall2_ptr C function pointer variable point to crosscall2. // It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2 +// Use a local trampoline, to avoid taking the address of a dynamically exported +// function. TEXT ·set_crosscall2(SB),NOSPLIT,$0-0 MOVQ _crosscall2_ptr(SB), AX - MOVQ $crosscall2(SB), BX + MOVQ $crosscall2_trampoline<>(SB), BX MOVQ BX, (AX) RET +TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0 + JMP crosscall2(SB) + // Called by C code generated by cmd/cgo. // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr) // Saves C callee-saved registers and calls cgocallback with three arguments. diff --git a/contrib/go/_std_1.21/src/runtime/cgo/asm_arm64.s b/contrib/go/_std_1.21/src/runtime/cgo/asm_arm64.s index ce8909b492..5492dc142c 100644 --- a/contrib/go/_std_1.21/src/runtime/cgo/asm_arm64.s +++ b/contrib/go/_std_1.21/src/runtime/cgo/asm_arm64.s @@ -7,12 +7,17 @@ // Set the x_crosscall2_ptr C function pointer variable point to crosscall2. // It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2 +// Use a local trampoline, to avoid taking the address of a dynamically exported +// function. TEXT ·set_crosscall2(SB),NOSPLIT,$0-0 MOVD _crosscall2_ptr(SB), R1 - MOVD $crosscall2(SB), R2 + MOVD $crosscall2_trampoline<>(SB), R2 MOVD R2, (R1) RET +TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0 + JMP crosscall2(SB) + // Called by C code generated by cmd/cgo. // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr) // Saves C callee-saved registers and calls cgocallback with three arguments. diff --git a/contrib/go/_std_1.21/src/runtime/extern.go b/contrib/go/_std_1.21/src/runtime/extern.go index 26dcf0bd52..de4a0ca2da 100644 --- a/contrib/go/_std_1.21/src/runtime/extern.go +++ b/contrib/go/_std_1.21/src/runtime/extern.go @@ -55,6 +55,13 @@ It is a comma-separated list of name=val pairs setting these named variables: cgocheck mode can be enabled using GOEXPERIMENT (which requires a rebuild), see https://pkg.go.dev/internal/goexperiment for details. + disablethp: setting disablethp=1 on Linux disables transparent huge pages for the heap. + It has no effect on other platforms. disablethp is meant for compatibility with versions + of Go before 1.21, which stopped working around a Linux kernel default that can result + in significant memory overuse. See https://go.dev/issue/64332. This setting will be + removed in a future release, so operators should tweak their Linux configuration to suit + their needs before then. See https://go.dev/doc/gc-guide#Linux_transparent_huge_pages. + dontfreezetheworld: by default, the start of a fatal panic or throw "freezes the world", preempting all threads to stop all running goroutines, which makes it possible to traceback all goroutines, and diff --git a/contrib/go/_std_1.21/src/runtime/malloc.go b/contrib/go/_std_1.21/src/runtime/malloc.go index 44479cc2be..b2026ad0dc 100644 --- a/contrib/go/_std_1.21/src/runtime/malloc.go +++ b/contrib/go/_std_1.21/src/runtime/malloc.go @@ -853,6 +853,10 @@ retry: // // The heap lock must not be held over this operation, since it will briefly acquire // the heap lock. +// +// Must be called on the system stack because it acquires the heap lock. +// +//go:systemstack func (h *mheap) enableMetadataHugePages() { // Enable huge pages for page structure. h.pages.enableChunkHugePages() diff --git a/contrib/go/_std_1.21/src/runtime/map.go b/contrib/go/_std_1.21/src/runtime/map.go index 6b85681447..22aeb86847 100644 --- a/contrib/go/_std_1.21/src/runtime/map.go +++ b/contrib/go/_std_1.21/src/runtime/map.go @@ -1481,12 +1481,24 @@ func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) dst.tophash[pos] = src.tophash[i] if t.IndirectKey() { - *(*unsafe.Pointer)(dstK) = *(*unsafe.Pointer)(srcK) + srcK = *(*unsafe.Pointer)(srcK) + if t.NeedKeyUpdate() { + kStore := newobject(t.Key) + typedmemmove(t.Key, kStore, srcK) + srcK = kStore + } + // Note: if NeedKeyUpdate is false, then the memory + // used to store the key is immutable, so we can share + // it between the original map and its clone. + *(*unsafe.Pointer)(dstK) = srcK } else { typedmemmove(t.Key, dstK, srcK) } if t.IndirectElem() { - *(*unsafe.Pointer)(dstEle) = *(*unsafe.Pointer)(srcEle) + srcEle = *(*unsafe.Pointer)(srcEle) + eStore := newobject(t.Elem) + typedmemmove(t.Elem, eStore, srcEle) + *(*unsafe.Pointer)(dstEle) = eStore } else { typedmemmove(t.Elem, dstEle, srcEle) } @@ -1510,14 +1522,14 @@ func mapclone2(t *maptype, src *hmap) *hmap { fatal("concurrent map clone and map write") } - if src.B == 0 { + if src.B == 0 && !(t.IndirectKey() && t.NeedKeyUpdate()) && !t.IndirectElem() { + // Quick copy for small maps. dst.buckets = newobject(t.Bucket) dst.count = src.count typedmemmove(t.Bucket, dst.buckets, src.buckets) return dst } - //src.B != 0 if dst.B == 0 { dst.buckets = newobject(t.Bucket) } @@ -1565,6 +1577,8 @@ func mapclone2(t *maptype, src *hmap) *hmap { continue } + // oldB < dst.B, so a single source bucket may go to multiple destination buckets. + // Process entries one at a time. for srcBmap != nil { // move from oldBlucket to new bucket for i := uintptr(0); i < bucketCnt; i++ { diff --git a/contrib/go/_std_1.21/src/runtime/mem_linux.go b/contrib/go/_std_1.21/src/runtime/mem_linux.go index c9823d3011..d63c38c209 100644 --- a/contrib/go/_std_1.21/src/runtime/mem_linux.go +++ b/contrib/go/_std_1.21/src/runtime/mem_linux.go @@ -170,4 +170,12 @@ func sysMapOS(v unsafe.Pointer, n uintptr) { print("runtime: mmap(", v, ", ", n, ") returned ", p, ", ", err, "\n") throw("runtime: cannot map pages in arena address space") } + + // Disable huge pages if the GODEBUG for it is set. + // + // Note that there are a few sysHugePage calls that can override this, but + // they're all for GC metadata. + if debug.disablethp != 0 { + sysNoHugePageOS(v, n) + } } diff --git a/contrib/go/_std_1.21/src/runtime/mgc.go b/contrib/go/_std_1.21/src/runtime/mgc.go index de5ae0ae00..a12dbfe9df 100644 --- a/contrib/go/_std_1.21/src/runtime/mgc.go +++ b/contrib/go/_std_1.21/src/runtime/mgc.go @@ -1186,7 +1186,9 @@ func gcMarkTermination() { // Enable huge pages on some metadata if we cross a heap threshold. if gcController.heapGoal() > minHeapForMetadataHugePages { - mheap_.enableMetadataHugePages() + systemstack(func() { + mheap_.enableMetadataHugePages() + }) } semrelease(&worldsema) diff --git a/contrib/go/_std_1.21/src/runtime/mgcscavenge.go b/contrib/go/_std_1.21/src/runtime/mgcscavenge.go index 4c6d6be4f0..659ca8df2e 100644 --- a/contrib/go/_std_1.21/src/runtime/mgcscavenge.go +++ b/contrib/go/_std_1.21/src/runtime/mgcscavenge.go @@ -1145,21 +1145,11 @@ func (s *scavengeIndex) alloc(ci chunkIdx, npages uint) { // Mark that we're considering this chunk as backed by huge pages. sc.setHugePage() - // Collapse dense chunks into huge pages and mark that - // we did that, but only if we're not allocating to - // use the entire chunk. If we're allocating an entire chunk, - // this is likely part of a much bigger allocation. For - // instance, if the caller is allocating a 1 GiB slice of bytes, we - // don't want to go and manually collapse all those pages; we want - // them to be demand-paged. If the caller is actually going to use - // all that memory, it'll naturally get backed by huge pages later. - // - // This also avoids having sysHugePageCollapse fail. On Linux, - // the call requires that some part of the huge page being collapsed - // is already paged in. - if !s.test && npages < pallocChunkPages { - sysHugePageCollapse(unsafe.Pointer(chunkBase(ci)), pallocChunkBytes) - } + // TODO(mknyszek): Consider eagerly backing memory with huge pages + // here. In the past we've attempted to use sysHugePageCollapse + // (which uses MADV_COLLAPSE on Linux, and is unsupported elswhere) + // for this purpose, but that caused performance issues in production + // environments. } s.chunks[ci].store(sc) } diff --git a/contrib/go/_std_1.21/src/runtime/mpagealloc.go b/contrib/go/_std_1.21/src/runtime/mpagealloc.go index 3e789ab85c..2861fa93eb 100644 --- a/contrib/go/_std_1.21/src/runtime/mpagealloc.go +++ b/contrib/go/_std_1.21/src/runtime/mpagealloc.go @@ -437,6 +437,10 @@ func (p *pageAlloc) grow(base, size uintptr) { // // The heap lock must not be held over this operation, since it will briefly acquire // the heap lock. +// +// Must be called on the system stack because it acquires the heap lock. +// +//go:systemstack func (p *pageAlloc) enableChunkHugePages() { // Grab the heap lock to turn on huge pages for new chunks and clone the current // heap address space ranges. diff --git a/contrib/go/_std_1.21/src/runtime/mstats.go b/contrib/go/_std_1.21/src/runtime/mstats.go index 9cdc565137..308bed67d7 100644 --- a/contrib/go/_std_1.21/src/runtime/mstats.go +++ b/contrib/go/_std_1.21/src/runtime/mstats.go @@ -367,6 +367,11 @@ func ReadMemStats(m *MemStats) { startTheWorld() } +// doubleCheckReadMemStats controls a double-check mode for ReadMemStats that +// ensures consistency between the values that ReadMemStats is using and the +// runtime-internal stats. +var doubleCheckReadMemStats = false + // readmemstats_m populates stats for internal runtime values. // // The world must be stopped. @@ -441,56 +446,65 @@ func readmemstats_m(stats *MemStats) { heapGoal := gcController.heapGoal() - // The world is stopped, so the consistent stats (after aggregation) - // should be identical to some combination of memstats. In particular: - // - // * memstats.heapInUse == inHeap - // * memstats.heapReleased == released - // * memstats.heapInUse + memstats.heapFree == committed - inStacks - inWorkBufs - inPtrScalarBits - // * memstats.totalAlloc == totalAlloc - // * memstats.totalFree == totalFree - // - // Check if that's actually true. - // - // TODO(mknyszek): Maybe don't throw here. It would be bad if a - // bug in otherwise benign accounting caused the whole application - // to crash. - if gcController.heapInUse.load() != uint64(consStats.inHeap) { - print("runtime: heapInUse=", gcController.heapInUse.load(), "\n") - print("runtime: consistent value=", consStats.inHeap, "\n") - throw("heapInUse and consistent stats are not equal") - } - if gcController.heapReleased.load() != uint64(consStats.released) { - print("runtime: heapReleased=", gcController.heapReleased.load(), "\n") - print("runtime: consistent value=", consStats.released, "\n") - throw("heapReleased and consistent stats are not equal") - } - heapRetained := gcController.heapInUse.load() + gcController.heapFree.load() - consRetained := uint64(consStats.committed - consStats.inStacks - consStats.inWorkBufs - consStats.inPtrScalarBits) - if heapRetained != consRetained { - print("runtime: global value=", heapRetained, "\n") - print("runtime: consistent value=", consRetained, "\n") - throw("measures of the retained heap are not equal") - } - if gcController.totalAlloc.Load() != totalAlloc { - print("runtime: totalAlloc=", gcController.totalAlloc.Load(), "\n") - print("runtime: consistent value=", totalAlloc, "\n") - throw("totalAlloc and consistent stats are not equal") - } - if gcController.totalFree.Load() != totalFree { - print("runtime: totalFree=", gcController.totalFree.Load(), "\n") - print("runtime: consistent value=", totalFree, "\n") - throw("totalFree and consistent stats are not equal") - } - // Also check that mappedReady lines up with totalMapped - released. - // This isn't really the same type of "make sure consistent stats line up" situation, - // but this is an opportune time to check. - if gcController.mappedReady.Load() != totalMapped-uint64(consStats.released) { - print("runtime: mappedReady=", gcController.mappedReady.Load(), "\n") - print("runtime: totalMapped=", totalMapped, "\n") - print("runtime: released=", uint64(consStats.released), "\n") - print("runtime: totalMapped-released=", totalMapped-uint64(consStats.released), "\n") - throw("mappedReady and other memstats are not equal") + if doubleCheckReadMemStats { + // Only check this if we're debugging. It would be bad to crash an application + // just because the debugging stats are wrong. We mostly rely on tests to catch + // these issues, and we enable the double check mode for tests. + // + // The world is stopped, so the consistent stats (after aggregation) + // should be identical to some combination of memstats. In particular: + // + // * memstats.heapInUse == inHeap + // * memstats.heapReleased == released + // * memstats.heapInUse + memstats.heapFree == committed - inStacks - inWorkBufs - inPtrScalarBits + // * memstats.totalAlloc == totalAlloc + // * memstats.totalFree == totalFree + // + // Check if that's actually true. + // + // Prevent sysmon and the tracer from skewing the stats since they can + // act without synchronizing with a STW. See #64401. + lock(&sched.sysmonlock) + lock(&trace.lock) + if gcController.heapInUse.load() != uint64(consStats.inHeap) { + print("runtime: heapInUse=", gcController.heapInUse.load(), "\n") + print("runtime: consistent value=", consStats.inHeap, "\n") + throw("heapInUse and consistent stats are not equal") + } + if gcController.heapReleased.load() != uint64(consStats.released) { + print("runtime: heapReleased=", gcController.heapReleased.load(), "\n") + print("runtime: consistent value=", consStats.released, "\n") + throw("heapReleased and consistent stats are not equal") + } + heapRetained := gcController.heapInUse.load() + gcController.heapFree.load() + consRetained := uint64(consStats.committed - consStats.inStacks - consStats.inWorkBufs - consStats.inPtrScalarBits) + if heapRetained != consRetained { + print("runtime: global value=", heapRetained, "\n") + print("runtime: consistent value=", consRetained, "\n") + throw("measures of the retained heap are not equal") + } + if gcController.totalAlloc.Load() != totalAlloc { + print("runtime: totalAlloc=", gcController.totalAlloc.Load(), "\n") + print("runtime: consistent value=", totalAlloc, "\n") + throw("totalAlloc and consistent stats are not equal") + } + if gcController.totalFree.Load() != totalFree { + print("runtime: totalFree=", gcController.totalFree.Load(), "\n") + print("runtime: consistent value=", totalFree, "\n") + throw("totalFree and consistent stats are not equal") + } + // Also check that mappedReady lines up with totalMapped - released. + // This isn't really the same type of "make sure consistent stats line up" situation, + // but this is an opportune time to check. + if gcController.mappedReady.Load() != totalMapped-uint64(consStats.released) { + print("runtime: mappedReady=", gcController.mappedReady.Load(), "\n") + print("runtime: totalMapped=", totalMapped, "\n") + print("runtime: released=", uint64(consStats.released), "\n") + print("runtime: totalMapped-released=", totalMapped-uint64(consStats.released), "\n") + throw("mappedReady and other memstats are not equal") + } + unlock(&trace.lock) + unlock(&sched.sysmonlock) } // We've calculated all the values we need. Now, populate stats. diff --git a/contrib/go/_std_1.21/src/runtime/os_windows.go b/contrib/go/_std_1.21/src/runtime/os_windows.go index f5c2429a05..735a905b61 100644 --- a/contrib/go/_std_1.21/src/runtime/os_windows.go +++ b/contrib/go/_std_1.21/src/runtime/os_windows.go @@ -127,15 +127,8 @@ var ( _AddVectoredContinueHandler, _ stdFunction - // Use RtlGenRandom to generate cryptographically random data. - // This approach has been recommended by Microsoft (see issue - // 15589 for details). - // The RtlGenRandom is not listed in advapi32.dll, instead - // RtlGenRandom function can be found by searching for SystemFunction036. - // Also some versions of Mingw cannot link to SystemFunction036 - // when building executable as Cgo. So load SystemFunction036 - // manually during runtime startup. - _RtlGenRandom stdFunction + // Use ProcessPrng to generate cryptographically random data. + _ProcessPrng stdFunction // Load ntdll.dll manually during startup, otherwise Mingw // links wrong printf function to cgo executable (see issue @@ -152,12 +145,12 @@ var ( ) var ( - advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0} - kernel32dll = [...]uint16{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0} - ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} - powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} - winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} - ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} + bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} + kernel32dll = [...]uint16{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0} + ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} + powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} + winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} + ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} ) // Function to be called by windows CreateThread @@ -256,11 +249,11 @@ func loadOptionalSyscalls() { } _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) - a32 := windowsLoadSystemLib(advapi32dll[:]) - if a32 == 0 { - throw("advapi32.dll not found") + bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) + if bcryptPrimitives == 0 { + throw("bcryptprimitives.dll not found") } - _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) + _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) n32 := windowsLoadSystemLib(ntdlldll[:]) if n32 == 0 { @@ -617,7 +610,7 @@ func initWine(k32 uintptr) { //go:nosplit func getRandomData(r []byte) { n := 0 - if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { + if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { n = len(r) } extendRandom(r, n) diff --git a/contrib/go/_std_1.21/src/runtime/pprof/proto.go b/contrib/go/_std_1.21/src/runtime/pprof/proto.go index cdc4bd7c80..db9384eb21 100644 --- a/contrib/go/_std_1.21/src/runtime/pprof/proto.go +++ b/contrib/go/_std_1.21/src/runtime/pprof/proto.go @@ -611,13 +611,14 @@ func (b *profileBuilder) emitLocation() uint64 { b.pb.uint64Opt(tagLocation_Address, uint64(firstFrame.PC)) for _, frame := range b.deck.frames { // Write out each line in frame expansion. - funcID := uint64(b.funcs[frame.Function]) + funcName := runtime_FrameSymbolName(&frame) + funcID := uint64(b.funcs[funcName]) if funcID == 0 { funcID = uint64(len(b.funcs)) + 1 - b.funcs[frame.Function] = int(funcID) + b.funcs[funcName] = int(funcID) newFuncs = append(newFuncs, newFunc{ id: funcID, - name: runtime_FrameSymbolName(&frame), + name: funcName, file: frame.File, startLine: int64(runtime_FrameStartLine(&frame)), }) diff --git a/contrib/go/_std_1.21/src/runtime/runtime.go b/contrib/go/_std_1.21/src/runtime/runtime.go index 0822d0e805..15119cf5df 100644 --- a/contrib/go/_std_1.21/src/runtime/runtime.go +++ b/contrib/go/_std_1.21/src/runtime/runtime.go @@ -101,12 +101,17 @@ func (g *godebugInc) IncNonDefault() { if newInc == nil { return } - // If other goroutines are racing here, no big deal. One will win, - // and all the inc functions will be using the same underlying - // *godebug.Setting. inc = new(func()) *inc = (*newInc)(g.name) - g.inc.Store(inc) + if raceenabled { + racereleasemerge(unsafe.Pointer(&g.inc)) + } + if !g.inc.CompareAndSwap(nil, inc) { + inc = g.inc.Load() + } + } + if raceenabled { + raceacquire(unsafe.Pointer(&g.inc)) } (*inc)() } diff --git a/contrib/go/_std_1.21/src/runtime/runtime1.go b/contrib/go/_std_1.21/src/runtime/runtime1.go index 92a7e021ee..7174c63af3 100644 --- a/contrib/go/_std_1.21/src/runtime/runtime1.go +++ b/contrib/go/_std_1.21/src/runtime/runtime1.go @@ -309,6 +309,7 @@ type dbgVar struct { var debug struct { cgocheck int32 clobberfree int32 + disablethp int32 dontfreezetheworld int32 efence int32 gccheckmark int32 @@ -342,6 +343,7 @@ var dbgvars = []*dbgVar{ {name: "allocfreetrace", value: &debug.allocfreetrace}, {name: "clobberfree", value: &debug.clobberfree}, {name: "cgocheck", value: &debug.cgocheck}, + {name: "disablethp", value: &debug.disablethp}, {name: "dontfreezetheworld", value: &debug.dontfreezetheworld}, {name: "efence", value: &debug.efence}, {name: "gccheckmark", value: &debug.gccheckmark}, |