diff options
author | Michael Stapelberg <stapelberg@golang.org> | 2024-05-17 14:19:19 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@golang.org> | 2024-05-17 14:13:36 +0000 |
commit | 1d4293e052f6cb6f021eafba93c865de80274f5f (patch) | |
tree | 4739f613490bc60e74e3419c0ef55dee72df534f | |
parent | ef7418827c4e1f83e93779b9f244ad84d96a4d94 (diff) | |
download | golang-protobuf-upstream-master.tar.gz |
internal/impl: fix size cache semantics with lazy decodingupstream-master
When a message (within an extension) is lazily decoded, its size cache is
initialized to 0 (the zero value for an int32). This doesn’t mean the size cache
reads 0, but rather that it was not initialized.
This fixes TestExtensionGetRace being flaky since CL 580015.
related to golang/protobuf#1609
Change-Id: Ia305badadd300679975f230005c3e33c94050e4a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/586396
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
-rw-r--r-- | internal/impl/encode.go | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/internal/impl/encode.go b/internal/impl/encode.go index 7769a54e..febd2122 100644 --- a/internal/impl/encode.go +++ b/internal/impl/encode.go @@ -49,8 +49,11 @@ func (mi *MessageInfo) sizePointer(p pointer, opts marshalOptions) (size int) { return 0 } if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() { - if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size >= 0 { - return int(size) + // The size cache contains the size + 1, to allow the + // zero value to be invalid, while also allowing for a + // 0 size to be cached. + if size := atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()); size > 0 { + return int(size - 1) } } return mi.sizePointerSlow(p, opts) @@ -60,7 +63,7 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int if flags.ProtoLegacy && mi.isMessageSet { size = sizeMessageSet(mi, p, opts) if mi.sizecacheOffset.IsValid() { - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size+1)) } return size } @@ -84,13 +87,16 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int } } if mi.sizecacheOffset.IsValid() { - if size > math.MaxInt32 { + if size > (math.MaxInt32 - 1) { // The size is too large for the int32 sizecache field. // We will need to recompute the size when encoding; // unfortunately expensive, but better than invalid output. - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), -1) + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), 0) } else { - atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size)) + // The size cache contains the size + 1, to allow the + // zero value to be invalid, while also allowing for a + // 0 size to be cached. + atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size+1)) } } return size |