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 <dneil@google.com>
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/encoding/protojson/encode_test.go b/encoding/protojson/encode_test.go
index 5e1570a..f1a05fe 100644
--- a/encoding/protojson/encode_test.go
+++ b/encoding/protojson/encode_test.go
@@ -1256,6 +1256,18 @@
   []
 ]`,
 	}, {
+		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{},
 		want:  `{}`,
diff --git a/encoding/protojson/well_known_types.go b/encoding/protojson/well_known_types.go
index 7a2fde3..72924a9 100644
--- a/encoding/protojson/well_known_types.go
+++ b/encoding/protojson/well_known_types.go
@@ -7,6 +7,7 @@
 import (
 	"bytes"
 	"fmt"
+	"math"
 	"strconv"
 	"strings"
 	"time"
@@ -495,6 +496,11 @@
 	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)
 }