mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-02-10 12:39:48 +00:00
Hyrum's Law dictates that if we do not prevent naughty behavior, people will rely on it. If we do not validate that the provided file descriptor is correct today, it will be near impossible to add proper validation checks later on. The logic added validates that the provided file descriptor is correct according to the same semantics as protoc, which was reversed engineered to derive the set of rules implemented here. The rules are unfortunately complicated because protobuf is a language full of many non-orthogonal features. While our logic is complicated, it is still 1/7th the size of the equivalent C++ code! Change-Id: I6acc5dc3bd2e4c6bea6cd9e81214f8104402602a Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/184837 Reviewed-by: Damien Neil <dneil@google.com>
368 lines
14 KiB
Go
368 lines
14 KiB
Go
// Copyright 2018 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 pack
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"google.golang.org/protobuf/encoding/prototext"
|
|
pdesc "google.golang.org/protobuf/reflect/protodesc"
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
|
|
|
"google.golang.org/protobuf/types/descriptorpb"
|
|
)
|
|
|
|
var msgDesc = func() pref.MessageDescriptor {
|
|
const s = `
|
|
name: "test.proto"
|
|
syntax: "proto2"
|
|
message_type: [{
|
|
name: "Message"
|
|
field: [
|
|
{name:"f1" number:1 label:LABEL_REPEATED type:TYPE_BOOL options:{packed:true}},
|
|
{name:"f2" number:2 label:LABEL_REPEATED type:TYPE_INT64 options:{packed:true}},
|
|
{name:"f3" number:3 label:LABEL_REPEATED type:TYPE_SINT64 options:{packed:true}},
|
|
{name:"f4" number:4 label:LABEL_REPEATED type:TYPE_UINT64 options:{packed:true}},
|
|
{name:"f5" number:5 label:LABEL_REPEATED type:TYPE_FIXED32 options:{packed:true}},
|
|
{name:"f6" number:6 label:LABEL_REPEATED type:TYPE_SFIXED32 options:{packed:true}},
|
|
{name:"f7" number:7 label:LABEL_REPEATED type:TYPE_FLOAT options:{packed:true}},
|
|
{name:"f8" number:8 label:LABEL_REPEATED type:TYPE_FIXED64 options:{packed:true}},
|
|
{name:"f9" number:9 label:LABEL_REPEATED type:TYPE_SFIXED64 options:{packed:true}},
|
|
{name:"f10" number:10 label:LABEL_REPEATED type:TYPE_DOUBLE options:{packed:true}},
|
|
{name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_STRING},
|
|
{name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BYTES},
|
|
{name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".Message"},
|
|
{name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_GROUP type_name:".Message.F14"}
|
|
]
|
|
nested_type: [{name: "F14"}]
|
|
}]
|
|
`
|
|
pb := new(descriptorpb.FileDescriptorProto)
|
|
if err := prototext.Unmarshal([]byte(s), pb); err != nil {
|
|
panic(err)
|
|
}
|
|
fd, err := pdesc.NewFile(pb, nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return fd.Messages().Get(0)
|
|
}()
|
|
|
|
// dhex decodes a hex-string and returns the bytes and panics if s is invalid.
|
|
func dhex(s string) []byte {
|
|
b, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func TestPack(t *testing.T) {
|
|
nan32 := math.Float32frombits(0x7fc00000)
|
|
nan64 := math.Float64frombits(0x7FF8000000000001)
|
|
tests := []struct {
|
|
raw []byte
|
|
msg Message
|
|
|
|
wantOutCompact string
|
|
wantOutMulti string
|
|
wantOutSource string
|
|
}{{
|
|
raw: dhex("080088808080800002088280808080000a09010002828080808000"),
|
|
msg: Message{
|
|
Tag{1, VarintType}, Bool(false),
|
|
Denormalized{5, Tag{1, VarintType}}, Uvarint(2),
|
|
Tag{1, VarintType}, Denormalized{5, Uvarint(2)},
|
|
Tag{1, BytesType}, LengthPrefix{Bool(true), Bool(false), Uvarint(2), Denormalized{5, Uvarint(2)}},
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{1, pack.VarintType}, pack.Bool(false),
|
|
pack.Denormalized{+5, pack.Tag{1, pack.VarintType}}, pack.Uvarint(2),
|
|
pack.Tag{1, pack.VarintType}, pack.Denormalized{+5, pack.Uvarint(2)},
|
|
pack.Tag{1, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Uvarint(2), pack.Denormalized{+5, pack.Uvarint(2)}},
|
|
}`,
|
|
}, {
|
|
raw: dhex("100010828080808000121980808080808080808001ffffffffffffffff7f828080808000"),
|
|
msg: Message{
|
|
Tag{2, VarintType}, Varint(0),
|
|
Tag{2, VarintType}, Denormalized{5, Varint(2)},
|
|
Tag{2, BytesType}, LengthPrefix{Varint(math.MinInt64), Varint(math.MaxInt64), Denormalized{5, Varint(2)}},
|
|
},
|
|
wantOutCompact: `Message{Tag{2, Varint}, Varint(0), Tag{2, Varint}, Denormalized{+5, Varint(2)}, Tag{2, Bytes}, LengthPrefix{Varint(-9223372036854775808), Varint(9223372036854775807), Denormalized{+5, Varint(2)}}}`,
|
|
}, {
|
|
raw: dhex("1801188180808080001a1affffffffffffffffff01feffffffffffffffff01818080808000"),
|
|
msg: Message{
|
|
Tag{3, VarintType}, Svarint(-1),
|
|
Tag{3, VarintType}, Denormalized{5, Svarint(-1)},
|
|
Tag{3, BytesType}, LengthPrefix{Svarint(math.MinInt64), Svarint(math.MaxInt64), Denormalized{5, Svarint(-1)}},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{3, Varint}, Svarint(-1),
|
|
Tag{3, Varint}, Denormalized{+5, Svarint(-1)},
|
|
Tag{3, Bytes}, LengthPrefix{Svarint(-9223372036854775808), Svarint(9223372036854775807), Denormalized{+5, Svarint(-1)}},
|
|
}`,
|
|
}, {
|
|
raw: dhex("200120818080808000221100ffffffffffffffffff01818080808000"),
|
|
msg: Message{
|
|
Tag{4, VarintType}, Uvarint(+1),
|
|
Tag{4, VarintType}, Denormalized{5, Uvarint(+1)},
|
|
Tag{4, BytesType}, LengthPrefix{Uvarint(0), Uvarint(math.MaxUint64), Denormalized{5, Uvarint(+1)}},
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{4, pack.VarintType}, pack.Uvarint(1),
|
|
pack.Tag{4, pack.VarintType}, pack.Denormalized{+5, pack.Uvarint(1)},
|
|
pack.Tag{4, pack.BytesType}, pack.LengthPrefix{pack.Uvarint(0), pack.Uvarint(18446744073709551615), pack.Denormalized{+5, pack.Uvarint(1)}},
|
|
}`,
|
|
}, {
|
|
raw: dhex("2d010000002a0800000000ffffffff"),
|
|
msg: Message{
|
|
Tag{5, Fixed32Type}, Uint32(+1),
|
|
Tag{5, BytesType}, LengthPrefix{Uint32(0), Uint32(math.MaxUint32)},
|
|
},
|
|
wantOutCompact: `Message{Tag{5, Fixed32}, Uint32(1), Tag{5, Bytes}, LengthPrefix{Uint32(0), Uint32(4294967295)}}`,
|
|
}, {
|
|
raw: dhex("35ffffffff320800000080ffffff7f"),
|
|
msg: Message{
|
|
Tag{6, Fixed32Type}, Int32(-1),
|
|
Tag{6, BytesType}, LengthPrefix{Int32(math.MinInt32), Int32(math.MaxInt32)},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{6, Fixed32}, Int32(-1),
|
|
Tag{6, Bytes}, LengthPrefix{Int32(-2147483648), Int32(2147483647)},
|
|
}`,
|
|
}, {
|
|
raw: dhex("3ddb0f49403a1401000000ffff7f7f0000c07f0000807f000080ff"),
|
|
msg: Message{
|
|
Tag{7, Fixed32Type}, Float32(math.Pi),
|
|
Tag{7, BytesType}, LengthPrefix{Float32(math.SmallestNonzeroFloat32), Float32(math.MaxFloat32), Float32(nan32), Float32(math.Inf(+1)), Float32(math.Inf(-1))},
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{7, pack.Fixed32Type}, pack.Float32(3.1415927),
|
|
pack.Tag{7, pack.BytesType}, pack.LengthPrefix{pack.Float32(1e-45), pack.Float32(3.4028235e+38), pack.Float32(math.NaN()), pack.Float32(math.Inf(+1)), pack.Float32(math.Inf(-1))},
|
|
}`,
|
|
}, {
|
|
raw: dhex("41010000000000000042100000000000000000ffffffffffffffff"),
|
|
msg: Message{
|
|
Tag{8, Fixed64Type}, Uint64(+1),
|
|
Tag{8, BytesType}, LengthPrefix{Uint64(0), Uint64(math.MaxUint64)},
|
|
},
|
|
wantOutCompact: `Message{Tag{8, Fixed64}, Uint64(1), Tag{8, Bytes}, LengthPrefix{Uint64(0), Uint64(18446744073709551615)}}`,
|
|
}, {
|
|
raw: dhex("49ffffffffffffffff4a100000000000000080ffffffffffffff7f"),
|
|
msg: Message{
|
|
Tag{9, Fixed64Type}, Int64(-1),
|
|
Tag{9, BytesType}, LengthPrefix{Int64(math.MinInt64), Int64(math.MaxInt64)},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{9, Fixed64}, Int64(-1),
|
|
Tag{9, Bytes}, LengthPrefix{Int64(-9223372036854775808), Int64(9223372036854775807)},
|
|
}`,
|
|
}, {
|
|
raw: dhex("51182d4454fb21094052280100000000000000ffffffffffffef7f010000000000f87f000000000000f07f000000000000f0ff"),
|
|
msg: Message{
|
|
Tag{10, Fixed64Type}, Float64(math.Pi),
|
|
Tag{10, BytesType}, LengthPrefix{Float64(math.SmallestNonzeroFloat64), Float64(math.MaxFloat64), Float64(nan64), Float64(math.Inf(+1)), Float64(math.Inf(-1))},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{10, Fixed64}, Float64(3.141592653589793),
|
|
Tag{10, Bytes}, LengthPrefix{Float64(5e-324), Float64(1.7976931348623157e+308), Float64(NaN), Float64(+Inf), Float64(-Inf)},
|
|
}`,
|
|
}, {
|
|
raw: dhex("5a06737472696e675a868080808000737472696e67"),
|
|
msg: Message{
|
|
Tag{11, BytesType}, String("string"),
|
|
Tag{11, BytesType}, Denormalized{+5, String("string")},
|
|
},
|
|
wantOutCompact: `Message{Tag{11, Bytes}, String("string"), Tag{11, Bytes}, Denormalized{+5, String("string")}}`,
|
|
}, {
|
|
raw: dhex("62056279746573628580808080006279746573"),
|
|
msg: Message{
|
|
Tag{12, BytesType}, Bytes("bytes"),
|
|
Tag{12, BytesType}, Denormalized{+5, Bytes("bytes")},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{12, Bytes}, Bytes("bytes"),
|
|
Tag{12, Bytes}, Denormalized{+5, Bytes("bytes")},
|
|
}`,
|
|
}, {
|
|
raw: dhex("6a28a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
|
|
msg: Message{
|
|
Tag{13, BytesType}, LengthPrefix(Message{
|
|
Tag{100, VarintType}, Uvarint(math.MaxUint64),
|
|
Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
|
|
Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
|
|
Tag{100, BytesType}, Bytes("bytes"),
|
|
Tag{100, StartGroupType}, Tag{100, EndGroupType},
|
|
}),
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{13, pack.BytesType}, pack.LengthPrefix(pack.Message{
|
|
pack.Tag{100, pack.VarintType}, pack.Uvarint(18446744073709551615),
|
|
pack.Tag{100, pack.Fixed32Type}, pack.Uint32(4294967295),
|
|
pack.Tag{100, pack.Fixed64Type}, pack.Uint64(18446744073709551615),
|
|
pack.Tag{100, pack.BytesType}, pack.Bytes("bytes"),
|
|
pack.Tag{100, pack.StartGroupType},
|
|
pack.Tag{100, pack.EndGroupType},
|
|
}),
|
|
}`,
|
|
}, {
|
|
raw: dhex("6aa88080808000a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
|
|
msg: Message{
|
|
Tag{13, BytesType}, Denormalized{5, LengthPrefix(Message{
|
|
Tag{100, VarintType}, Uvarint(math.MaxUint64),
|
|
Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
|
|
Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
|
|
Tag{100, BytesType}, Bytes("bytes"),
|
|
Tag{100, StartGroupType}, Tag{100, EndGroupType},
|
|
})},
|
|
},
|
|
wantOutCompact: `Message{Tag{13, Bytes}, Denormalized{+5, LengthPrefix(Message{Tag{100, Varint}, Uvarint(18446744073709551615), Tag{100, Fixed32}, Uint32(4294967295), Tag{100, Fixed64}, Uint64(18446744073709551615), Tag{100, Bytes}, Bytes("bytes"), Tag{100, StartGroup}, Tag{100, EndGroup}})}}`,
|
|
}, {
|
|
raw: dhex("73a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a40674"),
|
|
msg: Message{
|
|
Tag{14, StartGroupType}, Message{
|
|
Tag{100, VarintType}, Uvarint(math.MaxUint64),
|
|
Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
|
|
Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
|
|
Tag{100, BytesType}, Bytes("bytes"),
|
|
Tag{100, StartGroupType}, Tag{100, EndGroupType},
|
|
},
|
|
Tag{14, EndGroupType},
|
|
},
|
|
wantOutMulti: `Message{
|
|
Tag{14, StartGroup},
|
|
Message{
|
|
Tag{100, Varint}, Uvarint(18446744073709551615),
|
|
Tag{100, Fixed32}, Uint32(4294967295),
|
|
Tag{100, Fixed64}, Uint64(18446744073709551615),
|
|
Tag{100, Bytes}, Bytes("bytes"),
|
|
Tag{100, StartGroup},
|
|
Tag{100, EndGroup},
|
|
},
|
|
Tag{14, EndGroup},
|
|
}`,
|
|
}, {
|
|
raw: dhex("d0faa972cd02a5f09051c2d8aa0d6a26a89c311eddef024b423c0f6f47b64227a1600db56e3f73d4113096c9a88e2b99f2d847516853d76a1a6e9811c85a2ab3"),
|
|
msg: Message{
|
|
Tag{29970346, VarintType}, Uvarint(333),
|
|
Tag{21268228, Fixed32Type}, Uint32(229300418),
|
|
Tag{13, BytesType}, LengthPrefix(Message{
|
|
Tag{100805, VarintType}, Uvarint(30),
|
|
Tag{5883, Fixed32Type}, Uint32(255607371),
|
|
Tag{13, Type(7)},
|
|
Raw("G\xb6B'\xa1`\r\xb5n?s\xd4\x110\x96ɨ\x8e+\x99\xf2\xd8GQhS"),
|
|
}),
|
|
Tag{1706, Type(7)},
|
|
Raw("\x1an\x98\x11\xc8Z*\xb3"),
|
|
},
|
|
}, {
|
|
raw: dhex("3d08d0e57f"),
|
|
msg: Message{
|
|
Tag{7, Fixed32Type}, Float32(math.Float32frombits(
|
|
// TODO: Remove workaround for compiler bug (see https://golang.org/issues/27193).
|
|
func() uint32 { return 0x7fe5d008 }(),
|
|
)),
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{7, pack.Fixed32Type}, pack.Float32(math.Float32frombits(0x7fe5d008)),
|
|
}`,
|
|
}, {
|
|
raw: dhex("51a8d65110771bf97f"),
|
|
msg: Message{
|
|
Tag{10, Fixed64Type}, Float64(math.Float64frombits(0x7ff91b771051d6a8)),
|
|
},
|
|
wantOutSource: `pack.Message{
|
|
pack.Tag{10, pack.Fixed64Type}, pack.Float64(math.Float64frombits(0x7ff91b771051d6a8)),
|
|
}`,
|
|
}, {
|
|
raw: dhex("ab2c14481ab3e9a76d937fb4dd5e6c616ef311f62b7fe888785fca5609ffe81c1064e50dd7a9edb408d317e2891c0d54c719446938d41ab0ccf8e61dc28b0ebb"),
|
|
msg: Message{
|
|
Tag{709, StartGroupType},
|
|
Tag{2, EndGroupType},
|
|
Tag{9, VarintType}, Uvarint(26),
|
|
Tag{28655254, StartGroupType},
|
|
Message{
|
|
Tag{2034, StartGroupType},
|
|
Tag{194006, EndGroupType},
|
|
},
|
|
Tag{13, EndGroupType},
|
|
Tag{12, Fixed64Type}, Uint64(9865274810543764334),
|
|
Tag{15, VarintType}, Uvarint(95),
|
|
Tag{1385, BytesType}, Bytes("\xff\xe8\x1c\x10d\xe5\rש"),
|
|
Tag{17229, Fixed32Type}, Uint32(2313295827),
|
|
Tag{3, EndGroupType},
|
|
Tag{1, Fixed32Type}, Uint32(1142540116),
|
|
Tag{13, Fixed64Type}, Uint64(2154683029754926136),
|
|
Tag{28856, BytesType},
|
|
Raw("\xbb"),
|
|
},
|
|
}, {
|
|
raw: dhex("29baa4ac1c1e0a20183393bac434b8d3559337ec940050038770eaa9937f98e4"),
|
|
msg: Message{
|
|
Tag{5, Fixed64Type}, Uint64(1738400580611384506),
|
|
Tag{6, StartGroupType},
|
|
Message{
|
|
Tag{13771682, StartGroupType},
|
|
Message{
|
|
Tag{175415, VarintType}, Uvarint(7059),
|
|
},
|
|
Denormalized{+1, Tag{333, EndGroupType}},
|
|
Tag{10, VarintType}, Uvarint(3),
|
|
Tag{1792, Type(7)},
|
|
Raw("꩓\u007f\x98\xe4"),
|
|
},
|
|
},
|
|
}}
|
|
|
|
equateFloatBits := cmp.Options{
|
|
cmp.Comparer(func(x, y Float32) bool {
|
|
return math.Float32bits(float32(x)) == math.Float32bits(float32(y))
|
|
}),
|
|
cmp.Comparer(func(x, y Float64) bool {
|
|
return math.Float64bits(float64(x)) == math.Float64bits(float64(y))
|
|
}),
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
var msg Message
|
|
raw := tt.msg.Marshal()
|
|
msg.UnmarshalDescriptor(tt.raw, msgDesc)
|
|
|
|
if !bytes.Equal(raw, tt.raw) {
|
|
t.Errorf("Marshal() mismatch:\ngot %x\nwant %x", raw, tt.raw)
|
|
}
|
|
if !cmp.Equal(msg, tt.msg, equateFloatBits) {
|
|
t.Errorf("Unmarshal() mismatch:\ngot %+v\nwant %+v", msg, tt.msg)
|
|
}
|
|
if got, want := tt.msg.Size(), len(tt.raw); got != want {
|
|
t.Errorf("Size() = %v, want %v", got, want)
|
|
}
|
|
if tt.wantOutCompact != "" {
|
|
gotOut := fmt.Sprintf("%v", tt.msg)
|
|
if string(gotOut) != tt.wantOutCompact {
|
|
t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%v", gotOut, tt.wantOutCompact)
|
|
}
|
|
}
|
|
if tt.wantOutMulti != "" {
|
|
gotOut := fmt.Sprintf("%+v", tt.msg)
|
|
if string(gotOut) != tt.wantOutMulti {
|
|
t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%+v", gotOut, tt.wantOutMulti)
|
|
}
|
|
}
|
|
if tt.wantOutSource != "" {
|
|
gotOut := fmt.Sprintf("%#v", tt.msg)
|
|
if string(gotOut) != tt.wantOutSource {
|
|
t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%#v", gotOut, tt.wantOutSource)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|