Skip to content

Commit 8a5ed79

Browse files
authored
Merge pull request #622 from jmarais/master
Upstream commits from golang/protobuf
2 parents 3f2ed6d + 33d4760 commit 8a5ed79

File tree

5 files changed

+84
-28
lines changed

5 files changed

+84
-28
lines changed

jsonpb/jsonpb.go

100755100644
+21-7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import (
5656
)
5757

5858
const secondInNanos = int64(time.Second / time.Nanosecond)
59+
const maxSecondsInDuration = 315576000000
5960

6061
// Marshaler is a configurable object for converting between
6162
// protocol buffer objects and a JSON representation for them.
@@ -163,6 +164,11 @@ type isWkt interface {
163164
XXX_WellKnownType() string
164165
}
165166

167+
var (
168+
wktType = reflect.TypeOf((*isWkt)(nil)).Elem()
169+
messageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
170+
)
171+
166172
// marshalObject writes a struct to the Writer.
167173
func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeURL string) error {
168174
if jsm, ok := v.(JSONPBMarshaler); ok {
@@ -210,19 +216,26 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
210216
// Any is a bit more involved.
211217
return m.marshalAny(out, v, indent)
212218
case "Duration":
213-
// "Generated output always contains 0, 3, 6, or 9 fractional digits,
214-
// depending on required precision."
215219
s, ns := s.Field(0).Int(), s.Field(1).Int()
220+
if s < -maxSecondsInDuration || s > maxSecondsInDuration {
221+
return fmt.Errorf("seconds out of range %v", s)
222+
}
216223
if ns <= -secondInNanos || ns >= secondInNanos {
217224
return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
218225
}
219226
if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
220227
return errors.New("signs of seconds and nanos do not match")
221228
}
222-
if s < 0 {
229+
// Generated output always contains 0, 3, 6, or 9 fractional digits,
230+
// depending on required precision, followed by the suffix "s".
231+
f := "%d.%09d"
232+
if ns < 0 {
223233
ns = -ns
234+
if s == 0 {
235+
f = "-%d.%09d"
236+
}
224237
}
225-
x := fmt.Sprintf("%d.%09d", s, ns)
238+
x := fmt.Sprintf(f, s, ns)
226239
x = strings.TrimSuffix(x, "000")
227240
x = strings.TrimSuffix(x, "000")
228241
x = strings.TrimSuffix(x, ".000")
@@ -543,7 +556,8 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle
543556

544557
// Handle well-known types.
545558
// Most are handled up in marshalObject (because 99% are messages).
546-
if wkt, ok := v.Interface().(isWkt); ok {
559+
if v.Type().Implements(wktType) {
560+
wkt := v.Interface().(isWkt)
547561
switch wkt.XXX_WellKnownType() {
548562
case "NullValue":
549563
out.write("null")
@@ -1414,8 +1428,8 @@ func checkRequiredFields(pb proto.Message) error {
14141428
}
14151429

14161430
func checkRequiredFieldsInValue(v reflect.Value) error {
1417-
if pm, ok := v.Interface().(proto.Message); ok {
1418-
return checkRequiredFields(pm)
1431+
if v.Type().Implements(messageType) {
1432+
return checkRequiredFields(v.Interface().(proto.Message))
14191433
}
14201434
return nil
14211435
}

jsonpb/jsonpb_test.go

100755100644
+25-16
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ var (
363363
An: &types.Any{
364364
TypeUrl: "type.googleapis.com/google.protobuf.Duration",
365365
Value: []byte{
366-
// &durpb.Duration{Seconds: 1, Nanos: 212000000 }
366+
// &types.Duration{Seconds: 1, Nanos: 212000000 }
367367
1 << 3, 1, // seconds
368368
2 << 3, 0x80, 0xba, 0x8b, 0x65, // nanos
369369
},
@@ -472,10 +472,18 @@ var marshalingTests = []struct {
472472
{"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON},
473473
{"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON},
474474
{"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON},
475-
{"Duration", marshaler, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3}}, `{"dur":"3s"}`},
476-
{"Duration", marshaler, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3, Nanos: 1e6}}, `{"dur":"3.001s"}`},
477-
{"Duration beyond float64 precision", marshaler, &pb.KnownTypes{Dur: &types.Duration{Seconds: 100000000, Nanos: 1}}, `{"dur":"100000000.000000001s"}`},
478-
{"negative Duration", marshaler, &pb.KnownTypes{Dur: &types.Duration{Seconds: -123, Nanos: -456}}, `{"dur":"-123.000000456s"}`},
475+
{"Duration empty", marshaler, &types.Duration{}, `"0s"`},
476+
{"Duration with secs", marshaler, &types.Duration{Seconds: 3}, `"3s"`},
477+
{"Duration with -secs", marshaler, &types.Duration{Seconds: -3}, `"-3s"`},
478+
{"Duration with nanos", marshaler, &types.Duration{Nanos: 1e6}, `"0.001s"`},
479+
{"Duration with -nanos", marshaler, &types.Duration{Nanos: -1e6}, `"-0.001s"`},
480+
{"Duration with large secs", marshaler, &types.Duration{Seconds: 1e10, Nanos: 1}, `"10000000000.000000001s"`},
481+
{"Duration with 6-digit nanos", marshaler, &types.Duration{Nanos: 1e4}, `"0.000010s"`},
482+
{"Duration with 3-digit nanos", marshaler, &types.Duration{Nanos: 1e6}, `"0.001s"`},
483+
{"Duration with -secs -nanos", marshaler, &types.Duration{Seconds: -123, Nanos: -450}, `"-123.000000450s"`},
484+
{"Duration max value", marshaler, &types.Duration{Seconds: 315576000000, Nanos: 999999999}, `"315576000000.999999999s"`},
485+
{"Duration small negative", marshaler, &types.Duration{Nanos: -1}, `"-0.000000001s"`},
486+
{"Duration min value", marshaler, &types.Duration{Seconds: -315576000000, Nanos: -999999999}, `"-315576000000.999999999s"`},
479487
{"Struct", marshaler, &pb.KnownTypes{St: &types.Struct{
480488
Fields: map[string]*types.Value{
481489
"one": {Kind: &types.Value_StringValue{StringValue: "loneliest number"}},
@@ -546,15 +554,17 @@ func TestMarshalIllegalTime(t *testing.T) {
546554
pb proto.Message
547555
fail bool
548556
}{
549-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: 1, Nanos: 0}}, false},
550-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: -1, Nanos: 0}}, false},
551-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: 1, Nanos: -1}}, true},
552-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: -1, Nanos: 1}}, true},
553-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: 1, Nanos: 1000000000}}, true},
554-
{&pb.KnownTypes{Dur: &types.Duration{Seconds: -1, Nanos: -1000000000}}, true},
555-
{&pb.KnownTypes{Ts: &types.Timestamp{Seconds: 1, Nanos: 1}}, false},
556-
{&pb.KnownTypes{Ts: &types.Timestamp{Seconds: 1, Nanos: -1}}, true},
557-
{&pb.KnownTypes{Ts: &types.Timestamp{Seconds: 1, Nanos: 1000000000}}, true},
557+
{&types.Duration{Seconds: 1, Nanos: 0}, false},
558+
{&types.Duration{Seconds: -1, Nanos: 0}, false},
559+
{&types.Duration{Seconds: 1, Nanos: -1}, true},
560+
{&types.Duration{Seconds: -1, Nanos: 1}, true},
561+
{&types.Duration{Seconds: 315576000001}, true},
562+
{&types.Duration{Seconds: -315576000001}, true},
563+
{&types.Duration{Seconds: 1, Nanos: 1000000000}, true},
564+
{&types.Duration{Seconds: -1, Nanos: -1000000000}, true},
565+
{&types.Timestamp{Seconds: 1, Nanos: 1}, false},
566+
{&types.Timestamp{Seconds: 1, Nanos: -1}, true},
567+
{&types.Timestamp{Seconds: 1, Nanos: 1000000000}, true},
558568
}
559569
for _, tt := range tests {
560570
_, err := marshaler.MarshalToString(tt.pb)
@@ -604,8 +614,7 @@ func TestMarshalAnyJSONPBMarshaler(t *testing.T) {
604614
t.Errorf("an unexpected error occurred when marshalling Any to JSON: %v", err)
605615
}
606616
// same as expected above, but pretty-printed w/ indentation
607-
expected =
608-
`{
617+
expected = `{
609618
"@type": "type.googleapis.com/` + dynamicMessageName + `",
610619
"baz": [
611620
0,

proto/all_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ import (
4545
"testing"
4646
"time"
4747

48+
"github.com/gogo/protobuf/jsonpb"
4849
. "github.com/gogo/protobuf/proto"
4950
pb3 "github.com/gogo/protobuf/proto/proto3_proto"
5051
. "github.com/gogo/protobuf/proto/test_proto"
52+
descriptorpb "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
5153
)
5254

5355
var globalO *Buffer
@@ -2509,3 +2511,33 @@ func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) {
25092511
p2.Unmarshal(pbd)
25102512
}
25112513
}
2514+
2515+
// TestRace tests whether there are races among the different marshalers.
2516+
func TestRace(t *testing.T) {
2517+
m := &descriptorpb.FileDescriptorProto{
2518+
Options: &descriptorpb.FileOptions{
2519+
GoPackage: String("path/to/my/package"),
2520+
},
2521+
}
2522+
2523+
wg := &sync.WaitGroup{}
2524+
defer wg.Wait()
2525+
2526+
wg.Add(1)
2527+
go func() {
2528+
defer wg.Done()
2529+
Marshal(m)
2530+
}()
2531+
2532+
wg.Add(1)
2533+
go func() {
2534+
defer wg.Done()
2535+
(&jsonpb.Marshaler{}).MarshalToString(m)
2536+
}()
2537+
2538+
wg.Add(1)
2539+
go func() {
2540+
defer wg.Done()
2541+
_ = m.String()
2542+
}()
2543+
}

proto/properties.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ package proto
4343
import (
4444
"fmt"
4545
"log"
46-
"os"
4746
"reflect"
4847
"sort"
4948
"strconv"
@@ -205,7 +204,7 @@ func (p *Properties) Parse(s string) {
205204
// "bytes,49,opt,name=foo,def=hello!"
206205
fields := strings.Split(s, ",") // breaks def=, but handled below.
207206
if len(fields) < 2 {
208-
fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
207+
log.Printf("proto: tag has too few fields: %q", s)
209208
return
210209
}
211210

@@ -225,7 +224,7 @@ func (p *Properties) Parse(s string) {
225224
p.WireType = WireBytes
226225
// no numeric converter for non-numeric types
227226
default:
228-
fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
227+
log.Printf("proto: tag has unknown wire type: %q", s)
229228
return
230229
}
231230

proto/text.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
476476
return nil
477477
}
478478

479+
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
480+
479481
// writeAny writes an arbitrary field.
480482
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
481483
v = reflect.Indirect(v)
@@ -589,8 +591,8 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
589591
// mutating this value.
590592
v = v.Addr()
591593
}
592-
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
593-
text, err := etm.MarshalText()
594+
if v.Type().Implements(textMarshalerType) {
595+
text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
594596
if err != nil {
595597
return err
596598
}

0 commit comments

Comments
 (0)