From 0fd4f3a506894c05a9cad2d52c521a8ce953b49d Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Mon, 10 Aug 2020 10:46:34 -0700 Subject: [PATCH] encoding/protojson: restrict valid values for google.protobuf.Value.number_value The purpose of struct.proto is to be an exact mapping of JSON in protobufs. Since JSON doesn't support NaN and Inf, we should reject serialization of such values. Prior to this CL, they would be serialzed as a JSON string, which would change the interpretation of the value when round-tripped. Fixes golang/protobuf#1182 Change-Id: I6dba9973b1c24d99e5688b509611c0a952c00022 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/247737 Reviewed-by: Damien Neil Reviewed-by: Herbie Ong --- encoding/protojson/encode_test.go | 12 ++++++++++++ encoding/protojson/well_known_types.go | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/encoding/protojson/encode_test.go b/encoding/protojson/encode_test.go index 5e1570a4..f1a05fe1 100644 --- a/encoding/protojson/encode_test.go +++ b/encoding/protojson/encode_test.go @@ -1255,6 +1255,18 @@ func TestMarshal(t *testing.T) { {}, [] ]`, + }, { + desc: "Value with NaN", + input: structpb.NewNumberValue(math.NaN()), + wantErr: true, + }, { + desc: "Value with -Inf", + input: structpb.NewNumberValue(math.Inf(-1)), + wantErr: true, + }, { + desc: "Value with +Inf", + input: structpb.NewNumberValue(math.Inf(+1)), + wantErr: true, }, { desc: "Struct with nil map", input: &structpb.Struct{}, diff --git a/encoding/protojson/well_known_types.go b/encoding/protojson/well_known_types.go index 7a2fde33..72924a90 100644 --- a/encoding/protojson/well_known_types.go +++ b/encoding/protojson/well_known_types.go @@ -7,6 +7,7 @@ package protojson import ( "bytes" "fmt" + "math" "strconv" "strings" "time" @@ -495,6 +496,11 @@ func (e encoder) marshalKnownValue(m pref.Message) error { if fd == nil { return errors.New("%s: none of the oneof fields is set", genid.Value_message_fullname) } + if fd.Number() == genid.Value_NumberValue_field_number { + if v := m.Get(fd).Float(); math.IsNaN(v) || math.IsInf(v, 0) { + return errors.New("%s: invalid %v value", genid.Value_NumberValue_field_fullname, v) + } + } return e.marshalSingular(m.Get(fd), fd) }