aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@golang.org>2024-05-17 14:19:19 +0200
committerMichael Stapelberg <stapelberg@golang.org>2024-05-17 14:13:36 +0000
commit1d4293e052f6cb6f021eafba93c865de80274f5f (patch)
tree4739f613490bc60e74e3419c0ef55dee72df534f
parentef7418827c4e1f83e93779b9f244ad84d96a4d94 (diff)
downloadgolang-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.go18
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