mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-02-05 15:40:09 +00:00
proto: add decoding fuzz test for proto3 to editions conversion
Change-Id: Ic2536373eeb5c814059ddf5c7c0d675d0e06153c Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/564817 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Stapelberg <stapelberg@google.com> Auto-Submit: Lasse Folger <lassefolger@google.com>
This commit is contained in:
parent
8f6a6615d6
commit
5e8da94149
1636
internal/testprotos/editionsfuzztest/test3.pb.go
Normal file
1636
internal/testprotos/editionsfuzztest/test3.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
125
internal/testprotos/editionsfuzztest/test3.proto
Normal file
125
internal/testprotos/editionsfuzztest/test3.proto
Normal file
@ -0,0 +1,125 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package goproto.proto.test;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/editionsfuzztest";
|
||||
|
||||
message TestAllTypesProto3 {
|
||||
message NestedMessage {
|
||||
int32 a = 1;
|
||||
TestAllTypesProto3 corecursive = 2;
|
||||
}
|
||||
|
||||
enum NestedEnum {
|
||||
FOO = 0;
|
||||
BAR = 1;
|
||||
BAZ = 2;
|
||||
NEG = -1; // Intentionally negative.
|
||||
}
|
||||
|
||||
int32 singular_int32 = 81;
|
||||
int64 singular_int64 = 82;
|
||||
uint32 singular_uint32 = 83;
|
||||
uint64 singular_uint64 = 84;
|
||||
sint32 singular_sint32 = 85;
|
||||
sint64 singular_sint64 = 86;
|
||||
fixed32 singular_fixed32 = 87;
|
||||
fixed64 singular_fixed64 = 88;
|
||||
sfixed32 singular_sfixed32 = 89;
|
||||
sfixed64 singular_sfixed64 = 90;
|
||||
float singular_float = 91;
|
||||
double singular_double = 92;
|
||||
bool singular_bool = 93;
|
||||
string singular_string = 94;
|
||||
bytes singular_bytes = 95;
|
||||
NestedMessage singular_nested_message = 98;
|
||||
ForeignMessageProto3 singular_foreign_message = 99;
|
||||
NestedEnum singular_nested_enum = 101;
|
||||
ForeignEnumProto3 singular_foreign_enum = 102;
|
||||
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional sint32 optional_sint32 = 5;
|
||||
optional sint64 optional_sint64 = 6;
|
||||
optional fixed32 optional_fixed32 = 7;
|
||||
optional fixed64 optional_fixed64 = 8;
|
||||
optional sfixed32 optional_sfixed32 = 9;
|
||||
optional sfixed64 optional_sfixed64 = 10;
|
||||
optional float optional_float = 11;
|
||||
optional double optional_double = 12;
|
||||
optional bool optional_bool = 13;
|
||||
optional string optional_string = 14;
|
||||
optional bytes optional_bytes = 15;
|
||||
optional NestedMessage optional_nested_message = 18;
|
||||
optional ForeignMessageProto3 optional_foreign_message = 19;
|
||||
optional NestedEnum optional_nested_enum = 21;
|
||||
optional ForeignEnumProto3 optional_foreign_enum = 22;
|
||||
|
||||
repeated int32 repeated_int32 = 31;
|
||||
repeated int64 repeated_int64 = 32;
|
||||
repeated uint32 repeated_uint32 = 33;
|
||||
repeated uint64 repeated_uint64 = 34;
|
||||
repeated sint32 repeated_sint32 = 35;
|
||||
repeated sint64 repeated_sint64 = 36;
|
||||
repeated fixed32 repeated_fixed32 = 37;
|
||||
repeated fixed64 repeated_fixed64 = 38;
|
||||
repeated sfixed32 repeated_sfixed32 = 39;
|
||||
repeated sfixed64 repeated_sfixed64 = 40;
|
||||
repeated float repeated_float = 41;
|
||||
repeated double repeated_double = 42;
|
||||
repeated bool repeated_bool = 43;
|
||||
repeated string repeated_string = 44;
|
||||
repeated bytes repeated_bytes = 45;
|
||||
repeated NestedMessage repeated_nested_message = 48;
|
||||
repeated ForeignMessageProto3 repeated_foreign_message = 49;
|
||||
repeated NestedEnum repeated_nested_enum = 51;
|
||||
repeated ForeignEnumProto3 repeated_foreign_enum = 52;
|
||||
|
||||
map<int32, int32> map_int32_int32 = 56;
|
||||
map<int64, int64> map_int64_int64 = 57;
|
||||
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||
map<int32, float> map_int32_float = 66;
|
||||
map<int32, double> map_int32_double = 67;
|
||||
map<bool, bool> map_bool_bool = 68;
|
||||
map<string, string> map_string_string = 69;
|
||||
map<string, bytes> map_string_bytes = 70;
|
||||
map<string, NestedMessage> map_string_nested_message = 71;
|
||||
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||
|
||||
oneof oneof_field {
|
||||
uint32 oneof_uint32 = 111;
|
||||
NestedMessage oneof_nested_message = 112;
|
||||
string oneof_string = 113;
|
||||
bytes oneof_bytes = 114;
|
||||
bool oneof_bool = 115;
|
||||
uint64 oneof_uint64 = 116;
|
||||
float oneof_float = 117;
|
||||
double oneof_double = 118;
|
||||
NestedEnum oneof_enum = 119;
|
||||
}
|
||||
}
|
||||
|
||||
message ForeignMessageProto3 {
|
||||
int32 c = 1;
|
||||
int32 d = 2;
|
||||
}
|
||||
|
||||
enum ForeignEnumProto3 {
|
||||
FOREIGN_PROTO3_ZERO = 0;
|
||||
FOREIGN_PROTO3_FOO = 4;
|
||||
FOREIGN_PROTO3_BAR = 5;
|
||||
FOREIGN_PROTO3_BAZ = 6;
|
||||
}
|
1634
internal/testprotos/editionsfuzztest/test3editions.pb.go
Normal file
1634
internal/testprotos/editionsfuzztest/test3editions.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
139
internal/testprotos/editionsfuzztest/test3editions.proto
Normal file
139
internal/testprotos/editionsfuzztest/test3editions.proto
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
edition = "2023";
|
||||
|
||||
package goproto.proto.test;
|
||||
|
||||
option features.field_presence = IMPLICIT;
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/editionsfuzztest";
|
||||
|
||||
message TestAllTypesProto3Editions {
|
||||
message NestedMessage {
|
||||
int32 a = 1;
|
||||
TestAllTypesProto3Editions corecursive = 2;
|
||||
}
|
||||
|
||||
enum NestedEnum {
|
||||
FOO = 0;
|
||||
BAR = 1;
|
||||
BAZ = 2;
|
||||
NEG = -1; // Intentionally negative.
|
||||
}
|
||||
|
||||
int32 singular_int32 = 81;
|
||||
int64 singular_int64 = 82;
|
||||
uint32 singular_uint32 = 83;
|
||||
uint64 singular_uint64 = 84;
|
||||
sint32 singular_sint32 = 85;
|
||||
sint64 singular_sint64 = 86;
|
||||
fixed32 singular_fixed32 = 87;
|
||||
fixed64 singular_fixed64 = 88;
|
||||
sfixed32 singular_sfixed32 = 89;
|
||||
sfixed64 singular_sfixed64 = 90;
|
||||
float singular_float = 91;
|
||||
double singular_double = 92;
|
||||
bool singular_bool = 93;
|
||||
string singular_string = 94;
|
||||
bytes singular_bytes = 95;
|
||||
NestedMessage singular_nested_message = 98;
|
||||
ForeignMessageProto3Editions singular_foreign_message = 99;
|
||||
NestedEnum singular_nested_enum = 101;
|
||||
ForeignEnumProto3Editions singular_foreign_enum = 102;
|
||||
int32 optional_int32 = 1 [features.field_presence = EXPLICIT];
|
||||
|
||||
int64 optional_int64 = 2 [features.field_presence = EXPLICIT];
|
||||
|
||||
uint32 optional_uint32 = 3 [features.field_presence = EXPLICIT];
|
||||
|
||||
uint64 optional_uint64 = 4 [features.field_presence = EXPLICIT];
|
||||
|
||||
sint32 optional_sint32 = 5 [features.field_presence = EXPLICIT];
|
||||
|
||||
sint64 optional_sint64 = 6 [features.field_presence = EXPLICIT];
|
||||
|
||||
fixed32 optional_fixed32 = 7 [features.field_presence = EXPLICIT];
|
||||
|
||||
fixed64 optional_fixed64 = 8 [features.field_presence = EXPLICIT];
|
||||
|
||||
sfixed32 optional_sfixed32 = 9 [features.field_presence = EXPLICIT];
|
||||
|
||||
sfixed64 optional_sfixed64 = 10 [features.field_presence = EXPLICIT];
|
||||
|
||||
float optional_float = 11 [features.field_presence = EXPLICIT];
|
||||
|
||||
double optional_double = 12 [features.field_presence = EXPLICIT];
|
||||
|
||||
bool optional_bool = 13 [features.field_presence = EXPLICIT];
|
||||
|
||||
string optional_string = 14 [features.field_presence = EXPLICIT];
|
||||
|
||||
bytes optional_bytes = 15 [features.field_presence = EXPLICIT];
|
||||
|
||||
NestedMessage optional_nested_message = 18;
|
||||
ForeignMessageProto3Editions optional_foreign_message = 19;
|
||||
NestedEnum optional_nested_enum = 21 [features.field_presence = EXPLICIT];
|
||||
ForeignEnumProto3Editions optional_foreign_enum = 22 [features.field_presence = EXPLICIT];
|
||||
|
||||
repeated int32 repeated_int32 = 31;
|
||||
repeated int64 repeated_int64 = 32;
|
||||
repeated uint32 repeated_uint32 = 33;
|
||||
repeated uint64 repeated_uint64 = 34;
|
||||
repeated sint32 repeated_sint32 = 35;
|
||||
repeated sint64 repeated_sint64 = 36;
|
||||
repeated fixed32 repeated_fixed32 = 37;
|
||||
repeated fixed64 repeated_fixed64 = 38;
|
||||
repeated sfixed32 repeated_sfixed32 = 39;
|
||||
repeated sfixed64 repeated_sfixed64 = 40;
|
||||
repeated float repeated_float = 41;
|
||||
repeated double repeated_double = 42;
|
||||
repeated bool repeated_bool = 43;
|
||||
repeated string repeated_string = 44;
|
||||
repeated bytes repeated_bytes = 45;
|
||||
repeated NestedMessage repeated_nested_message = 48;
|
||||
repeated ForeignMessageProto3Editions repeated_foreign_message = 49;
|
||||
repeated NestedEnum repeated_nested_enum = 51;
|
||||
repeated ForeignEnumProto3Editions repeated_foreign_enum = 52;
|
||||
map<int32, int32> map_int32_int32 = 56;
|
||||
map<int64, int64> map_int64_int64 = 57;
|
||||
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||
map<int32, float> map_int32_float = 66;
|
||||
map<int32, double> map_int32_double = 67;
|
||||
map<bool, bool> map_bool_bool = 68;
|
||||
map<string, string> map_string_string = 69;
|
||||
map<string, bytes> map_string_bytes = 70;
|
||||
map<string, NestedMessage> map_string_nested_message = 71;
|
||||
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||
|
||||
oneof oneof_field {
|
||||
uint32 oneof_uint32 = 111;
|
||||
NestedMessage oneof_nested_message = 112;
|
||||
string oneof_string = 113;
|
||||
bytes oneof_bytes = 114;
|
||||
bool oneof_bool = 115;
|
||||
uint64 oneof_uint64 = 116;
|
||||
float oneof_float = 117;
|
||||
double oneof_double = 118;
|
||||
NestedEnum oneof_enum = 119;
|
||||
}
|
||||
}
|
||||
|
||||
message ForeignMessageProto3Editions {
|
||||
int32 c = 1;
|
||||
int32 d = 2;
|
||||
}
|
||||
|
||||
enum ForeignEnumProto3Editions {
|
||||
FOREIGN_PROTO3_EDITIONS_ZERO = 0;
|
||||
FOREIGN_PROTO3_EDITIONS_FOO = 4;
|
||||
FOREIGN_PROTO3_EDITIONS_BAR = 5;
|
||||
FOREIGN_PROTO3_EDITIONS_BAZ = 6;
|
||||
}
|
@ -35,48 +35,62 @@ func TestUnmarshalInvalidGroupField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// compareEquivalentProtos compares equivalent messages m0 and m1, where one is
|
||||
// typically a Protobuf Editions message and the other isn't. It unmarshals the
|
||||
// wireBytes into a message of type m0 and one of type m1 and compares the
|
||||
// resulting messages for equality (ignoring type names). m0 and m1 must
|
||||
// describe equivalent messages, meaning having the same field numbers and
|
||||
// types.
|
||||
func compareEquivalentProtos(t *testing.T, wireBytes []byte, m0, m1 proto.Message) {
|
||||
t.Helper()
|
||||
m0Instance := m0.ProtoReflect().Type().New().Interface()
|
||||
errM0 := proto.Unmarshal(wireBytes, m0Instance)
|
||||
m1Instance := m1.ProtoReflect().Type().New().Interface()
|
||||
errM1 := proto.Unmarshal(wireBytes, m1Instance)
|
||||
|
||||
// Check that the error are the same (possible nil)
|
||||
errorsMatch := (errM1 != nil) == (errM0 != nil)
|
||||
if errM1 != nil && errM0 != nil {
|
||||
errorsMatch = errM1.Error() == errM0.Error()
|
||||
}
|
||||
if !errorsMatch {
|
||||
t.Fatalf("errors not equal:\neditions error: %v\nproto2 error:%v", errM1, errM0)
|
||||
}
|
||||
|
||||
// Marshal the editions proto and unmarshal it into the equivalent proto2
|
||||
// message to be able to compare the messages.
|
||||
// This tests slightly more than necessary but should only lead to more
|
||||
// coverage (unless the marshalling would undo errors of the unmarshalling
|
||||
// which is very unlikely).
|
||||
roundTrippedM0 := m0.ProtoReflect().Type().New().Interface()
|
||||
err := roundTripMessage(roundTrippedM0, m1Instance)
|
||||
if err != nil {
|
||||
t.Fatalf("failed round tripping proto: %v", err)
|
||||
}
|
||||
|
||||
// The cmp package does not deal with NaN on its own and will report
|
||||
// NaN != NaN.
|
||||
optNaN64 := cmp.Comparer(func(x, y float32) bool {
|
||||
return (math.IsNaN(float64(x)) && math.IsNaN(float64(y))) || x == y
|
||||
})
|
||||
optNaN32 := cmp.Comparer(func(x, y float64) bool {
|
||||
return (math.IsNaN(x) && math.IsNaN(y)) || x == y
|
||||
})
|
||||
if diff := cmp.Diff(m0Instance, roundTrippedM0, protocmp.Transform(), optNaN64, optNaN32); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzProto2EditionConversion(f *testing.F) {
|
||||
f.Add([]byte("Hello World!"))
|
||||
f.Fuzz(func(t *testing.T, in []byte) {
|
||||
editionsProto := &testfuzzpb.TestAllTypesProto2Editions{}
|
||||
errEditions := proto.Unmarshal(in, editionsProto)
|
||||
proto2Proto := &testfuzzpb.TestAllTypesProto2{}
|
||||
errProto2 := proto.Unmarshal(in, proto2Proto)
|
||||
|
||||
// Check that the error are the same (possible nil)
|
||||
errorsMatch := (errEditions != nil) == (errProto2 != nil)
|
||||
if errEditions != nil && errProto2 != nil {
|
||||
errorsMatch = errEditions.Error() == errProto2.Error()
|
||||
}
|
||||
if !errorsMatch {
|
||||
t.Fatalf("errors not equal:\neditions error: %v\nproto2 error:%v", errEditions, errProto2)
|
||||
}
|
||||
|
||||
// Marshal the editions proto and unmarshal it into the equivalent proto2
|
||||
// message to be able to compare the messages.
|
||||
// This tests slightly more than necessary but should only lead to more
|
||||
// coverage (unless the marshalling would undo errors of the unmarshalling
|
||||
// which is very unlikely).
|
||||
marshalledEditionsProto, err := proto.Marshal(editionsProto)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal unmarshaled editions proto: %v", err)
|
||||
}
|
||||
roundTrippedProto2Proto := &testfuzzpb.TestAllTypesProto2{}
|
||||
err = proto.Unmarshal(marshalledEditionsProto, roundTrippedProto2Proto)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal marshaled editions proto into proto2 proto: %v", err)
|
||||
}
|
||||
|
||||
// The cmp package does not deal with NaN on its own and will report
|
||||
// NaN != NaN.
|
||||
optNaN64 := cmp.Comparer(func(x, y float32) bool {
|
||||
return (math.IsNaN(float64(x)) && math.IsNaN(float64(y))) || x == y
|
||||
})
|
||||
optNaN32 := cmp.Comparer(func(x, y float64) bool {
|
||||
return (math.IsNaN(x) && math.IsNaN(y)) || x == y
|
||||
})
|
||||
if diff := cmp.Diff(proto2Proto, roundTrippedProto2Proto, protocmp.Transform(), optNaN64, optNaN32); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
compareEquivalentProtos(t, in, (*testfuzzpb.TestAllTypesProto2)(nil), (*testfuzzpb.TestAllTypesProto2Editions)(nil))
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzProto3EditionConversion(f *testing.F) {
|
||||
f.Add([]byte("Hello World!"))
|
||||
f.Fuzz(func(t *testing.T, in []byte) {
|
||||
compareEquivalentProtos(t, in, (*testfuzzpb.TestAllTypesProto3)(nil), (*testfuzzpb.TestAllTypesProto3Editions)(nil))
|
||||
})
|
||||
}
|
||||
|
@ -2029,3 +2029,11 @@ func (f filterResolver) FindExtensionByNumber(message protoreflect.FullName, fie
|
||||
}
|
||||
return xt, nil
|
||||
}
|
||||
|
||||
func roundTripMessage(dst, src proto.Message) error {
|
||||
b, err := proto.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return proto.Unmarshal(b, dst)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user