Expect fail when serialize inf and nan for Value.number_value in json format. fixes #11259

Implemented in java, c++, python and upb. Also added conformance test.

https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Value
where it says:
attempting to serialize NaN or Infinity results in error. (We can't serialize these as string "NaN" or "Infinity" values like we do for regular fields, because they would parse as string_value, not number_value).

PiperOrigin-RevId: 500828964
pull/11507/head
Jie Luo 2 years ago committed by Copybara-Service
parent 2d6ee175e2
commit ca1cb1ba80
  1. 4
      conformance/binary_json_conformance_suite.cc
  2. 2
      conformance/failure_list_ruby.txt
  3. 16
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  4. 12
      src/google/protobuf/json/internal/unparser.cc

@ -3334,6 +3334,10 @@ void BinaryAndJsonConformanceSuite::RunJsonTestsForValue() {
return value.empty();
},
true);
ExpectSerializeFailureForJson("ValueRejectNanNumberValue", RECOMMENDED,
"optional_value: { number_value: nan}");
ExpectSerializeFailureForJson("ValueRejectInfNumberValue", RECOMMENDED,
"optional_value: { number_value: inf}");
}
void BinaryAndJsonConformanceSuite::RunJsonTestsForAny() {

@ -58,3 +58,5 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.UnpackedOu
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.UnpackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.UnpackedOutput.ProtobufOutput
Recommended.ValueRejectInfNumberValue.JsonOutput
Recommended.ValueRejectNanNumberValue.JsonOutput

@ -51,7 +51,6 @@ import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor.Type;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.DoubleValue;
@ -966,7 +965,16 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Invalid Value type.");
}
for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
printSingleFieldValue(entry.getKey(), entry.getValue());
FieldDescriptor field = entry.getKey();
if (field.getType() == FieldDescriptor.Type.DOUBLE) {
Double doubleValue = (Double) entry.getValue();
if (doubleValue.isNaN() || doubleValue.isInfinite()) {
throw new IllegalArgumentException(
"google.protobuf.Value cannot encode double values for "
+ "infinity or nan, because they would be parsed as a string.");
}
}
printSingleFieldValue(field, entry.getValue());
}
}
@ -1683,7 +1691,7 @@ public class JsonFormat {
Object key = parseFieldValue(keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
Object value = parseFieldValue(valueField, entry.getValue(), entryBuilder);
if (value == null) {
if (ignoringUnknownFields && valueField.getType() == Type.ENUM) {
if (ignoringUnknownFields && valueField.getType() == FieldDescriptor.Type.ENUM) {
continue;
} else {
throw new InvalidProtocolBufferException("Map value cannot be null.");
@ -1724,7 +1732,7 @@ public class JsonFormat {
for (int i = 0; i < array.size(); ++i) {
Object value = parseFieldValue(field, array.get(i), builder);
if (value == null) {
if (ignoringUnknownFields && field.getType() == Type.ENUM) {
if (ignoringUnknownFields && field.getType() == FieldDescriptor.Type.ENUM) {
continue;
} else {
throw new InvalidProtocolBufferException(

@ -34,6 +34,7 @@
#include <complex>
#include <cstdint>
#include <cstring>
#include <limits>
#include <memory>
#include <sstream>
#include <string>
@ -489,6 +490,17 @@ absl::Status WriteValue(JsonWriter& writer, const Msg<Traits>& msg,
if (Traits::GetSize(number_field, msg) > 0) {
auto x = Traits::GetDouble(number_field, msg);
RETURN_IF_ERROR(x.status());
if (std::isnan(*x)) {
return absl::InvalidArgumentError(
"google.protobuf.Value cannot encode double values for nan, "
"because it would be parsed as a string");
}
if (*x == std::numeric_limits<double>::infinity() ||
*x == -std::numeric_limits<double>::infinity()) {
return absl::InvalidArgumentError(
"google.protobuf.Value cannot encode double values for "
"infinity, because it would be parsed as a string");
}
writer.Write(*x);
return absl::OkStatus();
}

Loading…
Cancel
Save