Compare commits

...

6 Commits

Author SHA1 Message Date
Filip Petkovski a68998afc7
Merge 360edca70a into 49cdf0c42e 2025-06-20 15:32:00 -04:00
Damien Neil 49cdf0c42e testing, testing/synctest: handle T.Helper in synctest bubbles
Fixes #74199

Change-Id: I6a15fbd59a3a3f8c496440f56d09d695e1504e4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/682576
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
2025-06-20 12:29:58 -07:00
cuishuang 3bf1eecbd3 runtime: fix struct comment
Change-Id: I0c33830b13c8a187ac82504c7653abb8f8cf7530
Reviewed-on: https://go-review.googlesource.com/c/go/+/681655
Reviewed-by: Sean Liao <sean@liao.dev>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Sean Liao <sean@liao.dev>
2025-06-20 11:28:03 -07:00
Sean Liao 8ed23a2936 crypto/cipher: fix link to crypto/aes
Fixes #74309

Change-Id: I4d97514355d825124a8d879c2590b45b039f5fd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/682596
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-06-20 11:09:26 -07:00
Adam Bender ef60769b46 go/doc: add a golden test that reproduces #62640
For #62640.
For #61394.

This is a copy of https://go-review.googlesource.com/c/go/+/528402,
which has stalled in review and the owner is no longer working on Go.

Change-Id: Ic7a1ae65c70d4857ab1061ccae1a926bf5c4ff55
Reviewed-on: https://go-review.googlesource.com/c/go/+/681235
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
2025-06-20 10:05:12 -07:00
Filip Petkovski 360edca70a
encoding/json/jsontext: fix Decoder.Reset to preserve internal buffer capacity
The Decoder.Reset method is not preserving the internal buffer between resets,
causing buffer capacity to be lost and resulting in unnecessary allocations
when reusing decoders.
This is particularly problematic when decoding many small messages.

This commit fixes the Reset method to preserve the internal buffer. It makes sure
aliasing is removed if the buffer currently points to an internal byte slice of a bytes.Buffer.
It adds a TestDecoderReset test structured into subtests to better validate the different scenarios.
2025-06-16 12:33:49 +02:00
11 changed files with 210 additions and 4 deletions

View File

@ -82,7 +82,7 @@ func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
// NewGCMWithRandomNonce returns the given cipher wrapped in Galois Counter
// Mode, with randomly-generated nonces. The cipher must have been created by
// [aes.NewCipher].
// [crypto/aes.NewCipher].
//
// It generates a random 96-bit nonce, which is prepended to the ciphertext by Seal,
// and is extracted from the ciphertext by Open. The NonceSize of the AEAD is zero,

View File

