[release-branch.go1.24] all: merge master (c93477b) into release-branch.go1.24

Merge List:

+ 2024-12-11 c93477b5e5 crypto: use provided random Reader in FIPS mode
+ 2024-12-11 3104b6adbb log/slog: make DiscardHandler example package-level
+ 2024-12-11 5424f2e200 cmd/go: add more tests for GOAUTH's user provided authenticator
+ 2024-12-11 d5c1333eb4 net/http: document zero value of Protocols
+ 2024-12-11 a7c4cadce0 cmd/compile: update broken link
+ 2024-12-11 979c1cfbe8 net: avoid unnecessary interface lookup fetching all interface addresses
+ 2024-12-11 e424d78c3d internal/goos: fix bug in gengoos.go
+ 2024-12-11 6c25cf1c5f cmd/internal/objfile: break out dissassemblers to another package
+ 2024-12-11 e0c76d95ab syscall: remove a wrong comment in Clearenv
+ 2024-12-11 a9922d096f reflect: consistently document when value must be settable
+ 2024-12-10 4ce116a884 runtime: avoid panic in expired synctest timer chan read
+ 2024-12-10 e6de1b2deb html/template: escape script tags in JS errors case insensitively
+ 2024-12-10 fce17b0c77 crypto/internal/fips140/ecdsa: fix reseed_counter check for HMAC_DRBG_Generate_algorithm
+ 2024-12-09 d87878c62b runtime: make special offset a uintptr
+ 2024-12-09 6705ac6885 runtime: remove datadog-agent from prof labels hall of shame
+ 2024-12-09 07398d2e57 weak: align weak.Pointer documentation with runtime.AddCleanup
+ 2024-12-09 e3e1d73528 bufio: make the description of Peek's behavior better
+ 2024-12-09 e79b2e1e3a cmd/go: document the build cache as safe for concurrent use
+ 2024-12-08 c8fb6ae617 lib/wasm: provide fs.constants.O_DIRECTORY definition
+ 2024-12-07 8c3e391573 runtime: improve AddCleanup documentation
+ 2024-12-07 04cdaa9984 cmd/go: document c-shared buildmode for building WASI library/reactor
+ 2024-12-06 312f7c1bd3 runtime: add note that Callers never returns an entry PC

Change-Id: I52e035228121de3d8219ab13f195d4293daaaa34
This commit is contained in:
Carlos Amedee 2024-12-11 17:45:38 -05:00
commit 2297c34cdf
47 changed files with 406 additions and 227 deletions

View File

