proto: consistently use non-nil, zero-length []bytes for empty bytes strings
The fast-path decoder decodes zero-length repeated bytes values as
non-nil, zero-length []bytes. Do the same in the reflection decoder.
This isn't really a correctness issue, since there's no ambiguity about what a
nil entry in a [][]byte means. Still a good idea for consistency, and
retains v1 behavior.
Change-Id: Icd2cb726d14ff1f2b9f142e65756777a359971f3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/210257
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/proto/decode_gen.go b/proto/decode_gen.go
index 61d5f8a..c40c01d 100644
--- a/proto/decode_gen.go
+++ b/proto/decode_gen.go
@@ -167,7 +167,7 @@
if n < 0 {
return val, 0, wire.ParseError(n)
}
- return protoreflect.ValueOfBytes(append(([]byte)(nil), v...)), n, nil
+ return protoreflect.ValueOfBytes(append(emptyBuf[:], v...)), n, nil
case protoreflect.MessageKind:
if wtyp != wire.BytesType {
return val, 0, errUnknown
@@ -564,7 +564,7 @@
if n < 0 {
return 0, wire.ParseError(n)
}
- list.Append(protoreflect.ValueOfBytes(append(([]byte)(nil), v...)))
+ list.Append(protoreflect.ValueOfBytes(append(emptyBuf[:], v...)))
return n, nil
case protoreflect.MessageKind:
if wtyp != wire.BytesType {
@@ -598,3 +598,6 @@
return 0, errUnknown
}
}
+
+// We append to an empty array rather than a nil []byte to get non-nil zero-length byte slices.
+var emptyBuf [0]byte
diff --git a/proto/decode_test.go b/proto/decode_test.go
index a01da16..2c50dde 100644
--- a/proto/decode_test.go
+++ b/proto/decode_test.go
@@ -1773,6 +1773,22 @@
},
}
+func TestDecodeEmptyBytes(t *testing.T) {
+ // There's really nothing wrong with a nil entry in a [][]byte,
+ // but we take care to produce non-nil []bytes for zero-length
+ // byte strings, so test for it.
+ m := &testpb.TestAllTypes{}
+ b := pack.Message{
+ pack.Tag{45, pack.BytesType}, pack.Bytes(nil),
+ }.Marshal()
+ if err := proto.Unmarshal(b, m); err != nil {
+ t.Fatal(err)
+ }
+ if m.RepeatedBytes[0] == nil {
+ t.Errorf("unmarshaling repeated bytes field containing zero-length value: Got nil bytes, want non-nil")
+ }
+}
+
func build(m proto.Message, opts ...buildOpt) proto.Message {
for _, opt := range opts {
opt(m)