@ -138,7 +138,14 @@ func (d *Decoder) Reset(r io.Reader, opts ...Options) {
case d.s.Flags.Get(jsonflags.WithinArshalCall):
panic("jsontext: cannot reset Decoder passed to json.UnmarshalerFrom")
}
d.s.reset(nil, r, opts...)
// If the decoder was previously aliasing a bytes.Buffer,
// invalidate the alias to avoid writing into the bytes.Buffer's
// internal buffer.
b := d.s.buf[:0]
if _, ok := d.s.rd.(*bytes.Buffer); ok {
b = nil // avoid reusing b since it aliases the previous bytes.Buffer.
}
d.s.reset(b, r, opts...)
}
func (d *decoderState) reset(b []byte, r io.Reader, opts ...Options) {

View File

@ -1265,3 +1265,86 @@ func TestPeekableDecoder(t *testing.T) {
}
}
}
// TestDecoderReset tests that the decoder preserves its internal
// buffer between Reset calls to avoid frequent allocations when reusing the decoder.
// It ensures that the buffer capacity is maintained while avoiding aliasing
// issues with bytes.Buffer.
func TestDecoderReset(t *testing.T) {
// Create a decoder with a reasonably large JSON input to ensure buffer growth
largeJSON := `{"key1":"value1","key2":"value2","key3":"value3","key4":"value4","key5":"value5"}`
dec := NewDecoder(strings.NewReader(largeJSON))
t.Run("Test capacity preservation", func(t *testing.T) {
// Read the first JSON value to grow the internal buffer
val1, err := dec.ReadValue()
if err != nil {
t.Fatalf("first ReadValue failed: %v", err)
}
if string(val1) != largeJSON {
t.Fatalf("first ReadValue = %q, want %q", val1, largeJSON)
}
// Get the buffer capacity after first use
initialCapacity := cap(dec.s.buf)
if initialCapacity == 0 {
t.Fatalf("expected non-zero buffer capacity after first use")
}
// Reset with a new reader - this should preserve the buffer capacity
dec.Reset(strings.NewReader(largeJSON))
// Verify the buffer capacity is preserved (or at least not smaller)
preservedCapacity := cap(dec.s.buf)
if preservedCapacity < initialCapacity {
t.Fatalf("buffer capacity reduced after Reset: got %d, want at least %d", preservedCapacity, initialCapacity)
}
// Read the second JSON value to ensure the decoder still works correctly
val2, err := dec.ReadValue()
if err != nil {
t.Fatalf("second ReadValue failed: %v", err)
}
if string(val2) != largeJSON {
t.Fatalf("second ReadValue = %q, want %q", val2, largeJSON)
}
})
var bbBuf []byte
t.Run("Test aliasing with bytes.Buffer", func(t *testing.T) {
// Test with bytes.Buffer to verify proper aliasing behavior.
bb := bytes.NewBufferString(largeJSON)
dec.Reset(bb)
bbBuf = bb.Bytes()
// Read the third JSON value to ensure functionality with bytes.Buffer
val3, err := dec.ReadValue()
if err != nil {
t.Fatalf("fourth ReadValue failed: %v", err)
}
if string(val3) != largeJSON {
t.Fatalf("fourth ReadValue = %q, want %q", val3, largeJSON)
}
// The decoder buffer should alias bytes.Buffer's internal buffer.
if len(dec.s.buf) == 0 || len(bbBuf) == 0 || &dec.s.buf[0] != &bbBuf[0] {
t.Fatalf("decoder buffer does not alias bytes.Buffer")
}
})
t.Run("Test aliasing removed after Reset", func(t *testing.T) {
// Reset with a new reader and verify the buffer is not aliased.
dec.Reset(strings.NewReader(largeJSON))
val4, err := dec.ReadValue()
if err != nil {
t.Fatalf("fifth ReadValue failed: %v", err)
}
if string(val4) != largeJSON {
t.Fatalf("fourth ReadValue = %q, want %q", val4, largeJSON)
}
// The decoder buffer should not alias the bytes.Buffer's internal buffer.
if len(dec.s.buf) == 0 || len(bbBuf) == 0 || &dec.s.buf[0] == &bbBuf[0] {
t.Fatalf("decoder buffer aliases bytes.Buffer")
}
})
}

22
src/go/doc/testdata/issue62640.0.golden vendored Normal file
View File

@ -0,0 +1,22 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}

22
src/go/doc/testdata/issue62640.1.golden vendored Normal file
View File

@ -0,0 +1,22 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}

25
src/go/doc/testdata/issue62640.2.golden vendored Normal file
View File

@ -0,0 +1,25 @@
//
PACKAGE issue62640
IMPORTPATH
testdata/issue62640
FILENAMES
testdata/issue62640.go
TYPES
//
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F()
//
type S struct {
E
F int
}
// F should be hidden within S because of the S.F field.
func (S) F()

15
src/go/doc/testdata/issue62640.go vendored Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue62640
type E struct{}
// F should be hidden within S because of the S.F field.
func (E) F() {}
type S struct {
E
F int
}

View File

@ -312,8 +312,10 @@ type heapArena struct {
// during marking.
pageSpecials [pagesPerArena / 8]uint8
// pageUseSpanDartboard is a bitmap that indicates which spans are
// heap spans and also gcUsesSpanDartboard.
// pageUseSpanInlineMarkBits is a bitmap where each bit corresponds
// to a span, as only spans one page in size can have inline mark bits.
// The bit indicates that the span has a spanInlineMarkBits struct
// stored directly at the top end of the span's memory.
pageUseSpanInlineMarkBits [pagesPerArena / 8]uint8
// checkmarks stores the debug.gccheckmark state. It is only

View File

@ -0,0 +1,15 @@
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package synctest_test
import "testing"
// helperLog is a t.Helper which logs.
// Since it is a helper, the log prefix should contain
// the caller's file, not helper_test.go.
func helperLog(t *testing.T, s string) {
t.Helper()
t.Log(s)
}

View File

@ -140,6 +140,18 @@ func TestRun(t *testing.T) {
})
}
func TestHelper(t *testing.T) {
runTest(t, []string{"-test.v"}, func() {
synctest.Test(t, func(t *testing.T) {
helperLog(t, "log in helper")
})
}, `^=== RUN TestHelper
synctest_test.go:.* log in helper
--- PASS: TestHelper.*
PASS
$`)
}
func wantPanic(t *testing.T, want string) {
if e := recover(); e != nil {
if got := fmt.Sprint(e); got != want {

View File

@ -1261,6 +1261,9 @@ func (c *common) Skipped() bool {
// When printing file and line information, that function will be skipped.
// Helper may be called simultaneously from multiple goroutines.
func (c *common) Helper() {
if c.isSynctest {
c = c.parent
}
c.mu.Lock()
defer c.mu.Unlock()
if c.helperPCs == nil {