mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-04-17 11:42:38 +00:00
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>
This commit is contained in:
parent
9f1165c3bf
commit
5366f825ad
@ -233,7 +233,7 @@ var ProtoKinds = []ProtoKind{
|
||||
{
|
||||
Name: "Bytes",
|
||||
WireType: WireBytes,
|
||||
ToValue: "protoreflect.ValueOfBytes(append(([]byte)(nil), v...))",
|
||||
ToValue: "protoreflect.ValueOfBytes(append(emptyBuf[:], v...))",
|
||||
FromValue: "v.Bytes()",
|
||||
GoType: GoBytes,
|
||||
ToGoType: "append(emptyBuf[:], v...)",
|
||||
@ -344,6 +344,9 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp wire.Type, list protorefl
|
||||
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
|
||||
`))
|
||||
|
||||
func generateProtoEncode() string {
|
||||
|
@ -4711,7 +4711,7 @@ func consumeBytesValue(b []byte, _ protoreflect.Value, _ wire.Number, wtyp wire.
|
||||
if n < 0 {
|
||||
return protoreflect.Value{}, 0, wire.ParseError(n)
|
||||
}
|
||||
return protoreflect.ValueOfBytes(append(([]byte)(nil), v...)), n, nil
|
||||
return protoreflect.ValueOfBytes(append(emptyBuf[:], v...)), n, nil
|
||||
}
|
||||
|
||||
var coderBytesValue = valueCoderFuncs{
|
||||
@ -4751,7 +4751,7 @@ func consumeBytesSliceValue(b []byte, listv protoreflect.Value, _ wire.Number, w
|
||||
if n < 0 {
|
||||
return protoreflect.Value{}, 0, wire.ParseError(n)
|
||||
}
|
||||
list.Append(protoreflect.ValueOfBytes(append(([]byte)(nil), v...)))
|
||||
list.Append(protoreflect.ValueOfBytes(append(emptyBuf[:], v...)))
|
||||
return listv, n, nil
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ func (o UnmarshalOptions) unmarshalScalar(b []byte, wtyp wire.Type, fd protorefl
|
||||
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 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp wire.Type, list protorefl
|
||||
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 @@ func (o UnmarshalOptions) unmarshalList(b []byte, wtyp wire.Type, list protorefl
|
||||
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
|
||||
|
@ -1773,6 +1773,22 @@ var invalidFieldNumberTestProtos = []struct {
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user