@ -14,7 +14,7 @@
if (!globalThis.fs) {
let outputBuf = "";
globalThis.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_DIRECTORY: -1 }, // unused
writeSync(fd, buf) {
outputBuf += decoder.decode(buf);
const nl = outputBuf.lastIndexOf("\n");

View File

@ -133,9 +133,10 @@ func (b *Reader) readErr() error {
}
// Peek returns the next n bytes without advancing the reader. The bytes stop
// being valid at the next read call. If Peek returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is
// [ErrBufferFull] if n is larger than b's buffer size.
// being valid at the next read call. If necessary, Peek will read more bytes
// into the buffer in order to make n bytes available. If Peek returns fewer
// than n bytes, it also returns an error explaining why the read is short.
// The error is [ErrBufferFull] if n is larger than b's buffer size.
//
// Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding
// until the next read operation.

View File

@ -5,7 +5,8 @@
// This program generates Go code that applies rewrite rules to a Value.
// The generated code implements a function of type func (v *Value) bool
// which reports whether if did something.
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
// Ideas stolen from the Swift Java compiler:
// https://bitsavers.org/pdf/dec/tech_reports/WRL-2000-2.pdf
package main

View File

@ -2210,7 +2210,10 @@
// Build the listed main package, plus all packages it imports,
// into a C shared library. The only callable symbols will
// be those functions exported using a cgo //export comment.
// Requires exactly one main package to be listed.
// On wasip1, this mode builds it to a WASI reactor/library,
// of which the callable symbols are those functions exported
// using a //go:wasmexport directive. Requires exactly one
// main package to be listed.
//
// -buildmode=default
// Listed main packages are built into executables and listed
@ -2261,6 +2264,7 @@
// The go command caches build outputs for reuse in future builds.
// The default location for cache data is a subdirectory named go-build
// in the standard user cache directory for the current operating system.
// The cache is safe for concurrent invocations of the go command.
// Setting the GOCACHE environment variable overrides this default,
// and running 'go env GOCACHE' prints the current cache directory.
//

View File

@ -769,7 +769,10 @@ are:
Build the listed main package, plus all packages it imports,
into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment.
Requires exactly one main package to be listed.
On wasip1, this mode builds it to a WASI reactor/library,
of which the callable symbols are those functions exported
using a //go:wasmexport directive. Requires exactly one
main package to be listed.
-buildmode=default
Listed main packages are built into executables and listed
@ -806,6 +809,7 @@ var HelpCache = &base.Command{
The go command caches build outputs for reuse in future builds.
The default location for cache data is a subdirectory named go-build
in the standard user cache directory for the current operating system.
The cache is safe for concurrent invocations of the go command.
Setting the GOCACHE environment variable overrides this default,
and running 'go env GOCACHE' prints the current cache directory.

View File

@ -3,13 +3,8 @@
env GOPROXY=direct
env GOSUMDB=off
# Use a custom authenticator to provide custom credentials
mkdir $WORK/bin
env PATH=$WORK/bin${:}$PATH
cd auth
go build -o $WORK/bin/my-auth$GOEXE .
cd ..
# Without credentials, downloading a module from a path that requires HTTPS
# basic auth should fail.
@ -21,8 +16,10 @@ stderr '^\tserver response: ACCESS DENIED, buddy$'
! go mod tidy
stderr '^\tserver response: ACCESS DENIED, buddy$'
# With credentials from the my-auth binary, it should succeed.
env GOAUTH='my-auth'$GOEXE' --arg1 "value with spaces"'
# Initial invocation of authenticator is successful.
go build -o $WORK/bin/basic$GOEXE scripts/basic.go
# With credentials from the binary, it should succeed.
env GOAUTH='basic'$GOEXE
cp go.mod.orig go.mod
go get vcs-test.golang.org/auth/or401
# go imports should resolve correctly as well.
@ -30,7 +27,54 @@ go mod tidy
go list all
stdout vcs-test.golang.org/auth/or401
-- auth/main.go --
# Second invocation of authenticator is successful.
go build -o $WORK/bin/reinvocation$GOEXE scripts/reinvocation.go
# With credentials from the binary, it should succeed.
env GOAUTH='reinvocation'$GOEXE
cp go.mod.orig go.mod
go get vcs-test.golang.org/auth/or401
# go imports should resolve correctly as well.
go mod tidy
go list all
stdout vcs-test.golang.org/auth/or401
# Authenticator can parse arguments correctly.
go build -o $WORK/bin/arguments$GOEXE scripts/arguments.go
# With credentials from the binary, it should succeed.
env GOAUTH='arguments'$GOEXE' --arg1 "value with spaces"'
cp go.mod.orig go.mod
go get vcs-test.golang.org/auth/or401
# go imports should resolve correctly as well.
go mod tidy
go list all
stdout vcs-test.golang.org/auth/or401
# Authenticator provides bad credentials.
go build -o $WORK/bin/invalid$GOEXE scripts/invalid.go
# With credentials from the binary, it should fail.
env GOAUTH='invalid'$GOEXE
cp go.mod.orig go.mod
! go get vcs-test.golang.org/auth/or401
stderr '^\tserver response: ACCESS DENIED, buddy$'
# go imports should fail as well.
! go mod tidy
stderr '^\tserver response: ACCESS DENIED, buddy$'
-- go.mod.orig --
module private.example.com
-- main.go --
package useprivate
import "vcs-test.golang.org/auth/or401"
-- scripts/basic.go --
package main
import "fmt"
func main() {
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
}
-- scripts/reinvocation.go --
package main
import(
@ -45,11 +89,7 @@ import(
)
func main() {
arg1 := flag.String("arg1", "", "")
flag.Parse()
if *arg1 != "value with spaces" {
log.Fatal("argument with spaces does not work")
}
// wait for re-invocation
if !strings.HasPrefix(flag.Arg(0), "https://vcs-test.golang.org") {
return
@ -68,12 +108,28 @@ func main() {
}
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
}
-- scripts/arguments.go --
package main
-- auth/go.mod --
module my-auth
-- go.mod.orig --
module private.example.com
-- main.go --
package useprivate
import(
"flag"
"fmt"
"log"
)
import "vcs-test.golang.org/auth/or401"
func main() {
arg1 := flag.String("arg1", "", "")
flag.Parse()
if *arg1 != "value with spaces" {
log.Fatal("argument with spaces does not work")
}
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n")
}
-- scripts/invalid.go --
package main
import "fmt"
func main() {
fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic invalid\n\n")
}

View File

@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objfile
// Package disasm provides disassembly routines.
//
// It is broken out from cmd/internal/objfile so tools that don't need
// disassembling don't need to depend on x/arch disassembler code.
package disasm
import (
"bufio"
"bytes"
"container/list"
"debug/gosym"
"encoding/binary"
"fmt"
"io"
@ -19,6 +22,7 @@ import (
"strings"
"text/tabwriter"
"cmd/internal/objfile"
"cmd/internal/src"
"golang.org/x/arch/arm/armasm"
@ -32,8 +36,8 @@ import (
// Disasm is a disassembler for a given File.
type Disasm struct {
syms []Sym //symbols in file, sorted by address
pcln Liner // pcln table
syms []objfile.Sym // symbols in file, sorted by address
pcln objfile.Liner // pcln table
text []byte // bytes of text segment (actual instructions)
textStart uint64 // start PC of text
textEnd uint64 // end PC of text
@ -42,8 +46,12 @@ type Disasm struct {
byteOrder binary.ByteOrder // byte order for goarch
}
// Disasm returns a disassembler for the file f.
func (e *Entry) Disasm() (*Disasm, error) {
// DisasmForFile returns a disassembler for the file f.
func DisasmForFile(f *objfile.File) (*Disasm, error) {
return disasmForEntry(f.Entries()[0])
}
func disasmForEntry(e *objfile.Entry) (*Disasm, error) {
syms, err := e.Symbols()
if err != nil {
return nil, err
@ -269,7 +277,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
}
// Decode disassembles the text segment range [start, end), calling f for each instruction.
func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
func (d *Disasm) Decode(start, end uint64, relocs []objfile.Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
if start < d.textStart {
start = d.textStart
}
@ -452,9 +460,3 @@ var byteOrders = map[string]binary.ByteOrder{
"riscv64": binary.LittleEndian,
"s390x": binary.BigEndian,
}
type Liner interface {
// Given a pc, returns the corresponding file, line, and function data.
// If unknown, returns "",0,nil.
PCToLine(uint64) (string, int, *gosym.Func)
}

View File

@ -119,10 +119,6 @@ func (f *File) DWARF() (*dwarf.Data, error) {
return f.entries[0].DWARF()
}
func (f *File) Disasm() (*Disasm, error) {
return f.entries[0].Disasm()
}
func (e *Entry) Name() string {
return e.name
}
@ -181,3 +177,9 @@ func (e *Entry) LoadAddress() (uint64, error) {
func (e *Entry) DWARF() (*dwarf.Data, error) {
return e.raw.dwarf()
}
type Liner interface {
// Given a pc, returns the corresponding file, line, and function data.
// If unknown, returns "",0,nil.
PCToLine(uint64) (string, int, *gosym.Func)
}

View File

@ -40,6 +40,7 @@ import (
"strconv"
"strings"
"cmd/internal/disasm"
"cmd/internal/objfile"
"cmd/internal/telemetry/counter"
)
@ -82,7 +83,7 @@ func main() {
}
defer f.Close()
dis, err := f.Disasm()
dis, err := disasm.DisasmForFile(f)
if err != nil {
log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
}

View File

@ -24,6 +24,7 @@ import (
"sync"
"time"
"cmd/internal/disasm"
"cmd/internal/objfile"
"cmd/internal/telemetry/counter"
@ -162,7 +163,7 @@ func adjustURL(source string, duration, timeout time.Duration) (string, time.Dur
// (instead of invoking GNU binutils).
type objTool struct {
mu sync.Mutex
disasmCache map[string]*objfile.Disasm
disasmCache map[string]*disasm.Disasm
}
func (*objTool) Open(name string, start, limit, offset uint64, relocationSymbol string) (driver.ObjFile, error) {
@ -202,11 +203,11 @@ func (t *objTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]dr
return asm, nil
}
func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
func (t *objTool) cachedDisasm(file string) (*disasm.Disasm, error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.disasmCache == nil {
t.disasmCache = make(map[string]*objfile.Disasm)
t.disasmCache = make(map[string]*disasm.Disasm)
}
d := t.disasmCache[file]
if d != nil {
@ -216,7 +217,7 @@ func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
if err != nil {
return nil, err
}
d, err = f.Disasm()
d, err = disasm.DisasmForFile(f)
f.Close()
if err != nil {
return nil, err

View File

@ -8,6 +8,7 @@ import (
"bytes"
"crypto/internal/boring"
"crypto/internal/fips140/ecdh"
"crypto/internal/fips140only"
"errors"
"io"
)
@ -43,6 +44,10 @@ func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
return k, nil
}
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
privateKey, err := c.generate(rand)
if err != nil {
return nil, err

View File

@ -21,6 +21,7 @@ import (
"crypto/internal/boring"
"crypto/internal/boring/bbig"
"crypto/internal/fips140/ecdsa"
"crypto/internal/fips140only"
"crypto/internal/randutil"
"crypto/sha512"
"crypto/subtle"
@ -182,6 +183,9 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
}
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
if fips140only.Enabled && fips140only.ApprovedRandomReader(rand) {
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
privateKey, err := ecdsa.GenerateKey(c, rand)
if err != nil {
return nil, err
@ -228,6 +232,9 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
}
func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) {
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
// privateKeyToFIPS is very slow in FIPS mode because it performs a
// Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache
// it or attach it to the PrivateKey.

View File

@ -7,7 +7,9 @@ package drbg
import (
"crypto/internal/entropy"
"crypto/internal/fips140"
"crypto/internal/randutil"
"crypto/internal/sysrand"
"io"
"sync"
)
@ -56,3 +58,38 @@ func Read(b []byte) {
b = b[size:]
}
}
// DefaultReader is a sentinel type, embedded in the default
// [crypto/rand.Reader], used to recognize it when passed to
// APIs that accept a rand io.Reader.
type DefaultReader interface{ defaultReader() }
// ReadWithReader uses Reader to fill b with cryptographically secure random
// bytes. It is intended for use in APIs that expose a rand io.Reader.
//
// If Reader is not the default Reader from crypto/rand,
// [randutil.MaybeReadByte] and [fips140.RecordNonApproved] are called.
func ReadWithReader(r io.Reader, b []byte) error {
if _, ok := r.(DefaultReader); ok {
Read(b)
return nil
}
fips140.RecordNonApproved()
randutil.MaybeReadByte(r)
_, err := io.ReadFull(r, b)
return err
}
// ReadWithReaderDeterministic is like ReadWithReader, but it doesn't call
// [randutil.MaybeReadByte] on non-default Readers.
func ReadWithReaderDeterministic(r io.Reader, b []byte) error {
if _, ok := r.(DefaultReader); ok {
Read(b)
return nil
}
fips140.RecordNonApproved()
_, err := io.ReadFull(r, b)
return err
}

View File

@ -10,7 +10,6 @@ import (
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/nistec"
"crypto/internal/fips140deps/byteorder"
"crypto/internal/randutil"
"errors"
"io"
"math/bits"
@ -137,8 +136,6 @@ var p521Order = []byte{0x01, 0xff,
}
// GenerateKey generates a new ECDSA private key pair for the specified curve.
//
// In FIPS mode, rand is ignored.
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
fips140.RecordApproved()
// This procedure is equivalent to Key Pair Generation by Testing
@ -146,18 +143,13 @@ func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
for {
key := make([]byte, len(c.N))
if fips140.Enabled {
drbg.Read(key)
} else {
randutil.MaybeReadByte(rand)
if _, err := io.ReadFull(rand, key); err != nil {
return nil, err
}
// In tests, rand will return all zeros and NewPrivateKey will reject
// the zero key as it generates the identity as a public key. This also
// makes this function consistent with crypto/elliptic.GenerateKey.
key[1] ^= 0x42
if err := drbg.ReadWithReader(rand, key); err != nil {
return nil, err
}
// In tests, rand will return all zeros and NewPrivateKey will reject
// the zero key as it generates the identity as a public key. This also
// makes this function consistent with crypto/elliptic.GenerateKey.
key[1] ^= 0x42
// Mask off any excess bits if the size of the underlying field is not a
// whole number of bytes, which is only the case for P-521.

View File

@ -54,7 +54,8 @@ func testHash() []byte {
func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) error {
return fips140.PCT("ECDSA PCT", func() error {
hash := testHash()
sig, err := Sign(c, sha512.New, k, nil, hash)
drbg := newDRBG(sha512.New, k.d, bits2octets(P256(), hash), nil)
sig, err := sign(c, k, drbg, hash)
if err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"crypto/internal/fips140/bigmod"
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/nistec"
"crypto/internal/randutil"
"errors"
"io"
"sync"
@ -187,20 +186,11 @@ func NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) {
}
// GenerateKey generates a new ECDSA private key pair for the specified curve.
//
// In FIPS mode, rand is ignored.
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
fips140.RecordApproved()
k, Q, err := randomPoint(c, func(b []byte) error {
if fips140.Enabled {
drbg.Read(b)
return nil
} else {
randutil.MaybeReadByte(rand)
_, err := io.ReadFull(rand, b)
return err
}
return drbg.ReadWithReader(rand, b)
})
if err != nil {
return nil, err
@ -281,8 +271,6 @@ type Signature struct {
// the hash function H) using the private key, priv. If the hash is longer than
// the bit-length of the private key's curve order, the hash will be truncated
// to that length.
//
// The signature is randomized. If FIPS mode is enabled, rand is ignored.
func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
if priv.pub.curve != c.curve {
return nil, errors.New("ecdsa: private key does not match curve")
@ -296,13 +284,8 @@ func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey,
// advantage of closely resembling Deterministic ECDSA.
Z := make([]byte, len(priv.d))
if fips140.Enabled {
drbg.Read(Z)
} else {
randutil.MaybeReadByte(rand)
if _, err := io.ReadFull(rand, Z); err != nil {
return nil, err
}
if err := drbg.ReadWithReader(rand, Z); err != nil {
return nil, err
}
// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6

View File

@ -160,4 +160,6 @@ func (d *hmacDRBG) Generate(out []byte) {
d.hK = d.newHMAC(K)
d.hK.Write(d.V)
d.V = d.hK.Sum(d.V[:0])
d.reseedCounter++
}

View File

@ -11,7 +11,6 @@ import (
"crypto/internal/fips140/edwards25519"
"crypto/internal/fips140/sha512"
"errors"
"io"
"strconv"
)
@ -61,24 +60,14 @@ func (pub *PublicKey) Bytes() []byte {
}
// GenerateKey generates a new Ed25519 private key pair.
//
// In FIPS mode, rand is ignored. Otherwise, the output of this function is
// deterministic, and equivalent to reading 32 bytes from rand, and passing them
// to [NewKeyFromSeed].
func GenerateKey(rand io.Reader) (*PrivateKey, error) {
func GenerateKey() (*PrivateKey, error) {
priv := &PrivateKey{}
return generateKey(priv, rand)
return generateKey(priv)
}
func generateKey(priv *PrivateKey, rand io.Reader) (*PrivateKey, error) {
func generateKey(priv *PrivateKey) (*PrivateKey, error) {
fips140.RecordApproved()
if fips140.Enabled {
drbg.Read(priv.seed[:])
} else {
if _, err := io.ReadFull(rand, priv.seed[:]); err != nil {
return nil, err
}
}
drbg.Read(priv.seed[:])
precomputePrivateKey(priv)
if err := fipsPCT(priv); err != nil {
// This clearly can't happen, but FIPS 140-3 requires that we check.

View File

@ -8,15 +8,12 @@ import (
"crypto/internal/fips140"
"crypto/internal/fips140/bigmod"
"crypto/internal/fips140/drbg"
"crypto/internal/randutil"
"errors"
"io"
)
// GenerateKey generates a new RSA key pair of the given bit size.
// bits must be at least 128.
//
// When operating in FIPS mode, rand is ignored.
func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
if bits < 128 {
return nil, errors.New("rsa: key too small")
@ -94,7 +91,7 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
}
// randomPrime returns a random prime number of the given bit size following
// the process in FIPS 186-5, Appendix A.1.3. rand is ignored in FIPS mode.
// the process in FIPS 186-5, Appendix A.1.3.
func randomPrime(rand io.Reader, bits int) ([]byte, error) {
if bits < 64 {
return nil, errors.New("rsa: prime size must be at least 32-bit")
@ -102,13 +99,8 @@ func randomPrime(rand io.Reader, bits int) ([]byte, error) {
b := make([]byte, (bits+7)/8)
for {
if fips140.Enabled {
drbg.Read(b)
} else {
randutil.MaybeReadByte(rand)
if _, err := io.ReadFull(rand, b); err != nil {
return nil, err
}
if err := drbg.ReadWithReader(rand, b); err != nil {
return nil, err
}
if excess := len(b)*8 - bits; excess != 0 {
b[0] >>= excess

View File

@ -264,8 +264,6 @@ func PSSMaxSaltLength(pub *PublicKey, hash fips140.Hash) (int, error) {
}
// SignPSS calculates the signature of hashed using RSASSA-PSS.
//
// In FIPS mode, rand is ignored and can be nil.
func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte, saltLength int) ([]byte, error) {
fipsSelfTest()
fips140.RecordApproved()
@ -286,12 +284,8 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte,
fips140.RecordNonApproved()
}
salt := make([]byte, saltLength)
if fips140.Enabled {
drbg.Read(salt)
} else {
if _, err := io.ReadFull(rand, salt); err != nil {
return nil, err
}
if err := drbg.ReadWithReaderDeterministic(rand, salt); err != nil {
return nil, err
}
emBits := priv.pub.N.BitLen() - 1
@ -374,8 +368,6 @@ func checkApprovedHash(hash fips140.Hash) {
}
// EncryptOAEP encrypts the given message with RSAES-OAEP.
//
// In FIPS mode, random is ignored and can be nil.
func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
// Note that while we don't commit to deterministic execution with respect
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
@ -408,13 +400,8 @@ func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, m
db[len(db)-len(msg)-1] = 1
copy(db[len(db)-len(msg):], msg)
if fips140.Enabled {
drbg.Read(seed)
} else {
_, err := io.ReadFull(random, seed)
if err != nil {
return nil, err
}
if err := drbg.ReadWithReaderDeterministic(random, seed); err != nil {
return nil, err
}
mgf1XOR(db, mgfHash, seed)

View File

@ -5,11 +5,13 @@
package fips140only
import (
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/sha256"
"crypto/internal/fips140/sha3"
"crypto/internal/fips140/sha512"
"hash"
"internal/godebug"
"io"
)
// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
@ -24,3 +26,8 @@ func ApprovedHash(h hash.Hash) bool {
return false
}
}
func ApprovedRandomReader(r io.Reader) bool {
_, ok := r.(drbg.DefaultReader)
return ok
}

View File

@ -85,7 +85,7 @@ func TestConditionals(t *testing.T) {
t.Fatal(err)
}
ecdsa.SignDeterministic(ecdsa.P256(), sha256.New, kDSA, make([]byte, 32))
k25519, err := ed25519.GenerateKey(rand.Reader)
k25519, err := ed25519.GenerateKey()
if err != nil {
t.Fatal(err)
}

View File

@ -38,7 +38,9 @@ func init() {
Reader = &reader{}
}
type reader struct{}
type reader struct {
drbg.DefaultReader
}
func (r *reader) Read(b []byte) (n int, err error) {
boring.Unreachable()

View File

@ -17,6 +17,9 @@ import (
const (
// PSSSaltLengthAuto causes the salt in a PSS signature to be as large
// as possible when signing, and to be auto-detected when verifying.
//
// When signing in FIPS 140-3 mode, the salt length is capped at the length
// of the hash function used in the signature.
PSSSaltLengthAuto = 0
// PSSSaltLengthEqualsHash causes the salt length to equal the length
// of the hash used in the signature.
@ -67,6 +70,9 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) {
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
}
if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
if opts != nil && opts.Hash != 0 {
hash = opts.Hash
@ -188,6 +194,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
if fips140only.Enabled && !fips140only.ApprovedHash(hash) {
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
}
if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
defer hash.Reset()

View File

@ -322,6 +322,9 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
if fips140only.Enabled && bits%2 == 1 {
return nil, errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode")
}
if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
}
k, err := rsa.GenerateKey(random, bits)
if err != nil {

View File

@ -10,7 +10,6 @@ import (
"crypto"
"crypto/internal/boring"
"crypto/internal/cryptotest"
"crypto/internal/fips140"
"crypto/rand"
. "crypto/rsa"
"crypto/sha1"
@ -782,9 +781,6 @@ type testEncryptOAEPStruct struct {
}
func TestEncryptOAEP(t *testing.T) {
if fips140.Enabled {
t.Skip("FIPS mode overrides the deterministic random source")
}
sha1 := sha1.New()
n := new(big.Int)
for i, test := range testEncryptOAEPData {

View File

@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"regexp"
"strings"
"unicode/utf8"
)
@ -144,6 +145,8 @@ func indirectToJSONMarshaler(a any) any {
return v.Interface()
}
var scriptTagRe = regexp.MustCompile("(?i)<(/?)script")
// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
// neither side-effects nor free variables outside (NaN, Infinity).
func jsValEscaper(args ...any) string {
@ -181,9 +184,9 @@ func jsValEscaper(args ...any) string {
// In particular we:
// * replace "*/" comment end tokens with "* /", which does not
// terminate the comment
// * replace "</script" with "\x3C/script", and "<!--" with
// "\x3C!--", which prevents confusing script block termination
// semantics
// * replace "<script" and "</script" with "\x3Cscript" and "\x3C/script"
// (case insensitively), and "<!--" with "\x3C!--", which prevents
// confusing script block termination semantics
//
// We also put a space before the comment so that if it is flush against
// a division operator it is not turned into a line comment:
@ -192,8 +195,8 @@ func jsValEscaper(args ...any) string {
// x//* error marshaling y:
// second line of error message */null
errStr := err.Error()
errStr = string(scriptTagRe.ReplaceAll([]byte(errStr), []byte(`\x3C${1}script`)))
errStr = strings.ReplaceAll(errStr, "*/", "* /")
errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
return fmt.Sprintf(" /* %s */null ", errStr)
}

View File

@ -107,7 +107,7 @@ func TestNextJsCtx(t *testing.T) {
type jsonErrType struct{}
func (e *jsonErrType) MarshalJSON() ([]byte, error) {
return nil, errors.New("beep */ boop </script blip <!--")
return nil, errors.New("a */ b <script c </script d <!-- e <sCrIpT f </sCrIpT")
}
func TestJSValEscaper(t *testing.T) {
@ -160,7 +160,7 @@ func TestJSValEscaper(t *testing.T) {
{"</script", `"\u003c/script"`, false},
{"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
{nil, " null ", false},
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: a * / b \\x3Cscript c \\x3C/script d \\x3C!-- e \\x3Cscript f \\x3C/script */null ", true},
}
for _, test := range tests {

View File

@ -17,7 +17,7 @@ import (
var gooses []string
func main() {
data, err := os.ReadFile("../../internal/syslist/syslist..go")
data, err := os.ReadFile("../../internal/syslist/syslist.go")
if err != nil {
log.Fatal(err)
}

View File

@ -105,7 +105,7 @@ func TestMallocs(t *testing.T) {
}
}
func TestTimer(t *testing.T) {
func TestTimerReadBeforeDeadline(t *testing.T) {
synctest.Run(func() {
start := time.Now()
tm := time.NewTimer(5 * time.Second)
@ -116,6 +116,41 @@ func TestTimer(t *testing.T) {
})
}
func TestTimerReadAfterDeadline(t *testing.T) {
synctest.Run(func() {
delay := 1 * time.Second
want := time.Now().Add(delay)
tm := time.NewTimer(delay)
time.Sleep(2 * delay)
got := <-tm.C
if got != want {
t.Errorf("<-tm.C = %v, want %v", got, want)
}
})
}
func TestTimerReset(t *testing.T) {
synctest.Run(func() {
start := time.Now()
tm := time.NewTimer(1 * time.Second)
if got, want := <-tm.C, start.Add(1*time.Second); got != want {
t.Errorf("first sleep: <-tm.C = %v, want %v", got, want)
}
tm.Reset(2 * time.Second)
if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want {
t.Errorf("second sleep: <-tm.C = %v, want %v", got, want)
}
tm.Reset(3 * time.Second)
time.Sleep(1 * time.Second)
tm.Reset(3 * time.Second)
if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want {
t.Errorf("third sleep: <-tm.C = %v, want %v", got, want)
}
})
}
func TestTimeAfter(t *testing.T) {
synctest.Run(func() {
i := 0
@ -138,9 +173,11 @@ func TestTimeAfter(t *testing.T) {
func TestTimerFromOutsideBubble(t *testing.T) {
tm := time.NewTimer(10 * time.Millisecond)
synctest.Run(func() {
defer wantPanic(t, "timer moved between synctest groups")
<-tm.C
})
if tm.Stop() {
t.Errorf("synctest.Run unexpectedly returned before timer fired")
}
}
func TestChannelFromOutsideBubble(t *testing.T) {

View File

@ -10,7 +10,7 @@ import (
"os"
)
func ExampleDiscardHandler() {
func Example_discardHandler() {
// A slog.TextHandler can output log messages.
logger1 := slog.New(slog.NewTextHandler(
os.Stdout,

View File

@ -17,6 +17,7 @@ import (
)
// Protocols is a set of HTTP protocols.
// The zero value is an empty set of protocols.
//
// The supported protocols are:
//

View File

@ -129,22 +129,14 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
if err != nil {
return nil, os.NewSyscallError("parsenetlinkmessage", err)
}
var ift []Interface
if ifi == nil {
var err error
ift, err = interfaceTable(0)
if err != nil {
return nil, err
}
}
ifat, err := addrTable(ift, ifi, msgs)
ifat, err := addrTable(ifi, msgs)
if err != nil {
return nil, err
}
return ifat, nil
}
func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
func addrTable(ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) {
var ifat []Addr
loop:
for _, m := range msgs {
@ -153,14 +145,7 @@ loop:
break loop
case syscall.RTM_NEWADDR:
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
if len(ift) != 0 || ifi.Index == int(ifam.Index) {
if len(ift) != 0 {
var err error
ifi, err = interfaceByIndex(ift, int(ifam.Index))
if err != nil {
return nil, err
}
}
if ifi == nil || ifi.Index == int(ifam.Index) {
attrs, err := syscall.ParseNetlinkRouteAttr(&m)
if err != nil {
return nil, os.NewSyscallError("parsenetlinkrouteattr", err)

View File

@ -289,6 +289,7 @@ func (iter *MapIter) Key() Value {
// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value.
// As in Go, the key must be assignable to v's type and
// must not be derived from an unexported field.
// It panics if [Value.CanSet] returns false.
func (v Value) SetIterKey(iter *MapIter) {
if !iter.hiter.initialized() {
panic("reflect: Value.SetIterKey called before Next")
@ -332,6 +333,7 @@ func (iter *MapIter) Value() Value {
// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value.
// As in Go, the value must be assignable to v's type and
// must not be derived from an unexported field.
// It panics if [Value.CanSet] returns false.
func (v Value) SetIterValue(iter *MapIter) {
if !iter.hiter.initialized() {
panic("reflect: Value.SetIterValue called before Next")

View File

@ -240,6 +240,7 @@ func (iter *MapIter) Key() Value {
// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value.
// As in Go, the key must be assignable to v's type and
// must not be derived from an unexported field.
// It panics if [Value.CanSet] returns false.
func (v Value) SetIterKey(iter *MapIter) {
if !iter.hiter.Initialized() {
panic("reflect: Value.SetIterKey called before Next")
@ -283,6 +284,7 @@ func (iter *MapIter) Value() Value {
// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value.
// As in Go, the value must be assignable to v's type and
// must not be derived from an unexported field.
// It panics if [Value.CanSet] returns false.
func (v Value) SetIterValue(iter *MapIter) {
if !iter.hiter.Initialized() {
panic("reflect: Value.SetIterValue called before Next")

View File

@ -2072,7 +2072,8 @@ func (v Value) SetBool(x bool) {
}
// SetBytes sets v's underlying value.
// It panics if v's underlying value is not a slice of bytes.
// It panics if v's underlying value is not a slice of bytes
// or if [Value.CanSet] returns false.
func (v Value) SetBytes(x []byte) {
v.mustBeAssignable()
v.mustBe(Slice)
@ -2083,7 +2084,8 @@ func (v Value) SetBytes(x []byte) {
}
// setRunes sets v's underlying value.
// It panics if v's underlying value is not a slice of runes (int32s).
// It panics if v's underlying value is not a slice of runes (int32s)
// or if [Value.CanSet] returns false.
func (v Value) setRunes(x []rune) {
v.mustBeAssignable()
v.mustBe(Slice)
@ -2094,7 +2096,8 @@ func (v Value) setRunes(x []rune) {
}
// SetComplex sets v's underlying value to x.
// It panics if v's Kind is not [Complex64] or [Complex128], or if [Value.CanSet] returns false.
// It panics if v's Kind is not [Complex64] or [Complex128],
// or if [Value.CanSet] returns false.
func (v Value) SetComplex(x complex128) {
v.mustBeAssignable()
switch k := v.kind(); k {
@ -2108,7 +2111,8 @@ func (v Value) SetComplex(x complex128) {
}
// SetFloat sets v's underlying value to x.
// It panics if v's Kind is not [Float32] or [Float64], or if [Value.CanSet] returns false.
// It panics if v's Kind is not [Float32] or [Float64],
// or if [Value.CanSet] returns false.
func (v Value) SetFloat(x float64) {
v.mustBeAssignable()
switch k := v.kind(); k {
@ -2122,7 +2126,8 @@ func (v Value) SetFloat(x float64) {
}
// SetInt sets v's underlying value to x.
// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64], or if [Value.CanSet] returns false.
// It panics if v's Kind is not [Int], [Int8], [Int16], [Int32], or [Int64],
// or if [Value.CanSet] returns false.
func (v Value) SetInt(x int64) {
v.mustBeAssignable()
switch k := v.kind(); k {
@ -2142,8 +2147,9 @@ func (v Value) SetInt(x int64) {
}
// SetLen sets v's length to n.
// It panics if v's Kind is not [Slice] or if n is negative or
// greater than the capacity of the slice.
// It panics if v's Kind is not [Slice], or if n is negative or
// greater than the capacity of the slice,
// or if [Value.CanSet] returns false.
func (v Value) SetLen(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
@ -2155,8 +2161,9 @@ func (v Value) SetLen(n int) {
}
// SetCap sets v's capacity to n.
// It panics if v's Kind is not [Slice] or if n is smaller than the length or
// greater than the capacity of the slice.
// It panics if v's Kind is not [Slice], or if n is smaller than the length or
// greater than the capacity of the slice,
// or if [Value.CanSet] returns false.
func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
@ -2168,7 +2175,8 @@ func (v Value) SetCap(n int) {
}
// SetUint sets v's underlying value to x.
// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64], or if [Value.CanSet] returns false.
// It panics if v's Kind is not [Uint], [Uintptr], [Uint8], [Uint16], [Uint32], or [Uint64],
// or if [Value.CanSet] returns false.
func (v Value) SetUint(x uint64) {
v.mustBeAssignable()
switch k := v.kind(); k {
@ -2190,7 +2198,8 @@ func (v Value) SetUint(x uint64) {
}
// SetPointer sets the [unsafe.Pointer] value v to x.
// It panics if v's Kind is not [UnsafePointer].
// It panics if v's Kind is not [UnsafePointer]
// or if [Value.CanSet] returns false.
func (v Value) SetPointer(x unsafe.Pointer) {
v.mustBeAssignable()
v.mustBe(UnsafePointer)
@ -2558,8 +2567,8 @@ func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Po
// another n elements. After Grow(n), at least n elements can be appended
// to the slice without another allocation.
//
// It panics if v's Kind is not a [Slice] or if n is negative or too large to
// allocate the memory.
// It panics if v's Kind is not a [Slice], or if n is negative or too large to
// allocate the memory, or if [Value.CanSet] returns false.
func (v Value) Grow(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
@ -2647,6 +2656,7 @@ func AppendSlice(s, t Value) Value {
// It returns the number of elements copied.
// Dst and src each must have kind [Slice] or [Array], and
// dst and src must have the same element type.
// It dst is an [Array], it panics if [Value.CanSet] returns false.
//
// As a special case, src can have kind [String] if the element type of dst is kind [Uint8].
func Copy(dst, src Value) int {

View File

@ -12,8 +12,29 @@ import (
// AddCleanup attaches a cleanup function to ptr. Some time after ptr is no longer
// reachable, the runtime will call cleanup(arg) in a separate goroutine.
//
// A typical use is that ptr is an object wrapping an underlying resource (e.g.,
// a File object wrapping an OS file descriptor), arg is the underlying resource
// (e.g., the OS file descriptor), and the cleanup function releases the underlying
// resource (e.g., by calling the close system call).
//
// There are few constraints on ptr. In particular, multiple cleanups may be
// attached to the same pointer, or to different pointers within the same
// allocation.
//
// If ptr is reachable from cleanup or arg, ptr will never be collected
// and the cleanup will never run. AddCleanup panics if arg is equal to ptr.
// and the cleanup will never run. As a protection against simple cases of this,
// AddCleanup panics if arg is equal to ptr.
//
// There is no specified order in which cleanups will run.
// In particular, if several objects point to each other and all become
// unreachable at the same time, their cleanups all become eligible to run
// and can run in any order. This is true even if the objects form a cycle.
//
// A single goroutine runs all cleanup calls for a program, sequentially. If a
// cleanup function must run for a long time, it should create a new goroutine.
//
// If ptr has both a cleanup and a finalizer, the cleanup will only run once
// it has been finalized and becomes unreachable without an associated finalizer.
//
// The cleanup(arg) call is not always guaranteed to run; in particular it is not
// guaranteed to run before program exit.
@ -22,14 +43,6 @@ import (
// it may share same address with other zero-size objects in memory. See
// https://go.dev/ref/spec#Size_and_alignment_guarantees.
//
// There is no specified order in which cleanups will run.
//
// A single goroutine runs all cleanup calls for a program, sequentially. If a
// cleanup function must run for a long time, it should create a new goroutine.
//
// If ptr has both a cleanup and a finalizer, the cleanup will only run once
// it has been finalized and becomes unreachable without an associated finalizer.
//
// It is not guaranteed that a cleanup will run for objects allocated
// in initializers for package-level variables. Such objects may be
// linker-allocated, not heap-allocated.
@ -41,6 +54,16 @@ import (
// allocation may never run if it always exists in the same batch as a
// referenced object. Typically, this batching only happens for tiny
// (on the order of 16 bytes or less) and pointer-free objects.
//
// A cleanup may run as soon as an object becomes unreachable.
// In order to use cleanups correctly, the program must ensure that
// the object is reachable until it is safe to run its cleanup.
// Objects stored in global variables, or that can be found by tracing
// pointers from a global variable, are reachable. A function argument or
// receiver may become unreachable at the last point where the function
// mentions it. To ensure a cleanup does not get called prematurely,
// pass the object to the [KeepAlive] function after the last point
// where the object must remain reachable.
func AddCleanup[T, S any](ptr *T, cleanup func(S), arg S) Cleanup {
// Explicitly force ptr to escape to the heap.
ptr = abi.Escape(ptr)

View File

@ -350,6 +350,9 @@ func blockUntilEmptyFinalizerQueue(timeout int64) bool {
//
// SetFinalizer(obj, nil) clears any finalizer associated with obj.
//
// New Go code should consider using [AddCleanup] instead, which is much
// less error-prone than SetFinalizer.
//
// The argument obj must be a pointer to an object allocated by calling
// new, by taking the address of a composite literal, or by taking the
// address of a local variable.

View File

@ -1839,7 +1839,7 @@ const (
type special struct {
_ sys.NotInHeap
next *special // linked list in span
offset uint16 // span offset of object
offset uintptr // span offset of object
kind byte // kind of special
}
@ -1886,7 +1886,7 @@ func addspecial(p unsafe.Pointer, s *special, force bool) bool {
iter, exists := span.specialFindSplicePoint(offset, kind)
if !exists || force {
// Splice in record, fill in offset.
s.offset = uint16(offset)
s.offset = offset
s.next = *iter
*iter = s
spanHasSpecials(span)

View File

@ -331,7 +331,7 @@ func (span *mspan) incPinCounter(offset uintptr) {
rec = (*specialPinCounter)(mheap_.specialPinCounterAlloc.alloc())
unlock(&mheap_.speciallock)
// splice in record, fill in offset.
rec.special.offset = uint16(offset)
rec.special.offset = offset
rec.special.kind = _KindSpecialPinCounter
rec.special.next = *ref
*ref = (*special)(unsafe.Pointer(rec))

View File

@ -12,7 +12,6 @@ var labelSync uintptr
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/cloudwego/localsession
// - github.com/DataDog/datadog-agent
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
@ -47,7 +46,6 @@ func runtime_setProfLabel(labels unsafe.Pointer) {
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
// - github.com/cloudwego/localsession
// - github.com/DataDog/datadog-agent
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.

View File

@ -118,11 +118,16 @@ func (ci *Frames) Next() (frame Frame, more bool) {
}
f := funcInfo._Func()
entry := f.Entry()
// We store the pc of the start of the instruction following
// the instruction in question (the call or the inline mark).
// This is done for historical reasons, and to make FuncForPC
// work correctly for entries in the result of runtime.Callers.
// Decrement to get back to the instruction we care about.
//
// It is not possible to get pc == entry from runtime.Callers,
// but if the caller does provide one, provide best-effort
// results by avoiding backing out of the function entirely.
if pc > entry {
// We store the pc of the start of the instruction following
// the instruction in question (the call or the inline mark).
// This is done for historical reasons, and to make FuncForPC
// work correctly for entries in the result of runtime.Callers.
pc--
}
// It's important that interpret pc non-strictly as cgoTraceback may

View File

@ -1370,15 +1370,19 @@ func badTimer() {
// to send a value to its associated channel. If so, it does.
// The timer must not be locked.
func (t *timer) maybeRunChan() {
if sg := getg().syncGroup; sg != nil || t.isFake {
if t.isFake {
t.lock()
var timerGroup *synctestGroup
if t.ts != nil {
timerGroup = t.ts.syncGroup
}
t.unlock()
if sg == nil || !t.isFake || sg != timerGroup {
panic(plainError("timer moved between synctest groups"))
sg := getg().syncGroup
if sg == nil {
panic(plainError("synctest timer accessed from outside bubble"))
}
if timerGroup != nil && sg != timerGroup {
panic(plainError("timer moved between synctest bubbles"))
}
// No need to do anything here.
// synctest.Run will run the timer when it advances its fake clock.

View File

@ -124,7 +124,7 @@ func Setenv(key, value string) error {
}
func Clearenv() {
envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
envOnce.Do(copyenv)
envLock.Lock()
defer envLock.Unlock()

View File

@ -3,30 +3,7 @@
// license that can be found in the LICENSE file.
/*
Package weak provides weak pointers with the goal of memory efficiency.
The primary use-cases for weak pointers are for implementing caches,
canonicalization maps (like the unique package), and for tying together
the lifetimes of separate values (for example, through a map with weak
keys).
# Advice
This package is intended to target niche use-cases like the unique
package, and the structures inside are not intended to be general
replacements for regular Go pointers, maps, etc.
Misuse of the structures in this package may generate unexpected and
hard-to-reproduce bugs.
Using the facilities in this package to try and resolve out-of-memory
issues requires careful consideration, and even so, will likely be the
wrong answer if the solution does not fall into one of the listed
use-cases above.
The structures in this package are intended to be an implementation
detail of the package they are used by (again, see the unique package).
If you're writing a package intended to be used by others, as a rule of
thumb, avoid exposing the behavior of any weak structures in your package's
API.
Doing so will almost certainly make your package more difficult to use
correctly.
Package weak provides ways to safely reference memory weakly,
that is, without preventing its reclamation.
*/
package weak

View File

@ -12,11 +12,21 @@ import (
// Pointer is a weak pointer to a value of type T.
//
// Two Pointer values compare equal if the pointers
// that they were created from compare equal. This property is retained even
// after the object referenced by the pointer used to create a weak reference
// is reclaimed.
// Just like regular pointers, Pointer may reference any part of an
// object, such as the field of a struct or an element of an array.
// Objects that are only pointed to by weak pointers are not considered
// reachable and once the object becomes unreachable [Pointer.Value]
// may return nil.
//
// The primary use-cases for weak pointers are for implementing caches,
// canonicalization maps (like the unique package), and for tying together
// the lifetimes of separate values (for example, through a map with weak
// keys).
//
// Two Pointer values always compare equal if the pointers that they were
// created from compare equal. This property is retained even after the
// object referenced by the pointer used to create a weak reference is
// reclaimed.
// If multiple weak pointers are made to different offsets within same object
// (for example, pointers to different fields of the same struct), those pointers
// will not compare equal.
@ -24,14 +34,32 @@ import (
// then resurrected due to a finalizer, that weak pointer will not compare equal
// with weak pointers created after resurrection.
//
// Calling Make with a nil pointer returns a weak pointer whose Value method
// Calling [Make] with a nil pointer returns a weak pointer whose [Pointer.Value]
// always returns nil. The zero value of a Pointer behaves as if it was created
// by passing nil to Make and compares equal with such pointers.
// by passing nil to [Make] and compares equal with such pointers.
//
// [Pointer.Value] is not guaranteed to eventually return nil.
// [Pointer.Value] may return nil as soon as the object becomes
// unreachable.
// Values stored in global variables, or that can be found by tracing
// pointers from a global variable, are reachable. A function argument or
// receiver may become unreachable at the last point where the function
// mentions it. To ensure [Pointer.Value] does not return nil,
// pass a pointer to the object to the [runtime.KeepAlive] function after
// the last point where the object must remain reachable.
//
// Note that because [Pointer.Value] is not guaranteed to eventually return
// nil, even after an object is no longer referenced, the runtime is allowed to
// perform a space-saving optimization that batches objects together in a single
// allocation slot. The weak pointer for an unreferenced object in such an
// allocation may never be called if it always exists in the same batch as a
// referenced object. Typically, this batching only happens for tiny
// (on the order of 16 bytes or less) and pointer-free objects.
type Pointer[T any] struct {
u unsafe.Pointer
}
// Make creates a weak pointer from a strong pointer to some value of type T.
// Make creates a weak pointer from a pointer to some value of type T.
func Make[T any](ptr *T) Pointer[T] {
// Explicitly force ptr to escape to the heap.
ptr = abi.Escape(ptr)

View File

@ -43,9 +43,11 @@ func TestPointer(t *testing.T) {
func TestPointerEquality(t *testing.T) {
bt := make([]*T, 10)
wt := make([]weak.Pointer[T], 10)
wo := make([]weak.Pointer[int], 10)
for i := range bt {
bt[i] = new(T)
wt[i] = weak.Make(bt[i])
wo[i] = weak.Make(&bt[i].a)
}
for i := range bt {
st := wt[i].Value()
@ -55,6 +57,9 @@ func TestPointerEquality(t *testing.T) {
if wp := weak.Make(st); wp != wt[i] {
t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
}
if wp := weak.Make(&st.a); wp != wo[i] {
t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
}
if i == 0 {
continue
}
@ -72,6 +77,9 @@ func TestPointerEquality(t *testing.T) {
if wp := weak.Make(st); wp != wt[i] {
t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wt[i])
}
if wp := weak.Make(&st.a); wp != wo[i] {
t.Fatalf("new weak pointer not equal to existing weak pointer: %v vs. %v", wp, wo[i])
}
if i == 0 {
continue
}
@ -210,3 +218,12 @@ func TestIssue69210(t *testing.T) {
}
wg.Wait()
}
func TestIssue70739(t *testing.T) {
x := make([]*int, 4<<16)
wx1 := weak.Make(&x[1<<16])
wx2 := weak.Make(&x[1<<16])
if wx1 != wx2 {
t.Fatal("failed to look up special and made duplicate weak handle; see issue #70739")
}
}