mirror of https://github.com/golang/go.git
[release-branch.go1.24] all: merge master (c93477b) into release-branch.go1.24
Merge List: + 2024-12-11c93477b5e5crypto: use provided random Reader in FIPS mode + 2024-12-113104b6adbblog/slog: make DiscardHandler example package-level + 2024-12-115424f2e200cmd/go: add more tests for GOAUTH's user provided authenticator + 2024-12-11d5c1333eb4net/http: document zero value of Protocols + 2024-12-11a7c4cadce0cmd/compile: update broken link + 2024-12-11979c1cfbe8net: avoid unnecessary interface lookup fetching all interface addresses + 2024-12-11e424d78c3dinternal/goos: fix bug in gengoos.go + 2024-12-116c25cf1c5fcmd/internal/objfile: break out dissassemblers to another package + 2024-12-11e0c76d95absyscall: remove a wrong comment in Clearenv + 2024-12-11a9922d096freflect: consistently document when value must be settable + 2024-12-104ce116a884runtime: avoid panic in expired synctest timer chan read + 2024-12-10e6de1b2debhtml/template: escape script tags in JS errors case insensitively + 2024-12-10fce17b0c77crypto/internal/fips140/ecdsa: fix reseed_counter check for HMAC_DRBG_Generate_algorithm + 2024-12-09d87878c62bruntime: make special offset a uintptr + 2024-12-096705ac6885runtime: remove datadog-agent from prof labels hall of shame + 2024-12-0907398d2e57weak: align weak.Pointer documentation with runtime.AddCleanup + 2024-12-09e3e1d73528bufio: make the description of Peek's behavior better + 2024-12-09e79b2e1e3acmd/go: document the build cache as safe for concurrent use + 2024-12-08c8fb6ae617lib/wasm: provide fs.constants.O_DIRECTORY definition + 2024-12-078c3e391573runtime: improve AddCleanup documentation + 2024-12-0704cdaa9984cmd/go: document c-shared buildmode for building WASI library/reactor + 2024-12-06312f7c1bd3runtime: add note that Callers never returns an entry PC Change-Id: I52e035228121de3d8219ab13f195d4293daaaa34
This commit is contained in:
commit
2297c34cdf
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue