internal/fuzz: add fuzzers for prototext and protojson packages
Change-Id: Iee065070e6a983c303a3551a67fc32f0e94b649e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/212219
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/cmd/generate-corpus/main.go b/internal/cmd/generate-corpus/main.go
index f566166..8f77dea 100644
--- a/internal/cmd/generate-corpus/main.go
+++ b/internal/cmd/generate-corpus/main.go
@@ -15,6 +15,8 @@
"io/ioutil"
"log"
+ "google.golang.org/protobuf/encoding/protojson"
+ "google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
@@ -115,5 +117,21 @@
if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/wirefuzz/corpus/%x", sha1.Sum(wire)), wire, 0777); err != nil {
log.Fatal(err)
}
+
+ text, err := prototext.Marshal(m)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/textfuzz/corpus/%x", sha1.Sum(text)), text, 0777); err != nil {
+ log.Fatal(err)
+ }
+
+ json, err := protojson.Marshal(m)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/jsonfuzz/corpus/%x", sha1.Sum(json)), json, 0777); err != nil {
+ log.Fatal(err)
+ }
}
}
diff --git a/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866 b/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866
new file mode 100755
index 0000000..f8b6e00
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866
@@ -0,0 +1 @@
+{"testAllTypes":{"optionalInt32":1001, "optionalInt64":"1002", "optionalUint32":1003, "optionalUint64":"1004", "optionalSint32":1005, "optionalSint64":"1006", "optionalFixed32":1007, "optionalFixed64":"1008", "optionalSfixed32":1009, "optionalSfixed64":"1010", "optionalFloat":1011.5, "optionalDouble":1012.5, "optionalBool":true, "optionalString":"string", "optionalBytes":"Ynl0ZXM=", "optionalgroup":{"a":1017}, "optionalNestedMessage":{"a":42, "corecursive":{"optionalInt32":43}}, "optionalNestedEnum":"BAR", "repeatedInt32":[1001, 2001], "repeatedInt64":["1002", "2002"], "repeatedUint32":[1003, 2003], "repeatedUint64":["1004", "2004"], "repeatedSint32":[1005, 2005], "repeatedSint64":["1006", "2006"], "repeatedFixed32":[1007, 2007], "repeatedFixed64":["1008", "2008"], "repeatedSfixed32":[1009, 2009], "repeatedSfixed64":["1010", "2010"], "repeatedFloat":[1011.5, 2011.5], "repeatedDouble":[1012.5, 2012.5], "repeatedBool":[true, false], "repeatedString":["foo", "bar"], "repeatedBytes":["Rk9P", "QkFS"], "repeatedgroup":[{"a":1017}, {}, {"a":2017}], "repeatedNestedMessage":[{"a":1}, {}, {"a":2}], "repeatedNestedEnum":["FOO", "BAR"], "mapInt32Int32":{"1056":1156, "2056":2156}, "mapInt64Int64":{"1057":"1157", "2057":"2157"}, "mapUint32Uint32":{"1058":1158, "2058":2158}, "mapUint64Uint64":{"1059":"1159", "2059":"2159"}, "mapSint32Sint32":{"1060":1160, "2060":2160}, "mapSint64Sint64":{"1061":"1161", "2061":"2161"}, "mapFixed32Fixed32":{"1062":1162, "2062":2162}, "mapFixed64Fixed64":{"1063":"1163", "2063":"2163"}, "mapSfixed32Sfixed32":{"1064":1164, "2064":2164}, "mapSfixed64Sfixed64":{"1065":"1165", "2065":"2165"}, "mapInt32Float":{"1066":1166.5, "2066":2166.5}, "mapInt32Double":{"1067":1167.5, "2067":2167.5}, "mapBoolBool":{"false":true, "true":false}, "mapStringString":{"69.1.key":"69.1.val", "69.2.key":"69.2.val"}, "mapStringBytes":{"70.1.key":"NzAuMS52YWw=", "70.2.key":"NzAuMi52YWw="}, "mapStringNestedMessage":{"71.1.key":{"a":1171}, "71.2.key":{"a":2171}}, "mapStringNestedEnum":{"73.1.key":"FOO", "73.2.key":"BAR"}, "oneofUint32":1111}}
\ No newline at end of file
diff --git a/internal/fuzz/jsonfuzz/fuzz.go b/internal/fuzz/jsonfuzz/fuzz.go
new file mode 100644
index 0000000..969ad6d
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/fuzz.go
@@ -0,0 +1,39 @@
+// Copyright 2019 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 textfuzz includes a fuzzer for the text marshaler and unmarshaler.
+package textfuzz
+
+import (
+ "google.golang.org/protobuf/encoding/protojson"
+ "google.golang.org/protobuf/proto"
+
+ fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
+)
+
+// Fuzz is a fuzzer for proto.Marshal and proto.Unmarshal.
+func Fuzz(data []byte) (score int) {
+ m1 := &fuzzpb.Fuzz{}
+ if err := (protojson.UnmarshalOptions{
+ AllowPartial: true,
+ }).Unmarshal(data, m1); err != nil {
+ return 0
+ }
+ data1, err := protojson.MarshalOptions{
+ AllowPartial: true,
+ }.Marshal(m1)
+ if err != nil {
+ panic(err)
+ }
+ m2 := &fuzzpb.Fuzz{}
+ if err := (protojson.UnmarshalOptions{
+ AllowPartial: true,
+ }).Unmarshal(data1, m2); err != nil {
+ return 0
+ }
+ if !proto.Equal(m1, m2) {
+ panic("not equal")
+ }
+ return 1
+}
diff --git a/internal/fuzz/jsonfuzz/fuzz_test.go b/internal/fuzz/jsonfuzz/fuzz_test.go
new file mode 100644
index 0000000..a0e9d0c
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/fuzz_test.go
@@ -0,0 +1,34 @@
+// Copyright 2019 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 textfuzz
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ dir, err := os.Open("corpus")
+ if err != nil {
+ t.Fatal(err)
+ }
+ infos, err := dir.Readdir(0)
+ if err != nil {
+ t.Fatal(err)
+
+ }
+ for _, info := range infos {
+ name := info.Name()
+ t.Run(name, func(t *testing.T) {
+ b, err := ioutil.ReadFile(filepath.Join("corpus", name))
+ if err != nil {
+ t.Fatal(err)
+ }
+ Fuzz(b)
+ })
+ }
+}
diff --git a/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b b/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b
new file mode 100755
index 0000000..84107dd
--- /dev/null
+++ b/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b
@@ -0,0 +1 @@
+test_all_types:{optional_int32:1001 optional_int64:1002 optional_uint32:1003 optional_uint64:1004 optional_sint32:1005 optional_sint64:1006 optional_fixed32:1007 optional_fixed64:1008 optional_sfixed32:1009 optional_sfixed64:1010 optional_float:1011.5 optional_double:1012.5 optional_bool:true optional_string:"string" optional_bytes:"bytes" OptionalGroup:{a:1017} optional_nested_message:{a:42 corecursive:{optional_int32:43}} optional_nested_enum:BAR repeated_int32:1001 repeated_int32:2001 repeated_int64:1002 repeated_int64:2002 repeated_uint32:1003 repeated_uint32:2003 repeated_uint64:1004 repeated_uint64:2004 repeated_sint32:1005 repeated_sint32:2005 repeated_sint64:1006 repeated_sint64:2006 repeated_fixed32:1007 repeated_fixed32:2007 repeated_fixed64:1008 repeated_fixed64:2008 repeated_sfixed32:1009 repeated_sfixed32:2009 repeated_sfixed64:1010 repeated_sfixed64:2010 repeated_float:1011.5 repeated_float:2011.5 repeated_double:1012.5 repeated_double:2012.5 repeated_bool:true repeated_bool:false repeated_string:"foo" repeated_string:"bar" repeated_bytes:"FOO" repeated_bytes:"BAR" RepeatedGroup:{a:1017} RepeatedGroup:{} RepeatedGroup:{a:2017} repeated_nested_message:{a:1} repeated_nested_message:{} repeated_nested_message:{a:2} repeated_nested_enum:FOO repeated_nested_enum:BAR map_int32_int32:{key:1056 value:1156} map_int32_int32:{key:2056 value:2156} map_int64_int64:{key:1057 value:1157} map_int64_int64:{key:2057 value:2157} map_uint32_uint32:{key:1058 value:1158} map_uint32_uint32:{key:2058 value:2158} map_uint64_uint64:{key:1059 value:1159} map_uint64_uint64:{key:2059 value:2159} map_sint32_sint32:{key:1060 value:1160} map_sint32_sint32:{key:2060 value:2160} map_sint64_sint64:{key:1061 value:1161} map_sint64_sint64:{key:2061 value:2161} map_fixed32_fixed32:{key:1062 value:1162} map_fixed32_fixed32:{key:2062 value:2162} map_fixed64_fixed64:{key:1063 value:1163} map_fixed64_fixed64:{key:2063 value:2163} map_sfixed32_sfixed32:{key:1064 value:1164} map_sfixed32_sfixed32:{key:2064 value:2164} map_sfixed64_sfixed64:{key:1065 value:1165} map_sfixed64_sfixed64:{key:2065 value:2165} map_int32_float:{key:1066 value:1166.5} map_int32_float:{key:2066 value:2166.5} map_int32_double:{key:1067 value:1167.5} map_int32_double:{key:2067 value:2167.5} map_bool_bool:{key:false value:true} map_bool_bool:{key:true value:false} map_string_string:{key:"69.1.key" value:"69.1.val"} map_string_string:{key:"69.2.key" value:"69.2.val"} map_string_bytes:{key:"70.1.key" value:"70.1.val"} map_string_bytes:{key:"70.2.key" value:"70.2.val"} map_string_nested_message:{key:"71.1.key" value:{a:1171}} map_string_nested_message:{key:"71.2.key" value:{a:2171}} map_string_nested_enum:{key:"73.1.key" value:FOO} map_string_nested_enum:{key:"73.2.key" value:BAR} oneof_uint32:1111}
\ No newline at end of file
diff --git a/internal/fuzz/textfuzz/fuzz.go b/internal/fuzz/textfuzz/fuzz.go
new file mode 100644
index 0000000..bd89da0
--- /dev/null
+++ b/internal/fuzz/textfuzz/fuzz.go
@@ -0,0 +1,39 @@
+// Copyright 2019 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 textfuzz includes a fuzzer for the text marshaler and unmarshaler.
+package textfuzz
+
+import (
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
+
+ fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
+)
+
+// Fuzz is a fuzzer for proto.Marshal and proto.Unmarshal.
+func Fuzz(data []byte) (score int) {
+ m1 := &fuzzpb.Fuzz{}
+ if err := (prototext.UnmarshalOptions{
+ AllowPartial: true,
+ }).Unmarshal(data, m1); err != nil {
+ return 0
+ }
+ data1, err := prototext.MarshalOptions{
+ AllowPartial: true,
+ }.Marshal(m1)
+ if err != nil {
+ panic(err)
+ }
+ m2 := &fuzzpb.Fuzz{}
+ if err := (prototext.UnmarshalOptions{
+ AllowPartial: true,
+ }).Unmarshal(data1, m2); err != nil {
+ return 0
+ }
+ if !proto.Equal(m1, m2) {
+ panic("not equal")
+ }
+ return 1
+}
diff --git a/internal/fuzz/textfuzz/fuzz_test.go b/internal/fuzz/textfuzz/fuzz_test.go
new file mode 100644
index 0000000..a0e9d0c
--- /dev/null
+++ b/internal/fuzz/textfuzz/fuzz_test.go
@@ -0,0 +1,34 @@
+// Copyright 2019 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 textfuzz
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ dir, err := os.Open("corpus")
+ if err != nil {
+ t.Fatal(err)
+ }
+ infos, err := dir.Readdir(0)
+ if err != nil {
+ t.Fatal(err)
+
+ }
+ for _, info := range infos {
+ name := info.Name()
+ t.Run(name, func(t *testing.T) {
+ b, err := ioutil.ReadFile(filepath.Join("corpus", name))
+ if err != nil {
+ t.Fatal(err)
+ }
+ Fuzz(b)
+ })
+ }
+}